| /** |
| * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| /* |
| * @test |
| * @bug 8142968 8166568 8166286 8170618 8168149 |
| * @summary Basic test for jmod |
| * @library /test/lib |
| * @modules jdk.compiler |
| * jdk.jlink |
| * @build jdk.test.lib.compiler.CompilerUtils |
| * jdk.test.lib.util.FileUtils |
| * jdk.test.lib.Platform |
| * @run testng/othervm -Djava.io.tmpdir=. JmodTest |
| */ |
| |
| import java.io.*; |
| import java.lang.module.ModuleDescriptor; |
| import java.lang.reflect.Method; |
| import java.nio.file.*; |
| import java.util.*; |
| import java.util.function.Consumer; |
| import java.util.regex.Pattern; |
| import java.util.spi.ToolProvider; |
| import java.util.stream.Stream; |
| import jdk.test.lib.compiler.CompilerUtils; |
| import jdk.test.lib.util.FileUtils; |
| import org.testng.annotations.BeforeTest; |
| import org.testng.annotations.Test; |
| |
| import static java.io.File.pathSeparator; |
| import static java.lang.module.ModuleDescriptor.Version; |
| import static java.nio.charset.StandardCharsets.UTF_8; |
| import static java.util.stream.Collectors.toSet; |
| import static org.testng.Assert.*; |
| |
| public class JmodTest { |
| |
| static final ToolProvider JMOD_TOOL = ToolProvider.findFirst("jmod") |
| .orElseThrow(() -> |
| new RuntimeException("jmod tool not found") |
| ); |
| |
| static final String TEST_SRC = System.getProperty("test.src", "."); |
| static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); |
| static final Path EXPLODED_DIR = Paths.get("build"); |
| static final Path MODS_DIR = Paths.get("jmods"); |
| |
| static final String CLASSES_PREFIX = "classes/"; |
| static final String CMDS_PREFIX = "bin/"; |
| static final String LIBS_PREFIX = "lib/"; |
| static final String CONFIGS_PREFIX = "conf/"; |
| |
| @BeforeTest |
| public void buildExplodedModules() throws IOException { |
| if (Files.exists(EXPLODED_DIR)) |
| FileUtils.deleteFileTreeWithRetry(EXPLODED_DIR); |
| |
| for (String name : new String[] { "foo"/*, "bar", "baz"*/ } ) { |
| Path dir = EXPLODED_DIR.resolve(name); |
| assertTrue(compileModule(name, dir.resolve("classes"))); |
| copyResource(SRC_DIR.resolve("foo"), |
| dir.resolve("classes"), |
| "jdk/test/foo/resources/foo.properties"); |
| createCmds(dir.resolve("bin")); |
| createLibs(dir.resolve("lib")); |
| createConfigs(dir.resolve("conf")); |
| } |
| |
| if (Files.exists(MODS_DIR)) |
| FileUtils.deleteFileTreeWithRetry(MODS_DIR); |
| Files.createDirectories(MODS_DIR); |
| } |
| |
| // JDK-8166286 - jmod fails on symlink to directory |
| @Test |
| public void testSymlinks() throws IOException { |
| Path apaDir = EXPLODED_DIR.resolve("apa"); |
| Path classesDir = EXPLODED_DIR.resolve("apa").resolve("classes"); |
| assertTrue(compileModule("apa", classesDir)); |
| Path libDir = apaDir.resolve("lib"); |
| createFiles(libDir, List.of("foo/bar/libfoo.so")); |
| try { |
| Path link = Files.createSymbolicLink( |
| libDir.resolve("baz"), libDir.resolve("foo").toAbsolutePath()); |
| assertTrue(Files.exists(link)); |
| } catch (UnsupportedOperationException uoe) { |
| // OS does not support symlinks. Nothing to test! |
| return; |
| } |
| |
| Path jmod = MODS_DIR.resolve("apa.jmod"); |
| jmod("create", |
| "--libs=", libDir.toString(), |
| "--class-path", classesDir.toString(), |
| jmod.toString()) |
| .assertSuccess(); |
| } |
| |
| // JDK-8170618 - jmod should validate if any exported or open package is missing |
| @Test |
| public void testMissingPackages() throws IOException { |
| Path apaDir = EXPLODED_DIR.resolve("apa"); |
| Path classesDir = EXPLODED_DIR.resolve("apa").resolve("classes"); |
| if (Files.exists(classesDir)) |
| FileUtils.deleteFileTreeWithRetry(classesDir); |
| assertTrue(compileModule("apa", classesDir)); |
| FileUtils.deleteFileTreeWithRetry(classesDir.resolve("jdk")); |
| Path jmod = MODS_DIR.resolve("apa.jmod"); |
| jmod("create", |
| "--class-path", classesDir.toString(), |
| jmod.toString()) |
| .assertFailure() |
| .resultChecker(r -> { |
| assertContains(r.output, "Packages that are exported or open in apa are not present: [jdk.test.apa]"); |
| }); |
| if (Files.exists(classesDir)) |
| FileUtils.deleteFileTreeWithRetry(classesDir); |
| } |
| |
| @Test |
| public void testList() throws IOException { |
| String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); |
| jmod("create", |
| "--class-path", cp, |
| MODS_DIR.resolve("foo.jmod").toString()) |
| .assertSuccess(); |
| |
| jmod("list", |
| MODS_DIR.resolve("foo.jmod").toString()) |
| .assertSuccess() |
| .resultChecker(r -> { |
| // asserts dependent on the exact contents of foo |
| assertContains(r.output, CLASSES_PREFIX + "module-info.class"); |
| assertContains(r.output, CLASSES_PREFIX + "jdk/test/foo/Foo.class"); |
| assertContains(r.output, CLASSES_PREFIX + "jdk/test/foo/internal/Message.class"); |
| assertContains(r.output, CLASSES_PREFIX + "jdk/test/foo/resources/foo.properties"); |
| }); |
| } |
| |
| @Test |
| public void testExtractCWD() throws IOException { |
| Path cp = EXPLODED_DIR.resolve("foo").resolve("classes"); |
| jmod("create", |
| "--class-path", cp.toString(), |
| MODS_DIR.resolve("fooExtractCWD.jmod").toString()) |
| .assertSuccess(); |
| |
| jmod("extract", |
| MODS_DIR.resolve("fooExtractCWD.jmod").toString()) |
| .assertSuccess() |
| .resultChecker(r -> { |
| // module-info should exist, but jmod will have added its Packages attr. |
| assertTrue(Files.exists(Paths.get("classes/module-info.class"))); |
| assertSameContent(cp.resolve("jdk/test/foo/Foo.class"), |
| Paths.get("classes/jdk/test/foo/Foo.class")); |
| assertSameContent(cp.resolve("jdk/test/foo/internal/Message.class"), |
| Paths.get("classes/jdk/test/foo/internal/Message.class")); |
| assertSameContent(cp.resolve("jdk/test/foo/resources/foo.properties"), |
| Paths.get("classes/jdk/test/foo/resources/foo.properties")); |
| }); |
| } |
| |
| @Test |
| public void testExtractDir() throws IOException { |
| if (Files.exists(Paths.get("extractTestDir"))) |
| FileUtils.deleteFileTreeWithRetry(Paths.get("extractTestDir")); |
| Path cp = EXPLODED_DIR.resolve("foo").resolve("classes"); |
| Path bp = EXPLODED_DIR.resolve("foo").resolve("bin"); |
| Path lp = EXPLODED_DIR.resolve("foo").resolve("lib"); |
| Path cf = EXPLODED_DIR.resolve("foo").resolve("conf"); |
| |
| jmod("create", |
| "--conf", cf.toString(), |
| "--cmds", bp.toString(), |
| "--libs", lp.toString(), |
| "--class-path", cp.toString(), |
| MODS_DIR.resolve("fooExtractDir.jmod").toString()) |
| .assertSuccess(); |
| |
| jmod("extract", |
| "--dir", "extractTestDir", |
| MODS_DIR.resolve("fooExtractDir.jmod").toString()) |
| .assertSuccess(); |
| |
| jmod("extract", |
| "--dir", "extractTestDir", |
| MODS_DIR.resolve("fooExtractDir.jmod").toString()) |
| .assertSuccess() |
| .resultChecker(r -> { |
| // check a sample of the extracted files |
| Path p = Paths.get("extractTestDir"); |
| assertTrue(Files.exists(p.resolve("classes/module-info.class"))); |
| assertSameContent(cp.resolve("jdk/test/foo/Foo.class"), |
| p.resolve("classes/jdk/test/foo/Foo.class")); |
| assertSameContent(bp.resolve("first"), |
| p.resolve(CMDS_PREFIX).resolve("first")); |
| assertSameContent(lp.resolve("first.so"), |
| p.resolve(LIBS_PREFIX).resolve("second.so")); |
| assertSameContent(cf.resolve("second.cfg"), |
| p.resolve(CONFIGS_PREFIX).resolve("second.cfg")); |
| }); |
| } |
| |
| @Test |
| public void testMainClass() throws IOException { |
| Path jmod = MODS_DIR.resolve("fooMainClass.jmod"); |
| FileUtils.deleteFileIfExistsWithRetry(jmod); |
| String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); |
| |
| jmod("create", |
| "--class-path", cp, |
| "--main-class", "jdk.test.foo.Foo", |
| jmod.toString()) |
| .assertSuccess() |
| .resultChecker(r -> { |
| Optional<String> omc = getModuleDescriptor(jmod).mainClass(); |
| assertTrue(omc.isPresent()); |
| assertEquals(omc.get(), "jdk.test.foo.Foo"); |
| }); |
| } |
| |
| @Test |
| public void testModuleVersion() throws IOException { |
| Path jmod = MODS_DIR.resolve("fooVersion.jmod"); |
| FileUtils.deleteFileIfExistsWithRetry(jmod); |
| String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); |
| |
| jmod("create", |
| "--class-path", cp, |
| "--module-version", "5.4.3", |
| jmod.toString()) |
| .assertSuccess() |
| .resultChecker(r -> { |
| Optional<Version> ov = getModuleDescriptor(jmod).version(); |
| assertTrue(ov.isPresent()); |
| assertEquals(ov.get().toString(), "5.4.3"); |
| }); |
| } |
| |
| @Test |
| public void testConfig() throws IOException { |
| Path jmod = MODS_DIR.resolve("fooConfig.jmod"); |
| FileUtils.deleteFileIfExistsWithRetry(jmod); |
| Path cp = EXPLODED_DIR.resolve("foo").resolve("classes"); |
| Path cf = EXPLODED_DIR.resolve("foo").resolve("conf"); |
| |
| jmod("create", |
| "--class-path", cp.toString(), |
| "--config", cf.toString(), |
| jmod.toString()) |
| .assertSuccess() |
| .resultChecker(r -> { |
| try (Stream<String> s1 = findFiles(cf).map(p -> CONFIGS_PREFIX + p); |
| Stream<String> s2 = findFiles(cp).map(p -> CLASSES_PREFIX + p)) { |
| Set<String> expectedFilenames = Stream.concat(s1, s2) |
| .collect(toSet()); |
| assertJmodContent(jmod, expectedFilenames); |
| } |
| }); |
| } |
| |
| @Test |
| public void testCmds() throws IOException { |
| Path jmod = MODS_DIR.resolve("fooCmds.jmod"); |
| FileUtils.deleteFileIfExistsWithRetry(jmod); |
| Path cp = EXPLODED_DIR.resolve("foo").resolve("classes"); |
| Path bp = EXPLODED_DIR.resolve("foo").resolve("bin"); |
| |
| jmod("create", |
| "--cmds", bp.toString(), |
| "--class-path", cp.toString(), |
| jmod.toString()) |
| .assertSuccess() |
| .resultChecker(r -> { |
| try (Stream<String> s1 = findFiles(bp).map(p -> CMDS_PREFIX + p); |
| Stream<String> s2 = findFiles(cp).map(p -> CLASSES_PREFIX + p)) { |
| Set<String> expectedFilenames = Stream.concat(s1,s2) |
| .collect(toSet()); |
| assertJmodContent(jmod, expectedFilenames); |
| } |
| }); |
| } |
| |
| @Test |
| public void testLibs() throws IOException { |
| Path jmod = MODS_DIR.resolve("fooLibs.jmod"); |
| FileUtils.deleteFileIfExistsWithRetry(jmod); |
| Path cp = EXPLODED_DIR.resolve("foo").resolve("classes"); |
| Path lp = EXPLODED_DIR.resolve("foo").resolve("lib"); |
| |
| jmod("create", |
| "--libs=", lp.toString(), |
| "--class-path", cp.toString(), |
| jmod.toString()) |
| .assertSuccess() |
| .resultChecker(r -> { |
| try (Stream<String> s1 = findFiles(lp).map(p -> LIBS_PREFIX + p); |
| Stream<String> s2 = findFiles(cp).map(p -> CLASSES_PREFIX + p)) { |
| Set<String> expectedFilenames = Stream.concat(s1,s2) |
| .collect(toSet()); |
| assertJmodContent(jmod, expectedFilenames); |
| } |
| }); |
| } |
| |
| @Test |
| public void testAll() throws IOException { |
| Path jmod = MODS_DIR.resolve("fooAll.jmod"); |
| FileUtils.deleteFileIfExistsWithRetry(jmod); |
| Path cp = EXPLODED_DIR.resolve("foo").resolve("classes"); |
| Path bp = EXPLODED_DIR.resolve("foo").resolve("bin"); |
| Path lp = EXPLODED_DIR.resolve("foo").resolve("lib"); |
| Path cf = EXPLODED_DIR.resolve("foo").resolve("conf"); |
| |
| jmod("create", |
| "--conf", cf.toString(), |
| "--cmds=", bp.toString(), |
| "--libs=", lp.toString(), |
| "--class-path", cp.toString(), |
| jmod.toString()) |
| .assertSuccess() |
| .resultChecker(r -> { |
| try (Stream<String> s1 = findFiles(lp).map(p -> LIBS_PREFIX + p); |
| Stream<String> s2 = findFiles(cp).map(p -> CLASSES_PREFIX + p); |
| Stream<String> s3 = findFiles(bp).map(p -> CMDS_PREFIX + p); |
| Stream<String> s4 = findFiles(cf).map(p -> CONFIGS_PREFIX + p)) { |
| Set<String> expectedFilenames = Stream.concat(Stream.concat(s1,s2), |
| Stream.concat(s3, s4)) |
| .collect(toSet()); |
| assertJmodContent(jmod, expectedFilenames); |
| } |
| }); |
| } |
| |
| @Test |
| public void testExcludes() throws IOException { |
| Path jmod = MODS_DIR.resolve("fooLibs.jmod"); |
| FileUtils.deleteFileIfExistsWithRetry(jmod); |
| Path cp = EXPLODED_DIR.resolve("foo").resolve("classes"); |
| Path lp = EXPLODED_DIR.resolve("foo").resolve("lib"); |
| |
| jmod("create", |
| "--libs=", lp.toString(), |
| "--class-path", cp.toString(), |
| "--exclude", "**internal**", |
| "--exclude", "first.so", |
| jmod.toString()) |
| .assertSuccess() |
| .resultChecker(r -> { |
| Set<String> expectedFilenames = new HashSet<>(); |
| expectedFilenames.add(CLASSES_PREFIX + "module-info.class"); |
| expectedFilenames.add(CLASSES_PREFIX + "jdk/test/foo/Foo.class"); |
| expectedFilenames.add(CLASSES_PREFIX + "jdk/test/foo/resources/foo.properties"); |
| expectedFilenames.add(LIBS_PREFIX + "second.so"); |
| expectedFilenames.add(LIBS_PREFIX + "third/third.so"); |
| assertJmodContent(jmod, expectedFilenames); |
| |
| Set<String> unexpectedFilenames = new HashSet<>(); |
| unexpectedFilenames.add(CLASSES_PREFIX + "jdk/test/foo/internal/Message.class"); |
| unexpectedFilenames.add(LIBS_PREFIX + "first.so"); |
| assertJmodDoesNotContain(jmod, unexpectedFilenames); |
| }); |
| } |
| |
| @Test |
| public void describe() throws IOException { |
| String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); |
| jmod("create", |
| "--class-path", cp, |
| MODS_DIR.resolve("describeFoo.jmod").toString()) |
| .assertSuccess(); |
| |
| jmod("describe", |
| MODS_DIR.resolve("describeFoo.jmod").toString()) |
| .assertSuccess() |
| .resultChecker(r -> { |
| // Expect similar output: "foo... exports jdk.test.foo ... |
| // ... requires java.base mandated... contains jdk.test.foo.internal" |
| Pattern p = Pattern.compile("foo\\s+exports\\s+jdk.test.foo"); |
| assertTrue(p.matcher(r.output).find(), |
| "Expecting to find \"foo... exports jdk.test.foo\"" + |
| "in output, but did not: [" + r.output + "]"); |
| p = Pattern.compile( |
| "requires\\s+java.base\\s+mandated\\s+contains\\s+jdk.test.foo.internal"); |
| assertTrue(p.matcher(r.output).find(), |
| "Expecting to find \"requires java.base mandated..., " + |
| "contains jdk.test.foo.internal ...\"" + |
| "in output, but did not: [" + r.output + "]"); |
| }); |
| } |
| |
| @Test |
| public void testDuplicateEntries() throws IOException { |
| Path jmod = MODS_DIR.resolve("testDuplicates.jmod"); |
| FileUtils.deleteFileIfExistsWithRetry(jmod); |
| String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); |
| Path lp = EXPLODED_DIR.resolve("foo").resolve("lib"); |
| |
| jmod("create", |
| "--class-path", cp + pathSeparator + cp, |
| jmod.toString()) |
| .assertSuccess() |
| .resultChecker(r -> |
| assertContains(r.output, "Warning: ignoring duplicate entry") |
| ); |
| |
| FileUtils.deleteFileIfExistsWithRetry(jmod); |
| jmod("create", |
| "--class-path", cp, |
| "--libs", lp.toString() + pathSeparator + lp.toString(), |
| jmod.toString()) |
| .assertSuccess() |
| .resultChecker(r -> |
| assertContains(r.output, "Warning: ignoring duplicate entry") |
| ); |
| } |
| |
| @Test |
| public void testIgnoreModuleInfoInOtherSections() throws IOException { |
| Path jmod = MODS_DIR.resolve("testIgnoreModuleInfoInOtherSections.jmod"); |
| FileUtils.deleteFileIfExistsWithRetry(jmod); |
| String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); |
| |
| jmod("create", |
| "--class-path", cp, |
| "--libs", cp, |
| jmod.toString()) |
| .assertSuccess() |
| .resultChecker(r -> |
| assertContains(r.output, "Warning: ignoring entry") |
| ); |
| |
| FileUtils.deleteFileIfExistsWithRetry(jmod); |
| jmod("create", |
| "--class-path", cp, |
| "--cmds", cp, |
| jmod.toString()) |
| .assertSuccess() |
| .resultChecker(r -> |
| assertContains(r.output, "Warning: ignoring entry") |
| ); |
| } |
| |
| @Test |
| public void testLastOneWins() throws IOException { |
| Path workDir = Paths.get("lastOneWins"); |
| if (Files.exists(workDir)) |
| FileUtils.deleteFileTreeWithRetry(workDir); |
| Files.createDirectory(workDir); |
| Path jmod = MODS_DIR.resolve("lastOneWins.jmod"); |
| FileUtils.deleteFileIfExistsWithRetry(jmod); |
| Path cp = EXPLODED_DIR.resolve("foo").resolve("classes"); |
| Path bp = EXPLODED_DIR.resolve("foo").resolve("bin"); |
| Path lp = EXPLODED_DIR.resolve("foo").resolve("lib"); |
| Path cf = EXPLODED_DIR.resolve("foo").resolve("conf"); |
| |
| Path shouldNotBeAdded = workDir.resolve("shouldNotBeAdded"); |
| Files.createDirectory(shouldNotBeAdded); |
| Files.write(shouldNotBeAdded.resolve("aFile"), "hello".getBytes(UTF_8)); |
| |
| // Pairs of options. For options with required arguments the last one |
| // should win ( first should be effectively ignored, but may still be |
| // validated ). |
| jmod("create", |
| "--conf", shouldNotBeAdded.toString(), |
| "--conf", cf.toString(), |
| "--cmds", shouldNotBeAdded.toString(), |
| "--cmds", bp.toString(), |
| "--libs", shouldNotBeAdded.toString(), |
| "--libs", lp.toString(), |
| "--class-path", shouldNotBeAdded.toString(), |
| "--class-path", cp.toString(), |
| "--main-class", "does.NotExist", |
| "--main-class", "jdk.test.foo.Foo", |
| "--module-version", "00001", |
| "--module-version", "5.4.3", |
| "--do-not-resolve-by-default", |
| "--do-not-resolve-by-default", |
| "--warn-if-resolved=incubating", |
| "--warn-if-resolved=deprecated", |
| MODS_DIR.resolve("lastOneWins.jmod").toString()) |
| .assertSuccess() |
| .resultChecker(r -> { |
| ModuleDescriptor md = getModuleDescriptor(jmod); |
| Optional<String> omc = md.mainClass(); |
| assertTrue(omc.isPresent()); |
| assertEquals(omc.get(), "jdk.test.foo.Foo"); |
| Optional<Version> ov = md.version(); |
| assertTrue(ov.isPresent()); |
| assertEquals(ov.get().toString(), "5.4.3"); |
| |
| try (Stream<String> s1 = findFiles(lp).map(p -> LIBS_PREFIX + p); |
| Stream<String> s2 = findFiles(cp).map(p -> CLASSES_PREFIX + p); |
| Stream<String> s3 = findFiles(bp).map(p -> CMDS_PREFIX + p); |
| Stream<String> s4 = findFiles(cf).map(p -> CONFIGS_PREFIX + p)) { |
| Set<String> expectedFilenames = Stream.concat(Stream.concat(s1,s2), |
| Stream.concat(s3, s4)) |
| .collect(toSet()); |
| assertJmodContent(jmod, expectedFilenames); |
| } |
| }); |
| |
| jmod("extract", |
| "--dir", "blah", |
| "--dir", "lastOneWinsExtractDir", |
| jmod.toString()) |
| .assertSuccess() |
| .resultChecker(r -> { |
| assertTrue(Files.exists(Paths.get("lastOneWinsExtractDir"))); |
| assertTrue(Files.notExists(Paths.get("blah"))); |
| }); |
| } |
| |
| @Test |
| public void testPackagesAttribute() throws IOException { |
| Path jmod = MODS_DIR.resolve("foo.jmod"); |
| FileUtils.deleteFileIfExistsWithRetry(jmod); |
| String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); |
| |
| Set<String> expectedPackages = Set.of("jdk.test.foo", |
| "jdk.test.foo.internal", |
| "jdk.test.foo.resources"); |
| |
| jmod("create", |
| "--class-path", cp, |
| jmod.toString()) |
| .assertSuccess() |
| .resultChecker(r -> { |
| Set<String> pkgs = getModuleDescriptor(jmod).packages(); |
| assertEquals(pkgs, expectedPackages); |
| }); |
| } |
| |
| @Test |
| public void testVersion() { |
| jmod("--version") |
| .assertSuccess() |
| .resultChecker(r -> { |
| assertContains(r.output, System.getProperty("java.version")); |
| }); |
| } |
| |
| @Test |
| public void testHelp() { |
| jmod("--help") |
| .assertSuccess() |
| .resultChecker(r -> { |
| assertTrue(r.output.startsWith("Usage: jmod"), "Help not printed"); |
| assertFalse(r.output.contains("--do-not-resolve-by-default")); |
| assertFalse(r.output.contains("--warn-if-resolved")); |
| }); |
| } |
| |
| @Test |
| public void testHelpExtra() { |
| jmod("--help-extra") |
| .assertSuccess() |
| .resultChecker(r -> { |
| assertTrue(r.output.startsWith("Usage: jmod"), "Extra help not printed"); |
| assertContains(r.output, "--do-not-resolve-by-default"); |
| assertContains(r.output, "--warn-if-resolved"); |
| }); |
| } |
| |
| @Test |
| public void testTmpFileRemoved() throws IOException { |
| // Implementation detail: jmod tool creates <jmod-file>.tmp |
| // Ensure that it is removed in the event of a failure. |
| // The failure in this case is a class in the unnamed package. |
| |
| Path jmod = MODS_DIR.resolve("testTmpFileRemoved.jmod"); |
| Path tmp = MODS_DIR.resolve(".testTmpFileRemoved.jmod.tmp"); |
| FileUtils.deleteFileIfExistsWithRetry(jmod); |
| FileUtils.deleteFileIfExistsWithRetry(tmp); |
| String cp = EXPLODED_DIR.resolve("foo").resolve("classes") + File.pathSeparator + |
| EXPLODED_DIR.resolve("foo").resolve("classes") |
| .resolve("jdk").resolve("test").resolve("foo").toString(); |
| |
| jmod("create", |
| "--class-path", cp, |
| jmod.toString()) |
| .assertFailure() |
| .resultChecker(r -> { |
| assertContains(r.output, "unnamed package"); |
| assertTrue(Files.notExists(tmp), "Unexpected tmp file:" + tmp); |
| }); |
| } |
| |
| // --- |
| |
| static boolean compileModule(String name, Path dest) throws IOException { |
| return CompilerUtils.compile(SRC_DIR.resolve(name), dest); |
| } |
| |
| static void assertContains(String output, String subString) { |
| if (output.contains(subString)) |
| assertTrue(true); |
| else |
| assertTrue(false,"Expected to find [" + subString + "], in output [" |
| + output + "]" + "\n"); |
| } |
| |
| static ModuleDescriptor getModuleDescriptor(Path jmod) { |
| ClassLoader cl = ClassLoader.getSystemClassLoader(); |
| try (FileSystem fs = FileSystems.newFileSystem(jmod, cl)) { |
| String p = "/classes/module-info.class"; |
| try (InputStream is = Files.newInputStream(fs.getPath(p))) { |
| return ModuleDescriptor.read(is); |
| } |
| } catch (IOException ioe) { |
| throw new UncheckedIOException(ioe); |
| } |
| } |
| |
| static Stream<String> findFiles(Path dir) { |
| try { |
| return Files.find(dir, Integer.MAX_VALUE, (p, a) -> a.isRegularFile()) |
| .map(dir::relativize) |
| .map(Path::toString) |
| .map(p -> p.replace(File.separator, "/")); |
| } catch (IOException x) { |
| throw new UncheckedIOException(x); |
| } |
| } |
| |
| static Set<String> getJmodContent(Path jmod) { |
| JmodResult r = jmod("list", jmod.toString()).assertSuccess(); |
| return Stream.of(r.output.split("\r?\n")).collect(toSet()); |
| } |
| |
| static void assertJmodContent(Path jmod, Set<String> expected) { |
| Set<String> actual = getJmodContent(jmod); |
| if (!Objects.equals(actual, expected)) { |
| Set<String> unexpected = new HashSet<>(actual); |
| unexpected.removeAll(expected); |
| Set<String> notFound = new HashSet<>(expected); |
| notFound.removeAll(actual); |
| StringBuilder sb = new StringBuilder(); |
| sb.append("Unexpected but found:\n"); |
| unexpected.forEach(s -> sb.append("\t" + s + "\n")); |
| sb.append("Expected but not found:\n"); |
| notFound.forEach(s -> sb.append("\t" + s + "\n")); |
| assertTrue(false, "Jmod content check failed.\n" + sb.toString()); |
| } |
| } |
| |
| static void assertJmodDoesNotContain(Path jmod, Set<String> unexpectedNames) { |
| Set<String> actual = getJmodContent(jmod); |
| Set<String> unexpected = new HashSet<>(); |
| for (String name : unexpectedNames) { |
| if (actual.contains(name)) |
| unexpected.add(name); |
| } |
| if (!unexpected.isEmpty()) { |
| StringBuilder sb = new StringBuilder(); |
| for (String s : unexpected) |
| sb.append("Unexpected but found: " + s + "\n"); |
| sb.append("In :"); |
| for (String s : actual) |
| sb.append("\t" + s + "\n"); |
| assertTrue(false, "Jmod content check failed.\n" + sb.toString()); |
| } |
| } |
| |
| static void assertSameContent(Path p1, Path p2) { |
| try { |
| byte[] ba1 = Files.readAllBytes(p1); |
| byte[] ba2 = Files.readAllBytes(p2); |
| assertEquals(ba1, ba2); |
| } catch (IOException x) { |
| throw new UncheckedIOException(x); |
| } |
| } |
| |
| static JmodResult jmod(String... args) { |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| PrintStream ps = new PrintStream(baos); |
| System.out.println("jmod " + Arrays.asList(args)); |
| int ec = JMOD_TOOL.run(ps, ps, args); |
| return new JmodResult(ec, new String(baos.toByteArray(), UTF_8)); |
| } |
| |
| static class JmodResult { |
| final int exitCode; |
| final String output; |
| |
| JmodResult(int exitValue, String output) { |
| this.exitCode = exitValue; |
| this.output = output; |
| } |
| JmodResult assertSuccess() { assertTrue(exitCode == 0, output); return this; } |
| JmodResult assertFailure() { assertTrue(exitCode != 0, output); return this; } |
| JmodResult resultChecker(Consumer<JmodResult> r) { r.accept(this); return this; } |
| } |
| |
| static void createCmds(Path dir) throws IOException { |
| List<String> files = Arrays.asList( |
| "first", "second", "third" + File.separator + "third"); |
| createFiles(dir, files); |
| } |
| |
| static void createLibs(Path dir) throws IOException { |
| List<String> files = Arrays.asList( |
| "first.so", "second.so", "third" + File.separator + "third.so"); |
| createFiles(dir, files); |
| } |
| |
| static void createConfigs(Path dir) throws IOException { |
| List<String> files = Arrays.asList( |
| "first.cfg", "second.cfg", "third" + File.separator + "third.cfg"); |
| createFiles(dir, files); |
| } |
| |
| static void createFiles(Path dir, List<String> filenames) throws IOException { |
| for (String name : filenames) { |
| Path file = dir.resolve(name); |
| Files.createDirectories(file.getParent()); |
| Files.createFile(file); |
| try (OutputStream os = Files.newOutputStream(file)) { |
| os.write("blahblahblah".getBytes(UTF_8)); |
| } |
| } |
| } |
| |
| static void copyResource(Path srcDir, Path dir, String resource) throws IOException { |
| Path dest = dir.resolve(resource); |
| Files.deleteIfExists(dest); |
| |
| Files.createDirectories(dest.getParent()); |
| Files.copy(srcDir.resolve(resource), dest); |
| } |
| |
| // Standalone entry point. |
| public static void main(String[] args) throws Throwable { |
| JmodTest test = new JmodTest(); |
| test.buildExplodedModules(); |
| for (Method m : JmodTest.class.getDeclaredMethods()) { |
| if (m.getAnnotation(Test.class) != null) { |
| System.out.println("Invoking " + m.getName()); |
| m.invoke(test); |
| } |
| } |
| } |
| } |