db4d383614
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
278 lines
10 KiB
Java
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();
|
|
});
|
|
}
|
|
|
|
}
|