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 import java.io.*;
25 import java.lang.reflect.Method;
26 import java.nio.file.FileVisitResult;
27 import java.nio.file.Files;
28 import java.nio.file.Path;
29 import java.nio.file.Paths;
30 import java.nio.file.SimpleFileVisitor;
31 import java.nio.file.attribute.BasicFileAttributes;
32 import java.util.*;
33 import java.util.function.Consumer;
34 import java.util.jar.JarEntry;
35 import java.util.jar.JarInputStream;
36 import java.util.regex.Pattern;
37 import java.util.stream.Stream;
38 import javax.tools.JavaCompiler;
39 import javax.tools.JavaFileObject;
40 import javax.tools.StandardJavaFileManager;
41 import javax.tools.StandardLocation;
42 import javax.tools.ToolProvider;
43
44 import jdk.testlibrary.FileUtils;
45 import jdk.testlibrary.JDKToolFinder;
46 import org.testng.annotations.BeforeTest;
47 import org.testng.annotations.Test;
48
49 import static java.lang.String.format;
50 import static java.lang.System.out;
51
52 /*
53 * @test
54 * @library /lib/testlibrary
55 * @build jdk.testlibrary.FileUtils jdk.testlibrary.JDKToolFinder
56 * @compile Basic.java
57 * @run testng Basic
58 * @summary Basic test for Modular jars
59 */
60
61 public class Basic {
62 static final Path TEST_SRC = Paths.get(System.getProperty("test.src", "."));
63 static final Path TEST_CLASSES = Paths.get(System.getProperty("test.classes", "."));
64 static final Path MODULE_CLASSES = TEST_CLASSES.resolve("build");
65
66 // Details based on the checked in module source
67 static TestModuleData FOO = new TestModuleData("foo",
68 "1.123",
69 "jdk.test.foo.Foo",
70 "Hello World!!!", null,
71 "jdk.test.foo.internal");
72 static TestModuleData BAR = new TestModuleData("bar",
73 "4.5.6.7",
74 "jdk.test.bar.Bar",
75 "Hello from Bar!", null,
76 "jdk.test.bar",
77 "jdk.test.bar.internal");
78
79 static class TestModuleData {
80 final String moduleName;
81 final String mainClass;
82 final String version;
83 final String message;
84 final String hashes;
85 final Set<String> conceals;
86 TestModuleData(String mn, String v, String mc, String m, String h, String... pkgs) {
87 moduleName = mn; mainClass = mc; version = v; message = m; hashes = h;
88 conceals = new HashSet<>();
89 Stream.of(pkgs).forEach(conceals::add);
90 }
91 TestModuleData(String mn, String v, String mc, String m, String h, Set<String> pkgs) {
92 moduleName = mn; mainClass = mc; version = v; message = m; hashes = h;
93 conceals = pkgs;
94 }
95 static TestModuleData from(String s) {
96 try {
97 BufferedReader reader = new BufferedReader(new StringReader(s));
98 String line;
99 String message = null;
100 String name = null, version = null, mainClass = null;
101 String hashes = null;
102 Set<String> conceals = null;
103 while ((line = reader.readLine()) != null) {
104 if (line.startsWith("message:")) {
105 message = line.substring("message:".length());
106 } else if (line.startsWith("nameAndVersion:")) {
107 line = line.substring("nameAndVersion:".length());
108 int i = line.indexOf('@');
109 if (i != -1) {
110 name = line.substring(0, i);
111 version = line.substring(i + 1, line.length());
112 } else {
113 name = line;
114 }
115 } else if (line.startsWith("mainClass:")) {
116 mainClass = line.substring("mainClass:".length());
117 } else if (line.startsWith("hashes:")) {
118 hashes = line.substring("hashes:".length());
119 } else if (line.startsWith("conceals:")) {
120 line = line.substring("conceals:".length());
121 conceals = new HashSet<>();
122 int i = line.indexOf(',');
123 if (i != -1) {
124 String[] p = line.split(",");
125 Stream.of(p).forEach(conceals::add);
126 } else {
127 conceals.add(line);
128 }
129 } else {
130 throw new AssertionError("Unknown value " + line);
131 }
132 }
133
134 return new TestModuleData(name, version, mainClass, message, hashes, conceals);
135 } catch (IOException x) {
136 throw new UncheckedIOException(x);
137 }
138 }
139 }
140
141 static void assertModuleData(Result r, TestModuleData expected) {
142 //out.printf("%s%n", r.output);
143 TestModuleData received = TestModuleData.from(r.output);
144 if (expected.message != null)
145 assertTrue(expected.message.equals(received.message),
146 "Expected message:", expected.message, ", got:", received.message);
147 assertTrue(expected.moduleName.equals(received.moduleName),
148 "Expected moduleName: ", expected.moduleName, ", got:", received.moduleName);
149 assertTrue(expected.version.equals(received.version),
150 "Expected version: ", expected.version, ", got:", received.version);
151 assertTrue(expected.mainClass.equals(received.mainClass),
152 "Expected mainClass: ", expected.mainClass, ", got:", received.mainClass);
153 expected.conceals.forEach(p -> assertTrue(received.conceals.contains(p),
154 "Expected ", p, ", in ", received.conceals));
155 received.conceals.forEach(p -> assertTrue(expected.conceals.contains(p),
156 "Expected ", p, ", in ", expected.conceals));
157 }
158
159 @BeforeTest
160 public void compileModules() throws Exception {
161 compileModule(FOO.moduleName);
162 compileModule(BAR.moduleName, MODULE_CLASSES);
163 compileModule("baz"); // for service provider consistency checking
164 }
165
166 @Test
167 public void createFoo() throws IOException {
168 Path mp = Paths.get("createFoo");
169 createTestDir(mp);
170 Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName);
171 Path modularJar = mp.resolve(FOO.moduleName + ".jar");
172
173 jar("--create",
174 "--file=" + modularJar.toString(),
175 "--main-class=" + FOO.mainClass,
176 "--module-version=" + FOO.version,
177 "--no-manifest",
178 "-C", modClasses.toString(), ".")
179 .assertSuccess();
180 java(mp, FOO.moduleName + "/" + FOO.mainClass)
181 .assertSuccess()
182 .resultChecker(r -> assertModuleData(r, FOO));
183
184 try (InputStream fis = Files.newInputStream(modularJar);
185 JarInputStream jis = new JarInputStream(fis)) {
186 assertTrue(!jarContains(jis, "./"),
187 "Unexpected ./ found in ", modularJar.toString());
188 }
189 }
190
191 @Test
192 public void updateFoo() throws IOException {
193 Path mp = Paths.get("updateFoo");
194 createTestDir(mp);
195 Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName);
196 Path modularJar = mp.resolve(FOO.moduleName + ".jar");
197
198 jar("--create",
199 "--file=" + modularJar.toString(),
200 "--no-manifest",
201 "-C", modClasses.toString(), "jdk")
202 .assertSuccess();
203 jar("--update",
204 "--file=" + modularJar.toString(),
205 "--main-class=" + FOO.mainClass,
206 "--module-version=" + FOO.version,
207 "--no-manifest",
208 "-C", modClasses.toString(), "module-info.class")
209 .assertSuccess();
210 java(mp, FOO.moduleName + "/" + FOO.mainClass)
211 .assertSuccess()
212 .resultChecker(r -> assertModuleData(r, FOO));
213 }
214
215 @Test
216 public void partialUpdateFooMainClass() throws IOException {
217 Path mp = Paths.get("partialUpdateFooMainClass");
218 createTestDir(mp);
219 Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName);
220 Path modularJar = mp.resolve(FOO.moduleName + ".jar");
221
222 // A "bad" main class in first create ( and no version )
223 jar("--create",
224 "--file=" + modularJar.toString(),
225 "--main-class=" + "IAmNotTheEntryPoint",
226 "--no-manifest",
227 "-C", modClasses.toString(), ".") // includes module-info.class
228 .assertSuccess();
229 jar("--update",
230 "--file=" + modularJar.toString(),
231 "--main-class=" + FOO.mainClass,
232 "--module-version=" + FOO.version,
233 "--no-manifest")
234 .assertSuccess();
235 java(mp, FOO.moduleName + "/" + FOO.mainClass)
273 // i.e. no concealed list in first create
274 jar("--create",
275 "--file=" + modularJar.toString(),
276 "--no-manifest",
277 "-C", modClasses.toString(), "module-info.class",
278 "-C", modClasses.toString(), "jdk/test/foo/Foo.class")
279 .assertSuccess();
280 jar("--update",
281 "--file=" + modularJar.toString(),
282 "--main-class=" + FOO.mainClass,
283 "--module-version=" + FOO.version,
284 "--no-manifest",
285 "-C", modClasses.toString(), "jdk/test/foo/internal/Message.class")
286 .assertSuccess();
287 java(mp, FOO.moduleName + "/" + FOO.mainClass)
288 .assertSuccess()
289 .resultChecker(r -> assertModuleData(r, FOO));
290 }
291
292 @Test
293 public void partialUpdateFooAllFilesAndAttributes() throws IOException {
294 Path mp = Paths.get("partialUpdateFooAllFilesAndAttributes");
295 createTestDir(mp);
296 Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName);
297 Path modularJar = mp.resolve(FOO.moduleName + ".jar");
298
299 // all attributes and files
300 jar("--create",
301 "--file=" + modularJar.toString(),
302 "--main-class=" + FOO.mainClass,
303 "--module-version=" + FOO.version,
304 "--no-manifest",
305 "-C", modClasses.toString(), ".")
306 .assertSuccess();
307 jar("--update",
308 "--file=" + modularJar.toString(),
309 "--main-class=" + FOO.mainClass,
310 "--module-version=" + FOO.version,
311 "--no-manifest",
312 "-C", modClasses.toString(), ".")
511
512 @Test
513 public void servicesUpdateWithoutServiceImpl() throws IOException {
514 Path mp = Paths.get("servicesUpdateWithoutServiceImpl");
515 createTestDir(mp);
516 Path modClasses = MODULE_CLASSES.resolve("baz");
517 Path modularJar = mp.resolve("baz" + ".jar");
518
519 // Omit service impl
520 jar("--create",
521 "--file=" + modularJar.toString(),
522 "-C", modClasses.toString(), "jdk/test/baz/BazService.class")
523 .assertSuccess();
524 jar("--update",
525 "--file=" + modularJar.toString(),
526 "-C", modClasses.toString(), "module-info.class")
527 .assertFailure();
528 }
529
530 @Test
531 public void printModuleDescriptorFoo() throws IOException {
532 Path mp = Paths.get("printModuleDescriptorFoo");
533 createTestDir(mp);
534 Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName);
535 Path modularJar = mp.resolve(FOO.moduleName + ".jar");
536
537 jar("--create",
538 "--file=" + modularJar.toString(),
539 "--main-class=" + FOO.mainClass,
540 "--module-version=" + FOO.version,
541 "--no-manifest",
542 "-C", modClasses.toString(), ".")
543 .assertSuccess();
544
545 for (String option : new String[] {"--print-module-descriptor", "-p" }) {
546 jar(option,
547 "--file=" + modularJar.toString())
548 .assertSuccess()
549 .resultChecker(r ->
550 assertTrue(r.output.contains(FOO.moduleName + "@" + FOO.version),
594 return run(p);
595 }
596
597 static Result jar(String... args) {
598 return jarWithStdin(null, args);
599 }
600
601 static Path compileModule(String mn) throws IOException {
602 return compileModule(mn, null);
603 }
604
605 static Path compileModule(String mn, Path mp)
606 throws IOException
607 {
608 Path fooSourcePath = TEST_SRC.resolve("src").resolve(mn);
609 Path build = Files.createDirectories(MODULE_CLASSES.resolve(mn));
610 javac(build, mp, fileList(fooSourcePath));
611 return build;
612 }
613
614 // Re-enable when there is support in javax.tools for module path
615 // static void javac(Path dest, Path... sourceFiles) throws IOException {
616 // out.printf("Compiling %d source files %s%n", sourceFiles.length,
617 // Arrays.asList(sourceFiles));
618 // JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
619 // try (StandardJavaFileManager fileManager =
620 // compiler.getStandardFileManager(null, null, null)) {
621 //
622 // List<File> files = Stream.of(sourceFiles)
623 // .map(p -> p.toFile())
624 // .collect(Collectors.toList());
625 // List<File> dests = Stream.of(dest)
626 // .map(p -> p.toFile())
627 // .collect(Collectors.toList());
628 // Iterable<? extends JavaFileObject> compilationUnits =
629 // fileManager.getJavaFileObjectsFromFiles(files);
630 // fileManager.setLocation(StandardLocation.CLASS_OUTPUT, dests);
631 // JavaCompiler.CompilationTask task =
632 // compiler.getTask(null, fileManager, null, null, null, compilationUnits);
633 // boolean passed = task.call();
673
674 return run(new ProcessBuilder(commands));
675 }
676
677 static Path[] fileList(Path directory) throws IOException {
678 final List<Path> filePaths = new ArrayList<>();
679 Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
680 @Override
681 public FileVisitResult visitFile(Path file,
682 BasicFileAttributes attrs) {
683 filePaths.add(file);
684 return FileVisitResult.CONTINUE;
685 }
686 });
687 return filePaths.toArray(new Path[filePaths.size()]);
688 }
689
690 static void createTestDir(Path p) throws IOException{
691 if (Files.exists(p))
692 FileUtils.deleteFileTreeWithRetry(p);
693 Files.createDirectory(p);
694 }
695
696 static boolean jarContains(JarInputStream jis, String entryName)
697 throws IOException
698 {
699 JarEntry e;
700 while((e = jis.getNextJarEntry()) != null) {
701 if (e.getName().equals(entryName))
702 return true;
703 }
704 return false;
705 }
706
707 static void quickFail(Result r) {
708 if (r.ec != 0)
709 throw new RuntimeException(r.output);
710 }
711
712 static Result run(ProcessBuilder pb) {
713 Process p;
|
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 import java.io.*;
25 import java.lang.reflect.Method;
26 import java.nio.file.FileVisitResult;
27 import java.nio.file.Files;
28 import java.nio.file.Path;
29 import java.nio.file.Paths;
30 import java.nio.file.SimpleFileVisitor;
31 import java.nio.file.attribute.BasicFileAttributes;
32 import java.util.*;
33 import java.util.function.Consumer;
34 import java.util.jar.JarEntry;
35 import java.util.jar.JarInputStream;
36 import java.util.jar.Manifest;
37 import java.util.regex.Pattern;
38 import java.util.stream.Stream;
39 import javax.tools.JavaCompiler;
40 import javax.tools.JavaFileObject;
41 import javax.tools.StandardJavaFileManager;
42 import javax.tools.StandardLocation;
43 import javax.tools.ToolProvider;
44
45 import jdk.testlibrary.FileUtils;
46 import jdk.testlibrary.JDKToolFinder;
47 import org.testng.annotations.BeforeTest;
48 import org.testng.annotations.Test;
49
50 import static java.lang.String.format;
51 import static java.lang.System.out;
52
53 /*
54 * @test
55 * @library /lib/testlibrary
56 * @modules jdk.compiler
57 * jdk.jartool
58 * @build jdk.testlibrary.FileUtils jdk.testlibrary.JDKToolFinder
59 * @compile Basic.java
60 * @run testng Basic
61 * @summary Tests for plain Modular jars & Multi-Release Modular jars
62 */
63
64 public class Basic {
65 static final Path TEST_SRC = Paths.get(System.getProperty("test.src", "."));
66 static final Path TEST_CLASSES = Paths.get(System.getProperty("test.classes", "."));
67 static final Path MODULE_CLASSES = TEST_CLASSES.resolve("build");
68 static final Path MRJAR_DIR = MODULE_CLASSES.resolve("mrjar");
69
70 // Details based on the checked in module source
71 static TestModuleData FOO = new TestModuleData("foo",
72 "1.123",
73 "jdk.test.foo.Foo",
74 "Hello World!!!",
75 null, // no hashes
76 Set.of("java.base"),
77 Set.of("jdk.test.foo"),
78 null, // no uses
79 null, // no provides
80 Set.of("jdk.test.foo.internal"));
81 static TestModuleData BAR = new TestModuleData("bar",
82 "4.5.6.7",
83 "jdk.test.bar.Bar",
84 "Hello from Bar!",
85 null, // no hashes
86 Set.of("java.base", "foo"),
87 null, // no exports
88 null, // no uses
89 null, // no provides
90 Set.of("jdk.test.bar",
91 "jdk.test.bar.internal"));
92
93 static class TestModuleData {
94 final String moduleName;
95 final Set<String> requires;
96 final Set<String> exports;
97 final Set<String> uses;
98 final Set<String> provides;
99 final String mainClass;
100 final String version;
101 final String message;
102 final String hashes;
103 final Set<String> conceals;
104
105 TestModuleData(String mn, String v, String mc, String m, String h,
106 Set<String> requires, Set<String> exports, Set<String> uses,
107 Set<String> provides, Set<String> conceals) {
108 moduleName = mn; mainClass = mc; version = v; message = m; hashes = h;
109 this.requires = requires;
110 this.exports = exports;
111 this.uses = uses;
112 this.provides = provides;
113 this.conceals = conceals;
114 }
115 static TestModuleData from(String s) {
116 try {
117 BufferedReader reader = new BufferedReader(new StringReader(s));
118 String line;
119 String message = null;
120 String name = null, version = null, mainClass = null;
121 String hashes = null;
122 Set<String> requires, exports, uses, provides, conceals;
123 requires = exports = uses = provides = conceals = null;
124 while ((line = reader.readLine()) != null) {
125 if (line.startsWith("message:")) {
126 message = line.substring("message:".length());
127 } else if (line.startsWith("nameAndVersion:")) {
128 line = line.substring("nameAndVersion:".length());
129 int i = line.indexOf('@');
130 if (i != -1) {
131 name = line.substring(0, i);
132 version = line.substring(i + 1, line.length());
133 } else {
134 name = line;
135 }
136 } else if (line.startsWith("mainClass:")) {
137 mainClass = line.substring("mainClass:".length());
138 } else if (line.startsWith("requires:")) {
139 line = line.substring("requires:".length());
140 requires = stringToSet(line);
141 } else if (line.startsWith("exports:")) {
142 line = line.substring("exports:".length());
143 exports = stringToSet(line);
144 } else if (line.startsWith("uses:")) {
145 line = line.substring("uses:".length());
146 uses = stringToSet(line);
147 } else if (line.startsWith("provides:")) {
148 line = line.substring("provides:".length());
149 provides = stringToSet(line);
150 } else if (line.startsWith("hashes:")) {
151 hashes = line.substring("hashes:".length());
152 } else if (line.startsWith("conceals:")) {
153 line = line.substring("conceals:".length());
154 conceals = stringToSet(line);
155 } else {
156 throw new AssertionError("Unknown value " + line);
157 }
158 }
159
160 return new TestModuleData(name, version, mainClass, message,
161 hashes, requires, exports, uses,
162 provides, conceals);
163 } catch (IOException x) {
164 throw new UncheckedIOException(x);
165 }
166 }
167 static Set<String> stringToSet(String commaList) {
168 Set<String> s = new HashSet<>();
169 int i = commaList.indexOf(',');
170 if (i != -1) {
171 String[] p = commaList.split(",");
172 Stream.of(p).forEach(s::add);
173 } else {
174 s.add(commaList);
175 }
176 return s;
177 }
178 }
179
180 static void assertModuleData(Result r, TestModuleData expected) {
181 //out.printf("%s%n", r.output);
182 TestModuleData received = TestModuleData.from(r.output);
183 if (expected.message != null)
184 assertTrue(expected.message.equals(received.message),
185 "Expected message:", expected.message, ", got:", received.message);
186 assertTrue(expected.moduleName.equals(received.moduleName),
187 "Expected moduleName: ", expected.moduleName, ", got:", received.moduleName);
188 assertTrue(expected.version.equals(received.version),
189 "Expected version: ", expected.version, ", got:", received.version);
190 assertTrue(expected.mainClass.equals(received.mainClass),
191 "Expected mainClass: ", expected.mainClass, ", got:", received.mainClass);
192 assertSetsEqual(expected.requires, received.requires);
193 assertSetsEqual(expected.exports, received.exports);
194 assertSetsEqual(expected.uses, received.uses);
195 assertSetsEqual(expected.provides, received.provides);
196 assertSetsEqual(expected.conceals, received.conceals);
197 }
198
199 static void assertSetsEqual(Set<String> s1, Set<String> s2) {
200 if (s1 == null && s2 == null) // none expected, or received
201 return;
202 assertTrue(s1.size() == s2.size(),
203 "Unexpected set size difference: ", s1.size(), ", ", s2.size());
204 s1.forEach(p -> assertTrue(s2.contains(p), "Expected ", p, ", in ", s2));
205 }
206
207 @BeforeTest
208 public void compileModules() throws Exception {
209 compileModule(FOO.moduleName);
210 compileModule(BAR.moduleName, MODULE_CLASSES);
211 compileModule("baz"); // for service provider consistency checking
212
213 setupMRJARModuleInfo(FOO.moduleName);
214 setupMRJARModuleInfo(BAR.moduleName);
215 setupMRJARModuleInfo("baz");
216 }
217
218 @Test
219 public void createFoo() throws IOException {
220 Path mp = Paths.get("createFoo");
221 createTestDir(mp);
222 Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName);
223 Path modularJar = mp.resolve(FOO.moduleName + ".jar");
224
225 jar("--create",
226 "--file=" + modularJar.toString(),
227 "--main-class=" + FOO.mainClass,
228 "--module-version=" + FOO.version,
229 "--no-manifest",
230 "-C", modClasses.toString(), ".")
231 .assertSuccess();
232 java(mp, FOO.moduleName + "/" + FOO.mainClass)
233 .assertSuccess()
234 .resultChecker(r -> assertModuleData(r, FOO));
235 try (InputStream fis = Files.newInputStream(modularJar);
236 JarInputStream jis = new JarInputStream(fis)) {
237 assertTrue(!jarContains(jis, "./"),
238 "Unexpected ./ found in ", modularJar.toString());
239 }
240 }
241
242 /** Similar to createFoo, but with a Multi-Release Modular jar. */
243 @Test
244 public void createMRMJarFoo() throws IOException {
245 Path mp = Paths.get("createMRMJarFoo");
246 createTestDir(mp);
247 Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName);
248 Path mrjarDir = MRJAR_DIR.resolve(FOO.moduleName);
249 Path modularJar = mp.resolve(FOO.moduleName + ".jar");
250
251 // Positive test, create
252 jar("--create",
253 "--file=" + modularJar.toString(),
254 "--main-class=" + FOO.mainClass,
255 "--module-version=" + FOO.version,
256 "-m", mrjarDir.resolve("META-INF/MANIFEST.MF").toRealPath().toString(),
257 "-C", mrjarDir.toString(), "META-INF/versions/9/module-info.class",
258 "-C", modClasses.toString(), ".")
259 .assertSuccess();
260 java(mp, FOO.moduleName + "/" + FOO.mainClass)
261 .assertSuccess()
262 .resultChecker(r -> assertModuleData(r, FOO));
263 }
264
265
266 @Test
267 public void updateFoo() throws IOException {
268 Path mp = Paths.get("updateFoo");
269 createTestDir(mp);
270 Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName);
271 Path modularJar = mp.resolve(FOO.moduleName + ".jar");
272
273 jar("--create",
274 "--file=" + modularJar.toString(),
275 "--no-manifest",
276 "-C", modClasses.toString(), "jdk")
277 .assertSuccess();
278 jar("--update",
279 "--file=" + modularJar.toString(),
280 "--main-class=" + FOO.mainClass,
281 "--module-version=" + FOO.version,
282 "--no-manifest",
283 "-C", modClasses.toString(), "module-info.class")
284 .assertSuccess();
285 java(mp, FOO.moduleName + "/" + FOO.mainClass)
286 .assertSuccess()
287 .resultChecker(r -> assertModuleData(r, FOO));
288 }
289
290 @Test
291 public void updateMRMJarFoo() throws IOException {
292 Path mp = Paths.get("updateMRMJarFoo");
293 createTestDir(mp);
294 Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName);
295 Path mrjarDir = MRJAR_DIR.resolve(FOO.moduleName);
296 Path modularJar = mp.resolve(FOO.moduleName + ".jar");
297
298 jar("--create",
299 "--file=" + modularJar.toString(),
300 "--no-manifest",
301 "-C", modClasses.toString(), "jdk")
302 .assertSuccess();
303 jar("--update",
304 "--file=" + modularJar.toString(),
305 "--main-class=" + FOO.mainClass,
306 "--module-version=" + FOO.version,
307 "-m", mrjarDir.resolve("META-INF/MANIFEST.MF").toRealPath().toString(),
308 "-C", mrjarDir.toString(), "META-INF/versions/9/module-info.class",
309 "-C", modClasses.toString(), "module-info.class")
310 .assertSuccess();
311 java(mp, FOO.moduleName + "/" + FOO.mainClass)
312 .assertSuccess()
313 .resultChecker(r -> assertModuleData(r, FOO));
314 }
315
316 @Test
317 public void partialUpdateFooMainClass() throws IOException {
318 Path mp = Paths.get("partialUpdateFooMainClass");
319 createTestDir(mp);
320 Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName);
321 Path modularJar = mp.resolve(FOO.moduleName + ".jar");
322
323 // A "bad" main class in first create ( and no version )
324 jar("--create",
325 "--file=" + modularJar.toString(),
326 "--main-class=" + "IAmNotTheEntryPoint",
327 "--no-manifest",
328 "-C", modClasses.toString(), ".") // includes module-info.class
329 .assertSuccess();
330 jar("--update",
331 "--file=" + modularJar.toString(),
332 "--main-class=" + FOO.mainClass,
333 "--module-version=" + FOO.version,
334 "--no-manifest")
335 .assertSuccess();
336 java(mp, FOO.moduleName + "/" + FOO.mainClass)
374 // i.e. no concealed list in first create
375 jar("--create",
376 "--file=" + modularJar.toString(),
377 "--no-manifest",
378 "-C", modClasses.toString(), "module-info.class",
379 "-C", modClasses.toString(), "jdk/test/foo/Foo.class")
380 .assertSuccess();
381 jar("--update",
382 "--file=" + modularJar.toString(),
383 "--main-class=" + FOO.mainClass,
384 "--module-version=" + FOO.version,
385 "--no-manifest",
386 "-C", modClasses.toString(), "jdk/test/foo/internal/Message.class")
387 .assertSuccess();
388 java(mp, FOO.moduleName + "/" + FOO.mainClass)
389 .assertSuccess()
390 .resultChecker(r -> assertModuleData(r, FOO));
391 }
392
393 @Test
394 public void partialUpdateMRMJarFooNotAllFiles() throws IOException {
395 Path mp = Paths.get("partialUpdateMRMJarFooNotAllFiles");
396 createTestDir(mp);
397 Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName);
398 Path mrjarDir = MRJAR_DIR.resolve(FOO.moduleName);
399 Path modularJar = mp.resolve(FOO.moduleName + ".jar");
400
401 jar("--create",
402 "--file=" + modularJar.toString(),
403 "--module-version=" + FOO.version,
404 "-C", modClasses.toString(), ".")
405 .assertSuccess();
406 jar("--update",
407 "--file=" + modularJar.toString(),
408 "--main-class=" + FOO.mainClass,
409 "-m", mrjarDir.resolve("META-INF/MANIFEST.MF").toRealPath().toString(),
410 "-C", mrjarDir.toString(), "META-INF/versions/9/module-info.class")
411 .assertSuccess();
412 java(mp, FOO.moduleName + "/" + FOO.mainClass)
413 .assertSuccess()
414 .resultChecker(r -> assertModuleData(r, FOO));
415 }
416
417 @Test
418 public void partialUpdateFooAllFilesAndAttributes() throws IOException {
419 Path mp = Paths.get("partialUpdateFooAllFilesAndAttributes");
420 createTestDir(mp);
421 Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName);
422 Path modularJar = mp.resolve(FOO.moduleName + ".jar");
423
424 // all attributes and files
425 jar("--create",
426 "--file=" + modularJar.toString(),
427 "--main-class=" + FOO.mainClass,
428 "--module-version=" + FOO.version,
429 "--no-manifest",
430 "-C", modClasses.toString(), ".")
431 .assertSuccess();
432 jar("--update",
433 "--file=" + modularJar.toString(),
434 "--main-class=" + FOO.mainClass,
435 "--module-version=" + FOO.version,
436 "--no-manifest",
437 "-C", modClasses.toString(), ".")
636
637 @Test
638 public void servicesUpdateWithoutServiceImpl() throws IOException {
639 Path mp = Paths.get("servicesUpdateWithoutServiceImpl");
640 createTestDir(mp);
641 Path modClasses = MODULE_CLASSES.resolve("baz");
642 Path modularJar = mp.resolve("baz" + ".jar");
643
644 // Omit service impl
645 jar("--create",
646 "--file=" + modularJar.toString(),
647 "-C", modClasses.toString(), "jdk/test/baz/BazService.class")
648 .assertSuccess();
649 jar("--update",
650 "--file=" + modularJar.toString(),
651 "-C", modClasses.toString(), "module-info.class")
652 .assertFailure();
653 }
654
655 @Test
656 public void servicesCreateWithoutFailureMRMJAR() throws IOException {
657 Path mp = Paths.get("servicesCreateWithoutFailureMRMJAR");
658 createTestDir(mp);
659 Path modClasses = MODULE_CLASSES.resolve("baz");
660 Path mrjarDir = MRJAR_DIR.resolve("baz");
661 Path modularJar = mp.resolve("baz" + ".jar");
662
663 jar("--create",
664 "--file=" + modularJar.toString(),
665 "-m", mrjarDir.resolve("META-INF/MANIFEST.MF").toRealPath().toString(),
666 "-C", modClasses.toString(), "module-info.class",
667 "-C", mrjarDir.toString(), "META-INF/versions/9/module-info.class",
668 "-C", modClasses.toString(), "jdk/test/baz/BazService.class",
669 "-C", modClasses.toString(), "jdk/test/baz/internal/BazServiceImpl.class")
670 .assertSuccess();
671 }
672
673 @Test
674 public void printModuleDescriptorFoo() throws IOException {
675 Path mp = Paths.get("printModuleDescriptorFoo");
676 createTestDir(mp);
677 Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName);
678 Path modularJar = mp.resolve(FOO.moduleName + ".jar");
679
680 jar("--create",
681 "--file=" + modularJar.toString(),
682 "--main-class=" + FOO.mainClass,
683 "--module-version=" + FOO.version,
684 "--no-manifest",
685 "-C", modClasses.toString(), ".")
686 .assertSuccess();
687
688 for (String option : new String[] {"--print-module-descriptor", "-p" }) {
689 jar(option,
690 "--file=" + modularJar.toString())
691 .assertSuccess()
692 .resultChecker(r ->
693 assertTrue(r.output.contains(FOO.moduleName + "@" + FOO.version),
737 return run(p);
738 }
739
740 static Result jar(String... args) {
741 return jarWithStdin(null, args);
742 }
743
744 static Path compileModule(String mn) throws IOException {
745 return compileModule(mn, null);
746 }
747
748 static Path compileModule(String mn, Path mp)
749 throws IOException
750 {
751 Path fooSourcePath = TEST_SRC.resolve("src").resolve(mn);
752 Path build = Files.createDirectories(MODULE_CLASSES.resolve(mn));
753 javac(build, mp, fileList(fooSourcePath));
754 return build;
755 }
756
757 static void setupMRJARModuleInfo(String moduleName) throws IOException {
758 Path modClasses = MODULE_CLASSES.resolve(moduleName);
759 Path metaInfDir = MRJAR_DIR.resolve(moduleName).resolve("META-INF");
760 Path versionSection = metaInfDir.resolve("versions").resolve("9");
761 createTestDir(versionSection);
762
763 Path versionModuleInfo = versionSection.resolve("module-info.class");
764 System.out.println("copying " + modClasses.resolve("module-info.class") + " to " + versionModuleInfo);
765 Files.copy(modClasses.resolve("module-info.class"), versionModuleInfo);
766
767 Manifest manifest = new Manifest();
768 manifest.getMainAttributes().putValue("Manifest-Version", "1.0");
769 manifest.getMainAttributes().putValue("Multi-Release", "true");
770 try (OutputStream os = Files.newOutputStream(metaInfDir.resolve("MANIFEST.MF"))) {
771 manifest.write(os);
772 }
773 }
774
775 // Re-enable when there is support in javax.tools for module path
776 // static void javac(Path dest, Path... sourceFiles) throws IOException {
777 // out.printf("Compiling %d source files %s%n", sourceFiles.length,
778 // Arrays.asList(sourceFiles));
779 // JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
780 // try (StandardJavaFileManager fileManager =
781 // compiler.getStandardFileManager(null, null, null)) {
782 //
783 // List<File> files = Stream.of(sourceFiles)
784 // .map(p -> p.toFile())
785 // .collect(Collectors.toList());
786 // List<File> dests = Stream.of(dest)
787 // .map(p -> p.toFile())
788 // .collect(Collectors.toList());
789 // Iterable<? extends JavaFileObject> compilationUnits =
790 // fileManager.getJavaFileObjectsFromFiles(files);
791 // fileManager.setLocation(StandardLocation.CLASS_OUTPUT, dests);
792 // JavaCompiler.CompilationTask task =
793 // compiler.getTask(null, fileManager, null, null, null, compilationUnits);
794 // boolean passed = task.call();
834
835 return run(new ProcessBuilder(commands));
836 }
837
838 static Path[] fileList(Path directory) throws IOException {
839 final List<Path> filePaths = new ArrayList<>();
840 Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
841 @Override
842 public FileVisitResult visitFile(Path file,
843 BasicFileAttributes attrs) {
844 filePaths.add(file);
845 return FileVisitResult.CONTINUE;
846 }
847 });
848 return filePaths.toArray(new Path[filePaths.size()]);
849 }
850
851 static void createTestDir(Path p) throws IOException{
852 if (Files.exists(p))
853 FileUtils.deleteFileTreeWithRetry(p);
854 Files.createDirectories(p);
855 }
856
857 static boolean jarContains(JarInputStream jis, String entryName)
858 throws IOException
859 {
860 JarEntry e;
861 while((e = jis.getNextJarEntry()) != null) {
862 if (e.getName().equals(entryName))
863 return true;
864 }
865 return false;
866 }
867
868 static void quickFail(Result r) {
869 if (r.ec != 0)
870 throw new RuntimeException(r.output);
871 }
872
873 static Result run(ProcessBuilder pb) {
874 Process p;
|