1 /* 2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 import java.io.IOException; 25 import java.io.PrintWriter; 26 import java.io.StringWriter; 27 import java.lang.module.ModuleDescriptor; 28 import java.lang.reflect.Layer; 29 import java.nio.file.Files; 30 import java.nio.file.Path; 31 import java.nio.file.Paths; 32 import java.util.ArrayList; 33 import java.util.Collections; 34 import java.util.List; 35 import java.util.spi.ToolProvider; 36 import java.util.stream.Stream; 37 38 import jdk.tools.jlink.plugin.Plugin; 39 import jdk.tools.jlink.internal.PluginRepository; 40 import tests.Helper; 41 import tests.JImageGenerator; 42 43 /* 44 * @test 45 * @summary Test image creation 46 * @author Jean-Francois Denise 47 * @library ../lib 48 * @modules java.base/jdk.internal.jimage 49 * jdk.jdeps/com.sun.tools.classfile 50 * jdk.jlink/jdk.tools.jlink.internal 51 * jdk.jlink/jdk.tools.jimage 52 * jdk.compiler 53 * @build tests.* 54 * @run main/othervm -Xmx1g JLinkTest 55 */ 56 public class JLinkTest { 57 static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink") 58 .orElseThrow(() -> 59 new RuntimeException("jlink tool not found") 60 ); 61 62 // number of built-in plugins from jdk.jlink module 63 private static int getNumJlinkPlugins() { 64 ModuleDescriptor desc = Plugin.class.getModule().getDescriptor(); 65 return desc.provides().stream() 66 .filter(p -> p.service().equals(Plugin.class.getName())) 67 .map(p -> p.providers().size()) 68 .findAny() 69 .orElse(0); 70 } 71 72 private static boolean isOfJLinkModule(Plugin p) { 73 return p.getClass().getModule() == Plugin.class.getModule(); 74 } 75 76 public static void main(String[] args) throws Exception { 77 78 Helper helper = Helper.newHelper(); 79 if (helper == null) { 80 System.err.println("Test not run"); 81 return; 82 } 83 helper.generateDefaultModules(); 84 // expected num. of plugins from jdk.jlink module 85 int expectedJLinkPlugins = getNumJlinkPlugins(); 86 int totalPlugins = 0; 87 { 88 // number of built-in plugins 89 List<Plugin> builtInPlugins = new ArrayList<>(); 90 builtInPlugins.addAll(PluginRepository.getPlugins(Layer.boot())); 91 totalPlugins = builtInPlugins.size(); 92 // actual num. of plugins loaded from jdk.jlink module 93 int actualJLinkPlugins = 0; 94 for (Plugin p : builtInPlugins) { 95 p.getState(); 96 p.getType(); 97 if (isOfJLinkModule(p)) { 98 actualJLinkPlugins++; 99 } 100 } 101 if (expectedJLinkPlugins != actualJLinkPlugins) { 102 throw new AssertionError("Actual plugins loaded from jdk.jlink: " + 103 actualJLinkPlugins + " which doesn't match expected number : " + 104 expectedJLinkPlugins); 105 } 106 } 107 108 { 109 String moduleName = "bug8134651"; 110 JImageGenerator.getJLinkTask() 111 .modulePath(helper.defaultModulePath()) 112 .output(helper.createNewImageDir(moduleName)) 113 .addMods("leaf1") 114 .call().assertSuccess(); 115 JImageGenerator.getJLinkTask() 116 .modulePath(helper.defaultModulePath()) 117 .addMods("leaf1") 118 .option("--output") 119 .call().assertFailure("Error: no value given for --output"); 120 JImageGenerator.getJLinkTask() 121 .modulePath("") 122 .output(helper.createNewImageDir(moduleName)) 123 .addMods("leaf1") 124 .call().assertFailure("Error: no value given for --module-path"); 125 } 126 127 { 128 String moduleName = "m"; // 8163382 129 Path jmod = helper.generateDefaultJModule(moduleName).assertSuccess(); 130 JImageGenerator.getJLinkTask() 131 .modulePath(helper.defaultModulePath()) 132 .output(helper.createNewImageDir(moduleName)) 133 .addMods("m") 134 .call().assertSuccess(); 135 moduleName = "mod"; 136 jmod = helper.generateDefaultJModule(moduleName).assertSuccess(); 137 JImageGenerator.getJLinkTask() 138 .modulePath(helper.defaultModulePath()) 139 .output(helper.createNewImageDir(moduleName)) 140 .addMods("m") 141 .call().assertSuccess(); 142 } 143 144 { 145 String moduleName = "m_8165735"; // JDK-8165735 146 helper.generateDefaultJModule(moduleName+"dependency").assertSuccess(); 147 Path jmod = helper.generateDefaultJModule(moduleName, moduleName+"dependency").assertSuccess(); 148 JImageGenerator.getJLinkTask() 149 .modulePath(helper.defaultModulePath()) 150 .repeatedModulePath(".") // second --module-path overrides the first one 151 .output(helper.createNewImageDir(moduleName)) 152 .addMods(moduleName) 153 // second --module-path does not have that module 154 .call().assertFailure("Error: Module m_8165735 not found"); 155 156 JImageGenerator.getJLinkTask() 157 .modulePath(".") // first --module-path overridden later 158 .repeatedModulePath(helper.defaultModulePath()) 159 .output(helper.createNewImageDir(moduleName)) 160 .addMods(moduleName) 161 // second --module-path has that module 162 .call().assertSuccess(); 163 164 JImageGenerator.getJLinkTask() 165 .modulePath(helper.defaultModulePath()) 166 .output(helper.createNewImageDir(moduleName)) 167 .limitMods(moduleName) 168 .repeatedLimitMods("java.base") // second --limit-modules overrides first 169 .addMods(moduleName) 170 .call().assertFailure("Error: Module m_8165735dependency not found, required by m_8165735"); 171 172 JImageGenerator.getJLinkTask() 173 .modulePath(helper.defaultModulePath()) 174 .output(helper.createNewImageDir(moduleName)) 175 .limitMods("java.base") 176 .repeatedLimitMods(moduleName) // second --limit-modules overrides first 177 .addMods(moduleName) 178 .call().assertSuccess(); 179 } 180 181 { 182 // Help 183 StringWriter writer = new StringWriter(); 184 PrintWriter pw = new PrintWriter(writer); 185 JLINK_TOOL.run(pw, pw, "--help"); 186 String output = writer.toString(); 187 if (output.split("\n").length < 10) { 188 System.err.println(output); 189 throw new AssertionError("Help"); 190 } 191 } 192 193 { 194 // License files 195 Path file = Paths.get("LICENSE"); 196 Files.createFile(file); 197 String copied = "LICENSE"; 198 String[] arr = copied.split(","); 199 String[] copyFiles = new String[2]; 200 copyFiles[0] = "--copy-files"; 201 copyFiles[1] = file.toAbsolutePath().toString(); 202 Path imageDir = helper.generateDefaultImage(copyFiles, "composite2").assertSuccess(); 203 helper.checkImage(imageDir, "composite2", null, null, arr); 204 } 205 206 { 207 // List plugins 208 StringWriter writer = new StringWriter(); 209 PrintWriter pw = new PrintWriter(writer); 210 211 JLINK_TOOL.run(pw, pw, "--list-plugins"); 212 String output = writer.toString(); 213 long number = Stream.of(output.split("\\R")) 214 .filter((s) -> s.matches("Plugin Name:.*")) 215 .count(); 216 if (number != totalPlugins) { 217 System.err.println(output); 218 throw new AssertionError("Found: " + number + " expected " + totalPlugins); 219 } 220 } 221 222 // filter out files and resources + Skip debug + compress 223 { 224 String[] userOptions = {"--compress", "2", "--strip-debug", 225 "--exclude-resources", "*.jcov, */META-INF/*", "--exclude-files", 226 "*" + Helper.getDebugSymbolsExtension()}; 227 String moduleName = "excludezipskipdebugcomposite2"; 228 helper.generateDefaultJModule(moduleName, "composite2"); 229 String[] res = {".jcov", "/META-INF/"}; 230 String[] files = {Helper.getDebugSymbolsExtension()}; 231 Path imageDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess(); 232 helper.checkImage(imageDir, moduleName, res, files); 233 } 234 235 // filter out + Skip debug + compress with filter + sort resources 236 { 237 String[] userOptions2 = {"--compress=2:compress-filter=^/java.base/*", 238 "--strip-debug", "--exclude-resources", 239 "*.jcov, */META-INF/*", "--order-resources", 240 "*/module-info.class,/sortcomposite2/*,*/javax/management/*"}; 241 String moduleName = "excludezipfilterskipdebugcomposite2"; 242 helper.generateDefaultJModule(moduleName, "composite2"); 243 String[] res = {".jcov", "/META-INF/"}; 244 Path imageDir = helper.generateDefaultImage(userOptions2, moduleName).assertSuccess(); 245 helper.checkImage(imageDir, moduleName, res, null); 246 } 247 248 // default compress 249 { 250 testCompress(helper, "compresscmdcomposite2", "--compress", "2"); 251 } 252 253 { 254 testCompress(helper, "compressfiltercmdcomposite2", 255 "--compress=2:filter=^/java.base/java/lang/*"); 256 } 257 258 // compress 0 259 { 260 testCompress(helper, "compress0filtercmdcomposite2", 261 "--compress=0:filter=^/java.base/java/lang/*"); 262 } 263 264 // compress 1 265 { 266 testCompress(helper, "compress1filtercmdcomposite2", 267 "--compress=1:filter=^/java.base/java/lang/*"); 268 } 269 270 // compress 2 271 { 272 testCompress(helper, "compress2filtercmdcomposite2", 273 "--compress=2:filter=^/java.base/java/lang/*"); 274 } 275 276 // invalid compress level 277 { 278 String[] userOptions = {"--compress", "invalid"}; 279 String moduleName = "invalidCompressLevel"; 280 helper.generateDefaultJModule(moduleName, "composite2"); 281 helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: Invalid compression level invalid"); 282 } 283 284 // orphan argument - JDK-8166810 285 { 286 String[] userOptions = {"--compress", "2", "foo" }; 287 String moduleName = "orphanarg1"; 288 helper.generateDefaultJModule(moduleName, "composite2"); 289 helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: orphan argument: foo"); 290 } 291 292 // orphan argument - JDK-8166810 293 { 294 String[] userOptions = {"--output", "foo", "bar" }; 295 String moduleName = "orphanarg2"; 296 helper.generateDefaultJModule(moduleName, "composite2"); 297 helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: orphan argument: bar"); 298 } 299 } 300 301 private static void testCompress(Helper helper, String moduleName, String... userOptions) throws IOException { 302 helper.generateDefaultJModule(moduleName, "composite2"); 303 Path imageDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess(); 304 helper.checkImage(imageDir, moduleName, null, null); 305 } 306 }