1 /* 2 * Copyright (c) 2015, 2018, 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.nio.file.Files; 29 import java.nio.file.Path; 30 import java.nio.file.Paths; 31 import java.util.ArrayList; 32 import java.util.Collections; 33 import java.util.List; 34 import java.util.spi.ToolProvider; 35 import java.util.stream.Stream; 36 37 import jdk.tools.jlink.plugin.Plugin; 38 import jdk.tools.jlink.internal.PluginRepository; 39 import tests.Helper; 40 import tests.JImageGenerator; 41 42 /* 43 * @test 44 * @summary Test image creation 45 * @bug 8189777 46 * @bug 8194922 47 * @bug 8206962 48 * @author Jean-Francois Denise 49 * @requires (vm.compMode != "Xcomp" & os.maxMemory >= 2g) 50 * @library ../lib 51 * @modules java.base/jdk.internal.jimage 52 * jdk.jdeps/com.sun.tools.classfile 53 * jdk.jlink/jdk.tools.jlink.internal 54 * jdk.jlink/jdk.tools.jlink.plugin 55 * jdk.jlink/jdk.tools.jimage 56 * jdk.compiler 57 * @build tests.* 58 * @run main/othervm -Xmx1g JLinkTest 59 */ 60 public class JLinkTest { 61 static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink") 62 .orElseThrow(() -> 63 new RuntimeException("jlink tool not found") 64 ); 65 66 // number of built-in plugins from jdk.jlink module 67 private static int getNumJlinkPlugins() { 68 ModuleDescriptor desc = Plugin.class.getModule().getDescriptor(); 69 return desc.provides().stream() 70 .filter(p -> p.service().equals(Plugin.class.getName())) 71 .map(p -> p.providers().size()) 72 .findAny() 73 .orElse(0); 74 } 75 76 private static boolean isOfJLinkModule(Plugin p) { 77 return p.getClass().getModule() == Plugin.class.getModule(); 78 } 79 80 public static void main(String[] args) throws Exception { 81 82 Helper helper = Helper.newHelper(); 83 if (helper == null) { 84 System.err.println("Test not run"); 85 return; 86 } 87 helper.generateDefaultModules(); 88 // expected num. of plugins from jdk.jlink module 89 int expectedJLinkPlugins = getNumJlinkPlugins(); 90 int totalPlugins = 0; 91 { 92 // number of built-in plugins 93 List<Plugin> builtInPlugins = new ArrayList<>(); 94 builtInPlugins.addAll(PluginRepository.getPlugins(ModuleLayer.boot())); 95 totalPlugins = builtInPlugins.size(); 96 // actual num. of plugins loaded from jdk.jlink module 97 int actualJLinkPlugins = 0; 98 for (Plugin p : builtInPlugins) { 99 p.getState(); 100 p.getType(); 101 if (isOfJLinkModule(p)) { 102 actualJLinkPlugins++; 103 } 104 } 105 if (expectedJLinkPlugins != actualJLinkPlugins) { 106 throw new AssertionError("Actual plugins loaded from jdk.jlink: " + 107 actualJLinkPlugins + " which doesn't match expected number : " + 108 expectedJLinkPlugins); 109 } 110 } 111 112 { 113 // No --module-path specified. $JAVA_HOME/jmods should be assumed. 114 // The following should succeed as it uses only system modules. 115 String imageDir = "bug818977-no-modulepath"; 116 JImageGenerator.getJLinkTask() 117 .output(helper.createNewImageDir(imageDir)) 118 .addMods("jdk.scripting.nashorn") 119 .call().assertSuccess(); 120 } 121 122 { 123 // invalid --module-path specified. java.base not found it it. 124 // $JAVA_HOME/jmods should be added automatically. 125 // The following should succeed as it uses only system modules. 126 String imageDir = "bug8189777-invalid-modulepath"; 127 JImageGenerator.getJLinkTask() 128 .modulePath("does_not_exist_path") 129 .output(helper.createNewImageDir(imageDir)) 130 .addMods("jdk.scripting.nashorn") 131 .call().assertSuccess(); 132 } 133 134 { 135 // No --module-path specified. --add-modules ALL-MODULE-PATH specified. 136 String imageDir = "bug8189777-all-module-path"; 137 JImageGenerator.getJLinkTask() 138 .output(helper.createNewImageDir(imageDir)) 139 .addMods("ALL-MODULE-PATH") 140 .call().assertSuccess(); 141 } 142 143 { 144 String moduleName = "bug8134651"; 145 JImageGenerator.getJLinkTask() 146 .modulePath(helper.defaultModulePath()) 147 .output(helper.createNewImageDir(moduleName)) 148 .addMods("leaf1") 149 .call().assertSuccess(); 150 JImageGenerator.getJLinkTask() 151 .modulePath(helper.defaultModulePath()) 152 .addMods("leaf1") 153 .option("--output") 154 .call().assertFailure("Error: no value given for --output"); 155 JImageGenerator.getJLinkTask() 156 .modulePath("") 157 .output(helper.createNewImageDir(moduleName)) 158 .addMods("leaf1") 159 .call().assertFailure("Error: no value given for --module-path"); 160 // do not include standard module path - should be added automatically 161 JImageGenerator.getJLinkTask() 162 .modulePath(helper.defaultModulePath(false)) 163 .output(helper.createNewImageDir(moduleName)) 164 .addMods("leaf1") 165 .call().assertSuccess(); 166 // no --module-path. default sys mod path is assumed - but that won't contain 'leaf1' module 167 JImageGenerator.getJLinkTask() 168 .output(helper.createNewImageDir(moduleName)) 169 .addMods("leaf1") 170 .call().assertFailure("Error: Module leaf1 not found"); 171 } 172 173 { 174 String moduleName = "m"; // 8163382 175 Path jmod = helper.generateDefaultJModule(moduleName).assertSuccess(); 176 JImageGenerator.getJLinkTask() 177 .modulePath(helper.defaultModulePath()) 178 .output(helper.createNewImageDir(moduleName)) 179 .addMods("m") 180 .call().assertSuccess(); 181 moduleName = "mod"; 182 jmod = helper.generateDefaultJModule(moduleName).assertSuccess(); 183 JImageGenerator.getJLinkTask() 184 .modulePath(helper.defaultModulePath()) 185 .output(helper.createNewImageDir(moduleName)) 186 .addMods("m") 187 .call().assertSuccess(); 188 } 189 190 { 191 String moduleName = "m_8165735"; // JDK-8165735 192 helper.generateDefaultJModule(moduleName+"dependency").assertSuccess(); 193 Path jmod = helper.generateDefaultJModule(moduleName, moduleName+"dependency").assertSuccess(); 194 JImageGenerator.getJLinkTask() 195 .modulePath(helper.defaultModulePath()) 196 .repeatedModulePath(".") // second --module-path overrides the first one 197 .output(helper.createNewImageDir(moduleName)) 198 .addMods(moduleName) 199 // second --module-path does not have that module 200 .call().assertFailure("Error: Module m_8165735 not found"); 201 202 JImageGenerator.getJLinkTask() 203 .modulePath(".") // first --module-path overridden later 204 .repeatedModulePath(helper.defaultModulePath()) 205 .output(helper.createNewImageDir(moduleName)) 206 .addMods(moduleName) 207 // second --module-path has that module 208 .call().assertSuccess(); 209 210 JImageGenerator.getJLinkTask() 211 .modulePath(helper.defaultModulePath()) 212 .output(helper.createNewImageDir(moduleName)) 213 .limitMods(moduleName) 214 .repeatedLimitMods("java.base") // second --limit-modules overrides first 215 .addMods(moduleName) 216 .call().assertFailure("Error: Module m_8165735dependency not found, required by m_8165735"); 217 218 JImageGenerator.getJLinkTask() 219 .modulePath(helper.defaultModulePath()) 220 .output(helper.createNewImageDir(moduleName)) 221 .limitMods("java.base") 222 .repeatedLimitMods(moduleName) // second --limit-modules overrides first 223 .addMods(moduleName) 224 .call().assertSuccess(); 225 } 226 227 { 228 // Help 229 StringWriter writer = new StringWriter(); 230 PrintWriter pw = new PrintWriter(writer); 231 JLINK_TOOL.run(pw, pw, "--help"); 232 String output = writer.toString(); 233 if (output.split("\n").length < 10) { 234 System.err.println(output); 235 throw new AssertionError("Help"); 236 } 237 } 238 239 { 240 // List plugins 241 StringWriter writer = new StringWriter(); 242 PrintWriter pw = new PrintWriter(writer); 243 244 JLINK_TOOL.run(pw, pw, "--list-plugins"); 245 String output = writer.toString(); 246 long number = Stream.of(output.split("\\R")) 247 .filter((s) -> s.matches("Plugin Name:.*")) 248 .count(); 249 if (number != totalPlugins) { 250 System.err.println(output); 251 throw new AssertionError("Found: " + number + " expected " + totalPlugins); 252 } 253 } 254 255 // filter out files and resources + Skip debug + compress 256 { 257 String[] userOptions = {"--compress", "2", "--strip-debug", 258 "--exclude-resources", "*.jcov, */META-INF/*", "--exclude-files", 259 "*" + Helper.getDebugSymbolsExtension()}; 260 String moduleName = "excludezipskipdebugcomposite2"; 261 helper.generateDefaultJModule(moduleName, "composite2"); 262 String[] res = {".jcov", "/META-INF/"}; 263 String[] files = {Helper.getDebugSymbolsExtension()}; 264 Path imageDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess(); 265 helper.checkImage(imageDir, moduleName, res, files); 266 } 267 268 // filter out + Skip debug + compress with filter + sort resources 269 { 270 String[] userOptions2 = {"--compress=2:compress-filter=^/java.base/*", 271 "--strip-debug", "--exclude-resources", 272 "*.jcov, */META-INF/*", "--order-resources", 273 "*/module-info.class,/sortcomposite2/*,*/javax/management/*"}; 274 String moduleName = "excludezipfilterskipdebugcomposite2"; 275 helper.generateDefaultJModule(moduleName, "composite2"); 276 String[] res = {".jcov", "/META-INF/"}; 277 Path imageDir = helper.generateDefaultImage(userOptions2, moduleName).assertSuccess(); 278 helper.checkImage(imageDir, moduleName, res, null); 279 } 280 281 // module-info.class should not be excluded 282 { 283 String[] userOptions = { "--exclude-resources", "/jdk_8194922/module-info.class" }; 284 String moduleName = "jdk_8194922"; 285 helper.generateDefaultJModule(moduleName); 286 helper.generateDefaultImage(userOptions, moduleName). 287 assertFailure("Cannot exclude /jdk_8194922/module-info.class"); 288 } 289 290 // default compress 291 { 292 testCompress(helper, "compresscmdcomposite2", "--compress", "2"); 293 } 294 295 { 296 testCompress(helper, "compressfiltercmdcomposite2", 297 "--compress=2:filter=^/java.base/java/lang/*"); 298 } 299 300 // compress 0 301 { 302 testCompress(helper, "compress0filtercmdcomposite2", 303 "--compress=0:filter=^/java.base/java/lang/*"); 304 } 305 306 // compress 1 307 { 308 testCompress(helper, "compress1filtercmdcomposite2", 309 "--compress=1:filter=^/java.base/java/lang/*"); 310 } 311 312 // compress 2 313 { 314 testCompress(helper, "compress2filtercmdcomposite2", 315 "--compress=2:filter=^/java.base/java/lang/*"); 316 } 317 318 // invalid compress level 319 { 320 String[] userOptions = {"--compress", "invalid"}; 321 String moduleName = "invalidCompressLevel"; 322 helper.generateDefaultJModule(moduleName, "composite2"); 323 helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: Invalid compression level invalid"); 324 } 325 326 // orphan argument - JDK-8166810 327 { 328 String[] userOptions = {"--compress", "2", "foo" }; 329 String moduleName = "orphanarg1"; 330 helper.generateDefaultJModule(moduleName, "composite2"); 331 helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: invalid argument: foo"); 332 } 333 334 // orphan argument - JDK-8166810 335 { 336 String[] userOptions = {"--output", "foo", "bar" }; 337 String moduleName = "orphanarg2"; 338 helper.generateDefaultJModule(moduleName, "composite2"); 339 helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: invalid argument: bar"); 340 } 341 342 // basic check for --help - JDK-8173717 343 { 344 JImageGenerator.getJLinkTask() 345 .option("--help") 346 .call().assertSuccess(); 347 } 348 349 { 350 String imageDir = "bug8206962"; 351 JImageGenerator.getJLinkTask() 352 .modulePath(helper.defaultModulePath()) 353 .output(helper.createNewImageDir(imageDir)) 354 .addMods("java.base") 355 .option("--release-info=del") 356 .call().assertFailure("Error: No key specified for delete"); 357 } 358 } 359 360 private static void testCompress(Helper helper, String moduleName, String... userOptions) throws IOException { 361 helper.generateDefaultJModule(moduleName, "composite2"); 362 Path imageDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess(); 363 helper.checkImage(imageDir, moduleName, null, null); 364 } 365 }