8179249: Improve process output analysis in CDS tests

Added new API TestCommon.run(...).assertNormalExit(...), etc

Reviewed-by: mseledtsov
This commit is contained in:
Ioi Lam 2018-02-14 07:08:25 -08:00
parent e2f49705aa
commit a74437edc9
30 changed files with 444 additions and 317 deletions

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2018, 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
@ -48,39 +48,33 @@ public class AppendClasspath {
TestCommon.testDump(appJar, TestCommon.list("Hello"));
// PASS: 1) runtime with classpath containing the one used in dump time
OutputAnalyzer output = TestCommon.execCommon(
TestCommon.run(
"-cp", appJar + File.pathSeparator + appJar2,
"HelloMore");
TestCommon.checkExec(output);
"HelloMore")
.assertNormalExit();
final String errorMessage1 = "Unable to use shared archive";
final String errorMessage2 = "shared class paths mismatch";
// FAIL: 2) runtime with classpath different from the one used in dump time
// (runtime has an extra jar file prepended to the class path)
output = TestCommon.execCommon(
TestCommon.run(
"-cp", appJar2 + File.pathSeparator + appJar,
"HelloMore");
output.shouldContain(errorMessage1);
output.shouldContain(errorMessage2);
output.shouldHaveExitValue(1);
"HelloMore")
.assertAbnormalExit(errorMessage1, errorMessage2);
// FAIL: 3) runtime with classpath part of the one used in dump time
TestCommon.testDump(appJar + File.pathSeparator + appJar2,
TestCommon.list("Hello"));
output = TestCommon.execCommon(
TestCommon.run(
"-cp", appJar2,
"Hello");
output.shouldContain(errorMessage1);
output.shouldContain(errorMessage2);
output.shouldHaveExitValue(1);
"Hello")
.assertAbnormalExit(errorMessage1, errorMessage2);
// FAIL: 4) runtime with same set of jar files in the classpath but
// with different order
output = TestCommon.execCommon(
TestCommon.run(
"-cp", appJar2 + File.pathSeparator + appJar,
"HelloMore");
output.shouldContain(errorMessage1);
output.shouldContain(errorMessage2);
output.shouldHaveExitValue(1);
"HelloMore")
.assertAbnormalExit(errorMessage1, errorMessage2);
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2018, 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
@ -62,20 +62,13 @@ public class BootClassPathMismatch {
public void testBootClassPathMismatch() throws Exception {
String appJar = JarBuilder.getOrCreateHelloJar();
String appClasses[] = {"Hello"};
OutputAnalyzer dumpOutput = TestCommon.dump(
TestCommon.dump(
appJar, appClasses, "-Xbootclasspath/a:" + appJar);
String testDir = TestCommon.getTestDir("newdir");
String otherJar = testDir + File.separator + "hello.jar";
OutputAnalyzer execOutput = TestCommon.exec(
appJar, "-verbose:class", "-Xbootclasspath/a:" + otherJar, "Hello");
try {
TestCommon.checkExec(execOutput, mismatchMessage);
} catch (java.lang.RuntimeException re) {
String cause = re.getMessage();
if (!mismatchMessage.equals(cause)) {
throw re;
}
}
TestCommon.run(
"-cp", appJar, "-verbose:class", "-Xbootclasspath/a:" + otherJar, "Hello")
.assertAbnormalExit(mismatchMessage);
}
/* Error should be detected if:
@ -85,17 +78,10 @@ public class BootClassPathMismatch {
public void testBootClassPathMismatch2() throws Exception {
String appJar = JarBuilder.getOrCreateHelloJar();
String appClasses[] = {"Hello"};
OutputAnalyzer dumpOutput = TestCommon.dump(appJar, appClasses);
OutputAnalyzer execOutput = TestCommon.exec(
appJar, "-verbose:class", "-Xbootclasspath/a:" + appJar, "Hello");
try {
TestCommon.checkExec(execOutput, mismatchMessage);
} catch (java.lang.RuntimeException re) {
String cause = re.getMessage();
if (!mismatchMessage.equals(cause)) {
throw re;
}
}
TestCommon.dump(appJar, appClasses);
TestCommon.run(
"-cp", appJar, "-verbose:class", "-Xbootclasspath/a:" + appJar, "Hello")
.assertAbnormalExit(mismatchMessage);
}
/* No error if:
@ -105,13 +91,12 @@ public class BootClassPathMismatch {
public void testBootClassPathMatch() throws Exception {
String appJar = TestCommon.getTestJar("hello.jar");
String appClasses[] = {"Hello"};
OutputAnalyzer dumpOutput = TestCommon.dump(
TestCommon.dump(
appJar, appClasses, "-Xbootclasspath/a:" + appJar);
OutputAnalyzer execOutput = TestCommon.exec(
appJar, "-verbose:class",
"-Xbootclasspath/a:" + appJar, "Hello");
TestCommon.checkExec(execOutput,
"[class,load] Hello source: shared objects file");
TestCommon.run(
"-cp", appJar, "-verbose:class",
"-Xbootclasspath/a:" + appJar, "Hello")
.assertNormalExit("[class,load] Hello source: shared objects file");
}
private static void copyHelloToNewDir() throws Exception {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2018, 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
@ -76,17 +76,17 @@ public class CaseSensitiveClassPath {
} else {
jarPathUpper = Paths.get(appJarUpper);
}
boolean isSameFile = Files.isSameFile(jarPath, jarPathUpper);
out = TestCommon.exec(appJarUpper, "Hello", "-Xlog:class+path=info",
"-Xlog:cds");
if (TestCommon.isUnableToMap(out))
return;
if (Files.isSameFile(jarPath, jarPathUpper)) {
TestCommon.checkExec(out, "Hello World");
} else {
out.shouldContain("shared class paths mismatch")
.shouldHaveExitValue(1);
}
}
TestCommon.run("-cp", appJarUpper, "Hello", "-Xlog:class+path=info",
"-Xlog:cds")
.ifNoMappingFailure(output -> {
if (isSameFile) {
output.shouldContain("Hello World");
} else {
output.shouldContain("shared class paths mismatch");
output.shouldHaveExitValue(1);
}
});
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2018, 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
@ -68,29 +68,30 @@ public class ClassPathAttr {
"CpAttr4",
"CpAttr5"));
OutputAnalyzer output = TestCommon.execCommon(
TestCommon.run(
"-cp", cp,
"CpAttr1");
TestCommon.checkExec(output);
"CpAttr1")
.assertNormalExit();
// Logging test for class+path.
output = TestCommon.execCommon(
TestCommon.run(
"-Xlog:class+path",
"-cp", cp,
"CpAttr1");
if (!TestCommon.isUnableToMap(output)){
output.shouldMatch("checking shared classpath entry: .*cpattr2.jar");
output.shouldMatch("checking shared classpath entry: .*cpattr3.jar");
}
"CpAttr1")
.assertNormalExit(output -> {
output.shouldMatch("checking shared classpath entry: .*cpattr2.jar");
output.shouldMatch("checking shared classpath entry: .*cpattr3.jar");
});
// Make sure aliased TraceClassPaths still works
output = TestCommon.execCommon(
TestCommon.run(
"-XX:+TraceClassPaths",
"-cp", cp,
"CpAttr1");
if (!TestCommon.isUnableToMap(output)){
output.shouldMatch("checking shared classpath entry: .*cpattr2.jar");
output.shouldMatch("checking shared classpath entry: .*cpattr3.jar");
}
"CpAttr1")
.assertNormalExit(output -> {
output.shouldMatch("checking shared classpath entry: .*cpattr2.jar");
output.shouldMatch("checking shared classpath entry: .*cpattr3.jar");
});
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2018, 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
@ -24,7 +24,8 @@
/*
* @test
* @summary a simple test for loading a class using the ext class loader in AppCDS
* @summary a simple test for loading a class using the platform class loader
* (which used to be called the "extension loader) in AppCDS
* @requires vm.cds
* @library /test/lib
* @modules java.base/jdk.internal.misc
@ -53,19 +54,20 @@ public class HelloExtTest {
TestCommon.list("org/omg/CORBA/ORB", "[Ljava/lang/Comparable;"),
bootClassPath, "-verbose:class", "--add-modules", "java.corba");
OutputAnalyzer output = TestCommon.execCommon("-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI",
"-cp", appJar, bootClassPath, "-verbose:class", "--add-modules", "java.corba", "HelloExt");
String prefix = ".class.load. ";
String class_pattern = ".*LambdaForm[$]MH[/][0123456789].*";
String suffix = ".*source: shared objects file.*";
String pattern = prefix + class_pattern + suffix;
output.shouldNotMatch(pattern);
output = TestCommon.execCommon("-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI",
"-cp", appJar, bootClassPath, "-verbose:class",
"-XX:+PrintSharedArchiveAndExit", "-XX:+PrintSharedDictionary",
"--add-modules", "java.corba", "HelloExt");
output.shouldNotMatch(class_pattern);
TestCommon.run("-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI",
"-cp", appJar, bootClassPath, "-verbose:class", "--add-modules", "java.corba", "HelloExt")
.assertNormalExit(output -> output.shouldNotMatch(pattern));
TestCommon.run("-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI",
"-cp", appJar, bootClassPath, "-verbose:class",
"-XX:+PrintSharedArchiveAndExit", "-XX:+PrintSharedDictionary",
"--add-modules", "java.corba", "HelloExt")
.assertNormalExit(output -> output.shouldNotMatch(class_pattern));
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2018, 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
@ -51,12 +51,12 @@ public class IgnoreEmptyClassPaths {
TestCommon.testDump(cp_dump, TestCommon.list("Hello", "HelloMore"),
"-XX:+TraceClassPaths", "-XX:+IgnoreEmptyClassPaths");
OutputAnalyzer output = TestCommon.execCommon(
TestCommon.run(
"-verbose:class",
"-cp", cp_exec,
"-XX:+IgnoreEmptyClassPaths", // should affect classpath even if placed after the "-cp" argument
"-XX:+TraceClassPaths",
"HelloMore");
TestCommon.checkExec(output);
"HelloMore")
.assertNormalExit();
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2018, 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
@ -59,8 +59,7 @@ public class JvmtiAddPath {
static void run(String[] extra_matches, String cp, String... args) throws Exception {
String[] opts = {"-cp", cp, "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", use_whitebox_jar};
opts = TestCommon.concat(opts, args);
OutputAnalyzer output = TestCommon.execCommon(opts);
TestCommon.checkExec(output, extra_matches);
TestCommon.run(opts).assertNormalExit(extra_matches);
}
public static void main(String[] args) throws Exception {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2018, 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
@ -65,11 +65,11 @@ public class OldClassTest implements Opcodes {
OutputAnalyzer output = TestCommon.dump(jar, appClasses);
TestCommon.checkExecReturn(output, 0, true, "Pre JDK 1.5 class not supported by CDS");
output = TestCommon.execCommon(
TestCommon.run(
"-cp", jar,
"-verbose:class",
"Hello");
TestCommon.checkExecReturn(output, 0, true, "Hello Unicode world (Old)");
"Hello")
.assertNormalExit("Hello Unicode world (Old)");
// CASE 2: if we exlcude old version of this class, we should not pick up
// the newer version of this class in a subsequent classpath element.
@ -77,11 +77,11 @@ public class OldClassTest implements Opcodes {
output = TestCommon.dump(classpath, appClasses);
TestCommon.checkExecReturn(output, 0, true, "Pre JDK 1.5 class not supported by CDS");
output = TestCommon.execCommon(
TestCommon.run(
"-cp", classpath,
"-verbose:class",
"Hello");
TestCommon.checkExecReturn(output, 0, true, "Hello Unicode world (Old)");
"Hello")
.assertNormalExit("Hello Unicode world (Old)");
}
static void createTestJarFile(File jarSrcFile, File jarFile) throws Exception {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2018, 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
@ -67,81 +67,79 @@ public class PrintSharedArchiveAndExit {
TestCommon.testDump(cp, TestCommon.list("Hello"));
OutputAnalyzer output;
log("Normal execution -- all the JAR paths should be checked");
output = TestCommon.execCommon(
TestCommon.run(
"-cp", cp,
"-XX:+PrintSharedArchiveAndExit");
check(output, 0, true, lastCheckMsg);
"-XX:+PrintSharedArchiveAndExit")
.ifNoMappingFailure(output -> check(output, 0, true, lastCheckMsg));
output = TestCommon.execCommon(
TestCommon.run(
"-cp", cp,
"-XX:+PrintSharedArchiveAndExit",
"-XX:+PrintSharedDictionary"); // Test PrintSharedDictionary as well.
check(output, 0, true, lastCheckMsg, "java.lang.Object");
"-XX:+PrintSharedDictionary") // Test PrintSharedDictionary as well.
.ifNoMappingFailure(output -> check(output, 0, true, lastCheckMsg, "java.lang.Object"));
log("Normal execution -- Make sure -version, help message and app main()\n" +
"class are not invoked. These are checked inside check().");
output = TestCommon.execCommon("-cp", cp, "-XX:+PrintSharedArchiveAndExit", "-version");
check(output, 0, true, lastCheckMsg);
TestCommon.run("-cp", cp, "-XX:+PrintSharedArchiveAndExit", "-version")
.ifNoMappingFailure(output -> check(output, 0, true, lastCheckMsg));
output = TestCommon.execCommon("-cp", cp, "-XX:+PrintSharedArchiveAndExit", "-help");
check(output, 0, true, lastCheckMsg);
TestCommon.run("-cp", cp, "-XX:+PrintSharedArchiveAndExit", "-help")
.ifNoMappingFailure(output -> check(output, 0, true, lastCheckMsg));
output = TestCommon.execCommon("-cp", cp, "-XX:+PrintSharedArchiveAndExit", "Hello");
check(output, 0, true, lastCheckMsg);
TestCommon.run("-cp", cp, "-XX:+PrintSharedArchiveAndExit", "Hello")
.ifNoMappingFailure(output -> check(output, 0, true, lastCheckMsg));
log("Execution with simple errors -- with 'simple' errors like missing or modified\n" +
"JAR files, the VM should try to continue to print the remaining information.\n" +
"Use an invalid Boot CP -- all the JAR paths should be checked");
output = TestCommon.execCommon(
TestCommon.run(
"-cp", cp,
"-Xbootclasspath/a:foo.jar",
"-XX:+PrintSharedArchiveAndExit");
check(output, 1, true, lastCheckMsg, "[BOOT classpath mismatch, ");
"-XX:+PrintSharedArchiveAndExit")
.ifNoMappingFailure(output -> check(output, 1, true, lastCheckMsg, "[BOOT classpath mismatch, "));
log("Use an App CP shorter than the one at dump time -- all the JAR paths should be checked");
output = TestCommon.execCommon(
TestCommon.run(
"-cp", ".",
"-XX:+PrintSharedArchiveAndExit");
check(output, 1, true, lastCheckMsg, "Run time APP classpath is shorter than the one at dump time: .");
"-XX:+PrintSharedArchiveAndExit")
.ifNoMappingFailure(output -> check(output, 1, true, lastCheckMsg, "Run time APP classpath is shorter than the one at dump time: ."));
log("Use an invalid App CP -- all the JAR paths should be checked");
String invalidCP = "non-existing-dir" + File.pathSeparator + cp;
output = TestCommon.execCommon(
TestCommon.run(
"-cp", invalidCP,
"-XX:+PrintSharedArchiveAndExit");
check(output, 1, true, lastCheckMsg, "APP classpath mismatch, actual: -Djava.class.path=" + invalidCP);
"-XX:+PrintSharedArchiveAndExit")
.ifNoMappingFailure(output -> check(output, 1, true, lastCheckMsg, "APP classpath mismatch, actual: -Djava.class.path=" + invalidCP));
log("Changed modification time of hello.jar -- all the JAR paths should be checked");
(new File(appJar)).setLastModified(System.currentTimeMillis() + 2000);
output = TestCommon.execCommon(
TestCommon.run(
"-cp", cp,
"-XX:+PrintSharedArchiveAndExit");
check(output, 1, true, lastCheckMsg, "[Timestamp mismatch]");
"-XX:+PrintSharedArchiveAndExit")
.ifNoMappingFailure(output -> check(output, 1, true, lastCheckMsg, "[Timestamp mismatch]"));
log("Even if hello.jar is out of date, we should still be able to print the dictionary.");
output = TestCommon.execCommon(
TestCommon.run(
"-cp", cp,
"-XX:+PrintSharedArchiveAndExit",
"-XX:+PrintSharedDictionary"); // Test PrintSharedDictionary as well.
check(output, 1, true, lastCheckMsg, "java.lang.Object");
"-XX:+PrintSharedDictionary") // Test PrintSharedDictionary as well.
.ifNoMappingFailure(output -> check(output, 1, true, lastCheckMsg, "java.lang.Object"));
log("Remove hello.jar -- all the JAR paths should be checked");
(new File(appJar)).delete();
output = TestCommon.execCommon(
TestCommon.run(
"-cp", cp,
"-XX:+PrintSharedArchiveAndExit");
check(output, 1, true, lastCheckMsg, "[Required classpath entry does not exist: " + appJar + "]");
"-XX:+PrintSharedArchiveAndExit")
.ifNoMappingFailure(output -> check(output, 1, true, lastCheckMsg, "[Required classpath entry does not exist: " + appJar + "]"));
log("Execution with major errors -- with 'major' errors like the JSA file\n" +
"is missing, we should stop immediately to avoid crashing the JVM.");
output = TestCommon.execCommon(
TestCommon.run(
"-cp", cp,
"-XX:+PrintSharedArchiveAndExit",
"-XX:SharedArchiveFile=./no-such-fileappcds.jsa");
check(output, 1, false, lastCheckMsg);
"-XX:SharedArchiveFile=./no-such-fileappcds.jsa")
.ifNoMappingFailure(output -> check(output, 1, false, lastCheckMsg));
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2018, 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
@ -77,10 +77,10 @@ public class ProhibitedPackage {
OutputAnalyzer output;
// -Xshare:on
output = TestCommon.execCommon(
TestCommon.run(
"-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI",
"-cp", appJar, "-Xlog:class+load=info", "ProhibitedHelper");
TestCommon.checkExec(output, "Prohibited package name: java.lang");
"-cp", appJar, "-Xlog:class+load=info", "ProhibitedHelper")
.assertNormalExit("Prohibited package name: java.lang");
// -Xshare:auto
output = TestCommon.execAuto(

@ -51,56 +51,49 @@ public class SpecifySysLoaderProp {
// (0) Baseline. Do not specify -Djava.system.class.loader
// The test class should be loaded from archive
OutputAnalyzer output = TestCommon.execCommon(
TestCommon.run(
"-verbose:class",
"-cp", appJar,
"ReportMyLoader");
TestCommon.checkExec(output,
"[class,load] ReportMyLoader source: shared objects file",
"ReportMyLoader's loader = jdk.internal.loader.ClassLoaders$AppClassLoader@");
"ReportMyLoader")
.assertNormalExit("[class,load] ReportMyLoader source: shared objects file",
"ReportMyLoader's loader = jdk.internal.loader.ClassLoaders$AppClassLoader@");
// (1) Try to execute the archive with -Djava.system.class.loader=no.such.Klass,
// it should fail
output = TestCommon.execCommon(
TestCommon.run(
"-cp", appJar,
"-Djava.system.class.loader=no.such.Klass",
"ReportMyLoader");
try {
output.shouldContain(warning);
output.shouldContain("ClassNotFoundException: no.such.Klass");
} catch (Exception e) {
TestCommon.checkCommonExecExceptions(output, e);
}
"ReportMyLoader")
.assertAbnormalExit(output -> {
output.shouldContain(warning);
output.shouldContain("ClassNotFoundException: no.such.Klass");
});
// (2) Try to execute the archive with -Djava.system.class.loader=TestClassLoader,
// it should run, but AppCDS should be disabled
output = TestCommon.execCommon(
TestCommon.run(
"-verbose:class",
"-cp", appJar,
"-Djava.system.class.loader=TestClassLoader",
"ReportMyLoader");
TestCommon.checkExec(output,
"ReportMyLoader's loader = jdk.internal.loader.ClassLoaders$AppClassLoader@", //<-this is still printed because TestClassLoader simply delegates to Launcher$AppLoader, but ...
"TestClassLoader.called = true", //<-but this proves that TestClassLoader was indeed called.
"TestClassLoader: loadClass(\"ReportMyLoader\","); //<- this also proves that TestClassLoader was indeed called.
try {
"ReportMyLoader")
.assertNormalExit("ReportMyLoader's loader = jdk.internal.loader.ClassLoaders$AppClassLoader@", //<-this is still printed because TestClassLoader simply delegates to Launcher$AppLoader, but ...
"TestClassLoader.called = true", //<-but this proves that TestClassLoader was indeed called.
"TestClassLoader: loadClass(\"ReportMyLoader\",") //<- this also proves that TestClassLoader was indeed called.
.assertNormalExit(output -> {
output.shouldMatch(".class,load. TestClassLoader source: file:");
output.shouldMatch(".class,load. ReportMyLoader source: file:.*" + jarFileName);
} catch (Exception e) {
TestCommon.checkCommonExecExceptions(output, e);
}
});
// (3) Try to change the java.system.class.loader programmatically after
// the app's main method is executed. This should have no effect in terms of
// changing or switching the actual system class loader that's already in use.
output = TestCommon.execCommon(
TestCommon.run(
"-verbose:class",
"-cp", appJar,
"TrySwitchMyLoader");
TestCommon.checkExec(output,
"[class,load] ReportMyLoader source: shared objects file",
"TrySwitchMyLoader's loader = jdk.internal.loader.ClassLoaders$AppClassLoader@",
"ReportMyLoader's loader = jdk.internal.loader.ClassLoaders$AppClassLoader@",
"TestClassLoader.called = false");
"TrySwitchMyLoader")
.assertNormalExit("[class,load] ReportMyLoader source: shared objects file",
"TrySwitchMyLoader's loader = jdk.internal.loader.ClassLoaders$AppClassLoader@",
"ReportMyLoader's loader = jdk.internal.loader.ClassLoaders$AppClassLoader@",
"TestClassLoader.called = false");
}
}

@ -28,6 +28,7 @@ import jdk.test.lib.JDKToolFinder;
import jdk.test.lib.Platform;
import jdk.test.lib.cds.CDSOptions;
import jdk.test.lib.cds.CDSTestUtils;
import jdk.test.lib.cds.CDSTestUtils.Result;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.process.OutputAnalyzer;
import java.io.File;
@ -191,6 +192,14 @@ public class TestCommon extends CDSTestUtils {
return runWithArchive(opts);
}
// This is the new API for running a Java process with CDS enabled.
// See comments in the CDSTestUtils.Result class for how to use this method.
public static Result run(String... suffix) throws Exception {
AppCDSOptions opts = (new AppCDSOptions());
opts.addSuffix(suffix);
return new Result(opts, runWithArchive(opts));
}
public static OutputAnalyzer exec(String appJar, String... suffix) throws Exception {
AppCDSOptions opts = (new AppCDSOptions()).setAppJar(appJar);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2018, 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
@ -84,21 +84,22 @@ public class TraceLongClasspath {
"/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/jdk/lib/tools.jar" + ps +
"/scratch/xxxx/yyyy/ZZZZZZ/aaaaaaaaaa/xx/foobar_common/modules/foobar.ooo_12.1.3/ooo-manifest.jar";
longClassPath += ps + appJar;
String myCP = longClassPath + ps + appJar;
// Dump an archive with a specified JAR file in -classpath
TestCommon.testDump(longClassPath, TestCommon.list("Hello"));
TestCommon.testDump(myCP, TestCommon.list("Hello"));
// Then try to execute the archive with a different classpath and with -XX:+TraceClassPaths.
// The diagnosis "expecting" app classpath trace should show the entire classpath.
OutputAnalyzer output = TestCommon.execCommon(
TestCommon.run(
"-XX:+TraceClassPaths",
"-cp", appJar,
"Hello");
output.shouldContain("Unable to use shared archive");
output.shouldContain("shared class paths mismatch");
// the "expecting" app classpath from -XX:+TraceClassPaths should not
// be truncated
output.shouldContain(longClassPath);
output.shouldHaveExitValue(1);
"Hello")
.assertAbnormalExit(output -> {
output.shouldContain("Unable to use shared archive");
output.shouldContain("shared class paths mismatch");
// the "expecting" app classpath from -XX:+TraceClassPaths should not
// be truncated
output.shouldContain(myCP);
});
}
}

@ -45,6 +45,7 @@ public class VerifierTest implements Opcodes {
static final String MAP_FAIL =
"shared archive file was created with less restrictive verification setting";
static final String VFY_ERR = "java.lang.VerifyError";
static final String PASS_RESULT = "Hi, how are you?";
enum Testset1Part {
A, B
@ -110,12 +111,22 @@ public class VerifierTest implements Opcodes {
TestCommon.testDump(jar, appClasses);
}
static void checkRuntimeOutput(OutputAnalyzer output, String expected) throws Exception {
output.shouldContain(expected);
if (expected.equals(PASS_RESULT) ||
expected.equals(VFY_ERR)) {
output.shouldHaveExitValue(0);
} else {
output.shouldNotHaveExitValue(0);
}
}
static void testset_1(String jar, String[] noAppClasses, String[] appClasses, Testset1Part part)
throws Exception
{
String config[][] = {
// {dump_list, dumptime_verification_setting,
// runtime_verification_setting, runtime_output},
// runtime_verification_setting, expected_output_str},
// Dump app/ext with -Xverify:remote
{"app", VFY_REMOTE, VFY_REMOTE, VFY_ERR},
@ -166,7 +177,7 @@ public class VerifierTest implements Opcodes {
noAppClasses;
String dump_setting = config[i][1];
String runtime_setting = config[i][2];
String runtime_output = config[i][3];
String expected_output_str = config[i][3];
System.out.println("Test case [" + i + "]: dumping " + config[i][0] +
" with " + dump_setting +
", run with " + runtime_setting);
@ -178,17 +189,10 @@ public class VerifierTest implements Opcodes {
"-Xms256m",
"-Xmx256m");
}
OutputAnalyzer runtimeOutput = TestCommon.execCommon(
"-cp", jar,
runtime_setting,
"VerifierTest0");
try {
runtimeOutput.shouldContain(runtime_output);
} catch (RuntimeException re) {
// Check if the failure is due to archive mapping failure.
// If not, a RuntimeException will be thrown.
runtimeOutput.shouldContain("Unable to use shared archive");
}
TestCommon.run("-cp", jar,
runtime_setting,
"VerifierTest0")
.ifNoMappingFailure(output -> checkRuntimeOutput(output, expected_output_str));
prev_dump_setting = dump_setting;
}
}
@ -204,10 +208,9 @@ public class VerifierTest implements Opcodes {
"Hi$MyClass");
jar = TestCommon.getTestJar(jarName_hi + ".jar") + File.pathSeparator +
TestCommon.getTestJar(jarName_greet + ".jar");
final String PASS_RESULT = "Hi, how are you?";
String config2[][] = {
// {dump_list, dumptime_verification_setting,
// runtime_verification_setting, runtime_output},
// runtime_verification_setting, expected_output_str},
// Dump app/ext with -Xverify:remote
{"app", VFY_REMOTE, VFY_REMOTE, PASS_RESULT},
@ -226,7 +229,7 @@ public class VerifierTest implements Opcodes {
// config2[i][0] is always set to "app" in this test
String dump_setting = config2[i][1];
String runtime_setting = config2[i][2];
String runtime_output = config2[i][3];
String expected_output_str = config2[i][3];
System.out.println("Test case [" + i + "]: dumping " + config2[i][0] +
" with " + dump_setting +
", run with " + runtime_setting);
@ -237,19 +240,11 @@ public class VerifierTest implements Opcodes {
// issue - assert failure when dumping archive with the -Xverify:all
"-Xms256m",
"-Xmx256m");
OutputAnalyzer runtimeOutput = TestCommon.execCommon(
"-cp", jar,
runtime_setting,
"Hi");
try {
runtimeOutput.shouldContain(runtime_output);
} catch (RuntimeException re) {
// Check if the failure is due to archive mapping failure.
// If not, a RuntimeException will be thrown.
runtimeOutput.shouldContain("Unable to use shared archive");
}
TestCommon.run("-cp", jar,
runtime_setting,
"Hi")
.ifNoMappingFailure(output -> checkRuntimeOutput(output, expected_output_str));
}
}
static void createTestJarFile(File jarSrcFile, File jarFile) throws Exception {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2018, 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
@ -45,11 +45,10 @@ public class WrongClasspath {
TestCommon.testDump(appJar, TestCommon.list("Hello"));
// Then try to execute the archive without -classpath -- it should fail
OutputAnalyzer output = TestCommon.execCommon(
TestCommon.run(
/* "-cp", appJar, */ // <- uncomment this and the execution should succeed
"Hello");
output.shouldContain("Unable to use shared archive");
output.shouldContain("shared class paths mismatch");
output.shouldHaveExitValue(1);
"Hello")
.assertAbnormalExit("Unable to use shared archive",
"shared class paths mismatch");
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2018, 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
@ -79,7 +79,6 @@ public class ArrayTest {
}
String[] opts = new String[argsList.size()];
opts = argsList.toArray(opts);
output = TestCommon.execCommon(opts);
TestCommon.checkExec(output);
TestCommon.run(opts).assertNormalExit();
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2018, 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
@ -44,9 +44,6 @@ public class CheckAnonymousClass {
TestCommon.dump(appJar, TestCommon.list("Hello", "org/omg/CORBA/ORB"),
"--add-modules", "java.corba", "-Xlog:class+load=info");
OutputAnalyzer output = TestCommon.execCommon("-XX:+UnlockDiagnosticVMOptions",
"-cp", appJar, "-Xlog:class+load=info", "--add-modules", "java.corba", "Hello");
String prefix = ".class.load. ";
// class name pattern like the following:
// jdk.internal.loader.BuiltinClassLoader$$Lambda$1/1816757085
@ -55,20 +52,14 @@ public class CheckAnonymousClass {
String suffix = ".*source: shared objects file.*";
String pattern = prefix + class_pattern + suffix;
// during run time, anonymous classes shouldn't be loaded from the archive
try {
output.shouldNotMatch(pattern);
} catch (Exception e) {
TestCommon.checkCommonExecExceptions(output, e);
}
TestCommon.run("-XX:+UnlockDiagnosticVMOptions",
"-cp", appJar, "-Xlog:class+load=info", "--add-modules", "java.corba", "Hello")
.assertNormalExit(output -> output.shouldNotMatch(pattern));
// inspect the archive and make sure no anonymous class is in there
output = TestCommon.execCommon("-XX:+UnlockDiagnosticVMOptions",
TestCommon.run("-XX:+UnlockDiagnosticVMOptions",
"-cp", appJar, "-Xlog:class+load=info", "-XX:+PrintSharedArchiveAndExit",
"-XX:+PrintSharedDictionary", "--add-modules", "java.corba", "Hello");
try {
output.shouldNotMatch(class_pattern);
} catch (Exception e) {
TestCommon.checkCommonExecExceptions(output, e);
}
"-XX:+PrintSharedDictionary", "--add-modules", "java.corba", "Hello")
.assertNormalExit(output -> output.shouldNotMatch(class_pattern));
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2018, 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
@ -67,13 +67,13 @@ public class GCDuringDump {
TestCommon.testDump(appJar, TestCommon.list("Hello"),
extraArg, "-Xmx32m", gcLog);
OutputAnalyzer output = TestCommon.execCommon(
TestCommon.run(
"-cp", appJar,
"-Xmx32m",
"-XX:+PrintSharedSpaces",
gcLog,
"Hello");
TestCommon.checkExec(output);
"Hello")
.assertNormalExit();
}
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2018, 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
@ -113,7 +113,7 @@ public class GCSharedStringsDuringDump {
"-XX:SharedArchiveConfigFile=" + sharedArchiveCfgFile);
}
output = TestCommon.execCommon(
TestCommon.run(
"-cp", appJar,
bootClassPath,
"-Xmx32m",
@ -124,8 +124,8 @@ public class GCSharedStringsDuringDump {
"-XX:+WhiteBoxAPI",
"-XX:SharedReadOnlySize=30m",
gcLog,
"GCSharedStringsDuringDumpWb");
TestCommon.checkExec(output);
"GCSharedStringsDuringDumpWb")
.assertNormalExit();
}
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2018, 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
@ -90,13 +90,13 @@ public class AppClassInCP {
String classPath = appJar + File.pathSeparator + classDir;
System.out.println("classPath: " + classPath);
output = TestCommon.execCommon(
TestCommon.run(
"-XX:+UnlockDiagnosticVMOptions",
"-cp", classPath,
"--patch-module=java.naming=" + moduleJar,
"-Xlog:class+load",
"PatchMain", "javax.naming.spi.NamingManager", "mypackage.Hello");
TestCommon.checkExec(output,
"PatchMain", "javax.naming.spi.NamingManager", "mypackage.Hello")
.assertNormalExit(
"I pass!",
"Hello!",
"Hello source: shared objects file");

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2018, 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
@ -72,12 +72,12 @@ public class CustomPackage {
"PatchMain", "javax.naming.myspi.NamingManager");
TestCommon.checkDump(output, "Preload Warning: Cannot find javax/naming/myspi/NamingManager");
output = TestCommon.execCommon(
TestCommon.run(
"-XX:+UnlockDiagnosticVMOptions",
"--patch-module=java.naming=" + moduleJar,
"-Xlog:class+load",
"-Xlog:class+path=info",
"PatchMain", "javax.naming.myspi.NamingManager");
TestCommon.checkExec(output, "I pass!");
"PatchMain", "javax.naming.myspi.NamingManager")
.assertNormalExit("I pass!");
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2018, 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
@ -72,12 +72,12 @@ public class MismatchedPatchModule {
TestCommon.checkDump(output, "Loading classes to share");
// javax.naming.spi.NamingManager is not patched at runtime
output = TestCommon.execCommon(
TestCommon.run(
"-XX:+UnlockDiagnosticVMOptions",
"--patch-module=java.naming2=" + moduleJar,
"-Xlog:class+path=info",
"PatchMain", "javax.naming.spi.NamingManager");
output.shouldNotContain("I pass!");
"PatchMain", "javax.naming.spi.NamingManager")
.assertNormalExit(o -> o.shouldNotContain("I pass!"));
// Case 2: --patch-module specified for dump time but not for run time
System.out.println("Case 2: --patch-module specified for dump time but not for run time");
@ -89,11 +89,11 @@ public class MismatchedPatchModule {
TestCommon.checkDump(output, "Loading classes to share");
// javax.naming.spi.NamingManager is not patched at runtime
output = TestCommon.execCommon(
TestCommon.run(
"-XX:+UnlockDiagnosticVMOptions",
"-Xlog:class+path=info",
"PatchMain", "javax.naming.spi.NamingManager");
output.shouldNotContain("I pass!");
"PatchMain", "javax.naming.spi.NamingManager")
.assertNormalExit(o -> o.shouldNotContain("I pass!"));
// Case 3: --patch-module specified for run time but not for dump time
System.out.println("Case 3: --patch-module specified for run time but not for dump time");
@ -104,12 +104,12 @@ public class MismatchedPatchModule {
TestCommon.checkDump(output, "Loading classes to share");
// javax.naming.spi.NamingManager is patched at runtime
output = TestCommon.execCommon(
TestCommon.run(
"-XX:+UnlockDiagnosticVMOptions",
"--patch-module=java.naming=" + moduleJar,
"-Xlog:class+path=info",
"PatchMain", "javax.naming.spi.NamingManager");
TestCommon.checkExec(output, "I pass!");
"PatchMain", "javax.naming.spi.NamingManager")
.assertNormalExit("I pass!");
// Case 4: mismatched --patch-module entry counts between dump time and run time
System.out.println("Case 4: mismatched --patch-module entry counts between dump time and run time");
@ -121,12 +121,12 @@ public class MismatchedPatchModule {
TestCommon.checkDump(output, "Loading classes to share");
// javax.naming.spi.NamingManager is patched at runtime
output = TestCommon.execCommon(
TestCommon.run(
"-XX:+UnlockDiagnosticVMOptions",
"--patch-module=java.naming=" + moduleJar,
"--patch-module=java.naming2=" + moduleJar,
"-Xlog:class+path=info",
"PatchMain", "javax.naming.spi.NamingManager");
TestCommon.checkExec(output, "I pass!");
"PatchMain", "javax.naming.spi.NamingManager")
.assertNormalExit("I pass!");
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2018, 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
@ -64,10 +64,11 @@ public class PatchJavaBase {
"PatchMain", "java.lang.NewClass");
TestCommon.checkDump(output, "Loading classes to share");
output = TestCommon.execCommon(
TestCommon.run(
"-XX:+UnlockDiagnosticVMOptions",
"--patch-module=java.base=" + moduleJar,
"PatchMain", "java.lang.NewClass");
output.shouldContain("CDS is disabled when java.base module is patched");
"PatchMain", "java.lang.NewClass")
.assertAbnormalExit("Unable to use shared archive",
"CDS is disabled when java.base module is patched");
}
}

@ -70,12 +70,12 @@ public class Simple {
"PatchMain", "javax.naming.spi.NamingManager");
TestCommon.checkDump(output, "Loading classes to share");
output = TestCommon.execCommon(
TestCommon.run(
"-XX:+UnlockDiagnosticVMOptions",
"--patch-module=java.naming=" + moduleJar,
"-Xlog:class+load",
"-Xlog:class+path=info",
"PatchMain", "javax.naming.spi.NamingManager");
TestCommon.checkExec(output, "I pass!");
"PatchMain", "javax.naming.spi.NamingManager")
.assertNormalExit("I pass!");
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2018, 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
@ -92,13 +92,13 @@ public class SubClassOfPatchedClass {
String classPath = appJar + File.pathSeparator + classDir;
System.out.println("classPath: " + classPath);
output = TestCommon.execCommon(
TestCommon.run(
"-XX:+UnlockDiagnosticVMOptions",
"-cp", classPath,
"--patch-module=java.naming=" + moduleJar,
"-Xlog:class+load",
"PatchMain", "javax.naming.Reference", "mypackage.MyReference");
TestCommon.checkExec(output,
"PatchMain", "javax.naming.Reference", "mypackage.MyReference")
.assertNormalExit(
"I pass!",
"MyReference source: file:");
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2018, 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
@ -89,12 +89,12 @@ public class TwoJars {
"PatchMain", "javax.naming.spi.NamingManager");
TestCommon.checkDump(output, "Loading classes to share");
output = TestCommon.execCommon(
TestCommon.run(
"-XX:+UnlockDiagnosticVMOptions",
"--patch-module=java.naming=" + moduleJar2 + File.pathSeparator + moduleJar,
"-Xlog:class+load",
"-Xlog:class+path=info",
"PatchMain", "javax.naming.spi.NamingManager");
TestCommon.checkExec(output, "I pass");
"PatchMain", "javax.naming.spi.NamingManager")
.assertNormalExit("I pass");
}
}

@ -70,10 +70,10 @@ public class DummyClassesInBootClassPath {
}
String[] arguments = new String[argsList.size()];
arguments = argsList.toArray(arguments);
OutputAnalyzer execOutput = TestCommon.execCommon(
Testcommon.run(
"--add-modules", "java.activation", "-Xbootclasspath/a:" + appJar,
"DummyClassHelper", arguments[0], arguments[1]);
checkOutput(execOutput, classNames);
"DummyClassHelper", arguments[0], arguments[1])
.assertNormalExit(output -> checkOutput(output, classNames));
JarBuilder.build(true, "WhiteBox", "sun/hotspot/WhiteBox");
String whiteBoxJar = TestCommon.getTestJar("WhiteBox.jar");
@ -87,8 +87,8 @@ public class DummyClassesInBootClassPath {
String[] opts = {"-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI",
"--add-modules", "java.activation", bootClassPath, "-Xlog:class+path=trace",
"DummyClassHelper", arguments[0], arguments[1], arguments[2]};
execOutput = TestCommon.execCommon(opts);
checkOutput(execOutput, classNames);
Testcommon.run(opts)
.assertNormalExit(output -> checkOutput(output, classNames));
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2018, 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
@ -73,16 +73,14 @@ public class EmptyClassInBootClassPath {
argsList.add("useAppLoader");
String[] opts = new String[argsList.size()];
opts = argsList.toArray(opts);
OutputAnalyzer runOutput = TestCommon.execCommon(opts);
TestCommon.checkExec(runOutput, "appLoader found method main");
TestCommon.run(opts).assertNormalExit("appLoader found method main");
// case 2: load class in bootclasspath using boot loader
argsList.remove(argsList.size() - 1);
argsList.add("useBootLoader");
opts = new String[argsList.size()];
opts = argsList.toArray(opts);
runOutput = TestCommon.execCommon(opts);
TestCommon.checkExec(runOutput, EXPECTED_EXCEPTION);
TestCommon.run(opts).assertNormalExit(EXPECTED_EXCEPTION);
// case 3: load class in bootclasspath using app loader with '--limit-modules java.base'
argsList.add(0, "--limit-modules");
@ -91,16 +89,13 @@ public class EmptyClassInBootClassPath {
argsList.add("useAppLoader");
opts = new String[argsList.size()];
opts = argsList.toArray(opts);
runOutput = TestCommon.execCommon(opts);
TestCommon.checkExec(runOutput, EXPECTED_EXCEPTION);
TestCommon.run(opts).assertNormalExit(EXPECTED_EXCEPTION);
// case 4: load class in bootclasspath using boot loader with '--limit-modules java.base'
argsList.remove(argsList.size() - 1);
argsList.add("useBootLoader");
opts = new String[argsList.size()];
opts = argsList.toArray(opts);
runOutput = TestCommon.execCommon(opts);
TestCommon.checkExec(runOutput, EXPECTED_EXCEPTION);
TestCommon.run(opts).assertNormalExit(EXPECTED_EXCEPTION);
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2018, 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
@ -113,10 +113,9 @@ public class TransformRelatedClassesAppCDS extends TransformRelatedClasses {
log("runTestWithAppLoader(): testCaseId = %d", entry.testCaseId);
String params = TransformTestCommon.getAgentParams(entry, parent, child);
String agentParam = String.format("-javaagent:%s=%s", agentJar, params);
out = TestCommon.execCommon("-Xlog:class+load=info", "-cp", appJar,
agentParam, child);
TransformTestCommon.checkResults(entry, out, parent, child);
TestCommon.run("-Xlog:class+load=info", "-cp", appJar,
agentParam, child)
.assertNormalExit(output -> TransformTestCommon.checkResults(entry, output, parent, child));
}
}
@ -187,13 +186,13 @@ public class TransformRelatedClassesAppCDS extends TransformRelatedClasses {
String agentParam = "-javaagent:" + agentJar + "=" +
TransformTestCommon.getAgentParams(entry, parent, child);
out = TestCommon.execCommon("-Xlog:class+load=info",
"-cp", appJar,
"--add-opens=java.base/java.security=ALL-UNNAMED",
agentParam,
"CustomLoaderApp",
customJar, loaderType, child);
TransformTestCommon.checkResults(entry, out, parent, child);
TestCommon.run("-Xlog:class+load=info",
"-cp", appJar,
"--add-opens=java.base/java.security=ALL-UNNAMED",
agentParam,
"CustomLoaderApp",
customJar, loaderType, child)
.assertNormalExit(output -> TransformTestCommon.checkResults(entry, output, parent, child));
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2018, 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
@ -36,6 +36,160 @@ import jdk.test.lib.process.ProcessTools;
// This class contains common test utilities for testing CDS
public class CDSTestUtils {
public interface Checker {
public void check(OutputAnalyzer output) throws Exception;
}
/*
* INTRODUCTION
*
* When testing various CDS functionalities, we need to launch JVM processes
* using a "launch method" (such as TestCommon.run), and analyze the results of these
* processes.
*
* While typical jtreg tests would use OutputAnalyzer in such cases, due to the
* complexity of CDS failure modes, we have added the CDSTestUtils.Result class
* to make the analysis more convenient and less error prone.
*
* A Java process can end in one of the following 4 states:
*
* 1: Unexpected error - such as JVM crashing. In this case, the "launch method"
* will throw a RuntimeException.
* 2: Mapping Failure - this happens when the OS (intermittently) fails to map the
* CDS archive, normally caused by Address Space Layout Randomization.
* We usually treat this as "pass".
* 3: Normal Exit - the JVM process has finished without crashing, and the exit code is 0.
* 4: Abnormal Exit - the JVM process has finished without crashing, and the exit code is not 0.
*
* In most test cases, we need to check the JVM process's output in cases 3 and 4. However, we need
* to make sure that our test code is not confused by case 2.
*
* For example, a JVM process is expected to print the string "Hi" and exit with 0. With the old
* CDSTestUtils.runWithArchive API, the test may be written as this:
*
* OutputAnalyzer out = CDSTestUtils.runWithArchive(args);
* out.shouldContain("Hi");
*
* However, if the JVM process fails with mapping failure, the string "Hi" will not be in the output,
* and your test case will fail intermittently.
*
* Instead, the test case should be written as
*
* CCDSTestUtils.run(args).assertNormalExit("Hi");
*
* EXAMPLES/HOWTO
*
* 1. For simple substring matching:
*
* CCDSTestUtils.run(args).assertNormalExit("Hi");
* CCDSTestUtils.run(args).assertNormalExit("a", "b", "x");
* CCDSTestUtils.run(args).assertAbnormalExit("failure 1", "failure2");
*
* 2. For more complex output matching: using Lambda expressions
*
* CCDSTestUtils.run(args)
* .assertNormalExit(output -> output.shouldNotContain("this should not be printed");
* CCDSTestUtils.run(args)
* .assertAbnormalExit(output -> {
* output.shouldNotContain("this should not be printed");
* output.shouldHaveExitValue(123);
* });
*
* 3. Chaining several checks:
*
* CCDSTestUtils.run(args)
* .assertNormalExit(output -> output.shouldNotContain("this should not be printed")
* .assertNormalExit("should have this", "should have that");
*
* 4. [Rare use case] if a test sometimes exit normally, and sometimes abnormally:
*
* CCDSTestUtils.run(args)
* .ifNormalExit("ths string is printed when exiting with 0")
* .ifAbNormalExit("ths string is printed when exiting with 1");
*
* NOTE: you usually don't want to write your test case like this -- it should always
* exit with the same exit code. (But I kept this API because some existing test cases
* behave this way -- need to revisit).
*/
public static class Result {
private final OutputAnalyzer output;
private final CDSOptions options;
private final boolean hasMappingFailure;
private final boolean hasAbnormalExit;
private final boolean hasNormalExit;
public Result(CDSOptions opts, OutputAnalyzer out) throws Exception {
options = opts;
output = out;
hasMappingFailure = CDSTestUtils.checkCommonExecExceptions(output);
hasAbnormalExit = (!hasMappingFailure) && (output.getExitValue() != 0);
hasNormalExit = (!hasMappingFailure) && (output.getExitValue() == 0);
if (hasNormalExit) {
if ("on".equals(options.xShareMode) && output.getStderr().contains("java version")) {
// "-showversion" is always passed in the command-line by the execXXX methods.
// During normal exit, we require that the VM to show that sharing was enabled.
output.shouldContain("sharing");
}
}
}
public Result assertNormalExit(Checker checker) throws Exception {
if (!hasMappingFailure) {
checker.check(output);
output.shouldHaveExitValue(0);
}
return this;
}
public Result assertAbnormalExit(Checker checker) throws Exception {
if (!hasMappingFailure) {
checker.check(output);
output.shouldNotHaveExitValue(0);
}
return this;
}
public Result ifNormalExit(Checker checker) throws Exception {
if (hasNormalExit) {
checker.check(output);
}
return this;
}
public Result ifAbnormalExit(Checker checker) throws Exception {
if (hasAbnormalExit) {
checker.check(output);
}
return this;
}
public Result ifNoMappingFailure(Checker checker) throws Exception {
if (!hasMappingFailure) {
checker.check(output);
}
return this;
}
public Result assertNormalExit(String... matches) throws Exception {
if (!hasMappingFailure) {
checkMatches(output, matches);
output.shouldHaveExitValue(0);
}
return this;
}
public Result assertAbnormalExit(String... matches) throws Exception {
if (!hasMappingFailure) {
checkMatches(output, matches);
output.shouldNotHaveExitValue(0);
}
return this;
}
}
// Specify this property to copy sdandard output of the child test process to
// the parent/main stdout of the test.
// By default such output is logged into a file, and is copied into the main stdout.
@ -119,7 +273,7 @@ public class CDSTestUtils {
// of exceptions and common errors.
// Exception e argument - an exception to be re-thrown if none of the common
// exceptions match. Pass null if you wish not to re-throw any exception.
public static void checkCommonExecExceptions(OutputAnalyzer output, Exception e)
public static boolean checkCommonExecExceptions(OutputAnalyzer output, Exception e)
throws Exception {
if (output.getStdout().contains("http://bugreport.java.com/bugreport/crash.jsp")) {
throw new RuntimeException("Hotspot crashed");
@ -128,7 +282,7 @@ public class CDSTestUtils {
throw new RuntimeException("Test Failed");
}
if (output.getOutput().contains("shared class paths mismatch")) {
throw new RuntimeException("shared class paths mismatch");
// throw new RuntimeException("shared class paths mismatch");
}
if (output.getOutput().contains("Unable to unmap shared space")) {
throw new RuntimeException("Unable to unmap shared space");
@ -139,11 +293,17 @@ public class CDSTestUtils {
// and can be random (see ASLR).
if (isUnableToMap(output)) {
System.out.println(UnableToMapMsg);
return;
return true;
}
if (e != null)
if (e != null) {
throw e;
}
return false;
}
public static boolean checkCommonExecExceptions(OutputAnalyzer output) throws Exception {
return checkCommonExecExceptions(output, null);
}
@ -176,6 +336,12 @@ public class CDSTestUtils {
return false;
}
public static Result run(String... cliPrefix) throws Exception {
CDSOptions opts = new CDSOptions();
opts.setArchiveName(getDefaultArchiveName());
opts.addPrefix(cliPrefix);
return new Result(opts, runWithArchive(opts));
}
// Execute JVM with CDS archive, specify command line args suffix
public static OutputAnalyzer runWithArchive(String... cliPrefix)
@ -246,7 +412,7 @@ public class CDSTestUtils {
return output;
}
checkExtraMatches(output, extraMatches);
checkMatches(output, extraMatches);
return output;
}
@ -260,13 +426,13 @@ public class CDSTestUtils {
}
output.shouldHaveExitValue(expectedExitValue);
checkExtraMatches(output, extraMatches);
checkMatches(output, extraMatches);
return output;
}
public static OutputAnalyzer checkExtraMatches(OutputAnalyzer output,
String... extraMatches) throws Exception {
for (String match : extraMatches) {
public static OutputAnalyzer checkMatches(OutputAnalyzer output,
String... matches) throws Exception {
for (String match : matches) {
output.shouldContain(match);
}
return output;