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 * @bug 8156998 27 * @summary Test --inherit-runtime-environment 28 * @library /tools/lib 29 * @modules 30 * jdk.compiler/com.sun.tools.javac.api 31 * jdk.compiler/com.sun.tools.javac.main 32 * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask toolbox.JavaTask ModuleTestBase 33 * @run main InheritRuntimeEnvironmentTest 34 */ 35 36 import java.io.IOException; 37 import java.nio.file.Files; 38 import java.nio.file.Path; 39 import java.util.Arrays; 40 import java.util.Collections; 41 import java.util.List; 42 import java.util.stream.Collectors; 43 44 import toolbox.ModuleBuilder; 45 import toolbox.JavaTask; 46 import toolbox.JavacTask; 47 import toolbox.Task; 48 49 /** 50 * Tests that javac picks up runtime options with --inherit-runtime-environment. 51 * For each option, javac is first run using the option directly, as a control. 52 * javac is then run again, with the same option(s) being passed to the runtime, 53 * and --inherit-runtime-environment being used by javac. 54 * @author jjg 55 */ 56 public class InheritRuntimeEnvironmentTest extends ModuleTestBase { 57 public static void main(String... args) throws Exception { 58 InheritRuntimeEnvironmentTest t = new InheritRuntimeEnvironmentTest(); 59 t.runTests(); 60 } 61 62 /** 63 * Tests that code being compiled can access JDK-internal API using -add-exports. 64 * @param base 65 * @throws Exception 66 */ 67 @Test 68 public void testAddExports(Path base) throws Exception { 69 Path src = base.resolve("src"); 70 tb.writeJavaFiles(src, 71 "class C { com.sun.tools.javac.main.Main main; }"); 72 73 new TestCase(base) 74 .testOpts("--add-exports", "jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED") 75 .files(findJavaFiles(src)) 76 .run(); 77 } 78 79 /** 80 * Tests that code in the unnamed module can access a module on the module path using --add-modules. 81 */ 82 @Test 83 public void testAddModules(Path base) throws Exception { 84 Path modules = base.resolve("modules"); 85 new ModuleBuilder(tb, "m1") 86 .exports("pkg1") 87 .classes("package pkg1; public class C1 { }") 88 .build(modules); 89 90 Path src = base.resolve("src"); 91 tb.writeJavaFiles(src, 92 "class C { pkg1.C1 c1; }"); 93 94 new TestCase(base) 95 .testOpts("--module-path", modules.toString(), "--add-modules", "m1") 96 .files(findJavaFiles(src)) 97 .run(); 98 } 99 100 /** 101 * Tests that a module on the module path is not visible when --limit-modules is used to 102 * restrict the set of observable modules. 103 */ 104 @Test 105 public void testLimitModules(Path base) throws Exception { 106 Path modules = base.resolve("modules"); 107 new ModuleBuilder(tb, "m1") 108 .exports("pkg1") 109 .classes("package pkg1; public class C1 { }") 110 .build(modules); 111 112 Path src = base.resolve("src"); 113 new ModuleBuilder(tb, "m2") 114 .requires("m1") 115 .classes("package pkg2; public class C2 { pkg1.C1 c1; }") 116 .write(src); 117 118 // This is the control, to verify that by default, the module being compiled will 119 // be able to read modules on the module path 120 new TestCase(base) 121 .testOpts("--module-path", modules.toString()) 122 .otherOpts("--module-source-path", src.toString()) 123 .files(findJavaFiles(src)) 124 .run(); 125 126 Path emptyClassPath = base.resolve("emptyClassPath"); 127 128 Files.createDirectories(emptyClassPath); 129 130 // This is the test, to verify that the module being compiled will not be able to read 131 // modules on the module path when a --limit-modules is used 132 new TestCase(base) 133 .testOpts("--module-path", modules.toString(), "--limit-modules", "jdk.compiler") 134 .otherOpts("-XDrawDiagnostics", 135 "--module-source-path", src.toString(), 136 "-classpath", emptyClassPath.toString()) 137 .files(findJavaFiles(src)) 138 .expect(Task.Expect.FAIL, "compiler.err.module.not.found") 139 .run(); 140 } 141 142 /** 143 * Tests that a module being compiled can see another module on the module path 144 * using --module-path. 145 */ 146 @Test 147 public void testModulePath(Path base) throws Exception { 148 Path modules = base.resolve("modules"); 149 new ModuleBuilder(tb, "m1") 150 .exports("pkg1") 151 .classes("package pkg1; public class C1 { }") 152 .build(modules); 153 154 Path src = base.resolve("src"); 155 new ModuleBuilder(tb, "m2") 156 .requires("m1") 157 .classes("package pkg2; public class C2 { pkg1.C1 c1; }") 158 .write(src); 159 160 new TestCase(base) 161 .testOpts("--module-path", modules.toString()) 162 .otherOpts("--module-source-path", src.toString()) 163 .files(findJavaFiles(src)) 164 .run(); 165 } 166 167 /** 168 * Tests that a module being compiled can see classes patches into an existing module 169 * with --patch-module 170 */ 171 @Test 172 public void testPatchModule(Path base) throws Exception { 173 Path patchSrc = base.resolve("patchSrc"); 174 tb.writeJavaFiles(patchSrc, 175 "package java.util; public class Xyzzy { }"); 176 Path patch = base.resolve("patch"); 177 Files.createDirectories(patch); 178 179 new JavacTask(tb) 180 .options("--patch-module", "java.base=" + patchSrc.toString()) 181 .outdir(patch) 182 .sourcepath(patchSrc) 183 .files(findJavaFiles(patchSrc)) 184 .run() 185 .writeAll(); 186 187 Path src = base.resolve("src"); 188 tb.writeJavaFiles(src, 189 "public class C { java.util.Xyzzy x; }"); 190 191 new TestCase(base) 192 .testOpts("--patch-module", "java.base=" + patch) 193 .files(findJavaFiles(src)) 194 .run(); 195 } 196 197 /** 198 * Tests that options in @files are also effective. 199 * The test is similar to testModulePath, except that the test options are provided in an @-file. 200 */ 201 @Test 202 public void testAtFile(Path base) throws Exception { 203 Path modules = base.resolve("modules"); 204 new ModuleBuilder(tb, "m1") 205 .exports("pkg1") 206 .classes("package pkg1; public class C1 { }") 207 .build(modules); 208 209 Path src = base.resolve("src"); 210 new ModuleBuilder(tb, "m2") 211 .requires("m1") 212 .classes("package pkg2; public class C2 { pkg1.C1 c1; }") 213 .write(src); 214 215 Path atFile = base.resolve("atFile"); 216 tb.writeFile(atFile, "--module-path " + modules); 217 218 new TestCase(base) 219 .testOpts("@" + atFile) 220 .otherOpts("--module-source-path", src.toString()) 221 .files(findJavaFiles(src)) 222 .run(); 223 } 224 225 /** 226 * Tests that --inherit-runtime-environment works in conjunction with 227 * environment variables. 228 * This is a variant of testAddExports. 229 * The use of environment variables is sufficiently custom that it is 230 * not easy to do this directly with a simple TestCase. 231 */ 232 @Test 233 public void testEnvVars(Path base) throws Exception { 234 Path src = base.resolve("src"); 235 tb.writeJavaFiles(src, 236 "class C { com.sun.tools.javac.main.Main main; }"); 237 List<String> testOpts = 238 Arrays.asList("--add-exports", "jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED"); 239 List<Path> files = Arrays.asList(findJavaFiles(src)); 240 241 String envName = "_JAVAC_OPTIONS"; 242 String envValue = String.join(" ", testOpts); 243 244 out.println(" javac:"); 245 Path javacOutDir = base.resolve("out-javac"); 246 Files.createDirectories(javacOutDir); 247 248 out.println(" env: " + envName + "=" + envValue); 249 out.println(" outdir: " + javacOutDir); 250 out.println(" files: " + files); 251 252 new JavacTask(tb, Task.Mode.EXEC) 253 .envVar(envName, envValue) 254 .outdir(javacOutDir) 255 .files(files) 256 .run() 257 .writeAll() 258 .getOutput(Task.OutputKind.DIRECT); 259 260 out.println(" java:"); 261 Path javaOutDir = base.resolve("out-java"); 262 Files.createDirectories(javaOutDir); 263 264 Path atFile = base.resolve("atFile"); 265 tb.writeFile(atFile, String.join(" ", testOpts)); 266 267 List<String> vmOpts = Arrays.asList( 268 "@" + atFile, 269 "--module", "jdk.compiler/com.sun.tools.javac.Main" 270 ); 271 272 List<String> classArgs = join( 273 Arrays.asList("-d", javaOutDir.toString()), 274 files.stream() 275 .map(p -> p.toString()) 276 .collect(Collectors.toList()) 277 ); 278 279 envValue = "--inherit-runtime-environment"; 280 281 out.println(" env: " + envName + "=" + envValue); 282 out.println(" vmOpts: " + vmOpts); 283 out.println(" classArgs: " + classArgs); 284 285 new JavaTask(tb) 286 .envVar(envName, envValue) 287 .vmOptions(vmOpts) 288 .classArgs(classArgs) 289 .run() 290 .writeAll() 291 .getOutput(Task.OutputKind.STDERR); 292 } 293 294 /** 295 * Runs javac with given test options, first directly, and then again, specifying the 296 * options to the runtime, and using --inherit-runtime-environment. 297 */ 298 class TestCase { 299 final Path base; 300 List<String> testOpts = Collections.emptyList(); 301 List<String> otherOpts = Collections.emptyList(); 302 List<Path> files = Collections.emptyList(); 303 Task.Expect expect = Task.Expect.SUCCESS; 304 String expectedText; 305 306 /** 307 * Creates a test case, specifying a base directory for work files. 308 */ 309 TestCase(Path base) { 310 this.base = base; 311 } 312 313 /** 314 * Set the "test options" to be passed to javac or to the runtime. 315 */ 316 TestCase testOpts(String... testOpts) { 317 this.testOpts = Arrays.asList(testOpts); 318 return this; 319 } 320 321 /** 322 * Sets additional options required for the compilation. 323 */ 324 TestCase otherOpts(String... otherOpts) { 325 this.otherOpts = Arrays.asList(otherOpts); 326 return this; 327 } 328 329 /** 330 * Sets the files to be compiled. 331 */ 332 TestCase files(Path... files) { 333 this.files = Arrays.asList(files); 334 return this; 335 } 336 337 /** 338 * Sets the expected output, and any expected output from javac. 339 * The default is {@code Expect.SUCCESS} and no specific output expected. 340 */ 341 TestCase expect(Task.Expect expect, String expectedText) { 342 this.expect = expect; 343 this.expectedText = expectedText; 344 return this; 345 } 346 347 /** 348 * Runs the test case. 349 * First, javac is run passing the test options directly to javac. 350 * Then, javac is run again, passing the test options to the runtime, 351 * and using --inherit-runtime-environment. 352 */ 353 void run() throws IOException { 354 runJavac(); 355 runJava(); 356 } 357 358 private void runJavac() throws IOException { 359 out.println(" javac:"); 360 Path javacOutDir = base.resolve("out-javac"); 361 Files.createDirectories(javacOutDir); 362 363 List<String> options = join(testOpts, otherOpts); 364 365 out.println(" options: " + options); 366 out.println(" outdir: " + javacOutDir); 367 out.println(" files: " + files); 368 369 String log = new JavacTask(tb, Task.Mode.CMDLINE) 370 .options(options) 371 .outdir(javacOutDir) 372 .files(files) 373 .run(expect) 374 .writeAll() 375 .getOutput(Task.OutputKind.DIRECT); 376 377 if (expectedText != null && !log.contains(expectedText)) 378 error("expected text not found"); 379 } 380 381 private void runJava() throws IOException { 382 out.println(" java:"); 383 Path javaOutDir = base.resolve("out-java"); 384 Files.createDirectories(javaOutDir); 385 386 List<String> vmOpts = join( 387 testOpts, 388 Arrays.asList("--module", "jdk.compiler/com.sun.tools.javac.Main") 389 ); 390 391 List<String> classArgs = join( 392 Arrays.asList("--inherit-runtime-environment", 393 "-d", javaOutDir.toString()), 394 otherOpts, 395 files.stream() 396 .map(p -> p.toString()) 397 .collect(Collectors.toList()) 398 ); 399 400 out.println(" vmOpts: " + vmOpts); 401 out.println(" classArgs: " + classArgs); 402 403 String log = new JavaTask(tb) 404 .vmOptions(vmOpts) 405 .classArgs(classArgs) 406 .run(expect) 407 .writeAll() 408 .getOutput(Task.OutputKind.STDERR); 409 410 if (expectedText != null && !log.contains(expectedText)) 411 error("expected text not found"); 412 } 413 } 414 415 /** 416 * Join a series of lists. 417 */ 418 @SafeVarargs 419 private <T> List<T> join(List<T>... lists) { 420 return Arrays.stream(lists) 421 .flatMap(list -> list.stream()) 422 .collect(Collectors.toList()); 423 } 424 425 } 426