jdk/test/tools/jar/mmrjar/ConcealedPackage.java
changeset 43097 69b209a7a0a4
parent 43060 ed4f16888e12
parent 43096 22875dc4eec5
child 43098 124d24e7988c
equal deleted inserted replaced
43060:ed4f16888e12 43097:69b209a7a0a4
     1 /*
       
     2  * Copyright (c) 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 8146486
       
    27  * @summary Fail to create a MR modular JAR with a versioned entry in
       
    28  *          base-versioned empty package
       
    29  * @modules jdk.compiler
       
    30  *          jdk.jartool
       
    31  * @library /lib/testlibrary
       
    32  * @build jdk.testlibrary.FileUtils
       
    33  * @run testng ConcealedPackage
       
    34  */
       
    35 
       
    36 import org.testng.Assert;
       
    37 import org.testng.annotations.AfterClass;
       
    38 import org.testng.annotations.Test;
       
    39 
       
    40 import java.io.ByteArrayOutputStream;
       
    41 import java.io.IOException;
       
    42 import java.io.PrintStream;
       
    43 import java.io.UncheckedIOException;
       
    44 import java.nio.file.Files;
       
    45 import java.nio.file.Path;
       
    46 import java.nio.file.Paths;
       
    47 import java.util.Arrays;
       
    48 import java.util.Set;
       
    49 import java.util.spi.ToolProvider;
       
    50 import java.util.stream.Collectors;
       
    51 import java.util.stream.Stream;
       
    52 
       
    53 import jdk.testlibrary.FileUtils;
       
    54 
       
    55 public class ConcealedPackage {
       
    56     private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar")
       
    57            .orElseThrow(() -> new RuntimeException("jar tool not found"));
       
    58     private static final ToolProvider JAVAC_TOOL = ToolProvider.findFirst("javac")
       
    59             .orElseThrow(() -> new RuntimeException("javac tool not found"));
       
    60     private final String linesep = System.lineSeparator();
       
    61     private final Path testsrc;
       
    62     private final Path userdir;
       
    63     private final ByteArrayOutputStream outbytes = new ByteArrayOutputStream();
       
    64     private final PrintStream out = new PrintStream(outbytes, true);
       
    65     private final ByteArrayOutputStream errbytes = new ByteArrayOutputStream();
       
    66     private final PrintStream err = new PrintStream(errbytes, true);
       
    67 
       
    68     public ConcealedPackage() throws IOException {
       
    69         testsrc = Paths.get(System.getProperty("test.src"));
       
    70         userdir = Paths.get(System.getProperty("user.dir", "."));
       
    71 
       
    72         // compile the classes directory
       
    73         Path source = testsrc.resolve("src").resolve("classes");
       
    74         Path destination = Paths.get("classes");
       
    75         javac(source, destination);
       
    76 
       
    77         // compile the mr9 directory including module-info.java
       
    78         source = testsrc.resolve("src").resolve("mr9");
       
    79         destination = Paths.get("mr9");
       
    80         javac(source, destination);
       
    81 
       
    82         // move module-info.class for later use
       
    83         Files.move(destination.resolve("module-info.class"),
       
    84                 Paths.get("module-info.class"));
       
    85     }
       
    86 
       
    87     private void javac(Path source, Path destination) throws IOException {
       
    88         String[] args = Stream.concat(
       
    89                 Stream.of("-d", destination.toString()),
       
    90                 Files.walk(source)
       
    91                         .map(Path::toString)
       
    92                         .filter(s -> s.endsWith(".java"))
       
    93         ).toArray(String[]::new);
       
    94         JAVAC_TOOL.run(System.out, System.err, args);
       
    95     }
       
    96 
       
    97     private int jar(String cmd) {
       
    98         outbytes.reset();
       
    99         errbytes.reset();
       
   100         return JAR_TOOL.run(out, err, cmd.split(" +"));
       
   101     }
       
   102 
       
   103     @AfterClass
       
   104     public void cleanup() throws IOException {
       
   105         Files.walk(userdir, 1)
       
   106                 .filter(p -> !p.equals(userdir))
       
   107                 .forEach(p -> {
       
   108                     try {
       
   109                         if (Files.isDirectory(p)) {
       
   110                             FileUtils.deleteFileTreeWithRetry(p);
       
   111                         } else {
       
   112                             FileUtils.deleteFileIfExistsWithRetry(p);
       
   113                         }
       
   114                     } catch (IOException x) {
       
   115                         throw new UncheckedIOException(x);
       
   116                     }
       
   117                 });
       
   118     }
       
   119 
       
   120     // updates a valid multi-release jar with a new public class in
       
   121     // versioned section and fails
       
   122     @Test
       
   123     public void test1() {
       
   124         // successful build of multi-release jar
       
   125         int rc = jar("-cf mmr.jar -C classes . --release 9 -C mr9 p/Hi.class");
       
   126         Assert.assertEquals(rc, 0);
       
   127 
       
   128         jar("-tf mmr.jar");
       
   129 
       
   130         Set<String> actual = lines(outbytes);
       
   131         Set<String> expected = Set.of(
       
   132                 "META-INF/",
       
   133                 "META-INF/MANIFEST.MF",
       
   134                 "p/",
       
   135                 "p/Hi.class",
       
   136                 "META-INF/versions/9/p/Hi.class"
       
   137         );
       
   138         Assert.assertEquals(actual, expected);
       
   139 
       
   140         // failed build because of new public class
       
   141         rc = jar("-uf mmr.jar --release 9 -C mr9 p/internal/Bar.class");
       
   142         Assert.assertEquals(rc, 1);
       
   143 
       
   144         String s = new String(errbytes.toByteArray());
       
   145         Assert.assertTrue(Message.NOT_FOUND_IN_BASE_ENTRY.match(s, "p/internal/Bar.class"));
       
   146     }
       
   147 
       
   148     // updates a valid multi-release jar with a module-info class and new
       
   149     // concealed public class in versioned section and succeeds
       
   150     @Test
       
   151     public void test2() {
       
   152         // successful build of multi-release jar
       
   153         int rc = jar("-cf mmr.jar -C classes . --release 9 -C mr9 p/Hi.class");
       
   154         Assert.assertEquals(rc, 0);
       
   155 
       
   156         // successful build because of module-info and new public class
       
   157         rc = jar("-uf mmr.jar module-info.class --release 9 -C mr9 p/internal/Bar.class");
       
   158         Assert.assertEquals(rc, 0);
       
   159 
       
   160         String s = new String(errbytes.toByteArray());
       
   161         Assert.assertTrue(Message.NEW_CONCEALED_PACKAGE_WARNING.match(s, "p/internal/Bar.class"));
       
   162 
       
   163         jar("-tf mmr.jar");
       
   164 
       
   165         Set<String> actual = lines(outbytes);
       
   166         Set<String> expected = Set.of(
       
   167                 "META-INF/",
       
   168                 "META-INF/MANIFEST.MF",
       
   169                 "p/",
       
   170                 "p/Hi.class",
       
   171                 "META-INF/versions/9/p/Hi.class",
       
   172                 "META-INF/versions/9/p/internal/Bar.class",
       
   173                 "module-info.class"
       
   174         );
       
   175         Assert.assertEquals(actual, expected);
       
   176     }
       
   177 
       
   178     // jar tool fails building mmr.jar because of new public class
       
   179     @Test
       
   180     public void test3() {
       
   181         int rc = jar("-cf mmr.jar -C classes . --release 9 -C mr9 .");
       
   182         Assert.assertEquals(rc, 1);
       
   183 
       
   184         String s = new String(errbytes.toByteArray());
       
   185         Assert.assertTrue(Message.NOT_FOUND_IN_BASE_ENTRY.match(s, "p/internal/Bar.class"));
       
   186     }
       
   187 
       
   188     // jar tool succeeds building mmr.jar because of concealed package
       
   189     @Test
       
   190     public void test4() {
       
   191         int rc = jar("-cf mmr.jar module-info.class -C classes . " +
       
   192                 "--release 9 module-info.class -C mr9 .");
       
   193         Assert.assertEquals(rc, 0);
       
   194 
       
   195         String s = new String(errbytes.toByteArray());
       
   196         Assert.assertTrue(Message.NEW_CONCEALED_PACKAGE_WARNING.match(s, "p/internal/Bar.class"));
       
   197 
       
   198         jar("-tf mmr.jar");
       
   199 
       
   200         Set<String> actual = lines(outbytes);
       
   201         Set<String> expected = Set.of(
       
   202                 "META-INF/",
       
   203                 "META-INF/MANIFEST.MF",
       
   204                 "module-info.class",
       
   205                 "META-INF/versions/9/module-info.class",
       
   206                 "p/",
       
   207                 "p/Hi.class",
       
   208                 "META-INF/versions/9/p/",
       
   209                 "META-INF/versions/9/p/Hi.class",
       
   210                 "META-INF/versions/9/p/internal/",
       
   211                 "META-INF/versions/9/p/internal/Bar.class"
       
   212         );
       
   213         Assert.assertEquals(actual, expected);
       
   214     }
       
   215 
       
   216     // jar tool does two updates, no exported packages, all concealed
       
   217     @Test
       
   218     public void test5() throws IOException {
       
   219         // compile the mr10 directory
       
   220         Path source = testsrc.resolve("src").resolve("mr10");
       
   221         Path destination = Paths.get("mr10");
       
   222         javac(source, destination);
       
   223 
       
   224         // create a directory for this tests special files
       
   225         Files.createDirectory(Paths.get("test5"));
       
   226 
       
   227         // create an empty module-info.java
       
   228         String hi = "module hi {" + linesep + "}" + linesep;
       
   229         Path modinfo = Paths.get("test5", "module-info.java");
       
   230         Files.write(modinfo, hi.getBytes());
       
   231 
       
   232         // and compile it
       
   233         javac(modinfo, Paths.get("test5"));
       
   234 
       
   235         int rc = jar("--create --file mr.jar -C classes .");
       
   236         Assert.assertEquals(rc, 0);
       
   237 
       
   238         rc = jar("--update --file mr.jar -C test5 module-info.class"
       
   239                 + " --release 9 -C mr9 .");
       
   240         Assert.assertEquals(rc, 0);
       
   241 
       
   242         jar("tf mr.jar");
       
   243 
       
   244         Set<String> actual = lines(outbytes);
       
   245         Set<String> expected = Set.of(
       
   246                 "META-INF/",
       
   247                 "META-INF/MANIFEST.MF",
       
   248                 "p/",
       
   249                 "p/Hi.class",
       
   250                 "META-INF/versions/9/p/",
       
   251                 "META-INF/versions/9/p/Hi.class",
       
   252                 "META-INF/versions/9/p/internal/",
       
   253                 "META-INF/versions/9/p/internal/Bar.class",
       
   254                 "module-info.class"
       
   255         );
       
   256         Assert.assertEquals(actual, expected);
       
   257 
       
   258         jar("-d --file mr.jar");
       
   259 
       
   260         actual = lines(outbytes);
       
   261         expected = Set.of(
       
   262                 "hi",
       
   263                 "requires mandated java.base",
       
   264                 "contains p",
       
   265                 "contains p.internal"
       
   266         );
       
   267         Assert.assertEquals(actual, expected);
       
   268 
       
   269         rc = jar("--update --file mr.jar --release 10 -C mr10 .");
       
   270         Assert.assertEquals(rc, 0);
       
   271 
       
   272         jar("tf mr.jar");
       
   273 
       
   274         actual = lines(outbytes);
       
   275         expected = Set.of(
       
   276                 "META-INF/",
       
   277                 "META-INF/MANIFEST.MF",
       
   278                 "p/",
       
   279                 "p/Hi.class",
       
   280                 "META-INF/versions/9/p/",
       
   281                 "META-INF/versions/9/p/Hi.class",
       
   282                 "META-INF/versions/9/p/internal/",
       
   283                 "META-INF/versions/9/p/internal/Bar.class",
       
   284                 "META-INF/versions/10/p/",
       
   285                 "META-INF/versions/10/p/internal/",
       
   286                 "META-INF/versions/10/p/internal/bar/",
       
   287                 "META-INF/versions/10/p/internal/bar/Gee.class",
       
   288                 "module-info.class"
       
   289         );
       
   290         Assert.assertEquals(actual, expected);
       
   291 
       
   292         jar("-d --file mr.jar");
       
   293 
       
   294         actual = lines(outbytes);
       
   295         expected = Set.of(
       
   296                 "hi",
       
   297                 "requires mandated java.base",
       
   298                 "contains p",
       
   299                 "contains p.internal",
       
   300                 "contains p.internal.bar"
       
   301         );
       
   302         Assert.assertEquals(actual, expected);
       
   303     }
       
   304 
       
   305     private static Set<String> lines(ByteArrayOutputStream baos) {
       
   306         String s = new String(baos.toByteArray());
       
   307         return Arrays.stream(s.split("\\R"))
       
   308                      .map(l -> l.trim())
       
   309                      .filter(l -> l.length() > 0)
       
   310                      .collect(Collectors.toSet());
       
   311     }
       
   312 
       
   313     static enum Message {
       
   314         NOT_FOUND_IN_BASE_ENTRY(
       
   315           ", contains a new public class not found in base entries"
       
   316         ),
       
   317         NEW_CONCEALED_PACKAGE_WARNING(
       
   318             " is a public class" +
       
   319             " in a concealed package, placing this jar on the class path will result" +
       
   320             " in incompatible public interfaces"
       
   321         );
       
   322 
       
   323         final String msg;
       
   324         Message(String msg) {
       
   325             this.msg = msg;
       
   326         }
       
   327 
       
   328         /*
       
   329          * Test if the given output contains this message ignoring the line break.
       
   330          */
       
   331         boolean match(String output, String entry) {
       
   332             System.out.println("Expected: " + entry + msg);
       
   333             System.out.println("Found: " + output);
       
   334             return Arrays.stream(output.split("\\R"))
       
   335                          .collect(Collectors.joining(" "))
       
   336                          .contains(entry + msg);
       
   337         }
       
   338     }
       
   339 }