Path: blob/master/test/jdk/tools/jar/mmrjar/Basic.java
41149 views
/*1* Copyright (c) 2016, 2017, 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 8146486 817243226* @summary Fail to create a MR modular JAR with a versioned entry in27* base-versioned empty package28* @modules java.base/jdk.internal.module29* jdk.compiler30* jdk.jartool31* @library /test/lib32* @build jdk.test.lib.Platform33* jdk.test.lib.util.FileUtils34* @run testng Basic35*/3637import org.testng.Assert;38import org.testng.annotations.AfterClass;39import org.testng.annotations.Test;4041import java.io.ByteArrayInputStream;42import java.io.ByteArrayOutputStream;43import java.io.IOException;44import java.io.PrintStream;45import java.io.UncheckedIOException;46import java.lang.module.ModuleDescriptor;47import java.lang.module.ModuleDescriptor.Version;48import java.nio.file.Files;49import java.nio.file.Path;50import java.nio.file.Paths;51import java.util.Arrays;52import java.util.Optional;53import java.util.Set;54import java.util.spi.ToolProvider;55import java.util.stream.Collectors;56import java.util.stream.Stream;57import java.util.zip.ZipFile;5859import jdk.internal.module.ModuleInfoExtender;60import jdk.test.lib.util.FileUtils;6162public class Basic {63private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar")64.orElseThrow(() -> new RuntimeException("jar tool not found"));65private static final ToolProvider JAVAC_TOOL = ToolProvider.findFirst("javac")66.orElseThrow(() -> new RuntimeException("javac tool not found"));67private final String linesep = System.lineSeparator();68private final Path testsrc;69private final Path userdir;70private final ByteArrayOutputStream outbytes = new ByteArrayOutputStream();71private final PrintStream out = new PrintStream(outbytes, true);72private final ByteArrayOutputStream errbytes = new ByteArrayOutputStream();73private final PrintStream err = new PrintStream(errbytes, true);7475public Basic() throws IOException {76testsrc = Paths.get(System.getProperty("test.src"));77userdir = Paths.get(System.getProperty("user.dir", "."));7879// compile the classes directory80Path source = testsrc.resolve("src").resolve("classes");81Path destination = Paths.get("classes");82javac(source, destination);8384// compile the mr9 directory including module-info.java85source = testsrc.resolve("src").resolve("mr9");86destination = Paths.get("mr9");87javac(source, destination);8889// move module-info.class for later use90Files.move(destination.resolve("module-info.class"),91Paths.get("module-info.class"));92}9394private void javac(Path source, Path destination) throws IOException {95String[] args = Stream.concat(96Stream.of("-d", destination.toString()),97Files.walk(source)98.map(Path::toString)99.filter(s -> s.endsWith(".java"))100).toArray(String[]::new);101JAVAC_TOOL.run(System.out, System.err, args);102}103104private int jar(String cmd) {105outbytes.reset();106errbytes.reset();107return JAR_TOOL.run(out, err, cmd.split(" +"));108}109110@AfterClass111public void cleanup() throws IOException {112Files.walk(userdir, 1)113.filter(p -> !p.equals(userdir))114.forEach(p -> {115try {116if (Files.isDirectory(p)) {117FileUtils.deleteFileTreeWithRetry(p);118} else {119FileUtils.deleteFileIfExistsWithRetry(p);120}121} catch (IOException x) {122throw new UncheckedIOException(x);123}124});125}126127// updates a valid multi-release jar with a new public class in128// versioned section and fails129@Test130public void test1() {131// successful build of multi-release jar132int rc = jar("-cf mmr.jar -C classes . --release 9 -C mr9 p/Hi.class");133Assert.assertEquals(rc, 0);134135jar("-tf mmr.jar");136137Set<String> actual = lines(outbytes);138Set<String> expected = Set.of(139"META-INF/",140"META-INF/MANIFEST.MF",141"p/",142"p/Hi.class",143"META-INF/versions/9/p/Hi.class"144);145Assert.assertEquals(actual, expected);146147// failed build because of new public class148rc = jar("-uf mmr.jar --release 9 -C mr9 p/internal/Bar.class");149Assert.assertEquals(rc, 1);150151String s = new String(errbytes.toByteArray());152Assert.assertTrue(Message.NOT_FOUND_IN_BASE_ENTRY.match(s, "p/internal/Bar.class"));153}154155// updates a valid multi-release jar with a module-info class and new156// concealed public class in versioned section and succeeds157@Test158public void test2() {159// successful build of multi-release jar160int rc = jar("-cf mmr.jar -C classes . --release 9 -C mr9 p/Hi.class");161Assert.assertEquals(rc, 0);162163// successful build because of module-info and new public class164rc = jar("-uf mmr.jar module-info.class --release 9 -C mr9 p/internal/Bar.class");165Assert.assertEquals(rc, 0);166167String s = new String(errbytes.toByteArray());168Assert.assertTrue(Message.NEW_CONCEALED_PACKAGE_WARNING.match(s, "p/internal/Bar.class"));169170jar("-tf mmr.jar");171172Set<String> actual = lines(outbytes);173Set<String> expected = Set.of(174"META-INF/",175"META-INF/MANIFEST.MF",176"p/",177"p/Hi.class",178"META-INF/versions/9/p/Hi.class",179"META-INF/versions/9/p/internal/Bar.class",180"module-info.class"181);182Assert.assertEquals(actual, expected);183}184185// jar tool fails building mmr.jar because of new public class186@Test187public void test3() {188int rc = jar("-cf mmr.jar -C classes . --release 9 -C mr9 .");189Assert.assertEquals(rc, 1);190191String s = new String(errbytes.toByteArray());192Assert.assertTrue(Message.NOT_FOUND_IN_BASE_ENTRY.match(s, "p/internal/Bar.class"));193}194195// jar tool succeeds building mmr.jar because of concealed package196@Test197public void test4() {198int rc = jar("-cf mmr.jar module-info.class -C classes . " +199"--release 9 module-info.class -C mr9 .");200Assert.assertEquals(rc, 0);201202String s = new String(errbytes.toByteArray());203Assert.assertTrue(Message.NEW_CONCEALED_PACKAGE_WARNING.match(s, "p/internal/Bar.class"));204205jar("-tf mmr.jar");206207Set<String> actual = lines(outbytes);208Set<String> expected = Set.of(209"META-INF/",210"META-INF/MANIFEST.MF",211"module-info.class",212"META-INF/versions/9/module-info.class",213"p/",214"p/Hi.class",215"META-INF/versions/9/",216"META-INF/versions/9/p/",217"META-INF/versions/9/p/Hi.class",218"META-INF/versions/9/p/internal/",219"META-INF/versions/9/p/internal/Bar.class"220);221Assert.assertEquals(actual, expected);222}223224// jar tool does two updates, no exported packages, all concealed.225// Along with various --describe-module variants226@Test227public void test5() throws IOException {228// compile the mr10 directory229Path source = testsrc.resolve("src").resolve("mr10");230Path destination = Paths.get("mr10");231javac(source, destination);232233// create a directory for this tests special files234Files.createDirectory(Paths.get("test5"));235236// create an empty module-info.java237String hi = "module hi {" + linesep + "}" + linesep;238Path modinfo = Paths.get("test5", "module-info.java");239Files.write(modinfo, hi.getBytes());240241// and compile it242javac(modinfo, Paths.get("test5"));243244int rc = jar("--create --file mr.jar -C classes .");245Assert.assertEquals(rc, 0);246247rc = jar("--update --file mr.jar -C test5 module-info.class"248+ " --release 9 -C mr9 .");249Assert.assertEquals(rc, 0);250251jar("tf mr.jar");252253Set<String> actual = lines(outbytes);254Set<String> expected = Set.of(255"META-INF/",256"META-INF/MANIFEST.MF",257"p/",258"p/Hi.class",259"META-INF/versions/9/",260"META-INF/versions/9/p/",261"META-INF/versions/9/p/Hi.class",262"META-INF/versions/9/p/internal/",263"META-INF/versions/9/p/internal/Bar.class",264"module-info.class"265);266Assert.assertEquals(actual, expected);267268jar("-d --file mr.jar");269270String uri = (Paths.get("mr.jar")).toUri().toString();271uri = "jar:" + uri + "!/module-info.class";272273actual = lines(outbytes);274expected = Set.of(275"hi " + uri,276"requires java.base mandated",277"contains p",278"contains p.internal"279);280Assert.assertEquals(actual, expected);281282rc = jar("--update --file mr.jar --release 10 -C mr10 .");283Assert.assertEquals(rc, 0);284285jar("tf mr.jar");286287actual = lines(outbytes);288expected = Set.of(289"META-INF/",290"META-INF/MANIFEST.MF",291"p/",292"p/Hi.class",293"META-INF/versions/9/",294"META-INF/versions/9/p/",295"META-INF/versions/9/p/Hi.class",296"META-INF/versions/9/p/internal/",297"META-INF/versions/9/p/internal/Bar.class",298"META-INF/versions/10/",299"META-INF/versions/10/p/",300"META-INF/versions/10/p/internal/",301"META-INF/versions/10/p/internal/bar/",302"META-INF/versions/10/p/internal/bar/Gee.class",303"module-info.class"304);305Assert.assertEquals(actual, expected);306307jar("-d --file mr.jar");308309actual = lines(outbytes);310expected = Set.of(311"hi " + uri,312"requires java.base mandated",313"contains p",314"contains p.internal",315"contains p.internal.bar"316);317Assert.assertEquals(actual, expected);318319for (String release : new String[] {"9" , "10", "100", "1000"}) {320jar("-d --file mr.jar --release " + release);321actual = lines(outbytes);322Assert.assertEquals(actual, expected);323}324}325326// root and versioned module-info entries have different main-class, version327// attributes328@Test329public void test6() throws IOException {330// create a directory for this tests special files331Files.createDirectory(Paths.get("test6"));332Files.createDirectory(Paths.get("test6-v9"));333334// compile the classes directory335Path src = testsrc.resolve("src").resolve("classes");336Path dst = Paths.get("test6");337javac(src, dst);338339byte[] mdBytes = Files.readAllBytes(Paths.get("module-info.class"));340341ModuleInfoExtender mie = ModuleInfoExtender.newExtender(342new ByteArrayInputStream(mdBytes));343344mie.mainClass("p.Main");345mie.version(Version.parse("1.0"));346347ByteArrayOutputStream baos = new ByteArrayOutputStream();348mie.write(baos);349Files.write(Paths.get("test6", "module-info.class"), baos.toByteArray());350Files.write(Paths.get("test6-v9", "module-info.class"), baos.toByteArray());351352int rc = jar("--create --file mmr.jar -C test6 . --release 9 -C test6-v9 .");353Assert.assertEquals(rc, 0);354355356// different main-class357mie = ModuleInfoExtender.newExtender(new ByteArrayInputStream(mdBytes));358mie.mainClass("p.Main2");359mie.version(Version.parse("1.0"));360baos.reset();361mie.write(baos);362Files.write(Paths.get("test6-v9", "module-info.class"), baos.toByteArray());363364rc = jar("--create --file mmr.jar -C test6 . --release 9 -C test6-v9 .");365Assert.assertEquals(rc, 1);366367Assert.assertTrue(Message.CONTAINS_DIFFERENT_MAINCLASS.match(368new String(errbytes.toByteArray()),369"META-INF/versions/9/module-info.class"));370371// different version372mie = ModuleInfoExtender.newExtender(new ByteArrayInputStream(mdBytes));373mie.mainClass("p.Main");374mie.version(Version.parse("2.0"));375baos.reset();376mie.write(baos);377Files.write(Paths.get("test6-v9", "module-info.class"), baos.toByteArray());378379rc = jar("--create --file mmr.jar -C test6 . --release 9 -C test6-v9 .");380Assert.assertEquals(rc, 1);381382Assert.assertTrue(Message.CONTAINS_DIFFERENT_VERSION.match(383new String(errbytes.toByteArray()),384"META-INF/versions/9/module-info.class"));385386}387388// versioned mmr without root module-info.class389@Test390public void test7() throws IOException {391// create a directory for this tests special files392Files.createDirectory(Paths.get("test7"));393Files.createDirectory(Paths.get("test7-v9"));394Files.createDirectory(Paths.get("test7-v10"));395396// compile the classes directory397Path src = testsrc.resolve("src").resolve("classes");398Path dst = Paths.get("test7");399javac(src, dst);400401// move module-info.class to v9 later use402Files.copy(Paths.get("module-info.class"),403Paths.get("test7-v9", "module-info.class"));404405Files.copy(Paths.get("test7-v9", "module-info.class"),406Paths.get("test7-v10", "module-info.class"));407408int rc = jar("--create --file mmr.jar --main-class=p.Main -C test7 . --release 9 -C test7-v9 . --release 10 -C test7-v10 .");409Assert.assertEquals(rc, 0);410411jar("-d --file=mmr.jar");412Set<String> actual = lines(outbytes);413Set<String> expected = Set.of(414"releases: 9 10",415"No root module descriptor, specify --release"416);417Assert.assertEquals(actual, expected);418419String uriPrefix = "jar:" + (Paths.get("mmr.jar")).toUri().toString();420421jar("-d --file=mmr.jar --release 9");422actual = lines(outbytes);423expected = Set.of(424"releases: 9 10",425"m1 " + uriPrefix + "!/META-INF/versions/9/module-info.class",426"requires java.base mandated",427"exports p",428"main-class p.Main"429);430Assert.assertEquals(actual, expected);431432jar("-d --file=mmr.jar --release 10");433actual = lines(outbytes);434expected = Set.of(435"releases: 9 10",436"m1 " + uriPrefix + "!/META-INF/versions/10/module-info.class",437"requires java.base mandated",438"exports p",439"main-class p.Main"440);441Assert.assertEquals(actual, expected);442443for (String release : new String[] {"11", "12", "15", "100"}) {444jar("-d --file mmr.jar --release " + release);445actual = lines(outbytes);446Assert.assertEquals(actual, expected);447}448449Optional<String> exp = Optional.of("p.Main");450try (ZipFile zf = new ZipFile("mmr.jar")) {451Assert.assertTrue(zf.getEntry("module-info.class") == null);452453ModuleDescriptor md = ModuleDescriptor.read(454zf.getInputStream(zf.getEntry("META-INF/versions/9/module-info.class")));455Assert.assertEquals(md.mainClass(), exp);456457md = ModuleDescriptor.read(458zf.getInputStream(zf.getEntry("META-INF/versions/10/module-info.class")));459Assert.assertEquals(md.mainClass(), exp);460}461}462463private static Set<String> lines(ByteArrayOutputStream baos) {464String s = new String(baos.toByteArray());465return Arrays.stream(s.split("\\R"))466.map(l -> l.trim())467.filter(l -> l.length() > 0)468.collect(Collectors.toSet());469}470471static enum Message {472CONTAINS_DIFFERENT_MAINCLASS(473": module-info.class in a versioned directory contains different \"main-class\""474),475CONTAINS_DIFFERENT_VERSION(476": module-info.class in a versioned directory contains different \"version\""477),478NOT_FOUND_IN_BASE_ENTRY(479", contains a new public class not found in base entries"480),481NEW_CONCEALED_PACKAGE_WARNING(482" is a public class" +483" in a concealed package, placing this jar on the class path will result" +484" in incompatible public interfaces"485);486487final String msg;488Message(String msg) {489this.msg = msg;490}491492/*493* Test if the given output contains this message ignoring the line break.494*/495boolean match(String output, String entry) {496System.out.println("Expected: " + entry + msg);497System.out.println("Found: " + output);498return Arrays.stream(output.split("\\R"))499.collect(Collectors.joining(" "))500.contains(entry + msg);501}502}503}504505506