TransitiveDeps.java revision 3792:d516975e8110
1351278Sdim/*
2351278Sdim * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
3351278Sdim * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4351278Sdim *
5351278Sdim * This code is free software; you can redistribute it and/or modify it
6351278Sdim * under the terms of the GNU General Public License version 2 only, as
7351278Sdim * published by the Free Software Foundation.
8351278Sdim *
9351278Sdim * This code is distributed in the hope that it will be useful, but WITHOUT
10351278Sdim * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11351278Sdim * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12351278Sdim * version 2 for more details (a copy is included in the LICENSE file that
13351278Sdim * accompanied this code).
14360784Sdim *
15360784Sdim * You should have received a copy of the GNU General Public License version
16351278Sdim * 2 along with this work; if not, write to the Free Software Foundation,
17351278Sdim * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18351278Sdim *
19351278Sdim * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20351278Sdim * or visit www.oracle.com if you need additional information or have any
21351278Sdim * questions.
22360784Sdim */
23351278Sdim
24351278Sdim/*
25351278Sdim * @test
26351278Sdim * @summary Tests jdeps -m and -mp options on named modules and unnamed modules
27351278Sdim * @library ../lib
28351278Sdim * @build CompilerUtils JdepsUtil
29351278Sdim * @modules jdk.jdeps/com.sun.tools.jdeps
30351278Sdim * @run testng TransitiveDeps
31351278Sdim */
32351278Sdim
33360784Sdimimport java.io.File;
34351278Sdimimport java.io.IOException;
35351278Sdim
36351278Sdimimport java.nio.file.Files;
37351278Sdimimport java.nio.file.Path;
38351278Sdimimport java.nio.file.Paths;
39351278Sdimimport java.util.*;
40351278Sdimimport java.util.function.Function;
41351278Sdimimport java.util.stream.Collectors;
42351278Sdimimport java.util.stream.Stream;
43351278Sdim
44351278Sdim
45351278Sdimimport com.sun.tools.jdeps.DepsAnalyzer;
46351278Sdimimport com.sun.tools.jdeps.Graph;
47351278Sdimimport org.testng.annotations.DataProvider;
48351278Sdimimport org.testng.annotations.BeforeTest;
49351278Sdimimport org.testng.annotations.Test;
50351278Sdim
51351278Sdimimport static org.testng.Assert.assertTrue;
52351278Sdim
53351278Sdimpublic class TransitiveDeps {
54351278Sdim    private static final String TEST_SRC = System.getProperty("test.src");
55351278Sdim
56360784Sdim    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
57360784Sdim    private static final Path MODS_DIR = Paths.get("mods");
58360784Sdim    private static final Path LIBS_DIR = Paths.get("libs");
59360784Sdim
60360784Sdim    // the names of the modules in this test
61360784Sdim    private static String[] modules = new String[] {"unsafe", "mVI", "mVII"};
62360784Sdim    /**
63360784Sdim     * Compiles all modules used by the test
64360784Sdim     */
65360784Sdim    @BeforeTest
66360784Sdim    public void compileAll() throws Exception {
67360784Sdim        CompilerUtils.cleanDir(MODS_DIR);
68360784Sdim        CompilerUtils.cleanDir(LIBS_DIR);
69351278Sdim
70351278Sdim        for (String mn : modules) {
71351278Sdim            // compile a module
72351278Sdim            assertTrue(CompilerUtils.compileModule(SRC_DIR, MODS_DIR, mn));
73360784Sdim
74360784Sdim            // create JAR files with no module-info.class
75360784Sdim            Path root = MODS_DIR.resolve(mn);
76360784Sdim            try (Stream<Path> stream = Files.walk(root, Integer.MAX_VALUE)) {
77351278Sdim                Stream<Path> entries = stream.filter(f -> {
78351278Sdim                    String fn = f.getFileName().toString();
79351278Sdim                    return fn.endsWith(".class") && !fn.equals("module-info.class");
80351278Sdim                });
81351278Sdim                JdepsUtil.createJar(LIBS_DIR.resolve(mn + ".jar"), root, entries);
82351278Sdim            }
83351278Sdim        }
84351278Sdim    }
85351278Sdim
86351278Sdim    @DataProvider(name = "modules")
87351278Sdim    public Object[][] expected1() {
88360784Sdim        return new Object[][]{
89360784Sdim            { "mVII",
90360784Sdim               List.of(new ModuleMetaData("mVII")
91360784Sdim                            .requires("mVI")
92360784Sdim                            .requires("unsafe")
93360784Sdim                            .reference("p7.Main", "java.lang.Object", "java.base")
94360784Sdim                            .reference("p7.Main", "java.lang.String", "java.base")
95360784Sdim                            .reference("p7.Main", "org.safe.Lib", "unsafe")
96360784Sdim                            .reference("p7.Main", "p6.safe.Lib", "mVI"),
97360784Sdim                        new ModuleMetaData("mVI")
98360784Sdim                            .requires("unsafe")
99360784Sdim                            .reference("p6.indirect.UnsafeRef", "java.lang.Object", "java.base")
100360784Sdim                            .reference("p6.indirect.UnsafeRef", "org.unsafe.UseUnsafe ", "unsafe")
101360784Sdim                            .reference("p6.safe.Lib", "java.io.PrintStream", "java.base")
102360784Sdim                            .reference("p6.safe.Lib", "java.lang.Class", "java.base")
103360784Sdim                            .reference("p6.safe.Lib", "java.lang.Object", "java.base")
104360784Sdim                            .reference("p6.safe.Lib", "java.lang.String", "java.base")
105360784Sdim                            .reference("p6.safe.Lib", "java.lang.System", "java.base")
106360784Sdim                            .reference("p6.safe.Lib", "org.safe.Lib", "unsafe"),
107360784Sdim                        new ModuleMetaData("unsafe")
108360784Sdim                            .requires("jdk.unsupported")
109360784Sdim                            .reference("org.indirect.UnsafeRef", "java.lang.Object", "java.base")
110360784Sdim                            .reference("org.safe.Lib", "java.io.PrintStream", "java.base")
111360784Sdim                            .reference("org.safe.Lib", "java.lang.Class", "java.base")
112360784Sdim                            .reference("org.safe.Lib", "java.lang.Object", "java.base")
113360784Sdim                            .reference("org.safe.Lib", "java.lang.String", "java.base")
114360784Sdim                            .reference("org.safe.Lib", "java.lang.System", "java.base")
115360784Sdim                            .reference("org.unsafe.UseUnsafe", "java.lang.Object", "java.base")
116360784Sdim                            .jdkInternal("org.unsafe.UseUnsafe", "sun.misc.Unsafe", "java.base")
117360784Sdim                        )
118360784Sdim            },
119363496Sdim        };
120360784Sdim    }
121360784Sdim
122360784Sdim    @Test(dataProvider = "modules")
123360784Sdim    public void testModulePath(String name, List<ModuleMetaData> data) throws IOException {
124363496Sdim        Set<String> roots = Set.of("mVI", "unsafe");
125363496Sdim
126363496Sdim        String cmd1 = String.format("jdeps --module-path %s --add-modules %s -m %s%n", MODS_DIR,
127363496Sdim            roots.stream().collect(Collectors.joining(",")), name);
128363496Sdim        try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd1)) {
129363496Sdim            jdeps.verbose("-verbose:class")
130363496Sdim                .appModulePath(MODS_DIR.toString())
131363496Sdim                .addmods(roots)
132363496Sdim                .addmods(Set.of(name));
133363496Sdim
134363496Sdim            runJdeps(jdeps, data);
135360784Sdim        }
136360784Sdim        // run automatic modules
137360784Sdim        roots = Set.of("ALL-MODULE-PATH", "jdk.unsupported");
138360784Sdim
139360784Sdim        String cmd2 = String.format("jdeps --module-path %s --add-modules %s -m %s%n", LIBS_DIR,
140360784Sdim            roots.stream().collect(Collectors.joining(",")), name);
141360784Sdim
142360784Sdim        try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd2)) {
143360784Sdim            jdeps.verbose("-verbose:class")
144360784Sdim                .appModulePath(LIBS_DIR.toString())
145360784Sdim                .addmods(roots)
146360784Sdim                .addmods(Set.of(name));
147360784Sdim
148360784Sdim            runJdeps(jdeps, data);
149360784Sdim        }
150360784Sdim    }
151360784Sdim
152360784Sdim    @DataProvider(name = "jars")
153360784Sdim    public Object[][] expected2() {
154360784Sdim        return new Object[][]{
155360784Sdim            { "mVII", List.of(new ModuleMetaData("mVII.jar")
156360784Sdim                                .requires("mVI.jar")
157360784Sdim                                .requires("unsafe.jar")
158360784Sdim                                .reference("p7.Main", "java.lang.Object", "java.base")
159360784Sdim                                .reference("p7.Main", "java.lang.String", "java.base")
160360784Sdim                                .reference("p7.Main", "org.safe.Lib", "unsafe.jar")
161360784Sdim                                .reference("p7.Main", "p6.safe.Lib", "mVI.jar"))
162360784Sdim            },
163360784Sdim        };
164360784Sdim    }
165360784Sdim
166360784Sdim    @Test(dataProvider = "jars")
167360784Sdim    public void testClassPath(String name, List<ModuleMetaData> data) throws IOException {
168360784Sdim        String cpath = Arrays.stream(modules)
169360784Sdim            .filter(mn -> !mn.equals(name))
170360784Sdim            .map(mn -> LIBS_DIR.resolve(mn + ".jar").toString())
171360784Sdim            .collect(Collectors.joining(File.pathSeparator));
172360784Sdim
173360784Sdim        Path jarfile = LIBS_DIR.resolve(name + ".jar");
174360784Sdim
175360784Sdim        String cmd = String.format("jdeps -classpath %s %s%n", cpath, jarfile);
176360784Sdim        try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd)) {
177360784Sdim            jdeps.verbose("-verbose:class")
178360784Sdim                .addClassPath(cpath)
179360784Sdim                .addRoot(jarfile);
180360784Sdim
181360784Sdim            runJdeps(jdeps, data);
182360784Sdim        }
183360784Sdim    }
184360784Sdim
185360784Sdim    @DataProvider(name = "compileTimeView")
186360784Sdim    public Object[][] expected3() {
187360784Sdim        return new Object[][] {
188360784Sdim            {"mVII",
189360784Sdim             List.of(new ModuleMetaData("mVII.jar")
190360784Sdim                        .requires("mVI.jar")
191360784Sdim                        .requires("unsafe.jar")
192360784Sdim                        .reference("p7.Main", "java.lang.Object", "java.base")
193360784Sdim                        .reference("p7.Main", "java.lang.String", "java.base")
194360784Sdim                        .reference("p7.Main", "org.safe.Lib", "unsafe.jar")
195360784Sdim                        .reference("p7.Main", "p6.safe.Lib", "mVI.jar"),
196360784Sdim                    new ModuleMetaData("mVI.jar")
197360784Sdim                        .requires("unsafe.jar")
198360784Sdim                        .reference("p6.indirect.UnsafeRef", "java.lang.Object", "java.base")
199360784Sdim                        .reference("p6.indirect.UnsafeRef", "org.unsafe.UseUnsafe ", "unsafe.jar")
200360784Sdim                        .reference("p6.safe.Lib", "java.io.PrintStream", "java.base")
201360784Sdim                        .reference("p6.safe.Lib", "java.lang.Class", "java.base")
202360784Sdim                        .reference("p6.safe.Lib", "java.lang.Object", "java.base")
203360784Sdim                        .reference("p6.safe.Lib", "java.lang.String", "java.base")
204360784Sdim                        .reference("p6.safe.Lib", "java.lang.System", "java.base")
205360784Sdim                        .reference("p6.safe.Lib", "org.safe.Lib", "unsafe.jar"),
206360784Sdim                    new ModuleMetaData("unsafe.jar")
207360784Sdim                        .requires("jdk.unsupported")
208360784Sdim                        .reference("org.indirect.UnsafeRef", "java.lang.Object", "java.base")
209360784Sdim                        .reference("org.safe.Lib", "java.io.PrintStream", "java.base")
210360784Sdim                        .reference("org.safe.Lib", "java.lang.Class", "java.base")
211360784Sdim                        .reference("org.safe.Lib", "java.lang.Object", "java.base")
212360784Sdim                        .reference("org.safe.Lib", "java.lang.String", "java.base")
213360784Sdim                        .reference("org.safe.Lib", "java.lang.System", "java.base")
214360784Sdim                        .reference("org.unsafe.UseUnsafe", "java.lang.Object", "java.base")
215360784Sdim                        .jdkInternal("org.unsafe.UseUnsafe", "sun.misc.Unsafe", "java.base")
216360784Sdim                )
217360784Sdim            },
218360784Sdim        };
219360784Sdim    }
220360784Sdim
221360784Sdim    @Test(dataProvider = "compileTimeView")
222360784Sdim    public void compileTimeView(String name, List<ModuleMetaData> data) throws IOException {
223360784Sdim        String cpath = Arrays.stream(modules)
224360784Sdim                .filter(mn -> !mn.equals(name))
225360784Sdim                .map(mn -> LIBS_DIR.resolve(mn + ".jar").toString())
226360784Sdim                .collect(Collectors.joining(File.pathSeparator));
227360784Sdim
228360784Sdim        Path jarfile = LIBS_DIR.resolve(name + ".jar");
229360784Sdim
230360784Sdim        String cmd = String.format("jdeps -ct -classpath %s %s%n", cpath, jarfile);
231360784Sdim        try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd)) {
232360784Sdim            jdeps.verbose("-verbose:class")
233360784Sdim                .addClassPath(cpath)
234360784Sdim                .addRoot(jarfile);
235360784Sdim
236360784Sdim            runJdeps(jdeps, data, true, 0 /* -recursive */);
237360784Sdim        }
238360784Sdim    }
239351278Sdim
240351278Sdim    @DataProvider(name = "recursiveDeps")
241351278Sdim    public Object[][] expected4() {
242351278Sdim        return new Object[][] {
243351278Sdim            {"mVII",
244351278Sdim                List.of(new ModuleMetaData("mVII.jar")
245351278Sdim                        .requires("mVI.jar")
246351278Sdim                        .requires("unsafe.jar")
247351278Sdim                        .reference("p7.Main", "java.lang.Object", "java.base")
248351278Sdim                        .reference("p7.Main", "java.lang.String", "java.base")
249351278Sdim                        .reference("p7.Main", "org.safe.Lib", "unsafe.jar")
250351278Sdim                        .reference("p7.Main", "p6.safe.Lib", "mVI.jar"),
251351278Sdim                    new ModuleMetaData("mVI.jar")
252351278Sdim                        .requires("unsafe.jar")
253351278Sdim                        .reference("p6.safe.Lib", "java.io.PrintStream", "java.base")
254351278Sdim                        .reference("p6.safe.Lib", "java.lang.Class", "java.base")
255351278Sdim                        .reference("p6.safe.Lib", "java.lang.Object", "java.base")
256351278Sdim                        .reference("p6.safe.Lib", "java.lang.String", "java.base")
257351278Sdim                        .reference("p6.safe.Lib", "java.lang.System", "java.base")
258351278Sdim                        .reference("p6.safe.Lib", "org.safe.Lib", "unsafe.jar"),
259351278Sdim                    new ModuleMetaData("unsafe.jar")
260351278Sdim                        .requires("jdk.unsupported")
261351278Sdim                        .reference("org.indirect.UnsafeRef", "java.lang.Object", "java.base")
262351278Sdim                        .reference("org.safe.Lib", "java.io.PrintStream", "java.base")
263351278Sdim                        .reference("org.safe.Lib", "java.lang.Class", "java.base")
264351278Sdim                        .reference("org.safe.Lib", "java.lang.Object", "java.base")
265360784Sdim                        .reference("org.safe.Lib", "java.lang.String", "java.base")
266360784Sdim                        .reference("org.safe.Lib", "java.lang.System", "java.base")
267351278Sdim                )
268351278Sdim            },
269351278Sdim        };
270351278Sdim    }
271351278Sdim    @Test(dataProvider = "recursiveDeps")
272351278Sdim    public void recursiveDeps(String name, List<ModuleMetaData> data) throws IOException {
273360784Sdim        String cpath = Arrays.stream(modules)
274351278Sdim            .filter(mn -> !mn.equals(name))
275351278Sdim            .map(mn -> LIBS_DIR.resolve(mn + ".jar").toString())
276351278Sdim            .collect(Collectors.joining(File.pathSeparator));
277360784Sdim
278351278Sdim        Path jarfile = LIBS_DIR.resolve(name + ".jar");
279351278Sdim
280351278Sdim        String cmd = String.format("jdeps -R -classpath %s %s%n", cpath, jarfile);
281351278Sdim        try (JdepsUtil.Command jdeps = JdepsUtil.newCommand(cmd)) {
282351278Sdim            jdeps.verbose("-verbose:class").filter("-filter:archive")
283360784Sdim                .addClassPath(cpath)
284351278Sdim                .addRoot(jarfile);
285351278Sdim
286351278Sdim            runJdeps(jdeps, data, true, 0 /* -recursive */);
287351278Sdim        }
288351278Sdim    }
289351278Sdim
290351278Sdim    private void runJdeps(JdepsUtil.Command jdeps, List<ModuleMetaData> data)
291351278Sdim        throws IOException
292351278Sdim    {
293360784Sdim        runJdeps(jdeps, data, false, 1 /* depth */);
294351278Sdim    }
295351278Sdim
296351278Sdim    private void runJdeps(JdepsUtil.Command jdeps, List<ModuleMetaData> data,
297351278Sdim                          boolean compileTimeView, int depth)
298351278Sdim        throws IOException
299351278Sdim    {
300351278Sdim        // run the analyzer
301351278Sdim        DepsAnalyzer analyzer = jdeps.getDepsAnalyzer();
302351278Sdim        assertTrue(analyzer.run(compileTimeView, depth));
303351278Sdim        jdeps.dumpOutput(System.err);
304351278Sdim
305351278Sdim        // analyze result
306351278Sdim        Graph<DepsAnalyzer.Node> g1 = analyzer.moduleGraph();
307351278Sdim        Map<String, ModuleMetaData> dataMap = data.stream()
308351278Sdim            .collect(Collectors.toMap(ModuleMetaData::name, Function.identity()));
309351278Sdim
310351278Sdim        // the returned graph contains all nodes such as java.base and jdk.unsupported
311351278Sdim        g1.nodes().stream()
312            .filter(u -> dataMap.containsKey(u.name))
313            .forEach(u -> {
314                ModuleMetaData md = dataMap.get(u.name);
315                md.checkRequires(u.name, g1.adjacentNodes(u));
316            });
317
318        Graph<DepsAnalyzer.Node> g2 = analyzer.dependenceGraph();
319
320        g2.nodes().stream()
321            .filter(u -> dataMap.containsKey(u.name))
322            .forEach(u -> {
323                ModuleMetaData md = dataMap.get(u.name);
324                md.checkDependences(u.name, g2.adjacentNodes(u));
325            });
326    }
327}
328