Path: blob/master/test/jdk/tools/jmod/JmodTest.java
41144 views
/*1* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 8142968 8166568 8166286 8170618 8168149 824091026* @summary Basic test for jmod27* @library /test/lib28* @modules jdk.compiler29* jdk.jlink30* @build jdk.test.lib.compiler.CompilerUtils31* jdk.test.lib.util.FileUtils32* jdk.test.lib.Platform33* @run testng/othervm -Djava.io.tmpdir=. JmodTest34*/3536import java.io.*;37import java.lang.module.ModuleDescriptor;38import java.lang.reflect.Method;39import java.nio.file.*;40import java.util.*;41import java.util.function.Consumer;42import java.util.regex.Pattern;43import java.util.spi.ToolProvider;44import java.util.stream.Stream;45import jdk.test.lib.compiler.CompilerUtils;46import jdk.test.lib.util.FileUtils;47import org.testng.annotations.BeforeTest;48import org.testng.annotations.Test;4950import static java.io.File.pathSeparator;51import static java.lang.module.ModuleDescriptor.Version;52import static java.nio.charset.StandardCharsets.UTF_8;53import static java.util.stream.Collectors.toSet;54import static org.testng.Assert.*;5556public class JmodTest {5758static final ToolProvider JMOD_TOOL = ToolProvider.findFirst("jmod")59.orElseThrow(() ->60new RuntimeException("jmod tool not found")61);62static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar")63.orElseThrow(() ->64new RuntimeException("jar tool not found")65);6667static final String TEST_SRC = System.getProperty("test.src", ".");68static final Path SRC_DIR = Paths.get(TEST_SRC, "src");69static final Path EXPLODED_DIR = Paths.get("build");70static final Path MODS_DIR = Paths.get("jmods");7172static final String CLASSES_PREFIX = "classes/";73static final String CMDS_PREFIX = "bin/";74static final String LIBS_PREFIX = "lib/";75static final String CONFIGS_PREFIX = "conf/";7677@BeforeTest78public void buildExplodedModules() throws IOException {79if (Files.exists(EXPLODED_DIR))80FileUtils.deleteFileTreeWithRetry(EXPLODED_DIR);8182for (String name : new String[] { "foo"/*, "bar", "baz"*/ } ) {83Path dir = EXPLODED_DIR.resolve(name);84assertTrue(compileModule(name, dir.resolve("classes")));85copyResource(SRC_DIR.resolve("foo"),86dir.resolve("classes"),87"jdk/test/foo/resources/foo.properties");88createCmds(dir.resolve("bin"));89createLibs(dir.resolve("lib"));90createConfigs(dir.resolve("conf"));91}9293if (Files.exists(MODS_DIR))94FileUtils.deleteFileTreeWithRetry(MODS_DIR);95Files.createDirectories(MODS_DIR);96}9798// JDK-8166286 - jmod fails on symlink to directory99@Test100public void testDirSymlinks() throws IOException {101Path apaDir = EXPLODED_DIR.resolve("apa");102Path classesDir = EXPLODED_DIR.resolve("apa").resolve("classes");103assertTrue(compileModule("apa", classesDir));104Path libDir = apaDir.resolve("lib");105createFiles(libDir, List.of("foo/bar/libfoo.so"));106try {107Path link = Files.createSymbolicLink(108libDir.resolve("baz"), libDir.resolve("foo").toAbsolutePath());109assertTrue(Files.exists(link));110} catch (IOException|UnsupportedOperationException uoe) {111// OS does not support symlinks. Nothing to test!112System.out.println("Creating symlink failed. Test passes vacuously.");113uoe.printStackTrace();114return;115}116117Path jmod = MODS_DIR.resolve("apa.jmod");118jmod("create",119"--libs=" + libDir.toString(),120"--class-path", classesDir.toString(),121jmod.toString())122.assertSuccess();123Files.delete(jmod);124}125126// JDK-8267583 - jmod fails on symlink to class file127@Test128public void testFileSymlinks() throws IOException {129Path apaDir = EXPLODED_DIR.resolve("apa");130Path classesDir = EXPLODED_DIR.resolve("apa").resolve("classes");131assertTrue(compileModule("apa", classesDir));132133Files.move(classesDir.resolve("module-info.class"),134classesDir.resolve("module-info.class1"));135Files.move(classesDir.resolve(Paths.get("jdk", "test", "apa", "Apa.class")),136classesDir.resolve("Apa.class1"));137try {138Path link = Files.createSymbolicLink(139classesDir.resolve("module-info.class"),140classesDir.resolve("module-info.class1").toAbsolutePath());141assertTrue(Files.exists(link));142link = Files.createSymbolicLink(143classesDir.resolve(Paths.get("jdk", "test", "apa", "Apa.class")),144classesDir.resolve("Apa.class1").toAbsolutePath());145assertTrue(Files.exists(link));146} catch (IOException|UnsupportedOperationException uoe) {147// OS does not support symlinks. Nothing to test!148System.out.println("Creating symlinks failed. Test passes vacuously.");149uoe.printStackTrace();150return;151}152153Path jmod = MODS_DIR.resolve("apa.jmod");154jmod("create",155"--class-path", classesDir.toString(),156jmod.toString())157.assertSuccess();158Files.delete(jmod);159}160161// JDK-8170618 - jmod should validate if any exported or open package is missing162@Test163public void testMissingPackages() throws IOException {164Path apaDir = EXPLODED_DIR.resolve("apa");165Path classesDir = EXPLODED_DIR.resolve("apa").resolve("classes");166if (Files.exists(classesDir))167FileUtils.deleteFileTreeWithRetry(classesDir);168assertTrue(compileModule("apa", classesDir));169FileUtils.deleteFileTreeWithRetry(classesDir.resolve("jdk"));170Path jmod = MODS_DIR.resolve("apa.jmod");171jmod("create",172"--class-path", classesDir.toString(),173jmod.toString())174.assertFailure()175.resultChecker(r -> {176assertContains(r.output, "Packages that are exported or open in apa are not present: [jdk.test.apa]");177});178if (Files.exists(classesDir))179FileUtils.deleteFileTreeWithRetry(classesDir);180}181182@Test183public void testList() throws IOException {184String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();185jmod("create",186"--class-path", cp,187MODS_DIR.resolve("foo.jmod").toString())188.assertSuccess();189190jmod("list",191MODS_DIR.resolve("foo.jmod").toString())192.assertSuccess()193.resultChecker(r -> {194// asserts dependent on the exact contents of foo195assertContains(r.output, CLASSES_PREFIX + "module-info.class");196assertContains(r.output, CLASSES_PREFIX + "jdk/test/foo/Foo.class");197assertContains(r.output, CLASSES_PREFIX + "jdk/test/foo/internal/Message.class");198assertContains(r.output, CLASSES_PREFIX + "jdk/test/foo/resources/foo.properties");199});200}201202@Test203public void testExtractCWD() throws IOException {204Path cp = EXPLODED_DIR.resolve("foo").resolve("classes");205jmod("create",206"--class-path", cp.toString(),207MODS_DIR.resolve("fooExtractCWD.jmod").toString())208.assertSuccess();209210jmod("extract",211MODS_DIR.resolve("fooExtractCWD.jmod").toString())212.assertSuccess()213.resultChecker(r -> {214// module-info should exist, but jmod will have added its Packages attr.215assertTrue(Files.exists(Paths.get("classes/module-info.class")));216assertSameContent(cp.resolve("jdk/test/foo/Foo.class"),217Paths.get("classes/jdk/test/foo/Foo.class"));218assertSameContent(cp.resolve("jdk/test/foo/internal/Message.class"),219Paths.get("classes/jdk/test/foo/internal/Message.class"));220assertSameContent(cp.resolve("jdk/test/foo/resources/foo.properties"),221Paths.get("classes/jdk/test/foo/resources/foo.properties"));222});223}224225@Test226public void testExtractDir() throws IOException {227if (Files.exists(Paths.get("extractTestDir")))228FileUtils.deleteFileTreeWithRetry(Paths.get("extractTestDir"));229Path cp = EXPLODED_DIR.resolve("foo").resolve("classes");230Path bp = EXPLODED_DIR.resolve("foo").resolve("bin");231Path lp = EXPLODED_DIR.resolve("foo").resolve("lib");232Path cf = EXPLODED_DIR.resolve("foo").resolve("conf");233234jmod("create",235"--conf", cf.toString(),236"--cmds", bp.toString(),237"--libs", lp.toString(),238"--class-path", cp.toString(),239MODS_DIR.resolve("fooExtractDir.jmod").toString())240.assertSuccess();241242jmod("extract",243"--dir", "extractTestDir",244MODS_DIR.resolve("fooExtractDir.jmod").toString())245.assertSuccess();246247jmod("extract",248"--dir", "extractTestDir",249MODS_DIR.resolve("fooExtractDir.jmod").toString())250.assertSuccess()251.resultChecker(r -> {252// check a sample of the extracted files253Path p = Paths.get("extractTestDir");254assertTrue(Files.exists(p.resolve("classes/module-info.class")));255assertSameContent(cp.resolve("jdk/test/foo/Foo.class"),256p.resolve("classes/jdk/test/foo/Foo.class"));257assertSameContent(bp.resolve("first"),258p.resolve(CMDS_PREFIX).resolve("first"));259assertSameContent(lp.resolve("first.so"),260p.resolve(LIBS_PREFIX).resolve("second.so"));261assertSameContent(cf.resolve("second.cfg"),262p.resolve(CONFIGS_PREFIX).resolve("second.cfg"));263});264}265266@Test267public void testMainClass() throws IOException {268Path jmod = MODS_DIR.resolve("fooMainClass.jmod");269FileUtils.deleteFileIfExistsWithRetry(jmod);270String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();271272jmod("create",273"--class-path", cp,274"--main-class", "jdk.test.foo.Foo",275jmod.toString())276.assertSuccess()277.resultChecker(r -> {278Optional<String> omc = getModuleDescriptor(jmod).mainClass();279assertTrue(omc.isPresent());280assertEquals(omc.get(), "jdk.test.foo.Foo");281});282}283284@Test285public void testModuleVersion() throws IOException {286Path jmod = MODS_DIR.resolve("fooVersion.jmod");287FileUtils.deleteFileIfExistsWithRetry(jmod);288String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();289290jmod("create",291"--class-path", cp,292"--module-version", "5.4.3",293jmod.toString())294.assertSuccess()295.resultChecker(r -> {296Optional<Version> ov = getModuleDescriptor(jmod).version();297assertTrue(ov.isPresent());298assertEquals(ov.get().toString(), "5.4.3");299});300}301302@Test303public void testConfig() throws IOException {304Path jmod = MODS_DIR.resolve("fooConfig.jmod");305FileUtils.deleteFileIfExistsWithRetry(jmod);306Path cp = EXPLODED_DIR.resolve("foo").resolve("classes");307Path cf = EXPLODED_DIR.resolve("foo").resolve("conf");308309jmod("create",310"--class-path", cp.toString(),311"--config", cf.toString(),312jmod.toString())313.assertSuccess()314.resultChecker(r -> {315try (Stream<String> s1 = findFiles(cf).map(p -> CONFIGS_PREFIX + p);316Stream<String> s2 = findFiles(cp).map(p -> CLASSES_PREFIX + p)) {317Set<String> expectedFilenames = Stream.concat(s1, s2)318.collect(toSet());319assertJmodContent(jmod, expectedFilenames);320}321});322}323324@Test325public void testCmds() throws IOException {326Path jmod = MODS_DIR.resolve("fooCmds.jmod");327FileUtils.deleteFileIfExistsWithRetry(jmod);328Path cp = EXPLODED_DIR.resolve("foo").resolve("classes");329Path bp = EXPLODED_DIR.resolve("foo").resolve("bin");330331jmod("create",332"--cmds", bp.toString(),333"--class-path", cp.toString(),334jmod.toString())335.assertSuccess()336.resultChecker(r -> {337try (Stream<String> s1 = findFiles(bp).map(p -> CMDS_PREFIX + p);338Stream<String> s2 = findFiles(cp).map(p -> CLASSES_PREFIX + p)) {339Set<String> expectedFilenames = Stream.concat(s1,s2)340.collect(toSet());341assertJmodContent(jmod, expectedFilenames);342}343});344}345346@Test347public void testLibs() throws IOException {348Path jmod = MODS_DIR.resolve("fooLibs.jmod");349FileUtils.deleteFileIfExistsWithRetry(jmod);350Path cp = EXPLODED_DIR.resolve("foo").resolve("classes");351Path lp = EXPLODED_DIR.resolve("foo").resolve("lib");352353jmod("create",354"--libs=" + lp.toString(),355"--class-path", cp.toString(),356jmod.toString())357.assertSuccess()358.resultChecker(r -> {359try (Stream<String> s1 = findFiles(lp).map(p -> LIBS_PREFIX + p);360Stream<String> s2 = findFiles(cp).map(p -> CLASSES_PREFIX + p)) {361Set<String> expectedFilenames = Stream.concat(s1,s2)362.collect(toSet());363assertJmodContent(jmod, expectedFilenames);364}365});366}367368@Test369public void testAll() throws IOException {370Path jmod = MODS_DIR.resolve("fooAll.jmod");371FileUtils.deleteFileIfExistsWithRetry(jmod);372Path cp = EXPLODED_DIR.resolve("foo").resolve("classes");373Path bp = EXPLODED_DIR.resolve("foo").resolve("bin");374Path lp = EXPLODED_DIR.resolve("foo").resolve("lib");375Path cf = EXPLODED_DIR.resolve("foo").resolve("conf");376377jmod("create",378"--conf", cf.toString(),379"--cmds=" + bp.toString(),380"--libs=" + lp.toString(),381"--class-path", cp.toString(),382jmod.toString())383.assertSuccess()384.resultChecker(r -> {385try (Stream<String> s1 = findFiles(lp).map(p -> LIBS_PREFIX + p);386Stream<String> s2 = findFiles(cp).map(p -> CLASSES_PREFIX + p);387Stream<String> s3 = findFiles(bp).map(p -> CMDS_PREFIX + p);388Stream<String> s4 = findFiles(cf).map(p -> CONFIGS_PREFIX + p)) {389Set<String> expectedFilenames = Stream.concat(Stream.concat(s1,s2),390Stream.concat(s3, s4))391.collect(toSet());392assertJmodContent(jmod, expectedFilenames);393}394});395}396397@Test398public void testExcludes() throws IOException {399Path jmod = MODS_DIR.resolve("fooLibs.jmod");400FileUtils.deleteFileIfExistsWithRetry(jmod);401Path cp = EXPLODED_DIR.resolve("foo").resolve("classes");402Path lp = EXPLODED_DIR.resolve("foo").resolve("lib");403404jmod("create",405"--libs=" + lp.toString(),406"--class-path", cp.toString(),407"--exclude", "**internal**",408"--exclude", "first.so",409jmod.toString())410.assertSuccess()411.resultChecker(r -> {412Set<String> expectedFilenames = new HashSet<>();413expectedFilenames.add(CLASSES_PREFIX + "module-info.class");414expectedFilenames.add(CLASSES_PREFIX + "jdk/test/foo/Foo.class");415expectedFilenames.add(CLASSES_PREFIX + "jdk/test/foo/resources/foo.properties");416expectedFilenames.add(LIBS_PREFIX + "second.so");417expectedFilenames.add(LIBS_PREFIX + "third/third.so");418assertJmodContent(jmod, expectedFilenames);419420Set<String> unexpectedFilenames = new HashSet<>();421unexpectedFilenames.add(CLASSES_PREFIX + "jdk/test/foo/internal/Message.class");422unexpectedFilenames.add(LIBS_PREFIX + "first.so");423assertJmodDoesNotContain(jmod, unexpectedFilenames);424});425}426427@Test428public void describe() throws IOException {429String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();430jmod("create",431"--class-path", cp,432MODS_DIR.resolve("describeFoo.jmod").toString())433.assertSuccess();434435jmod("describe",436MODS_DIR.resolve("describeFoo.jmod").toString())437.assertSuccess()438.resultChecker(r -> {439// Expect similar output: "foo... exports jdk.test.foo ...440// ... requires java.base mandated... contains jdk.test.foo.internal"441Pattern p = Pattern.compile("foo\\s+exports\\s+jdk.test.foo");442assertTrue(p.matcher(r.output).find(),443"Expecting to find \"foo... exports jdk.test.foo\"" +444"in output, but did not: [" + r.output + "]");445p = Pattern.compile(446"requires\\s+java.base\\s+mandated\\s+contains\\s+jdk.test.foo.internal");447assertTrue(p.matcher(r.output).find(),448"Expecting to find \"requires java.base mandated..., " +449"contains jdk.test.foo.internal ...\"" +450"in output, but did not: [" + r.output + "]");451});452}453454@Test455public void testDuplicateEntries() throws IOException {456Path jmod = MODS_DIR.resolve("testDuplicates.jmod");457FileUtils.deleteFileIfExistsWithRetry(jmod);458String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();459Path lp = EXPLODED_DIR.resolve("foo").resolve("lib");460461jmod("create",462"--class-path", cp + pathSeparator + cp,463jmod.toString())464.assertSuccess()465.resultChecker(r ->466assertContains(r.output, "Warning: ignoring duplicate entry")467);468469FileUtils.deleteFileIfExistsWithRetry(jmod);470jmod("create",471"--class-path", cp,472"--libs", lp.toString() + pathSeparator + lp.toString(),473jmod.toString())474.assertSuccess()475.resultChecker(r ->476assertContains(r.output, "Warning: ignoring duplicate entry")477);478}479480@Test481public void testDuplicateEntriesFromJarFile() throws IOException {482String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();483Path jar = Paths.get("foo.jar");484Path jmod = MODS_DIR.resolve("testDuplicates.jmod");485FileUtils.deleteFileIfExistsWithRetry(jar);486FileUtils.deleteFileIfExistsWithRetry(jmod);487// create JAR file488assertTrue(JAR_TOOL.run(System.out, System.err, "cf", jar.toString(), "-C", cp, ".") == 0);489490jmod("create",491"--class-path", jar.toString() + pathSeparator + jar.toString(),492jmod.toString())493.assertSuccess()494.resultChecker(r ->495assertContains(r.output, "Warning: ignoring duplicate entry")496);497}498499@Test500public void testIgnoreModuleInfoInOtherSections() throws IOException {501Path jmod = MODS_DIR.resolve("testIgnoreModuleInfoInOtherSections.jmod");502FileUtils.deleteFileIfExistsWithRetry(jmod);503String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();504505jmod("create",506"--class-path", cp,507"--libs", cp,508jmod.toString())509.assertSuccess()510.resultChecker(r ->511assertContains(r.output, "Warning: ignoring entry")512);513514FileUtils.deleteFileIfExistsWithRetry(jmod);515jmod("create",516"--class-path", cp,517"--cmds", cp,518jmod.toString())519.assertSuccess()520.resultChecker(r ->521assertContains(r.output, "Warning: ignoring entry")522);523}524525@Test526public void testLastOneWins() throws IOException {527Path workDir = Paths.get("lastOneWins");528if (Files.exists(workDir))529FileUtils.deleteFileTreeWithRetry(workDir);530Files.createDirectory(workDir);531Path jmod = MODS_DIR.resolve("lastOneWins.jmod");532FileUtils.deleteFileIfExistsWithRetry(jmod);533Path cp = EXPLODED_DIR.resolve("foo").resolve("classes");534Path bp = EXPLODED_DIR.resolve("foo").resolve("bin");535Path lp = EXPLODED_DIR.resolve("foo").resolve("lib");536Path cf = EXPLODED_DIR.resolve("foo").resolve("conf");537538Path shouldNotBeAdded = workDir.resolve("shouldNotBeAdded");539Files.createDirectory(shouldNotBeAdded);540Files.write(shouldNotBeAdded.resolve("aFile"), "hello".getBytes(UTF_8));541542// Pairs of options. For options with required arguments the last one543// should win ( first should be effectively ignored, but may still be544// validated ).545jmod("create",546"--conf", shouldNotBeAdded.toString(),547"--conf", cf.toString(),548"--cmds", shouldNotBeAdded.toString(),549"--cmds", bp.toString(),550"--libs", shouldNotBeAdded.toString(),551"--libs", lp.toString(),552"--class-path", shouldNotBeAdded.toString(),553"--class-path", cp.toString(),554"--main-class", "does.NotExist",555"--main-class", "jdk.test.foo.Foo",556"--module-version", "00001",557"--module-version", "5.4.3",558"--do-not-resolve-by-default",559"--do-not-resolve-by-default",560"--warn-if-resolved=incubating",561"--warn-if-resolved=deprecated",562MODS_DIR.resolve("lastOneWins.jmod").toString())563.assertSuccess()564.resultChecker(r -> {565ModuleDescriptor md = getModuleDescriptor(jmod);566Optional<String> omc = md.mainClass();567assertTrue(omc.isPresent());568assertEquals(omc.get(), "jdk.test.foo.Foo");569Optional<Version> ov = md.version();570assertTrue(ov.isPresent());571assertEquals(ov.get().toString(), "5.4.3");572573try (Stream<String> s1 = findFiles(lp).map(p -> LIBS_PREFIX + p);574Stream<String> s2 = findFiles(cp).map(p -> CLASSES_PREFIX + p);575Stream<String> s3 = findFiles(bp).map(p -> CMDS_PREFIX + p);576Stream<String> s4 = findFiles(cf).map(p -> CONFIGS_PREFIX + p)) {577Set<String> expectedFilenames = Stream.concat(Stream.concat(s1,s2),578Stream.concat(s3, s4))579.collect(toSet());580assertJmodContent(jmod, expectedFilenames);581}582});583584jmod("extract",585"--dir", "blah",586"--dir", "lastOneWinsExtractDir",587jmod.toString())588.assertSuccess()589.resultChecker(r -> {590assertTrue(Files.exists(Paths.get("lastOneWinsExtractDir")));591assertTrue(Files.notExists(Paths.get("blah")));592});593}594595@Test596public void testPackagesAttribute() throws IOException {597Path jmod = MODS_DIR.resolve("foo.jmod");598FileUtils.deleteFileIfExistsWithRetry(jmod);599String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();600601Set<String> expectedPackages = Set.of("jdk.test.foo",602"jdk.test.foo.internal",603"jdk.test.foo.resources");604605jmod("create",606"--class-path", cp,607jmod.toString())608.assertSuccess()609.resultChecker(r -> {610Set<String> pkgs = getModuleDescriptor(jmod).packages();611assertEquals(pkgs, expectedPackages);612});613}614615@Test616public void testVersion() {617jmod("--version")618.assertSuccess()619.resultChecker(r -> {620assertContains(r.output, System.getProperty("java.version"));621});622}623624@Test625public void testHelp() {626jmod("--help")627.assertSuccess()628.resultChecker(r -> {629assertTrue(r.output.startsWith("Usage: jmod"), "Help not printed");630assertFalse(r.output.contains("--do-not-resolve-by-default"));631assertFalse(r.output.contains("--warn-if-resolved"));632});633}634635@Test636public void testHelpExtra() {637jmod("--help-extra")638.assertSuccess()639.resultChecker(r -> {640assertTrue(r.output.startsWith("Usage: jmod"), "Extra help not printed");641assertContains(r.output, "--do-not-resolve-by-default");642assertContains(r.output, "--warn-if-resolved");643});644}645646@Test647public void testTmpFileRemoved() throws IOException {648// Implementation detail: jmod tool creates <jmod-file>.tmp649// Ensure that it is removed in the event of a failure.650// The failure in this case is a class in the unnamed package.651652Path jmod = MODS_DIR.resolve("testTmpFileRemoved.jmod");653Path tmp = MODS_DIR.resolve(".testTmpFileRemoved.jmod.tmp");654FileUtils.deleteFileIfExistsWithRetry(jmod);655FileUtils.deleteFileIfExistsWithRetry(tmp);656String cp = EXPLODED_DIR.resolve("foo").resolve("classes") + File.pathSeparator +657EXPLODED_DIR.resolve("foo").resolve("classes")658.resolve("jdk").resolve("test").resolve("foo").toString();659660jmod("create",661"--class-path", cp,662jmod.toString())663.assertFailure()664.resultChecker(r -> {665assertContains(r.output, "unnamed package");666assertTrue(Files.notExists(tmp), "Unexpected tmp file:" + tmp);667});668}669670// ---671672static boolean compileModule(String name, Path dest) throws IOException {673return CompilerUtils.compile(SRC_DIR.resolve(name), dest);674}675676static void assertContains(String output, String subString) {677if (output.contains(subString))678assertTrue(true);679else680assertTrue(false,"Expected to find [" + subString + "], in output ["681+ output + "]" + "\n");682}683684static ModuleDescriptor getModuleDescriptor(Path jmod) {685ClassLoader cl = ClassLoader.getSystemClassLoader();686try (FileSystem fs = FileSystems.newFileSystem(jmod, cl)) {687String p = "/classes/module-info.class";688try (InputStream is = Files.newInputStream(fs.getPath(p))) {689return ModuleDescriptor.read(is);690}691} catch (IOException ioe) {692throw new UncheckedIOException(ioe);693}694}695696static Stream<String> findFiles(Path dir) {697try {698return Files.find(dir, Integer.MAX_VALUE, (p, a) -> a.isRegularFile())699.map(dir::relativize)700.map(Path::toString)701.map(p -> p.replace(File.separator, "/"));702} catch (IOException x) {703throw new UncheckedIOException(x);704}705}706707static Set<String> getJmodContent(Path jmod) {708JmodResult r = jmod("list", jmod.toString()).assertSuccess();709return Stream.of(r.output.split("\r?\n")).collect(toSet());710}711712static void assertJmodContent(Path jmod, Set<String> expected) {713Set<String> actual = getJmodContent(jmod);714if (!Objects.equals(actual, expected)) {715Set<String> unexpected = new HashSet<>(actual);716unexpected.removeAll(expected);717Set<String> notFound = new HashSet<>(expected);718notFound.removeAll(actual);719StringBuilder sb = new StringBuilder();720sb.append("Unexpected but found:\n");721unexpected.forEach(s -> sb.append("\t" + s + "\n"));722sb.append("Expected but not found:\n");723notFound.forEach(s -> sb.append("\t" + s + "\n"));724assertTrue(false, "Jmod content check failed.\n" + sb.toString());725}726}727728static void assertJmodDoesNotContain(Path jmod, Set<String> unexpectedNames) {729Set<String> actual = getJmodContent(jmod);730Set<String> unexpected = new HashSet<>();731for (String name : unexpectedNames) {732if (actual.contains(name))733unexpected.add(name);734}735if (!unexpected.isEmpty()) {736StringBuilder sb = new StringBuilder();737for (String s : unexpected)738sb.append("Unexpected but found: " + s + "\n");739sb.append("In :");740for (String s : actual)741sb.append("\t" + s + "\n");742assertTrue(false, "Jmod content check failed.\n" + sb.toString());743}744}745746static void assertSameContent(Path p1, Path p2) {747try {748byte[] ba1 = Files.readAllBytes(p1);749byte[] ba2 = Files.readAllBytes(p2);750assertEquals(ba1, ba2);751} catch (IOException x) {752throw new UncheckedIOException(x);753}754}755756static JmodResult jmod(String... args) {757ByteArrayOutputStream baos = new ByteArrayOutputStream();758PrintStream ps = new PrintStream(baos);759System.out.println("jmod " + Arrays.asList(args));760int ec = JMOD_TOOL.run(ps, ps, args);761return new JmodResult(ec, new String(baos.toByteArray(), UTF_8));762}763764static class JmodResult {765final int exitCode;766final String output;767768JmodResult(int exitValue, String output) {769this.exitCode = exitValue;770this.output = output;771}772JmodResult assertSuccess() { assertTrue(exitCode == 0, output); return this; }773JmodResult assertFailure() { assertTrue(exitCode != 0, output); return this; }774JmodResult resultChecker(Consumer<JmodResult> r) { r.accept(this); return this; }775}776777static void createCmds(Path dir) throws IOException {778List<String> files = Arrays.asList(779"first", "second", "third" + File.separator + "third");780createFiles(dir, files);781}782783static void createLibs(Path dir) throws IOException {784List<String> files = Arrays.asList(785"first.so", "second.so", "third" + File.separator + "third.so");786createFiles(dir, files);787}788789static void createConfigs(Path dir) throws IOException {790List<String> files = Arrays.asList(791"first.cfg", "second.cfg", "third" + File.separator + "third.cfg");792createFiles(dir, files);793}794795static void createFiles(Path dir, List<String> filenames) throws IOException {796for (String name : filenames) {797Path file = dir.resolve(name);798Files.createDirectories(file.getParent());799Files.createFile(file);800try (OutputStream os = Files.newOutputStream(file)) {801os.write("blahblahblah".getBytes(UTF_8));802}803}804}805806static void copyResource(Path srcDir, Path dir, String resource) throws IOException {807Path dest = dir.resolve(resource);808Files.deleteIfExists(dest);809810Files.createDirectories(dest.getParent());811Files.copy(srcDir.resolve(resource), dest);812}813814// Standalone entry point.815public static void main(String[] args) throws Throwable {816JmodTest test = new JmodTest();817test.buildExplodedModules();818for (Method m : JmodTest.class.getDeclaredMethods()) {819if (m.getAnnotation(Test.class) != null) {820System.out.println("Invoking " + m.getName());821m.invoke(test);822}823}824}825}826827828