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 /* 25 * @test 26 * @bug 8142968 8166568 8166286 8170618 8168149 27 * @summary Basic test for jmod 28 * @library /test/lib 29 * @modules jdk.compiler 30 * jdk.jlink 31 * @build jdk.test.lib.compiler.CompilerUtils 32 * jdk.test.lib.util.FileUtils 33 * jdk.test.lib.Platform 34 * @run testng/othervm -Djava.io.tmpdir=. JmodTest 35 */ 36 37 import java.io.*; 38 import java.lang.module.ModuleDescriptor; 39 import java.lang.reflect.Method; 40 import java.nio.file.*; 41 import java.util.*; 42 import java.util.function.Consumer; 43 import java.util.regex.Pattern; 44 import java.util.spi.ToolProvider; 45 import java.util.stream.Stream; 46 import jdk.test.lib.compiler.CompilerUtils; 47 import jdk.test.lib.util.FileUtils; 48 import org.testng.annotations.BeforeTest; 49 import org.testng.annotations.Test; 50 51 import static java.io.File.pathSeparator; 52 import static java.lang.module.ModuleDescriptor.Version; 53 import static java.nio.charset.StandardCharsets.UTF_8; 54 import static java.util.stream.Collectors.toSet; 55 import static org.testng.Assert.*; 56 57 public class JmodTest { 58 59 static final ToolProvider JMOD_TOOL = ToolProvider.findFirst("jmod") 60 .orElseThrow(() -> 61 new RuntimeException("jmod tool not found") 62 ); 63 64 static final String TEST_SRC = System.getProperty("test.src", "."); 65 static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); 66 static final Path EXPLODED_DIR = Paths.get("build"); 67 static final Path MODS_DIR = Paths.get("jmods"); 68 69 static final String CLASSES_PREFIX = "classes/"; 70 static final String CMDS_PREFIX = "bin/"; 71 static final String LIBS_PREFIX = "lib/"; 72 static final String CONFIGS_PREFIX = "conf/"; 73 74 @BeforeTest 75 public void buildExplodedModules() throws IOException { 76 if (Files.exists(EXPLODED_DIR)) 77 FileUtils.deleteFileTreeWithRetry(EXPLODED_DIR); 78 79 for (String name : new String[] { "foo"/*, "bar", "baz"*/ } ) { 80 Path dir = EXPLODED_DIR.resolve(name); 81 assertTrue(compileModule(name, dir.resolve("classes"))); 82 copyResource(SRC_DIR.resolve("foo"), 83 dir.resolve("classes"), 84 "jdk/test/foo/resources/foo.properties"); 85 createCmds(dir.resolve("bin")); 86 createLibs(dir.resolve("lib")); 87 createConfigs(dir.resolve("conf")); 88 } 89 90 if (Files.exists(MODS_DIR)) 91 FileUtils.deleteFileTreeWithRetry(MODS_DIR); 92 Files.createDirectories(MODS_DIR); 93 } 94 95 // JDK-8166286 - jmod fails on symlink to directory 96 @Test 97 public void testSymlinks() throws IOException { 98 Path apaDir = EXPLODED_DIR.resolve("apa"); 99 Path classesDir = EXPLODED_DIR.resolve("apa").resolve("classes"); 100 assertTrue(compileModule("apa", classesDir)); 101 Path libDir = apaDir.resolve("lib"); 102 createFiles(libDir, List.of("foo/bar/libfoo.so")); 103 try { 104 Path link = Files.createSymbolicLink( 105 libDir.resolve("baz"), libDir.resolve("foo").toAbsolutePath()); 106 assertTrue(Files.exists(link)); 107 } catch (IOException|UnsupportedOperationException uoe) { 108 // OS does not support symlinks. Nothing to test! 109 return; 110 } 111 112 Path jmod = MODS_DIR.resolve("apa.jmod"); 113 jmod("create", 114 "--libs=" + libDir.toString(), 115 "--class-path", classesDir.toString(), 116 jmod.toString()) 117 .assertSuccess(); 118 } 119 120 // JDK-8170618 - jmod should validate if any exported or open package is missing 121 @Test 122 public void testMissingPackages() throws IOException { 123 Path apaDir = EXPLODED_DIR.resolve("apa"); 124 Path classesDir = EXPLODED_DIR.resolve("apa").resolve("classes"); 125 if (Files.exists(classesDir)) 126 FileUtils.deleteFileTreeWithRetry(classesDir); 127 assertTrue(compileModule("apa", classesDir)); 128 FileUtils.deleteFileTreeWithRetry(classesDir.resolve("jdk")); 129 Path jmod = MODS_DIR.resolve("apa.jmod"); 130 jmod("create", 131 "--class-path", classesDir.toString(), 132 jmod.toString()) 133 .assertFailure() 134 .resultChecker(r -> { 135 assertContains(r.output, "Packages that are exported or open in apa are not present: [jdk.test.apa]"); 136 }); 137 if (Files.exists(classesDir)) 138 FileUtils.deleteFileTreeWithRetry(classesDir); 139 } 140 141 @Test 142 public void testList() throws IOException { 143 String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); 144 jmod("create", 145 "--class-path", cp, 146 MODS_DIR.resolve("foo.jmod").toString()) 147 .assertSuccess(); 148 149 jmod("list", 150 MODS_DIR.resolve("foo.jmod").toString()) 151 .assertSuccess() 152 .resultChecker(r -> { 153 // asserts dependent on the exact contents of foo 154 assertContains(r.output, CLASSES_PREFIX + "module-info.class"); 155 assertContains(r.output, CLASSES_PREFIX + "jdk/test/foo/Foo.class"); 156 assertContains(r.output, CLASSES_PREFIX + "jdk/test/foo/internal/Message.class"); 157 assertContains(r.output, CLASSES_PREFIX + "jdk/test/foo/resources/foo.properties"); 158 }); 159 } 160 161 @Test 162 public void testExtractCWD() throws IOException { 163 Path cp = EXPLODED_DIR.resolve("foo").resolve("classes"); 164 jmod("create", 165 "--class-path", cp.toString(), 166 MODS_DIR.resolve("fooExtractCWD.jmod").toString()) 167 .assertSuccess(); 168 169 jmod("extract", 170 MODS_DIR.resolve("fooExtractCWD.jmod").toString()) 171 .assertSuccess() 172 .resultChecker(r -> { 173 // module-info should exist, but jmod will have added its Packages attr. 174 assertTrue(Files.exists(Paths.get("classes/module-info.class"))); 175 assertSameContent(cp.resolve("jdk/test/foo/Foo.class"), 176 Paths.get("classes/jdk/test/foo/Foo.class")); 177 assertSameContent(cp.resolve("jdk/test/foo/internal/Message.class"), 178 Paths.get("classes/jdk/test/foo/internal/Message.class")); 179 assertSameContent(cp.resolve("jdk/test/foo/resources/foo.properties"), 180 Paths.get("classes/jdk/test/foo/resources/foo.properties")); 181 }); 182 } 183 184 @Test 185 public void testExtractDir() throws IOException { 186 if (Files.exists(Paths.get("extractTestDir"))) 187 FileUtils.deleteFileTreeWithRetry(Paths.get("extractTestDir")); 188 Path cp = EXPLODED_DIR.resolve("foo").resolve("classes"); 189 Path bp = EXPLODED_DIR.resolve("foo").resolve("bin"); 190 Path lp = EXPLODED_DIR.resolve("foo").resolve("lib"); 191 Path cf = EXPLODED_DIR.resolve("foo").resolve("conf"); 192 193 jmod("create", 194 "--conf", cf.toString(), 195 "--cmds", bp.toString(), 196 "--libs", lp.toString(), 197 "--class-path", cp.toString(), 198 MODS_DIR.resolve("fooExtractDir.jmod").toString()) 199 .assertSuccess(); 200 201 jmod("extract", 202 "--dir", "extractTestDir", 203 MODS_DIR.resolve("fooExtractDir.jmod").toString()) 204 .assertSuccess(); 205 206 jmod("extract", 207 "--dir", "extractTestDir", 208 MODS_DIR.resolve("fooExtractDir.jmod").toString()) 209 .assertSuccess() 210 .resultChecker(r -> { 211 // check a sample of the extracted files 212 Path p = Paths.get("extractTestDir"); 213 assertTrue(Files.exists(p.resolve("classes/module-info.class"))); 214 assertSameContent(cp.resolve("jdk/test/foo/Foo.class"), 215 p.resolve("classes/jdk/test/foo/Foo.class")); 216 assertSameContent(bp.resolve("first"), 217 p.resolve(CMDS_PREFIX).resolve("first")); 218 assertSameContent(lp.resolve("first.so"), 219 p.resolve(LIBS_PREFIX).resolve("second.so")); 220 assertSameContent(cf.resolve("second.cfg"), 221 p.resolve(CONFIGS_PREFIX).resolve("second.cfg")); 222 }); 223 } 224 225 @Test 226 public void testMainClass() throws IOException { 227 Path jmod = MODS_DIR.resolve("fooMainClass.jmod"); 228 FileUtils.deleteFileIfExistsWithRetry(jmod); 229 String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); 230 231 jmod("create", 232 "--class-path", cp, 233 "--main-class", "jdk.test.foo.Foo", 234 jmod.toString()) 235 .assertSuccess() 236 .resultChecker(r -> { 237 Optional<String> omc = getModuleDescriptor(jmod).mainClass(); 238 assertTrue(omc.isPresent()); 239 assertEquals(omc.get(), "jdk.test.foo.Foo"); 240 }); 241 } 242 243 @Test 244 public void testModuleVersion() throws IOException { 245 Path jmod = MODS_DIR.resolve("fooVersion.jmod"); 246 FileUtils.deleteFileIfExistsWithRetry(jmod); 247 String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); 248 249 jmod("create", 250 "--class-path", cp, 251 "--module-version", "5.4.3", 252 jmod.toString()) 253 .assertSuccess() 254 .resultChecker(r -> { 255 Optional<Version> ov = getModuleDescriptor(jmod).version(); 256 assertTrue(ov.isPresent()); 257 assertEquals(ov.get().toString(), "5.4.3"); 258 }); 259 } 260 261 @Test 262 public void testConfig() throws IOException { 263 Path jmod = MODS_DIR.resolve("fooConfig.jmod"); 264 FileUtils.deleteFileIfExistsWithRetry(jmod); 265 Path cp = EXPLODED_DIR.resolve("foo").resolve("classes"); 266 Path cf = EXPLODED_DIR.resolve("foo").resolve("conf"); 267 268 jmod("create", 269 "--class-path", cp.toString(), 270 "--config", cf.toString(), 271 jmod.toString()) 272 .assertSuccess() 273 .resultChecker(r -> { 274 try (Stream<String> s1 = findFiles(cf).map(p -> CONFIGS_PREFIX + p); 275 Stream<String> s2 = findFiles(cp).map(p -> CLASSES_PREFIX + p)) { 276 Set<String> expectedFilenames = Stream.concat(s1, s2) 277 .collect(toSet()); 278 assertJmodContent(jmod, expectedFilenames); 279 } 280 }); 281 } 282 283 @Test 284 public void testCmds() throws IOException { 285 Path jmod = MODS_DIR.resolve("fooCmds.jmod"); 286 FileUtils.deleteFileIfExistsWithRetry(jmod); 287 Path cp = EXPLODED_DIR.resolve("foo").resolve("classes"); 288 Path bp = EXPLODED_DIR.resolve("foo").resolve("bin"); 289 290 jmod("create", 291 "--cmds", bp.toString(), 292 "--class-path", cp.toString(), 293 jmod.toString()) 294 .assertSuccess() 295 .resultChecker(r -> { 296 try (Stream<String> s1 = findFiles(bp).map(p -> CMDS_PREFIX + p); 297 Stream<String> s2 = findFiles(cp).map(p -> CLASSES_PREFIX + p)) { 298 Set<String> expectedFilenames = Stream.concat(s1,s2) 299 .collect(toSet()); 300 assertJmodContent(jmod, expectedFilenames); 301 } 302 }); 303 } 304 305 @Test 306 public void testLibs() throws IOException { 307 Path jmod = MODS_DIR.resolve("fooLibs.jmod"); 308 FileUtils.deleteFileIfExistsWithRetry(jmod); 309 Path cp = EXPLODED_DIR.resolve("foo").resolve("classes"); 310 Path lp = EXPLODED_DIR.resolve("foo").resolve("lib"); 311 312 jmod("create", 313 "--libs=" + lp.toString(), 314 "--class-path", cp.toString(), 315 jmod.toString()) 316 .assertSuccess() 317 .resultChecker(r -> { 318 try (Stream<String> s1 = findFiles(lp).map(p -> LIBS_PREFIX + p); 319 Stream<String> s2 = findFiles(cp).map(p -> CLASSES_PREFIX + p)) { 320 Set<String> expectedFilenames = Stream.concat(s1,s2) 321 .collect(toSet()); 322 assertJmodContent(jmod, expectedFilenames); 323 } 324 }); 325 } 326 327 @Test 328 public void testAll() throws IOException { 329 Path jmod = MODS_DIR.resolve("fooAll.jmod"); 330 FileUtils.deleteFileIfExistsWithRetry(jmod); 331 Path cp = EXPLODED_DIR.resolve("foo").resolve("classes"); 332 Path bp = EXPLODED_DIR.resolve("foo").resolve("bin"); 333 Path lp = EXPLODED_DIR.resolve("foo").resolve("lib"); 334 Path cf = EXPLODED_DIR.resolve("foo").resolve("conf"); 335 336 jmod("create", 337 "--conf", cf.toString(), 338 "--cmds=" + bp.toString(), 339 "--libs=" + lp.toString(), 340 "--class-path", cp.toString(), 341 jmod.toString()) 342 .assertSuccess() 343 .resultChecker(r -> { 344 try (Stream<String> s1 = findFiles(lp).map(p -> LIBS_PREFIX + p); 345 Stream<String> s2 = findFiles(cp).map(p -> CLASSES_PREFIX + p); 346 Stream<String> s3 = findFiles(bp).map(p -> CMDS_PREFIX + p); 347 Stream<String> s4 = findFiles(cf).map(p -> CONFIGS_PREFIX + p)) { 348 Set<String> expectedFilenames = Stream.concat(Stream.concat(s1,s2), 349 Stream.concat(s3, s4)) 350 .collect(toSet()); 351 assertJmodContent(jmod, expectedFilenames); 352 } 353 }); 354 } 355 356 @Test 357 public void testExcludes() throws IOException { 358 Path jmod = MODS_DIR.resolve("fooLibs.jmod"); 359 FileUtils.deleteFileIfExistsWithRetry(jmod); 360 Path cp = EXPLODED_DIR.resolve("foo").resolve("classes"); 361 Path lp = EXPLODED_DIR.resolve("foo").resolve("lib"); 362 363 jmod("create", 364 "--libs=" + lp.toString(), 365 "--class-path", cp.toString(), 366 "--exclude", "**internal**", 367 "--exclude", "first.so", 368 jmod.toString()) 369 .assertSuccess() 370 .resultChecker(r -> { 371 Set<String> expectedFilenames = new HashSet<>(); 372 expectedFilenames.add(CLASSES_PREFIX + "module-info.class"); 373 expectedFilenames.add(CLASSES_PREFIX + "jdk/test/foo/Foo.class"); 374 expectedFilenames.add(CLASSES_PREFIX + "jdk/test/foo/resources/foo.properties"); 375 expectedFilenames.add(LIBS_PREFIX + "second.so"); 376 expectedFilenames.add(LIBS_PREFIX + "third/third.so"); 377 assertJmodContent(jmod, expectedFilenames); 378 379 Set<String> unexpectedFilenames = new HashSet<>(); 380 unexpectedFilenames.add(CLASSES_PREFIX + "jdk/test/foo/internal/Message.class"); 381 unexpectedFilenames.add(LIBS_PREFIX + "first.so"); 382 assertJmodDoesNotContain(jmod, unexpectedFilenames); 383 }); 384 } 385 386 @Test 387 public void describe() throws IOException { 388 String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); 389 jmod("create", 390 "--class-path", cp, 391 MODS_DIR.resolve("describeFoo.jmod").toString()) 392 .assertSuccess(); 393 394 jmod("describe", 395 MODS_DIR.resolve("describeFoo.jmod").toString()) 396 .assertSuccess() 397 .resultChecker(r -> { 398 // Expect similar output: "foo... exports jdk.test.foo ... 399 // ... requires java.base mandated... contains jdk.test.foo.internal" 400 Pattern p = Pattern.compile("foo\\s+exports\\s+jdk.test.foo"); 401 assertTrue(p.matcher(r.output).find(), 402 "Expecting to find \"foo... exports jdk.test.foo\"" + 403 "in output, but did not: [" + r.output + "]"); 404 p = Pattern.compile( 405 "requires\\s+java.base\\s+mandated\\s+contains\\s+jdk.test.foo.internal"); 406 assertTrue(p.matcher(r.output).find(), 407 "Expecting to find \"requires java.base mandated..., " + 408 "contains jdk.test.foo.internal ...\"" + 409 "in output, but did not: [" + r.output + "]"); 410 }); 411 } 412 413 @Test 414 public void testDuplicateEntries() throws IOException { 415 Path jmod = MODS_DIR.resolve("testDuplicates.jmod"); 416 FileUtils.deleteFileIfExistsWithRetry(jmod); 417 String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); 418 Path lp = EXPLODED_DIR.resolve("foo").resolve("lib"); 419 420 jmod("create", 421 "--class-path", cp + pathSeparator + cp, 422 jmod.toString()) 423 .assertSuccess() 424 .resultChecker(r -> 425 assertContains(r.output, "Warning: ignoring duplicate entry") 426 ); 427 428 FileUtils.deleteFileIfExistsWithRetry(jmod); 429 jmod("create", 430 "--class-path", cp, 431 "--libs", lp.toString() + pathSeparator + lp.toString(), 432 jmod.toString()) 433 .assertSuccess() 434 .resultChecker(r -> 435 assertContains(r.output, "Warning: ignoring duplicate entry") 436 ); 437 } 438 439 @Test 440 public void testIgnoreModuleInfoInOtherSections() throws IOException { 441 Path jmod = MODS_DIR.resolve("testIgnoreModuleInfoInOtherSections.jmod"); 442 FileUtils.deleteFileIfExistsWithRetry(jmod); 443 String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); 444 445 jmod("create", 446 "--class-path", cp, 447 "--libs", cp, 448 jmod.toString()) 449 .assertSuccess() 450 .resultChecker(r -> 451 assertContains(r.output, "Warning: ignoring entry") 452 ); 453 454 FileUtils.deleteFileIfExistsWithRetry(jmod); 455 jmod("create", 456 "--class-path", cp, 457 "--cmds", cp, 458 jmod.toString()) 459 .assertSuccess() 460 .resultChecker(r -> 461 assertContains(r.output, "Warning: ignoring entry") 462 ); 463 } 464 465 @Test 466 public void testLastOneWins() throws IOException { 467 Path workDir = Paths.get("lastOneWins"); 468 if (Files.exists(workDir)) 469 FileUtils.deleteFileTreeWithRetry(workDir); 470 Files.createDirectory(workDir); 471 Path jmod = MODS_DIR.resolve("lastOneWins.jmod"); 472 FileUtils.deleteFileIfExistsWithRetry(jmod); 473 Path cp = EXPLODED_DIR.resolve("foo").resolve("classes"); 474 Path bp = EXPLODED_DIR.resolve("foo").resolve("bin"); 475 Path lp = EXPLODED_DIR.resolve("foo").resolve("lib"); 476 Path cf = EXPLODED_DIR.resolve("foo").resolve("conf"); 477 478 Path shouldNotBeAdded = workDir.resolve("shouldNotBeAdded"); 479 Files.createDirectory(shouldNotBeAdded); 480 Files.write(shouldNotBeAdded.resolve("aFile"), "hello".getBytes(UTF_8)); 481 482 // Pairs of options. For options with required arguments the last one 483 // should win ( first should be effectively ignored, but may still be 484 // validated ). 485 jmod("create", 486 "--conf", shouldNotBeAdded.toString(), 487 "--conf", cf.toString(), 488 "--cmds", shouldNotBeAdded.toString(), 489 "--cmds", bp.toString(), 490 "--libs", shouldNotBeAdded.toString(), 491 "--libs", lp.toString(), 492 "--class-path", shouldNotBeAdded.toString(), 493 "--class-path", cp.toString(), 494 "--main-class", "does.NotExist", 495 "--main-class", "jdk.test.foo.Foo", 496 "--module-version", "00001", 497 "--module-version", "5.4.3", 498 "--do-not-resolve-by-default", 499 "--do-not-resolve-by-default", 500 "--warn-if-resolved=incubating", 501 "--warn-if-resolved=deprecated", 502 MODS_DIR.resolve("lastOneWins.jmod").toString()) 503 .assertSuccess() 504 .resultChecker(r -> { 505 ModuleDescriptor md = getModuleDescriptor(jmod); 506 Optional<String> omc = md.mainClass(); 507 assertTrue(omc.isPresent()); 508 assertEquals(omc.get(), "jdk.test.foo.Foo"); 509 Optional<Version> ov = md.version(); 510 assertTrue(ov.isPresent()); 511 assertEquals(ov.get().toString(), "5.4.3"); 512 513 try (Stream<String> s1 = findFiles(lp).map(p -> LIBS_PREFIX + p); 514 Stream<String> s2 = findFiles(cp).map(p -> CLASSES_PREFIX + p); 515 Stream<String> s3 = findFiles(bp).map(p -> CMDS_PREFIX + p); 516 Stream<String> s4 = findFiles(cf).map(p -> CONFIGS_PREFIX + p)) { 517 Set<String> expectedFilenames = Stream.concat(Stream.concat(s1,s2), 518 Stream.concat(s3, s4)) 519 .collect(toSet()); 520 assertJmodContent(jmod, expectedFilenames); 521 } 522 }); 523 524 jmod("extract", 525 "--dir", "blah", 526 "--dir", "lastOneWinsExtractDir", 527 jmod.toString()) 528 .assertSuccess() 529 .resultChecker(r -> { 530 assertTrue(Files.exists(Paths.get("lastOneWinsExtractDir"))); 531 assertTrue(Files.notExists(Paths.get("blah"))); 532 }); 533 } 534 535 @Test 536 public void testPackagesAttribute() throws IOException { 537 Path jmod = MODS_DIR.resolve("foo.jmod"); 538 FileUtils.deleteFileIfExistsWithRetry(jmod); 539 String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); 540 541 Set<String> expectedPackages = Set.of("jdk.test.foo", 542 "jdk.test.foo.internal", 543 "jdk.test.foo.resources"); 544 545 jmod("create", 546 "--class-path", cp, 547 jmod.toString()) 548 .assertSuccess() 549 .resultChecker(r -> { 550 Set<String> pkgs = getModuleDescriptor(jmod).packages(); 551 assertEquals(pkgs, expectedPackages); 552 }); 553 } 554 555 @Test 556 public void testVersion() { 557 jmod("--version") 558 .assertSuccess() 559 .resultChecker(r -> { 560 assertContains(r.output, System.getProperty("java.version")); 561 }); 562 } 563 564 @Test 565 public void testHelp() { 566 jmod("--help") 567 .assertSuccess() 568 .resultChecker(r -> { 569 assertTrue(r.output.startsWith("Usage: jmod"), "Help not printed"); 570 assertFalse(r.output.contains("--do-not-resolve-by-default")); 571 assertFalse(r.output.contains("--warn-if-resolved")); 572 }); 573 } 574 575 @Test 576 public void testHelpExtra() { 577 jmod("--help-extra") 578 .assertSuccess() 579 .resultChecker(r -> { 580 assertTrue(r.output.startsWith("Usage: jmod"), "Extra help not printed"); 581 assertContains(r.output, "--do-not-resolve-by-default"); 582 assertContains(r.output, "--warn-if-resolved"); 583 }); 584 } 585 586 @Test 587 public void testTmpFileRemoved() throws IOException { 588 // Implementation detail: jmod tool creates <jmod-file>.tmp 589 // Ensure that it is removed in the event of a failure. 590 // The failure in this case is a class in the unnamed package. 591 592 Path jmod = MODS_DIR.resolve("testTmpFileRemoved.jmod"); 593 Path tmp = MODS_DIR.resolve(".testTmpFileRemoved.jmod.tmp"); 594 FileUtils.deleteFileIfExistsWithRetry(jmod); 595 FileUtils.deleteFileIfExistsWithRetry(tmp); 596 String cp = EXPLODED_DIR.resolve("foo").resolve("classes") + File.pathSeparator + 597 EXPLODED_DIR.resolve("foo").resolve("classes") 598 .resolve("jdk").resolve("test").resolve("foo").toString(); 599 600 jmod("create", 601 "--class-path", cp, 602 jmod.toString()) 603 .assertFailure() 604 .resultChecker(r -> { 605 assertContains(r.output, "unnamed package"); 606 assertTrue(Files.notExists(tmp), "Unexpected tmp file:" + tmp); 607 }); 608 } 609 610 // --- 611 612 static boolean compileModule(String name, Path dest) throws IOException { 613 return CompilerUtils.compile(SRC_DIR.resolve(name), dest); 614 } 615 616 static void assertContains(String output, String subString) { 617 if (output.contains(subString)) 618 assertTrue(true); 619 else 620 assertTrue(false,"Expected to find [" + subString + "], in output [" 621 + output + "]" + "\n"); 622 } 623 624 static ModuleDescriptor getModuleDescriptor(Path jmod) { 625 ClassLoader cl = ClassLoader.getSystemClassLoader(); 626 try (FileSystem fs = FileSystems.newFileSystem(jmod, cl)) { 627 String p = "/classes/module-info.class"; 628 try (InputStream is = Files.newInputStream(fs.getPath(p))) { 629 return ModuleDescriptor.read(is); 630 } 631 } catch (IOException ioe) { 632 throw new UncheckedIOException(ioe); 633 } 634 } 635 636 static Stream<String> findFiles(Path dir) { 637 try { 638 return Files.find(dir, Integer.MAX_VALUE, (p, a) -> a.isRegularFile()) 639 .map(dir::relativize) 640 .map(Path::toString) 641 .map(p -> p.replace(File.separator, "/")); 642 } catch (IOException x) { 643 throw new UncheckedIOException(x); 644 } 645 } 646 647 static Set<String> getJmodContent(Path jmod) { 648 JmodResult r = jmod("list", jmod.toString()).assertSuccess(); 649 return Stream.of(r.output.split("\r?\n")).collect(toSet()); 650 } 651 652 static void assertJmodContent(Path jmod, Set<String> expected) { 653 Set<String> actual = getJmodContent(jmod); 654 if (!Objects.equals(actual, expected)) { 655 Set<String> unexpected = new HashSet<>(actual); 656 unexpected.removeAll(expected); 657 Set<String> notFound = new HashSet<>(expected); 658 notFound.removeAll(actual); 659 StringBuilder sb = new StringBuilder(); 660 sb.append("Unexpected but found:\n"); 661 unexpected.forEach(s -> sb.append("\t" + s + "\n")); 662 sb.append("Expected but not found:\n"); 663 notFound.forEach(s -> sb.append("\t" + s + "\n")); 664 assertTrue(false, "Jmod content check failed.\n" + sb.toString()); 665 } 666 } 667 668 static void assertJmodDoesNotContain(Path jmod, Set<String> unexpectedNames) { 669 Set<String> actual = getJmodContent(jmod); 670 Set<String> unexpected = new HashSet<>(); 671 for (String name : unexpectedNames) { 672 if (actual.contains(name)) 673 unexpected.add(name); 674 } 675 if (!unexpected.isEmpty()) { 676 StringBuilder sb = new StringBuilder(); 677 for (String s : unexpected) 678 sb.append("Unexpected but found: " + s + "\n"); 679 sb.append("In :"); 680 for (String s : actual) 681 sb.append("\t" + s + "\n"); 682 assertTrue(false, "Jmod content check failed.\n" + sb.toString()); 683 } 684 } 685 686 static void assertSameContent(Path p1, Path p2) { 687 try { 688 byte[] ba1 = Files.readAllBytes(p1); 689 byte[] ba2 = Files.readAllBytes(p2); 690 assertEquals(ba1, ba2); 691 } catch (IOException x) { 692 throw new UncheckedIOException(x); 693 } 694 } 695 696 static JmodResult jmod(String... args) { 697 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 698 PrintStream ps = new PrintStream(baos); 699 System.out.println("jmod " + Arrays.asList(args)); 700 int ec = JMOD_TOOL.run(ps, ps, args); 701 return new JmodResult(ec, new String(baos.toByteArray(), UTF_8)); 702 } 703 704 static class JmodResult { 705 final int exitCode; 706 final String output; 707 708 JmodResult(int exitValue, String output) { 709 this.exitCode = exitValue; 710 this.output = output; 711 } 712 JmodResult assertSuccess() { assertTrue(exitCode == 0, output); return this; } 713 JmodResult assertFailure() { assertTrue(exitCode != 0, output); return this; } 714 JmodResult resultChecker(Consumer<JmodResult> r) { r.accept(this); return this; } 715 } 716 717 static void createCmds(Path dir) throws IOException { 718 List<String> files = Arrays.asList( 719 "first", "second", "third" + File.separator + "third"); 720 createFiles(dir, files); 721 } 722 723 static void createLibs(Path dir) throws IOException { 724 List<String> files = Arrays.asList( 725 "first.so", "second.so", "third" + File.separator + "third.so"); 726 createFiles(dir, files); 727 } 728 729 static void createConfigs(Path dir) throws IOException { 730 List<String> files = Arrays.asList( 731 "first.cfg", "second.cfg", "third" + File.separator + "third.cfg"); 732 createFiles(dir, files); 733 } 734 735 static void createFiles(Path dir, List<String> filenames) throws IOException { 736 for (String name : filenames) { 737 Path file = dir.resolve(name); 738 Files.createDirectories(file.getParent()); 739 Files.createFile(file); 740 try (OutputStream os = Files.newOutputStream(file)) { 741 os.write("blahblahblah".getBytes(UTF_8)); 742 } 743 } 744 } 745 746 static void copyResource(Path srcDir, Path dir, String resource) throws IOException { 747 Path dest = dir.resolve(resource); 748 Files.deleteIfExists(dest); 749 750 Files.createDirectories(dest.getParent()); 751 Files.copy(srcDir.resolve(resource), dest); 752 } 753 754 // Standalone entry point. 755 public static void main(String[] args) throws Throwable { 756 JmodTest test = new JmodTest(); 757 test.buildExplodedModules(); 758 for (Method m : JmodTest.class.getDeclaredMethods()) { 759 if (m.getAnnotation(Test.class) != null) { 760 System.out.println("Invoking " + m.getName()); 761 m.invoke(test); 762 } 763 } 764 } 765 }