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