--- /dev/null 2016-12-10 08:16:53.177999985 +0000 +++ new/test/jdk/modules/incubator/ImageModules.java 2016-12-15 09:19:32.670478858 +0000 @@ -0,0 +1,382 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8170859 + * @summary Basic test for incubator modules in jmods and images + * @library /lib/testlibrary + * @modules jdk.compiler jdk.jartool jdk.jlink + * @build CompilerUtils + * @run testng/othervm ImageModules + */ + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.PrintStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; +import java.util.spi.ToolProvider; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import jdk.testlibrary.FileUtils; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static jdk.testlibrary.ProcessTools.executeCommand; +import static org.testng.Assert.*; + +public class ImageModules { + private static final String JAVA_HOME = System.getProperty("java.home"); + private static final Path JDK_JMODS = Paths.get(JAVA_HOME, "jmods"); + + private static final Path TEST_SRC = Paths.get(System.getProperty("test.src")); + private static final Path MODS_DIR = Paths.get("mods"); + private static final Path CP_DIR = Paths.get("cp"); + private static final Path JARS_DIR = Paths.get("jars"); + private static final Path JMODS_DIR = Paths.get("jmods"); + private static final Path IMAGE = Paths.get("image"); + + private static final String JAVA_BASE = "java.base"; + private final String[] modules = new String[] { "message.writer", + "message.converter" }; + + @BeforeTest + private void setup() throws Throwable { + Path src = TEST_SRC.resolve("src"); + for (String name : modules) { + assertTrue(CompilerUtils.compile(src.resolve(name), + MODS_DIR, + "--module-source-path", src.toString())); + } + + assertTrue(CompilerUtils.compile(src.resolve("cp"), + CP_DIR, + "--module-path", MODS_DIR.toString(), + "--add-modules", "message.writer")); + } + + @DataProvider(name = "singleModule") + public Object[][] singleModuleValues() throws IOException { + Object[][] values = new Object[][]{ + // { Extra args to the build the message.converter jmod + // Tokens to pass to the run time --add-modules option + // SUCCESS or FAILURE expected + // Messages expected in the run time output + // Messages that must not appear in the run time output }, + { "", + List.of("ALL-DEFAULT", "ALL-SYSTEM"), + ToolResult.ASSERT_SUCCESS, + List.of("hello world", "message.converter", "java.base"), + List.of("WARNING") }, + { "--do-not-resolve-by-default", + List.of("ALL-DEFAULT", "ALL-SYSTEM"), + ToolResult.ASSERT_FAILURE, + List.of("java.base", "java.lang.ClassNotFoundException: converter.MessageConverter"), + List.of("WARNING", "message.converter") }, + { "--warn-if-resolved=incubating", + List.of("ALL-DEFAULT", "ALL-SYSTEM"), + ToolResult.ASSERT_SUCCESS, + List.of("hello world", "message.converter", "java.base", + "WARNING: using incubating module(s): message.converter"), + List.of() }, + { "--do-not-resolve-by-default --warn-if-resolved=incubating", + List.of("ALL-DEFAULT", "ALL-SYSTEM"), + ToolResult.ASSERT_FAILURE, + List.of("java.base", "java.lang.ClassNotFoundException: converter.MessageConverter"), + List.of("WARNING", "message.converter") }, + { "--do-not-resolve-by-default --warn-if-resolved=incubating", + List.of("message.converter"), + ToolResult.ASSERT_SUCCESS, + List.of("hello world", "message.converter", "java.base", "WARNING"), + List.of() } + }; + return values; + } + + @Test(dataProvider = "singleModule") + public void singleModule(String extraJmodArg, + List addModsTokens, + Consumer assertExitCode, + List expectedOutput, + List unexpectedOutput) + throws Throwable + { + if (Files.notExists(JDK_JMODS)) { + System.out.println("JDK jmods not found test cannot run."); + return; + } + + FileUtils.deleteFileTreeUnchecked(JMODS_DIR); + FileUtils.deleteFileTreeUnchecked(IMAGE); + Files.createDirectories(JMODS_DIR); + Path converterJmod = JMODS_DIR.resolve("converter.jmod"); + + jmod("create", + "--class-path", MODS_DIR.resolve("message.converter").toString(), + extraJmodArg, + converterJmod.toString()) + .assertSuccess(); + + String mpath = JDK_JMODS.toString() + File.pathSeparator + JMODS_DIR.toString(); + jlink("--module-path", mpath, + "--add-modules", JAVA_BASE + ",message.converter", + "--output", IMAGE.toString()) + .assertSuccess(); + + for (String addModsToken : addModsTokens) { + String[] props = new String[] {"", "-Djdk.system.module.finder.disabledFastPath"}; + for (String systemProp : props) + java(IMAGE, + systemProp, + "--add-modules", addModsToken, + "-cp", CP_DIR.toString(), + "test.ConvertToLowerCase", "HEllo WoRlD") + .resultChecker(assertExitCode) + .resultChecker(r -> { + expectedOutput.forEach(e -> r.assertContains(e)); + unexpectedOutput.forEach(e -> r.assertDoesNotContains(e)); + }); + } + } + + @Test + public void singleModularJar() throws Throwable { + FileUtils.deleteFileTreeUnchecked(JARS_DIR); + Files.createDirectories(JARS_DIR); + Path converterJar = JARS_DIR.resolve("converter.jar"); + + jar("--create", + "--file", converterJar.toString(), + "--warn-if-resolved=incubating", + "-C", MODS_DIR.resolve("message.converter").toString() , ".") + .assertSuccess(); + + + java(Paths.get(JAVA_HOME), + "--module-path", JARS_DIR.toString(), + "--add-modules", "message.converter", + "-cp", CP_DIR.toString(), + "test.ConvertToLowerCase", "HEllo WoRlD") + .assertSuccess() + .resultChecker(r -> { + r.assertContains("WARNING: using incubating module(s): message.converter"); + }); + } + + @DataProvider(name = "twoModules") + public Object[][] twoModulesValues() throws IOException { + Object[][] values = new Object[][]{ + // { Extra args to the build the message.writer jmod + // Extra args to the build the message.converter jmod + // Tokens to pass to the run time --add-modules option + // SUCCESS or FAILURE expected + // Messages expected in the run time output + // Messages that must not appear in the run time output }, + { "", + "", + List.of("ALL-DEFAULT", "ALL-SYSTEM"), + ToolResult.ASSERT_SUCCESS, + List.of("HELLO CHEGAR !!!", "message.writer", "message.converter", "java.base"), + List.of() }, + { "", + "--do-not-resolve-by-default", + List.of("ALL-DEFAULT", "ALL-SYSTEM"), + ToolResult.ASSERT_SUCCESS, + List.of("HELLO CHEGAR !!!", "message.writer", "message.converter", "java.base"), + List.of() }, + { "--do-not-resolve-by-default", + "", + List.of("ALL-DEFAULT", "ALL-SYSTEM"), + ToolResult.ASSERT_FAILURE, + List.of("java.lang.ClassNotFoundException: writer.MessageWriter", "java.base"), + List.of("message.writer") }, + { "--do-not-resolve-by-default", + "--do-not-resolve-by-default", + List.of("ALL-DEFAULT", "ALL-SYSTEM"), + ToolResult.ASSERT_FAILURE, + List.of("java.lang.ClassNotFoundException: writer.MessageWriter", "java.base"), + List.of("message.converter", "message.writer") }, + // now add in warnings + { "--do-not-resolve-by-default --warn-if-resolved=incubating", + "", + List.of("message.writer"), + ToolResult.ASSERT_SUCCESS, + List.of("HELLO CHEGAR !!!", "message.writer", "message.converter", "java.base", + "WARNING: using incubating module(s): message.writer"), + List.of() }, + { "", + "--do-not-resolve-by-default --warn-if-resolved=incubating", + List.of("message.writer"), + ToolResult.ASSERT_SUCCESS, + List.of("HELLO CHEGAR !!!", "message.writer", "message.converter", "java.base", + "WARNING: using incubating module(s): message.converter"), + List.of() } }; + return values; + } + + @Test(dataProvider = "twoModules") + public void doNotResolveByDefaultTwoModules(String extraFirstJmodArg, + String extraSecondJmodArg, + List addModsTokens, + Consumer assertExitCode, + List expectedOutput, + List unexpectedOutput) + throws Throwable + { + if (Files.notExists(JDK_JMODS)) { + System.out.println("JDK jmods not found test cannot run."); + return; + } + + FileUtils.deleteFileTreeUnchecked(JMODS_DIR); + FileUtils.deleteFileTreeUnchecked(IMAGE); + Files.createDirectories(JMODS_DIR); + Path writerJmod = JMODS_DIR.resolve("writer.jmod"); + Path converterJmod = JMODS_DIR.resolve("converter.jmod"); + + jmod("create", + extraFirstJmodArg, + "--class-path", MODS_DIR.resolve("message.writer").toString(), + writerJmod.toString()); + + jmod("create", + "--class-path", MODS_DIR.resolve("message.converter").toString(), + extraSecondJmodArg, + converterJmod.toString()) + .assertSuccess(); + + String mpath = JDK_JMODS.toString() + File.pathSeparator + JMODS_DIR.toString(); + jlink("--module-path", mpath, + "--add-modules", JAVA_BASE + ",message.writer,message.converter", + "--output", IMAGE.toString()) + .assertSuccess(); + + for (String addModsToken : addModsTokens) { + String[] props = new String[] {"", "-Djdk.system.module.finder.disabledFastPath"}; + for (String systemProp : props) + java(IMAGE, + systemProp, + "--add-modules", addModsToken, + "-cp", CP_DIR.toString(), + "test.WriteUpperCase", "hello chegar !!!") + .resultChecker(assertExitCode) + .resultChecker(r -> { + expectedOutput.forEach(e -> r.assertContains(e)); + unexpectedOutput.forEach(e -> r.assertDoesNotContains(e)); + }); + } + } + + static final ToolProvider JMOD_TOOL = ToolProvider.findFirst("jmod") + .orElseThrow(() -> new RuntimeException("jmod tool not found")); + static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar") + .orElseThrow(() -> new RuntimeException("jar tool not found")); + static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink") + .orElseThrow(() -> new RuntimeException("jlink tool not found")); + + static ToolResult jmod(String... args) { return execTool(JMOD_TOOL, args); } + + static ToolResult jar(String... args) { return execTool(JAR_TOOL, args); } + + static ToolResult jlink(String... args) { return execTool(JLINK_TOOL, args); } + + static ToolResult java(Path image, String... opts) throws Throwable { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintStream ps = new PrintStream(baos); + String[] options = Stream.concat(Stream.of(getJava(image)), + Stream.of(opts).filter(s -> !s.equals(""))) + .toArray(String[]::new); + + ProcessBuilder pb = new ProcessBuilder(options); + int exitValue = executeCommand(pb).outputTo(ps) + .errorTo(ps) + .getExitValue(); + + return new ToolResult(exitValue, new String(baos.toByteArray(), UTF_8)); + } + + static ToolResult execTool(ToolProvider tool, String... args) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintStream ps = new PrintStream(baos); + List filteredArgs = Stream.of(args) + .map(s -> s.split(" ")).flatMap(Stream::of) + .filter(s -> !s.equals("")) + .collect(Collectors.toList()); + System.out.println(tool + " " + filteredArgs); + int ec = tool.run(ps, ps, filteredArgs.toArray(new String[] {})); + return new ToolResult(ec, new String(baos.toByteArray(), UTF_8)); + } + + static class ToolResult { + final int exitCode; + final String output; + + ToolResult(int exitValue, String output) { + this.exitCode = exitValue; + this.output = output; + } + + static Consumer ASSERT_SUCCESS = r -> + assertEquals(r.exitCode, 0, + "Expected exit code 0, got " + r.exitCode + + ", with output[" + r.output + "]"); + static Consumer ASSERT_FAILURE = r -> + assertNotEquals(r.exitCode, 0, + "Expected exit code != 0, got " + r.exitCode + + ", with output[" + r.output + "]"); + + ToolResult assertSuccess() { ASSERT_SUCCESS.accept(this); return this; } + ToolResult assertFailure() { ASSERT_FAILURE.accept(this); return this; } + ToolResult resultChecker(Consumer r) { r.accept(this); return this; } + + ToolResult assertContains(String subString) { + assertTrue(output.contains(subString), + "Expected to find [" + subString + "], in output [" + + output + "]" + "\n"); + return this; + } + ToolResult assertDoesNotContains(String subString) { + assertFalse(output.contains(subString), + "Expected to NOT find [" + subString + "], in output [" + + output + "]" + "\n"); + return this; + } + } + + static String getJava(Path image) { + boolean isWindows = System.getProperty("os.name").startsWith("Windows"); + Path java = image.resolve("bin").resolve(isWindows ? "java.exe" : "java"); + if (Files.notExists(java)) + throw new RuntimeException(java + " not found"); + return java.toAbsolutePath().toString(); + } +}