--- old/test/java/security/modules/JigsawSecurityUtils.java 2015-12-21 09:55:16.296473592 -0800 +++ /dev/null 2015-07-25 05:49:27.889711346 -0700 @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2015, 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. - */ - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; -import java.util.Map; -import java.lang.module.ModuleDescriptor; -import static java.lang.module.ModuleDescriptor.Builder; - -/** - * Jigsaw utility methods are part of this class. It exposes methods to generate - * module descriptor object and create service descriptor inside META-INF folder - * etc. - */ -public class JigsawSecurityUtils { - - /** - * Enum represents all supported module types in JDK9. - */ - public enum MODULE_TYPE { - - EXPLICIT, AUTO, UNNAMED; - } - - public static final String SPACE = " "; - - /** - * Constructs a Java Command line string based on modular structure followed - * by modular client and service. - */ - public static String[] getJavaCommand(Path modulePath, - StringBuilder classPath, String clientModuleName, - String mainClass, Map vmArgs) throws IOException { - - final StringBuilder command = new StringBuilder(); - vmArgs.forEach((key, value) -> command.append(key + value + SPACE)); - if (modulePath != null) { - command.append("-mp" + SPACE + modulePath.toRealPath() + SPACE); - } - if (classPath != null && classPath.length() > 0) { - command.append("-cp" + SPACE + classPath + SPACE); - } - if (clientModuleName != null && clientModuleName.length() > 0) { - command.append("-m" + SPACE + clientModuleName + "/"); - } - command.append(mainClass); - return command.toString().trim().split("[\\s]+"); - } - - /** - * Generate ModuleDescriptor object for explicit/auto based client/service - * modules. - */ - public static ModuleDescriptor generateModuleDescriptor( - boolean service, MODULE_TYPE moduleType, String moduleName, - String pkg, String serviceInterface, - String serviceImpl, String serviceModuleName, - List requiredModules, boolean depends) { - final Builder builder; - if (moduleType == MODULE_TYPE.EXPLICIT) { - System.out.println("Generating ModuleDescriptor object"); - builder = new Builder(moduleName).exports(pkg); - if (service) { - builder.provides(serviceInterface, serviceImpl); - } else { - builder.uses(serviceInterface); - if (depends) { - builder.requires(serviceModuleName); - } - } - } else { - System.out.println("ModuleDescriptor object not required."); - return null; - } - requiredModules.stream().forEach(reqMod -> builder.requires(reqMod)); - - return builder.build(); - } - - /** - * Generates service descriptor inside META-INF folder. - */ - public static boolean createMetaInfServiceDescriptor( - Path serviceDescriptorFile, String serviceImpl) { - boolean created = true; - System.out.println(String.format("Creating META-INF service descriptor" - + " for '%s' at path '%s'", serviceImpl, - serviceDescriptorFile)); - try { - Path parent = serviceDescriptorFile.getParent(); - if (parent != null) { - Files.createDirectories(parent); - } - Files.write(serviceDescriptorFile, serviceImpl.getBytes("UTF-8")); - System.out.println(String.format( - "META-INF service descriptor generated successfully")); - } catch (IOException e) { - e.printStackTrace(System.out); - created = false; - } - return created; - } - -} --- /dev/null 2015-07-25 05:49:27.889711346 -0700 +++ new/test/java/security/modules/ModularTest.java 2015-12-21 09:55:16.059476400 -0800 @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2015, 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. + */ + +import java.io.IOException; +import java.io.OutputStream; +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.Map; +import java.util.StringJoiner; +import java.util.Arrays; +import java.util.stream.Collectors; +import java.lang.module.ModuleDescriptor; +import jdk.testlibrary.OutputAnalyzer; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import jdk.internal.module.ModuleInfoWriter; +import static java.lang.module.ModuleDescriptor.Builder; + +/** + * Base class need to be extended by modular test for security. + */ +public abstract class ModularTest { + + /** + * Enum represents all supported module types supported in JDK9. i.e. + * EXPLICIT - Modules have module descriptor(module-info.java) + * defining the module. + * AUTO - Are regular jar files but provided in MODULE_PATH instead + * of CLASS_PATH. + * UNNAMED - Are regular jar but provided through CLASS_PATH. + */ + public enum MODULE_TYPE { + + EXPLICIT, AUTO, UNNAMED; + } + + public static final String SPACE = " "; + public static final Path SRC = Paths.get(System.getProperty("test.src")); + public static final String DESCRIPTOR = "MetaService"; + public static final String MODULAR = "Modular"; + public static final String AUTO = "AutoServiceType"; + public static final String JAR_EXTN = ".jar"; + + /** + * Setup test data for the test. + */ + @DataProvider(name = "TestParams") + public Object[][] setUpTestData() { + return getTestInput(); + } + + /** + * Test method for TestNG. + */ + @Test(dataProvider = "TestParams") + public void runTest(MODULE_TYPE cModuleType, MODULE_TYPE sModuletype, + boolean addMetaDesc, String failureMsgExpected, String[] args) + throws Exception { + + String testName = new StringJoiner("_").add(cModuleType.toString()) + .add(sModuletype.toString()).add( + (addMetaDesc) ? "DESCRIPTOR" : "NO_DESCRIPTOR") + .toString(); + + System.out.format("%nStarting Test case: '%s'", testName); + Path cJarPath = findJarPath(false, cModuleType, false, + (sModuletype == MODULE_TYPE.EXPLICIT)); + Path sJarPath = findJarPath(true, sModuletype, addMetaDesc, false); + System.out.format("%nClient jar path : %s ", cJarPath); + System.out.format("%nService jar path : %s ", sJarPath); + OutputAnalyzer output = executeTestClient(cModuleType, cJarPath, + sModuletype, sJarPath, args); + + if (output.getExitValue() != 0) { + if (failureMsgExpected != null + && output.getOutput().contains(failureMsgExpected)) { + System.out.println("PASS: Test is expected to fail here."); + } else { + System.out.format("%nUnexpected failure occured with exit code" + + " '%s'.", output.getExitValue()); + throw new RuntimeException("Unexpected failure occured."); + } + } + } + + /** + * Abstract method need to be implemented by each Test type to provide + * test parameters. + */ + public abstract Object[][] getTestInput(); + + /** + * Execute the test client to access required service. + */ + public abstract OutputAnalyzer executeTestClient(MODULE_TYPE cModuleType, + Path cJarPath, MODULE_TYPE sModuletype, Path sJarPath, + String... args) throws Exception; + + /** + * Find the Jar for service/client based on module type and if service + * descriptor required. + */ + public abstract Path findJarPath(boolean service, MODULE_TYPE moduleType, + boolean addMetaDesc, boolean dependsOnServiceModule); + + /** + * Constructs a Java Command line string based on modular structure followed + * by modular client and service. + */ + public String[] getJavaCommand(Path modulePath, String classPath, + String clientModuleName, String mainClass, + Map vmArgs, String... options) throws IOException { + + final StringJoiner command = new StringJoiner(SPACE, SPACE, SPACE); + vmArgs.forEach((key, value) -> command.add(key + value)); + if (modulePath != null) { + command.add("-mp").add(modulePath.toFile().getCanonicalPath()); + } + if (classPath != null && classPath.length() > 0) { + command.add("-cp").add(classPath); + } + if (clientModuleName != null && clientModuleName.length() > 0) { + command.add("-m").add(clientModuleName + "/" + mainClass); + } else { + command.add(mainClass); + } + command.add(Arrays.stream(options).collect(Collectors.joining(SPACE))); + return command.toString().trim().split("[\\s]+"); + } + + /** + * Generate ModuleDescriptor object for explicit/auto based client/Service + * modules type. + */ + public ModuleDescriptor generateModuleDescriptor(boolean isService, + MODULE_TYPE moduleType, String moduleName, String pkg, + String serviceInterface, String serviceImpl, + String serviceModuleName, List requiredModules, + boolean depends) { + + final Builder builder; + if (moduleType == MODULE_TYPE.EXPLICIT) { + System.out.format(" %nGenerating ModuleDescriptor object"); + builder = new Builder(moduleName).exports(pkg); + if (isService) { + builder.provides(serviceInterface, serviceImpl); + } else { + builder.uses(serviceInterface); + if (depends) { + builder.requires(serviceModuleName); + } + } + } else { + System.out.format(" %nModuleDescriptor object not required."); + return null; + } + requiredModules.stream().forEach(reqMod -> builder.requires(reqMod)); + return builder.build(); + } + + /** + * Generates service descriptor inside META-INF folder. + */ + public boolean createMetaInfServiceDescriptor( + Path serviceDescriptorFile, String serviceImpl) { + boolean created = true; + System.out.format("%nCreating META-INF service descriptor for '%s' " + + "at path '%s'", serviceImpl, serviceDescriptorFile); + try { + Path parent = serviceDescriptorFile.getParent(); + if (parent != null) { + Files.createDirectories(parent); + } + Files.write(serviceDescriptorFile, serviceImpl.getBytes("UTF-8")); + System.out.println( + "META-INF service descriptor generated successfully"); + } catch (IOException e) { + e.printStackTrace(System.out); + created = false; + } + return created; + } + + /** + * Generate modular/regular jar file. + */ + public void generateJar(ModuleDescriptor mDescriptor, Path jar, + Path compilePath) throws IOException { + System.out.format("%nCreating jar file '%s'", jar); + JarUtils.createJarFile(jar, compilePath); + if (mDescriptor != null) { + Path dir = Files.createTempDirectory("tmp"); + Path mi = dir.resolve("module-info.class"); + try (OutputStream out = Files.newOutputStream(mi)) { + ModuleInfoWriter.write(mDescriptor, out); + } + System.out.format("%nAdding 'module-info.class' to jar '%s'", jar); + JarUtils.updateJarFile(jar, dir); + } + } + + /** + * Copy pre-generated jar files to the module base path. + */ + public void copyJarsToModuleBase(MODULE_TYPE moduleType, Path jar, + Path mBasePath) throws IOException { + if (mBasePath != null) { + Files.createDirectories(mBasePath); + } + if (moduleType != MODULE_TYPE.UNNAMED) { + Path artifactName = mBasePath.resolve(jar.getFileName()); + System.out.format("%nCopy jar path: '%s' to module base path: %s", + jar, artifactName); + Files.copy(jar, artifactName); + } + } + + /** + * Construct class path string. + */ + public String buildClassPath(MODULE_TYPE cModuleType, + Path cJarPath, MODULE_TYPE sModuletype, + Path sJarPath) throws IOException { + StringJoiner classPath = new StringJoiner(File.pathSeparator); + classPath.add((cModuleType == MODULE_TYPE.UNNAMED) + ? cJarPath.toFile().getCanonicalPath() : ""); + classPath.add((sModuletype == MODULE_TYPE.UNNAMED) + ? sJarPath.toFile().getCanonicalPath() : ""); + return classPath.toString(); + } + + /** + * Construct executable module name for java. It is fixed for explicit + * module type while it is same as jar file name for automated module type. + */ + public String getModuleName(MODULE_TYPE moduleType, + Path jarPath, String mName) { + String jarName = jarPath.toFile().getName(); + return (moduleType == MODULE_TYPE.EXPLICIT) ? mName + : ((moduleType == MODULE_TYPE.AUTO) ? jarName.substring(0, + jarName.indexOf(JAR_EXTN)) : ""); + } + + /** + * Delete all the files inside the base module path. + */ + public void cleanModuleBasePath(Path mBasePath) { + Arrays.asList(mBasePath.toFile().listFiles()).forEach(f -> { + System.out.println("delete: " + f); + f.delete(); + }); + } + +}