JLinkTest.java revision 17000:fa3c4a60a616
1/*
2 * Copyright (c) 2015, 2017, 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
24import java.io.IOException;
25import java.io.PrintWriter;
26import java.io.StringWriter;
27import java.lang.module.ModuleDescriptor;
28import java.nio.file.Files;
29import java.nio.file.Path;
30import java.nio.file.Paths;
31import java.util.ArrayList;
32import java.util.Collections;
33import java.util.List;
34import java.util.spi.ToolProvider;
35import java.util.stream.Stream;
36
37import jdk.tools.jlink.plugin.Plugin;
38import jdk.tools.jlink.internal.PluginRepository;
39import tests.Helper;
40import tests.JImageGenerator;
41
42/*
43 * @test
44 * @summary Test image creation
45 * @author Jean-Francois Denise
46 * @library ../lib
47 * @modules java.base/jdk.internal.jimage
48 *          jdk.jdeps/com.sun.tools.classfile
49 *          jdk.jlink/jdk.tools.jlink.internal
50 *          jdk.jlink/jdk.tools.jlink.plugin
51 *          jdk.jlink/jdk.tools.jimage
52 *          jdk.compiler
53 * @build tests.*
54 * @run main/othervm -Xmx1g JLinkTest
55 */
56public class JLinkTest {
57    static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink")
58        .orElseThrow(() ->
59            new RuntimeException("jlink tool not found")
60        );
61
62    // number of built-in plugins from jdk.jlink module
63    private static int getNumJlinkPlugins() {
64        ModuleDescriptor desc = Plugin.class.getModule().getDescriptor();
65        return desc.provides().stream()
66                .filter(p -> p.service().equals(Plugin.class.getName()))
67                .map(p -> p.providers().size())
68                .findAny()
69                .orElse(0);
70    }
71
72    private static boolean isOfJLinkModule(Plugin p) {
73        return p.getClass().getModule() == Plugin.class.getModule();
74    }
75
76    public static void main(String[] args) throws Exception {
77
78        Helper helper = Helper.newHelper();
79        if (helper == null) {
80            System.err.println("Test not run");
81            return;
82        }
83        helper.generateDefaultModules();
84        // expected num. of plugins from jdk.jlink module
85        int expectedJLinkPlugins = getNumJlinkPlugins();
86        int totalPlugins = 0;
87        {
88            // number of built-in plugins
89            List<Plugin> builtInPlugins = new ArrayList<>();
90            builtInPlugins.addAll(PluginRepository.getPlugins(ModuleLayer.boot()));
91            totalPlugins = builtInPlugins.size();
92            // actual num. of plugins loaded from jdk.jlink module
93            int actualJLinkPlugins = 0;
94            for (Plugin p : builtInPlugins) {
95                p.getState();
96                p.getType();
97                if (isOfJLinkModule(p)) {
98                    actualJLinkPlugins++;
99                }
100            }
101            if (expectedJLinkPlugins != actualJLinkPlugins) {
102                throw new AssertionError("Actual plugins loaded from jdk.jlink: " +
103                        actualJLinkPlugins + " which doesn't match expected number : " +
104                        expectedJLinkPlugins);
105            }
106        }
107
108        {
109            String moduleName = "bug8134651";
110            JImageGenerator.getJLinkTask()
111                    .modulePath(helper.defaultModulePath())
112                    .output(helper.createNewImageDir(moduleName))
113                    .addMods("leaf1")
114                    .call().assertSuccess();
115            JImageGenerator.getJLinkTask()
116                    .modulePath(helper.defaultModulePath())
117                    .addMods("leaf1")
118                    .option("--output")
119                    .call().assertFailure("Error: no value given for --output");
120            JImageGenerator.getJLinkTask()
121                    .modulePath("")
122                    .output(helper.createNewImageDir(moduleName))
123                    .addMods("leaf1")
124                    .call().assertFailure("Error: no value given for --module-path");
125        }
126
127        {
128            String moduleName = "m"; // 8163382
129            Path jmod = helper.generateDefaultJModule(moduleName).assertSuccess();
130            JImageGenerator.getJLinkTask()
131                    .modulePath(helper.defaultModulePath())
132                    .output(helper.createNewImageDir(moduleName))
133                    .addMods("m")
134                    .call().assertSuccess();
135            moduleName = "mod";
136            jmod = helper.generateDefaultJModule(moduleName).assertSuccess();
137            JImageGenerator.getJLinkTask()
138                    .modulePath(helper.defaultModulePath())
139                    .output(helper.createNewImageDir(moduleName))
140                    .addMods("m")
141                    .call().assertSuccess();
142        }
143
144        {
145            String moduleName = "m_8165735"; // JDK-8165735
146            helper.generateDefaultJModule(moduleName+"dependency").assertSuccess();
147            Path jmod = helper.generateDefaultJModule(moduleName, moduleName+"dependency").assertSuccess();
148            JImageGenerator.getJLinkTask()
149                    .modulePath(helper.defaultModulePath())
150                    .repeatedModulePath(".") // second --module-path overrides the first one
151                    .output(helper.createNewImageDir(moduleName))
152                    .addMods(moduleName)
153                    // second --module-path does not have that module
154                    .call().assertFailure("Error: Module m_8165735 not found");
155
156            JImageGenerator.getJLinkTask()
157                    .modulePath(".") // first --module-path overridden later
158                    .repeatedModulePath(helper.defaultModulePath())
159                    .output(helper.createNewImageDir(moduleName))
160                    .addMods(moduleName)
161                    // second --module-path has that module
162                    .call().assertSuccess();
163
164            JImageGenerator.getJLinkTask()
165                    .modulePath(helper.defaultModulePath())
166                    .output(helper.createNewImageDir(moduleName))
167                    .limitMods(moduleName)
168                    .repeatedLimitMods("java.base") // second --limit-modules overrides first
169                    .addMods(moduleName)
170                    .call().assertFailure("Error: Module m_8165735dependency not found, required by m_8165735");
171
172            JImageGenerator.getJLinkTask()
173                    .modulePath(helper.defaultModulePath())
174                    .output(helper.createNewImageDir(moduleName))
175                    .limitMods("java.base")
176                    .repeatedLimitMods(moduleName) // second --limit-modules overrides first
177                    .addMods(moduleName)
178                    .call().assertSuccess();
179        }
180
181        {
182            // Help
183            StringWriter writer = new StringWriter();
184            PrintWriter pw = new PrintWriter(writer);
185            JLINK_TOOL.run(pw, pw, "--help");
186            String output = writer.toString();
187            if (output.split("\n").length < 10) {
188                System.err.println(output);
189                throw new AssertionError("Help");
190            }
191        }
192
193        {
194            // List plugins
195            StringWriter writer = new StringWriter();
196            PrintWriter pw = new PrintWriter(writer);
197
198            JLINK_TOOL.run(pw, pw, "--list-plugins");
199            String output = writer.toString();
200            long number = Stream.of(output.split("\\R"))
201                    .filter((s) -> s.matches("Plugin Name:.*"))
202                    .count();
203            if (number != totalPlugins) {
204                System.err.println(output);
205                throw new AssertionError("Found: " + number + " expected " + totalPlugins);
206            }
207        }
208
209        // filter out files and resources + Skip debug + compress
210        {
211            String[] userOptions = {"--compress", "2", "--strip-debug",
212                "--exclude-resources", "*.jcov, */META-INF/*", "--exclude-files",
213                "*" + Helper.getDebugSymbolsExtension()};
214            String moduleName = "excludezipskipdebugcomposite2";
215            helper.generateDefaultJModule(moduleName, "composite2");
216            String[] res = {".jcov", "/META-INF/"};
217            String[] files = {Helper.getDebugSymbolsExtension()};
218            Path imageDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess();
219            helper.checkImage(imageDir, moduleName, res, files);
220        }
221
222        // filter out + Skip debug + compress with filter + sort resources
223        {
224            String[] userOptions2 = {"--compress=2:compress-filter=^/java.base/*",
225                "--strip-debug", "--exclude-resources",
226                "*.jcov, */META-INF/*", "--order-resources",
227                "*/module-info.class,/sortcomposite2/*,*/javax/management/*"};
228            String moduleName = "excludezipfilterskipdebugcomposite2";
229            helper.generateDefaultJModule(moduleName, "composite2");
230            String[] res = {".jcov", "/META-INF/"};
231            Path imageDir = helper.generateDefaultImage(userOptions2, moduleName).assertSuccess();
232            helper.checkImage(imageDir, moduleName, res, null);
233        }
234
235        // default compress
236        {
237            testCompress(helper, "compresscmdcomposite2", "--compress", "2");
238        }
239
240        {
241            testCompress(helper, "compressfiltercmdcomposite2",
242                    "--compress=2:filter=^/java.base/java/lang/*");
243        }
244
245        // compress 0
246        {
247            testCompress(helper, "compress0filtercmdcomposite2",
248                    "--compress=0:filter=^/java.base/java/lang/*");
249        }
250
251        // compress 1
252        {
253            testCompress(helper, "compress1filtercmdcomposite2",
254                    "--compress=1:filter=^/java.base/java/lang/*");
255        }
256
257        // compress 2
258        {
259            testCompress(helper, "compress2filtercmdcomposite2",
260                    "--compress=2:filter=^/java.base/java/lang/*");
261        }
262
263        // invalid compress level
264        {
265            String[] userOptions = {"--compress", "invalid"};
266            String moduleName = "invalidCompressLevel";
267            helper.generateDefaultJModule(moduleName, "composite2");
268            helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: Invalid compression level invalid");
269        }
270
271        // orphan argument - JDK-8166810
272        {
273            String[] userOptions = {"--compress", "2", "foo" };
274            String moduleName = "orphanarg1";
275            helper.generateDefaultJModule(moduleName, "composite2");
276            helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: invalid argument: foo");
277        }
278
279        // orphan argument - JDK-8166810
280        {
281            String[] userOptions = {"--output", "foo", "bar" };
282            String moduleName = "orphanarg2";
283            helper.generateDefaultJModule(moduleName, "composite2");
284            helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: invalid argument: bar");
285        }
286
287        // basic check for --help - JDK-8173717
288        {
289            JImageGenerator.getJLinkTask()
290                    .option("--help")
291                    .call().assertSuccess();
292        }
293    }
294
295    private static void testCompress(Helper helper, String moduleName, String... userOptions) throws IOException {
296        helper.generateDefaultJModule(moduleName, "composite2");
297        Path imageDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess();
298        helper.checkImage(imageDir, moduleName, null, null);
299    }
300}
301