jdk-24/jdk/test/java/security/modules/ModularTest.java
Alan Bateman db4d383614 8142968: Module System implementation
Initial integration of JEP 200, JEP 260, JEP 261, and JEP 282

Co-authored-by: Alex Buckley <alex.buckley@oracle.com>
Co-authored-by: Jonathan Gibbons <jonathan.gibbons@oracle.com>
Co-authored-by: Karen Kinnear <karen.kinnear@oracle.com>
Co-authored-by: Mandy Chung <mandy.chung@oracle.com>
Co-authored-by: Mark Reinhold <mark.reinhold@oracle.com>
Co-authored-by: Chris Hegarty <chris.hegarty@oracle.com>
Co-authored-by: Alexandr Scherbatiy <alexandr.scherbatiy@oracle.com>
Co-authored-by: Amy Lu <amy.lu@oracle.com>
Co-authored-by: Calvin Cheung <calvin.cheung@oracle.com>
Co-authored-by: Daniel Fuchs <daniel.fuchs@oracle.com>
Co-authored-by: Erik Joelsson <erik.joelsson@oracle.com>
Co-authored-by: Harold Seigel <harold.seigel@oracle.com>
Co-authored-by: Jaroslav Bachorik <jaroslav.bachorik@oracle.com>
Co-authored-by: Jean-Francois Denise <jean-francois.denise@oracle.com>
Co-authored-by: Jan Lahoda <jan.lahoda@oracle.com>
Co-authored-by: James Laskey <james.laskey@oracle.com>
Co-authored-by: Lois Foltan <lois.foltan@oracle.com>
Co-authored-by: Miroslav Kos <miroslav.kos@oracle.com>
Co-authored-by: Huaming Li <huaming.li@oracle.com>
Co-authored-by: Sean Mullan <sean.mullan@oracle.com>
Co-authored-by: Naoto Sato <naoto.sato@oracle.com>
Co-authored-by: Masayoshi Okutsu <masayoshi.okutsu@oracle.com>
Co-authored-by: Peter Levart <peter.levart@gmail.com>
Co-authored-by: Philip Race <philip.race@oracle.com>
Co-authored-by: Claes Redestad <claes.redestad@oracle.com>
Co-authored-by: Sergey Bylokhov <sergey.bylokhov@oracle.com>
Co-authored-by: Alexandre Iline <alexandre.iline@oracle.com>
Co-authored-by: Volker Simonis <volker.simonis@gmail.com>
Co-authored-by: Staffan Larsen <staffan.larsen@oracle.com>
Co-authored-by: Stuart Marks <stuart.marks@oracle.com>
Co-authored-by: Semyon Sadetsky <semyon.sadetsky@oracle.com>
Co-authored-by: Serguei Spitsyn <serguei.spitsyn@oracle.com>
Co-authored-by: Sundararajan Athijegannathan <sundararajan.athijegannathan@oracle.com>
Co-authored-by: Valerie Peng <valerie.peng@oracle.com>
Co-authored-by: Vincent Ryan <vincent.x.ryan@oracle.com>
Co-authored-by: Weijun Wang <weijun.wang@oracle.com>
Co-authored-by: Yuri Nesterenko <yuri.nesterenko@oracle.com>
Co-authored-by: Yekaterina Kantserova <yekaterina.kantserova@oracle.com>
Co-authored-by: Alexander Kulyakthin <alexander.kulyakhtin@oracle.com>
Co-authored-by: Felix Yang <felix.yang@oracle.com>
Co-authored-by: Andrei Eremeev <andrei.eremeev@oracle.com>
Co-authored-by: Frank Yuan <frank.yuan@oracle.com>
Co-authored-by: Sergei Pikalev <sergei.pikalev@oracle.com>
Co-authored-by: Sibabrata Sahoo <sibabrata.sahoo@oracle.com>
Co-authored-by: Tiantian Du <tiantian.du@oracle.com>
Co-authored-by: Sha Jiang <sha.jiang@oracle.com>
Reviewed-by: alanb, mchung, naoto, rriggs, psandoz, plevart, mullan, ascarpino, vinnie, prr, sherman, dfuchs, mhaupt
2016-03-17 19:04:16 +00:00

278 lines
10 KiB
Java

/*
* 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<String, String> 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<String> 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();
});
}
}