1 /* 2 * Copyright (c) 2016, 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 /* 25 * @test 26 * @bug 8170859 27 * @summary Basic test for incubator modules in jmods and images 28 * @library /lib/testlibrary /test/lib 29 * @key intermittent 30 * @modules jdk.compiler jdk.jartool jdk.jlink 31 * @build jdk.test.lib.Platform 32 * jdk.test.lib.util.FileUtils 33 * jdk.test.lib.compiler.CompilerUtils 34 * @run testng/othervm ImageModules 35 */ 36 37 import java.io.ByteArrayOutputStream; 38 import java.io.File; 39 import java.io.IOException; 40 import java.io.PrintStream; 41 import java.nio.file.Files; 42 import java.nio.file.Path; 43 import java.nio.file.Paths; 44 import java.util.List; 45 import java.util.function.Consumer; 46 import java.util.spi.ToolProvider; 47 import java.util.stream.Collectors; 48 import java.util.stream.Stream; 49 50 import jdk.test.lib.compiler.CompilerUtils; 51 import jdk.test.lib.util.FileUtils; 52 import org.testng.annotations.BeforeTest; 53 import org.testng.annotations.DataProvider; 54 import org.testng.annotations.Test; 55 56 import static java.nio.charset.StandardCharsets.UTF_8; 57 import static jdk.testlibrary.ProcessTools.executeCommand; 58 import static org.testng.Assert.*; 59 60 public class ImageModules { 61 private static final String JAVA_HOME = System.getProperty("java.home"); 62 private static final Path JDK_JMODS = Paths.get(JAVA_HOME, "jmods"); 63 64 private static final Path TEST_SRC = Paths.get(System.getProperty("test.src")); 65 private static final Path MODS_DIR = Paths.get("mods"); 66 private static final Path CP_DIR = Paths.get("cp"); 67 private static final Path JARS_DIR = Paths.get("jars"); 68 private static final Path JMODS_DIR = Paths.get("jmods"); 69 private static final Path IMAGE = Paths.get("image"); 70 71 private static final String JAVA_BASE = "java.base"; 72 private final String[] modules = new String[] { "message.writer", 73 "message.converter" }; 74 75 @BeforeTest 76 private void setup() throws Throwable { 77 Path src = TEST_SRC.resolve("src"); 78 for (String name : modules) { 79 assertTrue(CompilerUtils.compile(src.resolve(name), 80 MODS_DIR, 81 "--module-source-path", src.toString())); 82 } 83 84 assertTrue(CompilerUtils.compile(src.resolve("cp"), 85 CP_DIR, 86 "--module-path", MODS_DIR.toString(), 87 "--add-modules", "message.writer")); 88 } 89 90 @DataProvider(name = "singleModule") 91 public Object[][] singleModuleValues() throws IOException { 92 Object[][] values = new Object[][]{ 93 // { Extra args to the build the message.converter jmod 94 // Tokens to pass to the run time --add-modules option 95 // SUCCESS or FAILURE expected 96 // Messages expected in the run time output 97 // Messages that must not appear in the run time output }, 98 { "", 99 List.of("ALL-DEFAULT", "ALL-SYSTEM"), 100 ToolResult.ASSERT_SUCCESS, 101 List.of("hello world", "message.converter", "java.base"), 102 List.of("WARNING") }, 103 { "--do-not-resolve-by-default", 104 List.of("ALL-DEFAULT"), 105 ToolResult.ASSERT_FAILURE, 106 List.of("java.base", "java.lang.ClassNotFoundException: converter.MessageConverter"), 107 List.of("WARNING", "message.converter") }, 108 { "--warn-if-resolved=incubating", 109 List.of("ALL-DEFAULT", "ALL-SYSTEM"), 110 ToolResult.ASSERT_SUCCESS, 111 List.of("hello world", "message.converter", "java.base", 112 "WARNING: Using incubator modules: message.converter"), 113 List.of() }, 114 { "--do-not-resolve-by-default --warn-if-resolved=incubating", 115 List.of("ALL-DEFAULT"), 116 ToolResult.ASSERT_FAILURE, 117 List.of("java.base", "java.lang.ClassNotFoundException: converter.MessageConverter"), 118 List.of("WARNING", "message.converter") }, 119 { "--do-not-resolve-by-default --warn-if-resolved=incubating", 120 List.of("message.converter"), 121 ToolResult.ASSERT_SUCCESS, 122 List.of("hello world", "message.converter", "java.base", "WARNING"), 123 List.of() } 124 }; 125 return values; 126 } 127 128 @Test(dataProvider = "singleModule") 129 public void singleModule(String extraJmodArg, 130 List<String> addModsTokens, 131 Consumer<ToolResult> assertExitCode, 132 List<String> expectedOutput, 133 List<String> unexpectedOutput) 134 throws Throwable 135 { 136 if (Files.notExists(JDK_JMODS)) { 137 System.out.println("JDK jmods not found test cannot run."); 138 return; 139 } 140 141 FileUtils.deleteFileTreeUnchecked(JMODS_DIR); 142 FileUtils.deleteFileTreeUnchecked(IMAGE); 143 Files.createDirectories(JMODS_DIR); 144 Path converterJmod = JMODS_DIR.resolve("converter.jmod"); 145 146 jmod("create", 147 "--class-path", MODS_DIR.resolve("message.converter").toString(), 148 extraJmodArg, 149 converterJmod.toString()) 150 .assertSuccess(); 151 152 String mpath = JDK_JMODS.toString() + File.pathSeparator + JMODS_DIR.toString(); 153 jlink("--module-path", mpath, 154 "--add-modules", JAVA_BASE + ",message.converter", 155 "--output", IMAGE.toString()) 156 .assertSuccess(); 157 158 for (String addModsToken : addModsTokens) { 159 String[] props = new String[] {"", "-Djdk.system.module.finder.disabledFastPath"}; 160 for (String systemProp : props) 161 java(IMAGE, 162 systemProp, 163 "--add-modules", addModsToken, 164 "-cp", CP_DIR.toString(), 165 "test.ConvertToLowerCase", "HEllo WoRlD") 166 .resultChecker(assertExitCode) 167 .resultChecker(r -> { 168 expectedOutput.forEach(e -> r.assertContains(e)); 169 unexpectedOutput.forEach(e -> r.assertDoesNotContains(e)); 170 }); 171 } 172 } 173 174 @Test 175 public void singleModularJar() throws Throwable { 176 FileUtils.deleteFileTreeUnchecked(JARS_DIR); 177 Files.createDirectories(JARS_DIR); 178 Path converterJar = JARS_DIR.resolve("converter.jar"); 179 180 jar("--create", 181 "--file", converterJar.toString(), 182 "--warn-if-resolved=incubating", 183 "-C", MODS_DIR.resolve("message.converter").toString() , ".") 184 .assertSuccess(); 185 186 187 java(Paths.get(JAVA_HOME), 188 "--module-path", JARS_DIR.toString(), 189 "--add-modules", "message.converter", 190 "-cp", CP_DIR.toString(), 191 "test.ConvertToLowerCase", "HEllo WoRlD") 192 .assertSuccess() 193 .resultChecker(r -> { 194 r.assertContains("WARNING: Using incubator modules: message.converter"); 195 }); 196 } 197 198 @DataProvider(name = "twoModules") 199 public Object[][] twoModulesValues() throws IOException { 200 Object[][] values = new Object[][]{ 201 // { Extra args to the build the message.writer jmod 202 // Extra args to the build the message.converter jmod 203 // Tokens to pass to the run time --add-modules option 204 // SUCCESS or FAILURE expected 205 // Messages expected in the run time output 206 // Messages that must not appear in the run time output }, 207 { "", 208 "", 209 List.of("ALL-DEFAULT", "ALL-SYSTEM"), 210 ToolResult.ASSERT_SUCCESS, 211 List.of("HELLO CHEGAR !!!", "message.writer", "message.converter", "java.base"), 212 List.of() }, 213 { "", 214 "--do-not-resolve-by-default", 215 List.of("ALL-DEFAULT", "ALL-SYSTEM"), 216 ToolResult.ASSERT_SUCCESS, 217 List.of("HELLO CHEGAR !!!", "message.writer", "message.converter", "java.base"), 218 List.of() }, 219 { "--do-not-resolve-by-default", 220 "", 221 List.of("ALL-DEFAULT"), 222 ToolResult.ASSERT_FAILURE, 223 List.of("java.lang.ClassNotFoundException: writer.MessageWriter", "java.base"), 224 List.of("message.writer") }, 225 { "--do-not-resolve-by-default", 226 "--do-not-resolve-by-default", 227 List.of("ALL-DEFAULT"), 228 ToolResult.ASSERT_FAILURE, 229 List.of("java.lang.ClassNotFoundException: writer.MessageWriter", "java.base"), 230 List.of("message.converter", "message.writer") }, 231 // now add in warnings 232 { "--do-not-resolve-by-default --warn-if-resolved=incubating", 233 "", 234 List.of("message.writer"), 235 ToolResult.ASSERT_SUCCESS, 236 List.of("HELLO CHEGAR !!!", "message.writer", "message.converter", "java.base", 237 "WARNING: Using incubator modules: message.writer"), 238 List.of() }, 239 { "", 240 "--do-not-resolve-by-default --warn-if-resolved=incubating", 241 List.of("message.writer"), 242 ToolResult.ASSERT_SUCCESS, 243 List.of("HELLO CHEGAR !!!", "message.writer", "message.converter", "java.base", 244 "WARNING: Using incubator modules: message.converter"), 245 List.of() } 246 }; 247 return values; 248 } 249 250 @Test(dataProvider = "twoModules") 251 public void doNotResolveByDefaultTwoModules(String extraFirstJmodArg, 252 String extraSecondJmodArg, 253 List<String> addModsTokens, 254 Consumer<ToolResult> assertExitCode, 255 List<String> expectedOutput, 256 List<String> unexpectedOutput) 257 throws Throwable 258 { 259 if (Files.notExists(JDK_JMODS)) { 260 System.out.println("JDK jmods not found test cannot run."); 261 return; 262 } 263 264 FileUtils.deleteFileTreeUnchecked(JMODS_DIR); 265 FileUtils.deleteFileTreeUnchecked(IMAGE); 266 Files.createDirectories(JMODS_DIR); 267 Path writerJmod = JMODS_DIR.resolve("writer.jmod"); 268 Path converterJmod = JMODS_DIR.resolve("converter.jmod"); 269 270 jmod("create", 271 extraFirstJmodArg, 272 "--class-path", MODS_DIR.resolve("message.writer").toString(), 273 writerJmod.toString()); 274 275 jmod("create", 276 "--class-path", MODS_DIR.resolve("message.converter").toString(), 277 extraSecondJmodArg, 278 converterJmod.toString()) 279 .assertSuccess(); 280 281 String mpath = JDK_JMODS.toString() + File.pathSeparator + JMODS_DIR.toString(); 282 jlink("--module-path", mpath, 283 "--add-modules", JAVA_BASE + ",message.writer,message.converter", 284 "--output", IMAGE.toString()) 285 .assertSuccess(); 286 287 for (String addModsToken : addModsTokens) { 288 String[] props = new String[] {"", "-Djdk.system.module.finder.disabledFastPath"}; 289 for (String systemProp : props) 290 java(IMAGE, 291 systemProp, 292 "--add-modules", addModsToken, 293 "-cp", CP_DIR.toString(), 294 "test.WriteUpperCase", "hello chegar !!!") 295 .resultChecker(assertExitCode) 296 .resultChecker(r -> { 297 expectedOutput.forEach(e -> r.assertContains(e)); 298 unexpectedOutput.forEach(e -> r.assertDoesNotContains(e)); 299 }); 300 } 301 } 302 303 static final ToolProvider JMOD_TOOL = ToolProvider.findFirst("jmod") 304 .orElseThrow(() -> new RuntimeException("jmod tool not found")); 305 static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar") 306 .orElseThrow(() -> new RuntimeException("jar tool not found")); 307 static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink") 308 .orElseThrow(() -> new RuntimeException("jlink tool not found")); 309 310 static ToolResult jmod(String... args) { return execTool(JMOD_TOOL, args); } 311 312 static ToolResult jar(String... args) { return execTool(JAR_TOOL, args); } 313 314 static ToolResult jlink(String... args) { return execTool(JLINK_TOOL, args); } 315 316 static ToolResult java(Path image, String... opts) throws Throwable { 317 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 318 PrintStream ps = new PrintStream(baos); 319 String[] options = Stream.concat(Stream.of(getJava(image)), 320 Stream.of(opts).filter(s -> !s.equals(""))) 321 .toArray(String[]::new); 322 323 ProcessBuilder pb = new ProcessBuilder(options); 324 int exitValue = executeCommand(pb).outputTo(ps) 325 .errorTo(ps) 326 .getExitValue(); 327 328 return new ToolResult(exitValue, new String(baos.toByteArray(), UTF_8)); 329 } 330 331 static ToolResult execTool(ToolProvider tool, String... args) { 332 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 333 PrintStream ps = new PrintStream(baos); 334 List<String> filteredArgs = Stream.of(args) 335 .map(s -> s.split(" ")).flatMap(Stream::of) 336 .filter(s -> !s.equals("")) 337 .collect(Collectors.toList()); 338 System.out.println(tool + " " + filteredArgs); 339 int ec = tool.run(ps, ps, filteredArgs.toArray(new String[] {})); 340 return new ToolResult(ec, new String(baos.toByteArray(), UTF_8)); 341 } 342 343 static class ToolResult { 344 final int exitCode; 345 final String output; 346 347 ToolResult(int exitValue, String output) { 348 this.exitCode = exitValue; 349 this.output = output; 350 } 351 352 static Consumer<ToolResult> ASSERT_SUCCESS = r -> 353 assertEquals(r.exitCode, 0, 354 "Expected exit code 0, got " + r.exitCode 355 + ", with output[" + r.output + "]"); 356 static Consumer<ToolResult> ASSERT_FAILURE = r -> 357 assertNotEquals(r.exitCode, 0, 358 "Expected exit code != 0, got " + r.exitCode 359 + ", with output[" + r.output + "]"); 360 361 ToolResult assertSuccess() { ASSERT_SUCCESS.accept(this); return this; } 362 ToolResult assertFailure() { ASSERT_FAILURE.accept(this); return this; } 363 ToolResult resultChecker(Consumer<ToolResult> r) { r.accept(this); return this; } 364 365 ToolResult assertContains(String subString) { 366 assertTrue(output.contains(subString), 367 "Expected to find [" + subString + "], in output [" 368 + output + "]" + "\n"); 369 return this; 370 } 371 ToolResult assertDoesNotContains(String subString) { 372 assertFalse(output.contains(subString), 373 "Expected to NOT find [" + subString + "], in output [" 374 + output + "]" + "\n"); 375 return this; 376 } 377 } 378 379 static String getJava(Path image) { 380 boolean isWindows = System.getProperty("os.name").startsWith("Windows"); 381 Path java = image.resolve("bin").resolve(isWindows ? "java.exe" : "java"); 382 if (Files.notExists(java)) 383 throw new RuntimeException(java + " not found"); 384 return java.toAbsolutePath().toString(); 385 } 386 }