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