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 }