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