1 /*
2 * Copyright (c) 2014, 2018, 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 * @library /test/lib
27 * @modules jdk.compiler
28 * jdk.jartool
29 * jdk.jlink
30 * @build BasicTest jdk.test.lib.compiler.CompilerUtils
31 * @run testng BasicTest
32 * @bug 8234076
33 * @summary Basic test of starting an application as a module
34 */
35
36 import java.io.File;
37 import java.nio.file.Files;
38 import java.nio.file.Path;
39 import java.nio.file.Paths;
40 import java.util.spi.ToolProvider;
41
42 import jdk.test.lib.compiler.CompilerUtils;
43 import jdk.test.lib.process.ProcessTools;
44 import jdk.test.lib.process.OutputAnalyzer;
45 import jdk.test.lib.Utils;
46
47 import org.testng.annotations.BeforeTest;
48 import org.testng.annotations.Test;
49 import static org.testng.Assert.*;
50
51
52 @Test
53 public class BasicTest {
54 private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar")
55 .orElseThrow(() ->
56 new RuntimeException("jar tool not found")
57 );
58 private static final ToolProvider JMOD_TOOL = ToolProvider.findFirst("jmod")
59 .orElseThrow(() ->
60 new RuntimeException("jmod tool not found")
61 );
62
63 private static final Path USER_DIR = Paths.get(System.getProperty("user.dir"));
64
65 private static final String TEST_SRC = System.getProperty("test.src");
66
67 private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
68 private static final Path MODS_DIR = Paths.get("mods");
69
70 // the module name of the test module
71 private static final String TEST_MODULE = "test";
72
73 // the module main class
74 private static final String MAIN_CLASS = "jdk.test.Main";
75
76 // for Windows specific launcher tests
77 static final boolean IS_WINDOWS = System.getProperty("os.name", "unknown").startsWith("Windows");
78
79 @BeforeTest
80 public void compileTestModule() throws Exception {
81
82 // javac -d mods/$TESTMODULE src/$TESTMODULE/**
83 boolean compiled
84 = CompilerUtils.compile(SRC_DIR.resolve(TEST_MODULE),
85 MODS_DIR.resolve(TEST_MODULE));
86
87 assertTrue(compiled, "test module did not compile");
88 }
89
90 /**
91 * Execute "java" with the given arguments, returning the exit code.
92 */
93 private int exec(String... args) throws Exception {
94 return ProcessTools.executeTestJava(args)
95 .outputTo(System.out)
96 .errorTo(System.out)
97 .getExitValue();
98 }
99
100
101 /**
102 * The initial module is loaded from an exploded module
103 */
104 public void testRunWithExplodedModule() throws Exception {
105 String dir = MODS_DIR.toString();
106 String subdir = MODS_DIR.resolve(TEST_MODULE).toString();
107 String mid = TEST_MODULE + "/" + MAIN_CLASS;
108
109 // java --module-path mods -module $TESTMODULE/$MAINCLASS
110 int exitValue = exec("--module-path", dir, "--module", mid);
111 assertTrue(exitValue == 0);
112
113 // java --module-path mods/$TESTMODULE --module $TESTMODULE/$MAINCLASS
114 exitValue = exec("--module-path", subdir, "--module", mid);
115 assertTrue(exitValue == 0);
116
117 // java --module-path=mods --module=$TESTMODULE/$MAINCLASS
118 exitValue = exec("--module-path=" + dir, "--module=" + mid);
119 assertTrue(exitValue == 0);
120
121 // java --module-path=mods/$TESTMODULE --module=$TESTMODULE/$MAINCLASS
122 exitValue = exec("--module-path=" + subdir, "--module=" + mid);
123 assertTrue(exitValue == 0);
124
125 // java -p mods -m $TESTMODULE/$MAINCLASS
126 exitValue = exec("-p", dir, "-m", mid);
127 assertTrue(exitValue == 0);
128
129 // java -p mods/$TESTMODULE -m $TESTMODULE/$MAINCLASS
130 exitValue = exec("-p", subdir, "-m", mid);
131 assertTrue(exitValue == 0);
132 }
133
134
135 /**
136 * The initial module is loaded from a modular JAR file
137 */
138 public void testRunWithModularJar() throws Exception {
139 Path dir = Files.createTempDirectory(USER_DIR, "mlib");
140 Path jar = dir.resolve("m.jar");
141
142 // jar --create ...
143 String classes = MODS_DIR.resolve(TEST_MODULE).toString();
144 String[] args = {
145 "--create",
146 "--file=" + jar,
147 "--main-class=" + MAIN_CLASS,
148 "-C", classes, "."
149 };
150 int rc = JAR_TOOL.run(System.out, System.out, args);
151 assertTrue(rc == 0);
152
153 // java --module-path mlib -module $TESTMODULE
154 int exitValue = exec("--module-path", dir.toString(),
155 "--module", TEST_MODULE);
156 assertTrue(exitValue == 0);
157
158 // java --module-path mlib/m.jar -module $TESTMODULE
159 exitValue = exec("--module-path", jar.toString(),
160 "--module", TEST_MODULE);
161 assertTrue(exitValue == 0);
162 }
163
164
165 /**
166 * Attempt to run with the initial module packaged as a JMOD file.
167 */
168 public void testTryRunWithJMod() throws Exception {
169 Path dir = Files.createTempDirectory(USER_DIR, "mlib");
170
171 // jmod create ...
172 String cp = MODS_DIR.resolve(TEST_MODULE).toString();
173 String jmod = dir.resolve("m.jmod").toString();
174 String[] args = {
175 "create",
176 "--class-path", cp,
177 "--main-class", MAIN_CLASS,
178 jmod
179 };
180
181 assertEquals(JMOD_TOOL.run(System.out, System.out, args), 0);
182
183 // java --module-path mods --module $TESTMODULE
184 int exitValue = exec("--module-path", dir.toString(),
185 "--module", TEST_MODULE);
186 assertTrue(exitValue != 0);
187 }
188
189
190 /**
191 * Run the test with a non-existent file on the application module path.
192 * It should be silently ignored.
193 */
194 public void testRunWithNonExistentEntry() throws Exception {
195 String mp = "DoesNotExist" + File.pathSeparator + MODS_DIR.toString();
196 String mid = TEST_MODULE + "/" + MAIN_CLASS;
197
198 // java --module-path mods --module $TESTMODULE/$MAINCLASS
199 int exitValue = exec("--module-path", mp, "--module", mid);
200 assertTrue(exitValue == 0);
201 }
202
203
204 /**
205 * Attempt to run an unknown initial module
206 */
207 public void testTryRunWithBadModule() throws Exception {
208 String modulepath = MODS_DIR.toString();
209
210 // java --module-path mods -m $TESTMODULE
211 int exitValue = exec("--module-path", modulepath, "-m", "rhubarb");
212 assertTrue(exitValue != 0);
213 }
214
215
216 /**
217 * Attempt to run with -m specifying a main class that does not
218 * exist.
219 */
220 public void testTryRunWithBadMainClass() throws Exception {
221 String modulepath = MODS_DIR.toString();
222 String mid = TEST_MODULE + "/p.rhubarb";
223
224 // java --module-path mods -m $TESTMODULE/$MAINCLASS
225 int exitValue = exec("--module-path", modulepath, "-m", mid);
226 assertTrue(exitValue != 0);
227 }
228
229
230 /**
231 * Attempt to run with -m specifying a modular JAR that does not have
232 * a MainClass attribute
233 */
234 public void testTryRunWithMissingMainClass() throws Exception {
235 Path dir = Files.createTempDirectory(USER_DIR, "mlib");
236
237 // jar --create ...
238 String classes = MODS_DIR.resolve(TEST_MODULE).toString();
239 String jar = dir.resolve("m.jar").toString();
240 String[] args = {
241 "--create",
242 "--file=" + jar,
243 "-C", classes, "."
244 };
245 int rc = JAR_TOOL.run(System.out, System.out, args);
246 assertTrue(rc == 0);
247
248 // java --module-path mods -m $TESTMODULE
249 int exitValue = exec("--module-path", dir.toString(), "-m", TEST_MODULE);
250 assertTrue(exitValue != 0);
251 }
252
253
254 /**
255 * Attempt to run with -m specifying a main class that is a different
256 * module to that specified to -m
257 */
258 public void testTryRunWithMainClassInWrongModule() throws Exception {
259 String modulepath = MODS_DIR.toString();
260 String mid = "java.base/" + MAIN_CLASS;
261
262 // java --module-path mods --module $TESTMODULE/$MAINCLASS
263 int exitValue = exec("--module-path", modulepath, "--module", mid);
264 assertTrue(exitValue != 0);
265 }
266
267
268 /**
269 * Helper method that creates a ProcessBuilder with command line arguments
270 * while setting the _JAVA_LAUNCHER_DEBUG environment variable.
271 */
272 private ProcessBuilder createProcessWithLauncherDebugging(String... cmds) {
273 ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(Utils.addTestJavaOpts(cmds));
274 pb.environment().put("_JAVA_LAUNCHER_DEBUG", "true");
275
276 return pb;
277 }
278
279 /**
280 * Test the ability for the Windows launcher to do proper application argument
281 * detection and expansion, when using the long form module option and all passed in
282 * command line arguments are prefixed with a dash.
283 *
284 * These tests are not expected to work on *nixes, and are ignored.
285 */
286 public void testWindowsWithLongFormModuleOption() throws Exception {
287 if (!IS_WINDOWS) {
288 return;
289 }
290
291 String dir = MODS_DIR.toString();
292 String mid = TEST_MODULE + "/" + MAIN_CLASS;
293
294 // java --module-path=mods --module=$TESTMODULE/$MAINCLASS --help
295 // We should be able to find the argument --help as an application argument
296 ProcessTools.executeProcess(
297 createProcessWithLauncherDebugging(
298 "--module-path=" + dir,
299 "--module=" + mid,
300 "--help"))
301 .outputTo(System.out)
302 .errorTo(System.out)
303 .shouldContain("F--help");
304
305 // java --module-path=mods --module=$TESTMODULE/$MAINCLASS <...src/test>/*.java --help
306 // We should be able to see argument expansion happen
307 ProcessTools.executeProcess(
308 createProcessWithLauncherDebugging(
309 "--module-path=" + dir,
310 "--module=" + mid,
311 SRC_DIR.resolve(TEST_MODULE).toString() + "\\*.java",
312 "--help"))
313 .outputTo(System.out)
314 .errorTo(System.out)
315 .shouldContain("F--help")
316 .shouldContain("module-info.java");
317 }
318
319
320 /**
321 * Test that --module= is terminating for VM argument processing just like --module
322 */
323 public void testLongFormModuleOptionTermination() throws Exception {
324 String dir = MODS_DIR.toString();
325 String mid = TEST_MODULE + "/" + MAIN_CLASS;
326
327 // java --module-path=mods --module=$TESTMODULE/$MAINCLASS --module-path=mods --module=$TESTMODULE/$MAINCLASS
328 // The first --module= will terminate the VM arguments processing. The second pair of module-path and module will be
329 // deemed as application arguments
330 OutputAnalyzer output = ProcessTools.executeProcess(
331 createProcessWithLauncherDebugging(
332 "--module-path=" + dir,
333 "--module=" + mid,
334 "--module-path=" + dir,
335 "--module=" + mid))
336 .outputTo(System.out)
337 .errorTo(System.out)
338 .shouldContain("argv[ 0] = '--module-path=" + dir)
339 .shouldContain("argv[ 1] = '--module=" + mid);
340
341 if (IS_WINDOWS) {
342 output.shouldContain("F--module-path=" + dir).shouldContain("F--module=" + mid);
343 }
344
345 // java --module=$TESTMODULE/$MAINCLASS --module-path=mods
346 // This command line will not work as --module= is terminating and the module will be not found
347 int exitValue = exec("--module=" + mid, "--module-path" + dir);
348 assertTrue(exitValue != 0);
349 }
350 }