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 * @library /lib/testlibrary 30 * @build jdk.testlibrary.FileUtils 31 * @run testng ConcealedPackage 32 */ 33 34 import org.testng.Assert; 35 import org.testng.annotations.AfterClass; 36 import org.testng.annotations.Test; 37 38 import java.io.ByteArrayOutputStream; 39 import java.io.IOException; 40 import java.io.PrintStream; 41 import java.io.UncheckedIOException; 42 import java.nio.file.Files; 43 import java.nio.file.Path; 44 import java.nio.file.Paths; 45 import java.util.Arrays; 46 import java.util.Set; 47 import java.util.spi.ToolProvider; 48 import java.util.stream.Collectors; 49 import java.util.stream.Stream; 50 51 import jdk.testlibrary.FileUtils; 52 53 public class ConcealedPackage { 54 private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar") 55 .orElseThrow(() -> new RuntimeException("jar tool not found")); 56 private static final ToolProvider JAVAC_TOOL = ToolProvider.findFirst("javac") 57 .orElseThrow(() -> new RuntimeException("javac tool not found")); 58 final private Path userdir; 59 final private ByteArrayOutputStream outbytes = new ByteArrayOutputStream(); 60 final private PrintStream out = new PrintStream(outbytes, true); 61 final private ByteArrayOutputStream errbytes = new ByteArrayOutputStream(); 62 final private PrintStream err = new PrintStream(errbytes, true); 63 64 public ConcealedPackage() throws IOException { 65 Path testsrc = Paths.get(System.getProperty("test.src")); 66 userdir = Paths.get(System.getProperty("user.dir", ".")); 67 68 // compile the classes directory 69 Path source = testsrc.resolve("src").resolve("classes"); 70 Path destination = Paths.get("classes"); 71 javac(source, destination); 72 73 // compile the mr9 directory including module-info.java 74 source = testsrc.resolve("src").resolve("mr9"); 75 destination = Paths.get("mr9"); 76 javac(source, destination); 77 78 // move module-info.class for later use 79 Files.move(destination.resolve("module-info.class"), 80 Paths.get("module-info.class")); 81 } 82 83 private void javac(Path source, Path destination) throws IOException { 84 String[] args = Stream.concat( 85 Stream.of("-d", destination.toString()), 86 Files.walk(source) 87 .map(Path::toString) 88 .filter(s -> s.endsWith(".java")) 89 ).toArray(String[]::new); 90 JAVAC_TOOL.run(System.out, System.err, args); 91 } 92 93 private int jar(String cmd) { 94 outbytes.reset(); 95 errbytes.reset(); 96 return JAR_TOOL.run(out, err, cmd.split(" +")); 97 } 98 99 @AfterClass 100 public void cleanup() throws IOException { 101 Files.walk(userdir, 1) 102 .filter(p -> !p.equals(userdir)) 103 .forEach(p -> { 104 try { 105 if (Files.isDirectory(p)) { 106 FileUtils.deleteFileTreeWithRetry(p); 107 } else { 108 FileUtils.deleteFileIfExistsWithRetry(p); 109 } 110 } catch (IOException x) { 111 throw new UncheckedIOException(x); 112 } 113 }); 114 } 115 116 117 @Test // updates a valid multi-release jar with a new public class in 118 // versioned section and fails 119 public void test1() { 120 // successful build of multi-release jar 121 int rc = jar("-cf mmr.jar -C classes . --release 9 -C mr9 p/Hi.class"); 122 Assert.assertEquals(rc, 0); 123 124 jar("-tf mmr.jar"); 125 126 String s = new String(outbytes.toByteArray()); 127 Set<String> actual = Arrays.stream(s.split("\n")).collect(Collectors.toSet()); 128 Set<String> expected = Set.of( 129 "META-INF/", 130 "META-INF/MANIFEST.MF", 131 "p/", 132 "p/Hi.class", 133 "META-INF/versions/9/p/Hi.class" 134 ); 135 Assert.assertEquals(actual, expected); 136 137 // failed build because of new public class 138 rc = jar("-uf mmr.jar --release 9 -C mr9 p/internal/Bar.class"); 139 Assert.assertEquals(rc, 1); 140 141 s = new String(errbytes.toByteArray()); 142 Assert.assertTrue(s.contains("p/internal/Bar.class, contains a new public " 143 + "class not found in base entries") 144 ); 145 } 146 147 @Test // updates a valid multi-release jar with a module-info class and new 148 // concealed public class in versioned section and succeeds 149 public void test2() { 150 // successful build of multi-release jar 151 int rc = jar("-cf mmr.jar -C classes . --release 9 -C mr9 p/Hi.class"); 152 Assert.assertEquals(rc, 0); 153 154 // successful build because of module-info and new public class 155 rc = jar("-uf mmr.jar module-info.class --release 9 -C mr9 p/internal/Bar.class"); 156 Assert.assertEquals(rc, 0); 157 158 String s = new String(errbytes.toByteArray()); 159 Assert.assertTrue(s.contains("p/internal/Bar.class is a public class in a " 160 + "concealed package, \nplacing this jar on the class path " 161 + "will result in incompatible public interfaces") 162 ); 163 164 jar("-tf mmr.jar"); 165 166 s = new String(outbytes.toByteArray()); 167 Set<String> actual = Arrays.stream(s.split("\n")).collect(Collectors.toSet()); 168 Set<String> expected = Set.of( 169 "META-INF/", 170 "META-INF/MANIFEST.MF", 171 "p/", 172 "p/Hi.class", 173 "META-INF/versions/9/p/Hi.class", 174 "META-INF/versions/9/p/internal/Bar.class", 175 "module-info.class" 176 ); 177 Assert.assertEquals(actual, expected); 178 } 179 180 @Test // jar tool fails building mmr.jar because of new public class 181 public void test3() { 182 int rc = jar("-cf mmr.jar -C classes . --release 9 -C mr9 ."); 183 Assert.assertEquals(rc, 1); 184 185 String s = new String(errbytes.toByteArray()); 186 Assert.assertTrue(s.contains("p/internal/Bar.class, contains a new public " 187 + "class not found in base entries") 188 ); 189 } 190 191 @Test // jar tool succeeds building mmr.jar because of concealed package 192 public void test4() { 193 int rc = jar("-cf mmr.jar module-info.class -C classes . " + 194 "--release 9 module-info.class -C mr9 ."); 195 Assert.assertEquals(rc, 0); 196 197 String s = new String(errbytes.toByteArray()); 198 Assert.assertTrue(s.contains("p/internal/Bar.class is a public class in a " 199 + "concealed package, \nplacing this jar on the class path " 200 + "will result in incompatible public interfaces") 201 ); 202 203 jar("-tf mmr.jar"); 204 205 s = new String(outbytes.toByteArray()); 206 Set<String> actual = Arrays.stream(s.split("\n")).collect(Collectors.toSet()); 207 Set<String> expected = Set.of( 208 "META-INF/", 209 "META-INF/MANIFEST.MF", 210 "module-info.class", 211 "META-INF/versions/9/module-info.class", 212 "p/", 213 "p/Hi.class", 214 "META-INF/versions/9/p/", 215 "META-INF/versions/9/p/Hi.class", 216 "META-INF/versions/9/p/internal/", 217 "META-INF/versions/9/p/internal/Bar.class" 218 ); 219 Assert.assertEquals(actual, expected); 220 } 221 }