ModuleFinderTest.java revision 13901:b2a69d66dc65
1/*
2 * Copyright (c) 2015, 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 * @modules java.base/jdk.internal.module
27 * @build ModuleFinderTest
28 * @run testng ModuleFinderTest
29 * @summary Basic tests for java.lang.module.ModuleFinder
30 */
31
32import java.io.OutputStream;
33import java.lang.module.FindException;
34import java.lang.module.InvalidModuleDescriptorException;
35import java.lang.module.ModuleDescriptor;
36import java.lang.module.ModuleFinder;
37import java.lang.module.ModuleReference;
38import java.nio.file.Files;
39import java.nio.file.Path;
40import java.nio.file.Paths;
41import java.util.Set;
42import java.util.jar.JarEntry;
43import java.util.jar.JarOutputStream;
44import java.util.stream.Collectors;
45
46import jdk.internal.module.ModuleInfoWriter;
47
48import org.testng.annotations.Test;
49import static org.testng.Assert.*;
50
51@Test
52public class ModuleFinderTest {
53
54    private static final Path USER_DIR
55        = Paths.get(System.getProperty("user.dir"));
56
57
58    /**
59     * Test ModuleFinder.ofSystem
60     */
61    public void testOfSystem() {
62        ModuleFinder finder = ModuleFinder.ofSystem();
63
64        assertTrue(finder.find("java.se").isPresent());
65        assertTrue(finder.find("java.base").isPresent());
66        assertFalse(finder.find("java.rhubarb").isPresent());
67
68        Set<String> names = finder.findAll().stream()
69            .map(ModuleReference::descriptor)
70            .map(ModuleDescriptor::name)
71            .collect(Collectors.toSet());
72        assertTrue(names.contains("java.se"));
73        assertTrue(names.contains("java.base"));
74        assertFalse(names.contains("java.rhubarb"));
75    }
76
77
78    /**
79     * Test ModuleFinder.of with zero entries
80     */
81    public void testOfZeroEntries() {
82        ModuleFinder finder = ModuleFinder.of();
83        assertTrue(finder.findAll().isEmpty());
84        assertFalse(finder.find("java.rhubarb").isPresent());
85    }
86
87
88    /**
89     * Test ModuleFinder.of with one directory of modules
90     */
91    public void testOfOneDirectory() throws Exception {
92        Path dir = Files.createTempDirectory(USER_DIR, "mods");
93        createExplodedModule(dir.resolve("m1"), "m1");
94        createModularJar(dir.resolve("m2.jar"), "m2");
95
96        ModuleFinder finder = ModuleFinder.of(dir);
97        assertTrue(finder.findAll().size() == 2);
98        assertTrue(finder.find("m1").isPresent());
99        assertTrue(finder.find("m2").isPresent());
100        assertFalse(finder.find("java.rhubarb").isPresent());
101    }
102
103
104    /**
105     * Test ModuleFinder.of with two directories
106     */
107    public void testOfTwoDirectories() throws Exception {
108        Path dir1 = Files.createTempDirectory(USER_DIR, "mods1");
109        createExplodedModule(dir1.resolve("m1"), "m1@1.0");
110        createModularJar(dir1.resolve("m2.jar"), "m2@1.0");
111
112        Path dir2 = Files.createTempDirectory(USER_DIR, "mods2");
113        createExplodedModule(dir2.resolve("m1"), "m1@2.0");
114        createModularJar(dir2.resolve("m2.jar"), "m2@2.0");
115        createExplodedModule(dir2.resolve("m3"), "m3");
116        createModularJar(dir2.resolve("m4.jar"), "m4");
117
118        ModuleFinder finder = ModuleFinder.of(dir1, dir2);
119        assertTrue(finder.findAll().size() == 4);
120        assertTrue(finder.find("m1").isPresent());
121        assertTrue(finder.find("m2").isPresent());
122        assertTrue(finder.find("m3").isPresent());
123        assertTrue(finder.find("m4").isPresent());
124        assertFalse(finder.find("java.rhubarb").isPresent());
125
126        // check that m1@1.0 (and not m1@2.0) is found
127        ModuleDescriptor m1 = finder.find("m1").get().descriptor();
128        assertEquals(m1.version().get().toString(), "1.0");
129
130        // check that m2@1.0 (and not m2@2.0) is found
131        ModuleDescriptor m2 = finder.find("m2").get().descriptor();
132        assertEquals(m2.version().get().toString(), "1.0");
133    }
134
135
136    /**
137     * Test ModuleFinder.of with one JAR file
138     */
139    public void testOfOneJarFile() throws Exception {
140        Path dir = Files.createTempDirectory(USER_DIR, "mods");
141        Path jar1 = createModularJar(dir.resolve("m1.jar"), "m1");
142
143        ModuleFinder finder = ModuleFinder.of(jar1);
144        assertTrue(finder.findAll().size() == 1);
145        assertTrue(finder.find("m1").isPresent());
146        assertFalse(finder.find("java.rhubarb").isPresent());
147    }
148
149
150    /**
151     * Test ModuleFinder.of with two JAR files
152     */
153    public void testOfTwoJarFiles() throws Exception {
154        Path dir = Files.createTempDirectory(USER_DIR, "mods");
155
156        Path jar1 = createModularJar(dir.resolve("m1.jar"), "m1");
157        Path jar2 = createModularJar(dir.resolve("m2.jar"), "m2");
158
159        ModuleFinder finder = ModuleFinder.of(jar1, jar2);
160        assertTrue(finder.findAll().size() == 2);
161        assertTrue(finder.find("m1").isPresent());
162        assertTrue(finder.find("m2").isPresent());
163        assertFalse(finder.find("java.rhubarb").isPresent());
164    }
165
166
167    /**
168     * Test ModuleFinder.of with many JAR files
169     */
170    public void testOfManyJarFiles() throws Exception {
171        Path dir = Files.createTempDirectory(USER_DIR, "mods");
172
173        Path jar1 = createModularJar(dir.resolve("m1@1.0.jar"), "m1@1.0");
174        Path jar2 = createModularJar(dir.resolve("m2@1.0.jar"), "m2");
175        Path jar3 = createModularJar(dir.resolve("m1@2.0.jar"), "m1@2.0"); // shadowed
176        Path jar4 = createModularJar(dir.resolve("m3@1.0.jar"), "m3");
177
178        ModuleFinder finder = ModuleFinder.of(jar1, jar2, jar3, jar4);
179        assertTrue(finder.findAll().size() == 3);
180        assertTrue(finder.find("m1").isPresent());
181        assertTrue(finder.find("m2").isPresent());
182        assertTrue(finder.find("m3").isPresent());
183        assertFalse(finder.find("java.rhubarb").isPresent());
184
185        // check that m1@1.0 (and not m1@2.0) is found
186        ModuleDescriptor m1 = finder.find("m1").get().descriptor();
187        assertEquals(m1.version().get().toString(), "1.0");
188    }
189
190
191    /**
192     * Test ModuleFinder.of with one exploded module.
193     */
194    public void testOfOneExplodedModule() throws Exception {
195        Path dir = Files.createTempDirectory(USER_DIR, "mods");
196        Path m1_dir = createExplodedModule(dir.resolve("m1"), "m1");
197
198        ModuleFinder finder = ModuleFinder.of(m1_dir);
199        assertTrue(finder.findAll().size() == 1);
200        assertTrue(finder.find("m1").isPresent());
201        assertFalse(finder.find("java.rhubarb").isPresent());
202    }
203
204
205    /**
206     * Test ModuleFinder.of with two exploded modules.
207     */
208    public void testOfTwoExplodedModules() throws Exception {
209        Path dir = Files.createTempDirectory(USER_DIR, "mods");
210        Path m1_dir = createExplodedModule(dir.resolve("m1"), "m1");
211        Path m2_dir = createExplodedModule(dir.resolve("m2"), "m2");
212
213        ModuleFinder finder = ModuleFinder.of(m1_dir, m2_dir);
214        assertTrue(finder.findAll().size() == 2);
215        assertTrue(finder.find("m1").isPresent());
216        assertTrue(finder.find("m2").isPresent());
217        assertFalse(finder.find("java.rhubarb").isPresent());
218    }
219
220
221    /**
222     * Test ModuleFinder.of with a mix of module directories and JAR files.
223     */
224    public void testOfMixDirectoriesAndJars() throws Exception {
225
226        // directory with m1@1.0 and m2@1.0
227        Path dir1 = Files.createTempDirectory(USER_DIR, "mods1");
228        createExplodedModule(dir1.resolve("m1"), "m1@1.0");
229        createModularJar(dir1.resolve("m2.jar"), "m2@1.0");
230
231        // JAR files: m1@2.0, m2@2.0, m3@2.0, m4@2.0
232        Path dir2 = Files.createTempDirectory(USER_DIR, "mods2");
233        Path jar1 = createModularJar(dir2.resolve("m1.jar"), "m1@2.0");
234        Path jar2 = createModularJar(dir2.resolve("m2.jar"), "m2@2.0");
235        Path jar3 = createModularJar(dir2.resolve("m3.jar"), "m3@2.0");
236        Path jar4 = createModularJar(dir2.resolve("m4.jar"), "m4@2.0");
237
238        // directory with m3@3.0 and m4@3.0
239        Path dir3 = Files.createTempDirectory(USER_DIR, "mods3");
240        createExplodedModule(dir3.resolve("m3"), "m3@3.0");
241        createModularJar(dir3.resolve("m4.jar"), "m4@3.0");
242
243        // JAR files: m5 and m6
244        Path dir4 = Files.createTempDirectory(USER_DIR, "mods4");
245        Path jar5 = createModularJar(dir4.resolve("m5.jar"), "m5@4.0");
246        Path jar6 = createModularJar(dir4.resolve("m6.jar"), "m6@4.0");
247
248
249        ModuleFinder finder
250            = ModuleFinder.of(dir1, jar1, jar2, jar3, jar4, dir3, jar5, jar6);
251        assertTrue(finder.findAll().size() == 6);
252        assertTrue(finder.find("m1").isPresent());
253        assertTrue(finder.find("m2").isPresent());
254        assertTrue(finder.find("m3").isPresent());
255        assertTrue(finder.find("m4").isPresent());
256        assertTrue(finder.find("m5").isPresent());
257        assertTrue(finder.find("m6").isPresent());
258        assertFalse(finder.find("java.rhubarb").isPresent());
259
260        // m1 and m2 should be located in dir1
261        ModuleDescriptor m1 = finder.find("m1").get().descriptor();
262        assertEquals(m1.version().get().toString(), "1.0");
263        ModuleDescriptor m2 = finder.find("m2").get().descriptor();
264        assertEquals(m2.version().get().toString(), "1.0");
265
266        // m3 and m4 should be located in JAR files
267        ModuleDescriptor m3 = finder.find("m3").get().descriptor();
268        assertEquals(m3.version().get().toString(), "2.0");
269        ModuleDescriptor m4 = finder.find("m4").get().descriptor();
270        assertEquals(m4.version().get().toString(), "2.0");
271
272        // m5 and m6 should be located in JAR files
273        ModuleDescriptor m5 = finder.find("m5").get().descriptor();
274        assertEquals(m5.version().get().toString(), "4.0");
275        ModuleDescriptor m6 = finder.find("m6").get().descriptor();
276        assertEquals(m6.version().get().toString(), "4.0");
277    }
278
279
280    /**
281     * Test ModuleFinder.of with a mix of module directories and exploded
282     * modules.
283     */
284    public void testOfMixDirectoriesAndExplodedModules() throws Exception {
285        // directory with m1@1.0 and m2@1.0
286        Path dir1 = Files.createTempDirectory(USER_DIR, "mods1");
287        createExplodedModule(dir1.resolve("m1"), "m1@1.0");
288        createModularJar(dir1.resolve("m2.jar"), "m2@1.0");
289
290        // exploded modules: m1@2.0, m2@2.0, m3@2.0, m4@2.0
291        Path dir2 = Files.createTempDirectory(USER_DIR, "mods2");
292        Path m1_dir = createExplodedModule(dir2.resolve("m1"), "m1@2.0");
293        Path m2_dir = createExplodedModule(dir2.resolve("m2"), "m2@2.0");
294        Path m3_dir = createExplodedModule(dir2.resolve("m3"), "m3@2.0");
295        Path m4_dir = createExplodedModule(dir2.resolve("m4"), "m4@2.0");
296
297        ModuleFinder finder = ModuleFinder.of(dir1, m1_dir, m2_dir, m3_dir, m4_dir);
298        assertTrue(finder.findAll().size() == 4);
299        assertTrue(finder.find("m1").isPresent());
300        assertTrue(finder.find("m2").isPresent());
301        assertTrue(finder.find("m3").isPresent());
302        assertTrue(finder.find("m4").isPresent());
303        assertFalse(finder.find("java.rhubarb").isPresent());
304
305        // m1 and m2 should be located in dir1
306        ModuleDescriptor m1 = finder.find("m1").get().descriptor();
307        assertEquals(m1.version().get().toString(), "1.0");
308        ModuleDescriptor m2 = finder.find("m2").get().descriptor();
309        assertEquals(m2.version().get().toString(), "1.0");
310
311        // m3 and m4 should be located in dir2
312        ModuleDescriptor m3 = finder.find("m3").get().descriptor();
313        assertEquals(m3.version().get().toString(), "2.0");
314        ModuleDescriptor m4 = finder.find("m4").get().descriptor();
315        assertEquals(m4.version().get().toString(), "2.0");
316    }
317
318
319    /**
320     * Test ModuleFinder.of with a path to a file that does not exist.
321     */
322    public void testOfWithDoesNotExistEntry() throws Exception {
323        Path dir1 = Files.createTempDirectory(USER_DIR, "mods1");
324
325        Path dir2 = Files.createTempDirectory(USER_DIR, "mods2");
326        createModularJar(dir2.resolve("m2.jar"), "m2@1.0");
327
328        Files.delete(dir1);
329
330        ModuleFinder finder = ModuleFinder.of(dir1, dir2);
331
332        assertTrue(finder.find("m2").isPresent());
333        assertTrue(finder.findAll().size() == 1);
334        assertFalse(finder.find("java.rhubarb").isPresent());
335    }
336
337
338    /**
339     * Test ModuleFinder.of with a file path to an unrecognized file type.
340     */
341    public void testOfWithUnrecognizedEntry() throws Exception {
342        Path dir = Files.createTempDirectory(USER_DIR, "mods");
343        Path mod = Files.createTempFile(dir, "m", "mod");
344
345        ModuleFinder finder = ModuleFinder.of(mod);
346        try {
347            finder.find("java.rhubarb");
348            assertTrue(false);
349        } catch (FindException e) {
350            // expected
351        }
352
353        finder = ModuleFinder.of(mod);
354        try {
355            finder.findAll();
356            assertTrue(false);
357        } catch (FindException e) {
358            // expected
359        }
360    }
361
362
363    /**
364     * Test ModuleFinder.of with a directory that contains two
365     * versions of the same module
366     */
367    public void testOfDuplicateModulesInDirectory() throws Exception {
368        Path dir = Files.createTempDirectory(USER_DIR, "mods");
369        createModularJar(dir.resolve("m1@1.0.jar"), "m1");
370        createModularJar(dir.resolve("m1@2.0.jar"), "m1");
371
372        ModuleFinder finder = ModuleFinder.of(dir);
373        try {
374            finder.find("m1");
375            assertTrue(false);
376        } catch (FindException expected) { }
377
378        finder = ModuleFinder.of(dir);
379        try {
380            finder.findAll();
381            assertTrue(false);
382        } catch (FindException expected) { }
383    }
384
385
386    /**
387     * Test ModuleFinder.of with a truncated module-info.class
388     */
389    public void testOfWithTruncatedModuleInfo() throws Exception {
390        Path dir = Files.createTempDirectory(USER_DIR, "mods");
391
392        // create an empty <dir>/rhubarb/module-info.class
393        Path subdir = Files.createDirectory(dir.resolve("rhubarb"));
394        Files.createFile(subdir.resolve("module-info.class"));
395
396        ModuleFinder finder = ModuleFinder.of(dir);
397        try {
398            finder.find("rhubarb");
399            assertTrue(false);
400        } catch (FindException e) {
401            assertTrue(e.getCause() instanceof InvalidModuleDescriptorException);
402        }
403
404        finder = ModuleFinder.of(dir);
405        try {
406            finder.findAll();
407            assertTrue(false);
408        } catch (FindException e) {
409            assertTrue(e.getCause() instanceof InvalidModuleDescriptorException);
410        }
411    }
412
413
414    /**
415     * Test ModuleFinder.compose
416     */
417    public void testCompose() throws Exception {
418        Path dir1 = Files.createTempDirectory(USER_DIR, "mods1");
419        createExplodedModule(dir1.resolve("m1"), "m1@1.0");
420        createExplodedModule(dir1.resolve("m2"), "m2@1.0");
421
422        Path dir2 = Files.createTempDirectory(USER_DIR, "mods2");
423        createExplodedModule(dir2.resolve("m1"), "m1@2.0");
424        createExplodedModule(dir2.resolve("m2"), "m2@2.0");
425        createExplodedModule(dir2.resolve("m3"), "m3");
426        createExplodedModule(dir2.resolve("m4"), "m4");
427
428        ModuleFinder finder1 = ModuleFinder.of(dir1);
429        ModuleFinder finder2 = ModuleFinder.of(dir2);
430
431        ModuleFinder finder = ModuleFinder.compose(finder1, finder2);
432        assertTrue(finder.findAll().size() == 4);
433        assertTrue(finder.find("m1").isPresent());
434        assertTrue(finder.find("m2").isPresent());
435        assertTrue(finder.find("m3").isPresent());
436        assertTrue(finder.find("m4").isPresent());
437        assertFalse(finder.find("java.rhubarb").isPresent());
438
439        // check that m1@1.0 (and not m1@2.0) is found
440        ModuleDescriptor m1 = finder.find("m1").get().descriptor();
441        assertEquals(m1.version().get().toString(), "1.0");
442
443        // check that m2@1.0 (and not m2@2.0) is found
444        ModuleDescriptor m2 = finder.find("m2").get().descriptor();
445        assertEquals(m2.version().get().toString(), "1.0");
446    }
447
448
449    /**
450     * Test ModuleFinder.empty
451     */
452    public void testEmpty() {
453        ModuleFinder finder = ModuleFinder.empty();
454        assertTrue(finder.findAll().isEmpty());
455        assertFalse(finder.find("java.rhubarb").isPresent());
456    }
457
458
459    /**
460     * Test null handling
461     */
462    public void testNulls() {
463
464        try {
465            ModuleFinder.ofSystem().find(null);
466            assertTrue(false);
467        } catch (NullPointerException expected) { }
468
469        try {
470            ModuleFinder.of().find(null);
471            assertTrue(false);
472        } catch (NullPointerException expected) { }
473
474        try {
475            ModuleFinder.empty().find(null);
476            assertTrue(false);
477        } catch (NullPointerException expected) { }
478
479        try {
480            ModuleFinder.of((Path[])null);
481            assertTrue(false);
482        } catch (NullPointerException expected) { }
483
484        try {
485            ModuleFinder.of((Path)null);
486            assertTrue(false);
487        } catch (NullPointerException expected) { }
488
489        // compose
490        ModuleFinder finder = ModuleFinder.of();
491        try {
492            ModuleFinder.compose(finder, null);
493            assertTrue(false);
494        } catch (NullPointerException expected) { }
495        try {
496            ModuleFinder.compose(null, finder);
497            assertTrue(false);
498        } catch (NullPointerException expected) { }
499
500    }
501
502
503    /**
504     * Parses a string of the form {@code name[@version]} and returns a
505     * ModuleDescriptor with that name and version. The ModuleDescriptor
506     * will have a requires on java.base.
507     */
508    static ModuleDescriptor newModuleDescriptor(String mid) {
509        String mn;
510        String vs;
511        int i = mid.indexOf("@");
512        if (i == -1) {
513            mn = mid;
514            vs = null;
515        } else {
516            mn = mid.substring(0, i);
517            vs = mid.substring(i+1);
518        }
519        ModuleDescriptor.Builder builder
520                = new ModuleDescriptor.Builder(mn).requires("java.base");
521        if (vs != null)
522            builder.version(vs);
523        return builder.build();
524    }
525
526    /**
527     * Creates an exploded module in the given directory and containing a
528     * module descriptor with the given module name/version.
529     */
530    static Path createExplodedModule(Path dir, String mid) throws Exception {
531        ModuleDescriptor descriptor = newModuleDescriptor(mid);
532        Files.createDirectories(dir);
533        Path mi = dir.resolve("module-info.class");
534        try (OutputStream out = Files.newOutputStream(mi)) {
535            ModuleInfoWriter.write(descriptor, out);
536        }
537        return dir;
538    }
539
540    /**
541     * Creates a JAR file with the given file path and containing a module
542     * descriptor with the given module name/version.
543     */
544    static Path createModularJar(Path file, String mid, String ... entries)
545        throws Exception
546    {
547        ModuleDescriptor descriptor = newModuleDescriptor(mid);
548        try (OutputStream out = Files.newOutputStream(file)) {
549            try (JarOutputStream jos = new JarOutputStream(out)) {
550
551                JarEntry je = new JarEntry("module-info.class");
552                jos.putNextEntry(je);
553                ModuleInfoWriter.write(descriptor, jos);
554                jos.closeEntry();
555
556                for (String entry : entries) {
557                    je = new JarEntry(entry);
558                    jos.putNextEntry(je);
559                    jos.closeEntry();
560                }
561            }
562
563        }
564        return file;
565    }
566
567}
568
569