diff --git a/test/jdk/jdk/crac/DryRunTest.java b/test/jdk/jdk/crac/DryRunTest.java index 5148fa2d24b..8c04f366448 100644 --- a/test/jdk/jdk/crac/DryRunTest.java +++ b/test/jdk/jdk/crac/DryRunTest.java @@ -23,14 +23,20 @@ import java.io.File; import java.io.FileOutputStream; +import java.io.IOException; import jdk.crac.*; +import jdk.test.lib.crac.CracBuilder; +import jdk.test.lib.crac.CracEngine; +import jdk.test.lib.crac.CracTest; /** * @test DryRunTest - * @run main/othervm -XX:CREngine=simengine -XX:CRaCCheckpointTo=./cr -XX:+UnlockDiagnosticVMOptions -XX:+CRPrintResourcesOnCheckpoint DryRunTest + * @library /test/lib + * @build DryRunTest + * @run driver jdk.test.lib.crac.CracTest */ -public class DryRunTest { +public class DryRunTest implements CracTest { static class CRResource implements Resource { @Override public void beforeCheckpoint(Context context) throws Exception { @@ -42,7 +48,14 @@ public void afterRestore(Context context) throws Exception { } } - static public void main(String[] args) throws Exception { + @Override + public void test() throws Exception { + new CracBuilder().engine(CracEngine.SIMULATE).printResources(true) + .startCheckpoint().waitForSuccess(); + } + + @Override + public void exec() throws Exception { Resource resource = new CRResource(); Core.getGlobalContext().register(resource); diff --git a/test/jdk/jdk/crac/FileDescriptorsCloseTest.java b/test/jdk/jdk/crac/FileDescriptorsCloseTest.java deleted file mode 100644 index 303ec97ebe0..00000000000 --- a/test/jdk/jdk/crac/FileDescriptorsCloseTest.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2023, Azul Systems, Inc. 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 jdk.crac.CheckpointException; -import jdk.crac.RestoreException; -import jdk.test.lib.JDKToolFinder; -import jdk.test.lib.Utils; -import jdk.test.lib.process.ProcessTools; - -import java.io.IOException; -import java.lang.reflect.Method; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.*; -import java.util.stream.Collectors; - -/** - * @test - * @library /test/lib - * @build CheckpointRestore - * @run main FileDescriptorsCloseTest testCheckpointWithOpenFds - * @run main FileDescriptorsCloseTest testIgnoredFileDescriptors - */ -public class FileDescriptorsCloseTest { - private static final String EXTRA_FD_WRAPPER = Path.of(Utils.TEST_SRC, "extra_fd_wrapper.sh").toString(); - - public static void main(String[] args) throws Throwable { - if (args.length < 1) { - throw new IllegalArgumentException(); - } - FileDescriptorsCloseTest.class.getMethod(args[0]).invoke(null); - } - - public static void testCheckpointWithOpenFds() throws Throwable { - List cmd = new ArrayList<>(); - cmd.add(EXTRA_FD_WRAPPER); - cmd.add(JDKToolFinder.getJDKTool("java")); - cmd.add("-cp"); - cmd.add(System.getProperty("java.class.path")); - cmd.add("-XX:CRaCCheckpointTo=./cr"); - cmd.add(CheckpointRestore.class.getSimpleName()); - // Note that the process is killed after checkpoint - ProcessTools.executeProcess(cmd.toArray(new String[0])) - .shouldHaveExitValue(137); - - ProcessTools.executeTestJvm("-XX:CRaCRestoreFrom=./cr") - .shouldHaveExitValue(0) - .shouldContain(CheckpointRestore.RESTORED_MESSAGE); - } - - public static void testIgnoredFileDescriptors() throws Throwable { - List cmd = new ArrayList<>(); - cmd.add(EXTRA_FD_WRAPPER); - cmd.addAll(Arrays.asList("-o", "43", "/dev/stdout")); - cmd.addAll(Arrays.asList("-o", "45", "/dev/urandom")); - cmd.add(JDKToolFinder.getJDKTool("java")); - cmd.add("-cp"); - cmd.add(System.getProperty("java.class.path")); - cmd.add("-XX:CRaCCheckpointTo=./cr"); - cmd.add("-XX:CRaCIgnoredFileDescriptors=43,/dev/null,44,/dev/urandom"); - cmd.add("FileDescriptorsCloseTest$TestIgnoredDescriptors"); - // Note that the process is killed after checkpoint - ProcessTools.executeProcess(cmd.toArray(new String[0])) - .shouldHaveExitValue(137); - - ProcessTools.executeTestJvm("-XX:CRaCRestoreFrom=./cr") - .shouldHaveExitValue(0) - .shouldContain(CheckpointRestore.RESTORED_MESSAGE); - } - - public static class TestIgnoredDescriptors { - public static void main(String[] args) throws IOException, RestoreException, CheckpointException { - try (var stream = Files.list(Path.of("/proc/self/fd"))) { - Map fds = stream.filter(Files::isSymbolicLink) - .collect(Collectors.toMap( - f -> Integer.parseInt(f.toFile().getName()), - f -> { - try { - return Files.readSymbolicLink(f).toFile().getAbsoluteFile().toString(); - } catch (IOException e) { - throw new RuntimeException(e); - } - })); - if (fds.containsKey(42)) { - throw new IllegalStateException("Oh no, 42 was not supposed to be ignored"); - } else if (!fds.containsKey(0) || !fds.containsKey(1) || !fds.containsKey(2)) { - throw new IllegalStateException("Missing standard I/O? Available: " + fds); - } else if (!fds.containsKey(43)) { - throw new IllegalStateException("Missing FD 43"); - } else if (!fds.containsValue("/dev/urandom")) { - throw new IllegalStateException("Missing /dev/urandom"); - } - } - CheckpointRestore.main(args); - } - } -} diff --git a/test/jdk/jdk/crac/JarFileFactoryCacheTest/JarFileFactoryCacheTest.java b/test/jdk/jdk/crac/JarFileFactoryCacheTest/JarFileFactoryCacheTest.java index c45bb8af593..8007687e3ff 100644 --- a/test/jdk/jdk/crac/JarFileFactoryCacheTest/JarFileFactoryCacheTest.java +++ b/test/jdk/jdk/crac/JarFileFactoryCacheTest/JarFileFactoryCacheTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Azul Systems, Inc. All rights reserved. + * Copyright (c) 2022-2023, Azul Systems, Inc. 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 @@ -22,30 +22,53 @@ */ import jdk.crac.*; +import jdk.test.lib.crac.CracBuilder; +import jdk.test.lib.crac.CracEngine; +import jdk.test.lib.crac.CracTest; +import java.io.File; import java.io.InputStream; import java.net.URL; +import java.nio.file.Files; import java.nio.file.Path; /** * @test JarFileFactoryCacheTest * @library /test/lib - * @run main/othervm -XX:CREngine=simengine -XX:CRaCCheckpointTo=./cr -XX:+UnlockDiagnosticVMOptions -XX:+CRPrintResourcesOnCheckpoint JarFileFactoryCacheTest + * @build JarFileFactoryCacheTest + * @run driver jdk.test.lib.crac.CracTest */ -public class JarFileFactoryCacheTest { - static public void main(String[] args) throws Exception { - jdk.test.lib.util.JarUtils.createJarFile( - Path.of("test.jar"), - Path.of(System.getProperty("test.src")), - "test.txt"); +public class JarFileFactoryCacheTest implements CracTest { + @Override + public void test() throws Exception { + new CracBuilder().engine(CracEngine.SIMULATE).printResources(true) + .startCheckpoint().waitForSuccess(); + } + + @Override + public void exec() throws Exception { + Path temp = Files.createTempDirectory(JarFileFactoryCacheTest.class.getName()); + Path testFilePath = temp.resolve("test.txt"); + try { + Files.writeString(testFilePath, "test\n"); + jdk.test.lib.util.JarUtils.createJarFile( + Path.of("test.jar"), temp, "test.txt"); + } finally { + File testTxt = testFilePath.toFile(); + if (testTxt.exists()) { + assert testTxt.delete(); + } + assert temp.toFile().delete(); + } URL url = new URL("jar:file:test.jar!/test.txt"); InputStream inputStream = url.openStream(); byte[] content = inputStream.readAllBytes(); if (content.length != 5) { - throw new AssertionError("wrong content"); + throw new AssertionError("wrong content: " + new String(content)); } inputStream.close(); + // Nulling the variables is actually necessary! inputStream = null; url = null; diff --git a/test/jdk/jdk/crac/JarFileFactoryCacheTest/test.txt b/test/jdk/jdk/crac/JarFileFactoryCacheTest/test.txt deleted file mode 100644 index 9daeafb9864..00000000000 --- a/test/jdk/jdk/crac/JarFileFactoryCacheTest/test.txt +++ /dev/null @@ -1 +0,0 @@ -test diff --git a/test/jdk/jdk/crac/LazyProps.java b/test/jdk/jdk/crac/LazyProps.java index 0b98e2ccbca..86bb19b65be 100644 --- a/test/jdk/jdk/crac/LazyProps.java +++ b/test/jdk/jdk/crac/LazyProps.java @@ -22,34 +22,36 @@ */ import jdk.crac.*; -import jdk.test.lib.process.ProcessTools; -import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.crac.CracBuilder; +import jdk.test.lib.crac.CracEngine; +import jdk.test.lib.crac.CracTest; /** * @test * @library /test/lib - * @run main LazyProps + * @build LazyProps + * @run driver jdk.test.lib.crac.CracTest */ -public class LazyProps { - static public void main(String[] args) throws Exception { - if (args.length == 0) { - OutputAnalyzer output = ProcessTools.executeTestJvm( - "-XX:CREngine=simengine", "-XX:CRaCCheckpointTo=./cr", - "LazyProps", - "-runTest"); - output.shouldHaveExitValue(0); - output.shouldContain("jdk.crac beforeCheckpoint"); - } else { - Resource resource = new Resource() { - @Override - public void beforeCheckpoint(Context context) throws Exception { } - @Override - public void afterRestore(Context context) throws Exception { } - }; - Core.getGlobalContext().register(resource); +public class LazyProps implements CracTest { + @Override + public void test() throws Exception { + new CracBuilder().engine(CracEngine.SIMULATE) + .captureOutput(true) + .startCheckpoint().waitForSuccess() + .outputAnalyzer().shouldContain("jdk.crac beforeCheckpoint"); + } + + @Override + public void exec() throws RestoreException, CheckpointException { + Resource resource = new Resource() { + @Override + public void beforeCheckpoint(Context context) throws Exception { } + @Override + public void afterRestore(Context context) throws Exception { } + }; + Core.getGlobalContext().register(resource); - System.setProperty("jdk.crac.debug", "true"); - Core.checkpointRestore(); - } + System.setProperty("jdk.crac.debug", "true"); + Core.checkpointRestore(); } } diff --git a/test/jdk/jdk/crac/LeaveRunning.java b/test/jdk/jdk/crac/LeaveRunning.java index 5023e4f716e..bea544f0efe 100644 --- a/test/jdk/jdk/crac/LeaveRunning.java +++ b/test/jdk/jdk/crac/LeaveRunning.java @@ -23,38 +23,29 @@ * questions. */ -import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; +import jdk.crac.*; + +import jdk.test.lib.crac.CracBuilder; +import jdk.test.lib.crac.CracTest; /** * @test * @library /test/lib - * @build CheckpointRestore - * @run main LeaveRunning + * @build LeaveRunning + * @run driver jdk.test.lib.crac.CracTest */ -public class LeaveRunning { - public static void main(String[] args) { - OutputAnalyzer output; - try { - ProcessBuilder pb = ProcessTools.createTestJvm( - "-XX:CRaCCheckpointTo=./cr", CheckpointRestore.class.getSimpleName()); - pb.environment().put("CRAC_CRIU_LEAVE_RUNNING", ""); - output = ProcessTools.executeProcess(pb); - } catch (Exception e) { - throw new RuntimeException(e); - } - - output.shouldHaveExitValue(0); - output.shouldContain(CheckpointRestore.RESTORED_MESSAGE); - - try { - output = ProcessTools.executeTestJvm( - "-XX:CRaCRestoreFrom=./cr"); - } catch (Exception e) { - throw new RuntimeException(e); - } +public class LeaveRunning implements CracTest { + @Override + public void test() throws Exception { + CracBuilder builder = new CracBuilder().env("CRAC_CRIU_LEAVE_RUNNING", "") + .captureOutput(true); + builder.startCheckpoint().waitForSuccess().outputAnalyzer().shouldContain(RESTORED_MESSAGE); + builder.doRestore().outputAnalyzer().shouldContain(RESTORED_MESSAGE); + } - output.shouldHaveExitValue(0); - output.shouldContain(CheckpointRestore.RESTORED_MESSAGE); + @Override + public void exec() throws Exception { + Core.checkpointRestore(); + System.out.println(RESTORED_MESSAGE); } } diff --git a/test/jdk/jdk/crac/MXBean.java b/test/jdk/jdk/crac/MXBean.java index a5f2032d147..336e3eecd12 100644 --- a/test/jdk/jdk/crac/MXBean.java +++ b/test/jdk/jdk/crac/MXBean.java @@ -26,51 +26,48 @@ import jdk.crac.*; import jdk.crac.management.*; +import jdk.test.lib.crac.CracBuilder; +import jdk.test.lib.crac.CracEngine; +import jdk.test.lib.crac.CracTest; import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; -import java.lang.management.ManagementFactory; import java.time.Instant; import java.time.ZoneId; import java.time.format.DateTimeFormatter; +import static jdk.test.lib.Asserts.assertLT; + /** * @test * @library /test/lib - * @run main MXBean + * @build MXBean + * @run driver jdk.test.lib.crac.CracTest */ -public class MXBean { +public class MXBean implements CracTest { static final long TIME_TOLERANCE = 10_000; // ms - static class Test { - public static void main(String[] args) throws CheckpointException, RestoreException { - CRaCMXBean cracMXBean = CRaCMXBean.getCRaCMXBean(); + @Override + public void exec() throws CheckpointException, RestoreException { + CRaCMXBean cracMXBean = CRaCMXBean.getCRaCMXBean(); - Core.checkpointRestore(); + Core.checkpointRestore(); - System.out.println("UptimeSinceRestore " + cracMXBean.getUptimeSinceRestore()); + System.out.println("UptimeSinceRestore " + cracMXBean.getUptimeSinceRestore()); - long restoreTime = cracMXBean.getRestoreTime(); - System.out.println("RestoreTime " + restoreTime + " " + - DateTimeFormatter.ofPattern("E dd LLL yyyy HH:mm:ss.n").format( - Instant.ofEpochMilli(restoreTime) - .atZone(ZoneId.systemDefault()))); - } + long restoreTime = cracMXBean.getRestoreTime(); + System.out.println("RestoreTime " + restoreTime + " " + + DateTimeFormatter.ofPattern("E dd LLL yyyy HH:mm:ss.n").format( + Instant.ofEpochMilli(restoreTime) + .atZone(ZoneId.systemDefault()))); } - public static void main(String[] args) { + @Override + public void test() throws Exception { long start = System.currentTimeMillis(); - OutputAnalyzer output; - try { - output = ProcessTools.executeTestJvm( - "-XX:CREngine=simengine", "-XX:CRaCCheckpointTo=./cr", - "MXBean$Test"); - } catch (Exception e) { - throw new RuntimeException(e); - } - - output.shouldHaveExitValue(0); + OutputAnalyzer output = new CracBuilder().engine(CracEngine.SIMULATE) + .captureOutput(true) + .startCheckpoint().waitForSuccess().outputAnalyzer(); long restoreUptime = Long.parseLong(output.firstMatch("UptimeSinceRestore ([0-9-]+)", 1)); if (restoreUptime < 0 || TIME_TOLERANCE < restoreUptime) { @@ -80,8 +77,6 @@ public static void main(String[] args) { long restoreTime = Long.parseLong(output.firstMatch("RestoreTime ([0-9-]+)", 1)); restoreTime -= start; - if (restoreTime < -TIME_TOLERANCE || TIME_TOLERANCE < restoreTime) { - throw new Error("bad RestoreTime: " + restoreTime); - } + assertLT(Math.abs(restoreTime), TIME_TOLERANCE, "bad RestoreTime: " + restoreTime); } } diff --git a/test/jdk/jdk/crac/RefQueueTest.java b/test/jdk/jdk/crac/RefQueueTest.java index 77c47b9d5f0..2cee22c2a7a 100644 --- a/test/jdk/jdk/crac/RefQueueTest.java +++ b/test/jdk/jdk/crac/RefQueueTest.java @@ -25,18 +25,27 @@ import java.lang.ref.Cleaner; import jdk.crac.*; +import jdk.test.lib.crac.CracBuilder; +import jdk.test.lib.crac.CracEngine; +import jdk.test.lib.crac.CracTest; /** * @test - * The test will inherit FD with asmtools open and checkpoint would complain; as a workaround we'll add this to classpath - * @library ${jtreg.home}/lib/asmtools.jar - * @run main/othervm -XX:CREngine=simengine -XX:CRaCCheckpointTo=./cr RefQueueTest + * @library /test/lib + * @build RefQueueTest + * @run driver jdk.test.lib.crac.CracTest */ -public class RefQueueTest { +public class RefQueueTest implements CracTest { private static final Cleaner cleaner = Cleaner.create(); - static public void main(String[] args) throws Exception { + @Override + public void test() throws Exception { + new CracBuilder().engine(CracEngine.SIMULATE) + .startCheckpoint().waitForSuccess(); + } + @Override + public void exec() throws Exception { File badFile = File.createTempFile("jtreg-RefQueueTest", null); OutputStream badStream = new FileOutputStream(badFile); badStream.write('j'); diff --git a/test/jdk/jdk/crac/RestoreEnvironmentTest.java b/test/jdk/jdk/crac/RestoreEnvironmentTest.java index 154a3e2d298..bffb0bf795e 100644 --- a/test/jdk/jdk/crac/RestoreEnvironmentTest.java +++ b/test/jdk/jdk/crac/RestoreEnvironmentTest.java @@ -21,26 +21,51 @@ * have any questions. */ -import jdk.crac.*; +import jdk.test.lib.crac.CracBuilder; +import jdk.test.lib.crac.CracTest; -public class RestoreEnvironmentTest { - static public void main(String[] args) throws Exception { - { - String testVarName = "RESTORE_ENVIRONMENT_TEST_VAR"; +import java.io.IOException; - for (int i = 0; i < 3; ++i) { - var testVar = java.lang.System.getenv(testVarName + i); - System.out.println("(before checkpoint) " + testVarName + i + "=" + testVar); - } +/* + * @test RestoreEnvironmentTest + * @summary the test checks that actual environment variables are propagated into a restored process. + * @library /test/lib + * @build RestoreEnvironmentTest + * @run driver/timeout=120 jdk.test.lib.crac.CracTest + */ +public class RestoreEnvironmentTest implements CracTest { + static final String TEST_VAR_NAME = "RESTORE_ENVIRONMENT_TEST_VAR"; + static final String BEFORE_CHECKPOINT = "BeforeCheckpoint"; + static final String AFTER_RESTORE = "AfterRestore"; + static final String NEW_VALUE = "NewValue"; + public static final String PREFIX = "(after restore) "; + + @Override + public void test() throws Exception { + CracBuilder builder = new CracBuilder().captureOutput(true) + .env(TEST_VAR_NAME + 0, BEFORE_CHECKPOINT) + .env(TEST_VAR_NAME + 1, BEFORE_CHECKPOINT); + builder.doCheckpoint(); + builder.env(TEST_VAR_NAME + 1, AFTER_RESTORE); + builder.env(TEST_VAR_NAME + 2, NEW_VALUE); + builder.doRestore().outputAnalyzer() + .shouldContain(PREFIX + TEST_VAR_NAME + "0=" + BEFORE_CHECKPOINT) + .shouldContain(PREFIX + TEST_VAR_NAME + "1=" + AFTER_RESTORE) + .shouldContain(PREFIX + TEST_VAR_NAME + "2=" + NEW_VALUE); + } + + @Override + public void exec() throws Exception { + for (int i = 0; i < 3; ++i) { + var testVar = java.lang.System.getenv(TEST_VAR_NAME + i); + System.out.println("(before checkpoint) " + TEST_VAR_NAME + i + "=" + testVar); + } - jdk.crac.Core.checkpointRestore(); + jdk.crac.Core.checkpointRestore(); - System.out.print("(after restore) "); - for (int i = 0; i < 3; ++i) { - var testVar = java.lang.System.getenv(testVarName + i); - System.out.print(testVarName + i + "=" + testVar + ";"); - } + for (int i = 0; i < 3; ++i) { + var testVar = java.lang.System.getenv(TEST_VAR_NAME + i); + System.out.println(PREFIX + TEST_VAR_NAME + i + "=" + testVar + ""); } - System.out.println(); } } diff --git a/test/jdk/jdk/crac/RestoreEnvironmentTest.sh b/test/jdk/jdk/crac/RestoreEnvironmentTest.sh deleted file mode 100644 index 9906135270f..00000000000 --- a/test/jdk/jdk/crac/RestoreEnvironmentTest.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/sh - -# Copyright 2019-2021 Azul Systems, Inc. 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 Azul Systems, 385 Moffett Park Drive, Suite 115, Sunnyvale, -# CA 94089 USA or visit www.azul.com if you need additional information or -# have any questions. - -## -## @test RestoreEnvironmentTest.sh -## @summary the test checks that actual environment variables are propagated into a restored process. -## @compile RestoreEnvironmentTest.java -## @run shell/timeout=120 RestoreEnvironmentTest.sh -## - -set -x - -CHECKPOINT_DIR=cr_dir -BEFORE=BeforeCheckpoint -AFTER=AfterRestore -NEWVAL=NewValue - -echo CHECKPOINT_DIR=$CHECKPOINT_DIR -rm -rf CHECKPOINT_DIR - -echo === Checkpointing... -export RESTORE_ENVIRONMENT_TEST_VAR0=$BEFORE -export RESTORE_ENVIRONMENT_TEST_VAR1=$BEFORE -${TESTJAVA}/bin/java -cp ${TESTCLASSPATH} -XX:CRaCCheckpointTo=$CHECKPOINT_DIR RestoreEnvironmentTest - -echo === Restoring... -export RESTORE_ENVIRONMENT_TEST_VAR1=$AFTER -RESULT=`RESTORE_ENVIRONMENT_TEST_VAR2=$NEWVAL ${TESTJAVA}/bin/java -cp ${TESTCLASSPATH} -XX:CRaCRestoreFrom=$CHECKPOINT_DIR` - -EXPECTED="(after restore) RESTORE_ENVIRONMENT_TEST_VAR0=$BEFORE;RESTORE_ENVIRONMENT_TEST_VAR1=$AFTER;RESTORE_ENVIRONMENT_TEST_VAR2=$NEWVAL;" -echo RESULT=$RESULT -echo EXPECTED=$EXPECTED -if [ "$EXPECTED" != "$RESULT" ]; then - echo FAILED - exit 1 -fi -echo PASSED diff --git a/test/jdk/jdk/crac/SecureRandom/Test.java b/test/jdk/jdk/crac/SecureRandom/InterlockTest.java similarity index 64% rename from test/jdk/jdk/crac/SecureRandom/Test.java rename to test/jdk/jdk/crac/SecureRandom/InterlockTest.java index 05550030ba3..b7d95e1ee1e 100644 --- a/test/jdk/jdk/crac/SecureRandom/Test.java +++ b/test/jdk/jdk/crac/SecureRandom/InterlockTest.java @@ -18,39 +18,48 @@ // CA 94089 USA or visit www.azul.com if you need additional information or // have any questions. - import jdk.crac.*; -import java.util.Random; -import java.security.SecureRandom; -import java.util.concurrent.atomic.AtomicLong; +import jdk.test.lib.crac.CracBuilder; +import jdk.test.lib.crac.CracTest; +import jdk.test.lib.crac.CracTestArg; -public class Test implements Resource { +import java.io.IOException; +import java.security.SecureRandom; - private static final AtomicLong counter = new AtomicLong(0); - private static boolean stop = false; +/* + * @test + * @summary Verify that secure random is not interlocked during checkpoint/restore. + * @library /test/lib + * @build InterlockTest + * @run driver/timeout=60 jdk.test.lib.crac.CracTest SHA1PRNG 100 + * @run driver/timeout=60 jdk.test.lib.crac.CracTest NativePRNGBlocking 100 + * @run driver/timeout=60 jdk.test.lib.crac.CracTest NativePRNGNonBlocking 100 + * @run driver/timeout=60 jdk.test.lib.crac.CracTest NativePRNG 100 + */ +public class InterlockTest implements Resource, CracTest { private static final long MIN_TIMEOUT = 100; private static final long MAX_TIMEOUT = 1000; - private static SecureRandom sr; - private static String algName = null; - private static class TestThread1 extends Thread { - private long timeout; + private boolean stop = false; + private SecureRandom sr; - TestThread1(long timeout) { - this.timeout = timeout; - } + @CracTestArg(0) + String algName; + + @CracTestArg(1) + int numThreads; + private class TestThread1 extends Thread { @Override public void run() { while (!stop) { - Test.set(); + set(); } } }; - private static class TestThread2 extends Thread implements Resource { - private long timeout; - private SecureRandom sr; + private class TestThread2 extends Thread implements Resource { + private final SecureRandom sr; synchronized void set() { sr.nextInt(); @@ -59,8 +68,7 @@ synchronized void clean() { sr.nextInt(); } - TestThread2(long timeout) throws Exception { - this.timeout = timeout; + TestThread2() throws Exception { sr = SecureRandom.getInstance(algName); Core.getGlobalContext().register(this); } @@ -83,11 +91,11 @@ public void afterRestore(Context context) throws Exception { } }; - synchronized static void clean() { + synchronized void clean() { sr.nextInt(); } - synchronized static void set() { + synchronized void set() { sr.nextInt(); } @@ -106,31 +114,26 @@ public void afterRestore(Context context) throws Exception { stop = true; } - public static void main(String args[]) throws Exception { - if (args.length < 1) { throw new RuntimeException("Alg name is not provided"); } - if (args.length < 2) { throw new RuntimeException("number of threads is missing"); } - algName = args[0]; - int numThreads; - try{ - numThreads = Integer.parseInt(args[1]); - } catch (NumberFormatException ex){ - throw new RuntimeException("invalid number of threads"); - } - Test test = new Test(); - test.sr = SecureRandom.getInstance(algName); - Core.getGlobalContext().register(test); + @Override + public void test() throws Exception { + new CracBuilder().doCheckpointAndRestore(); + } + + @Override + public void exec() throws Exception { + sr = SecureRandom.getInstance(algName); + Core.getGlobalContext().register(this); - Random random = new Random(); Thread[] threads = new Thread[numThreads]; - for(int i=0; i context) throws IOException { + + channel.socket().close(); + + // causes the channel deregistration + if (selType == SelectionType.SELECT_NOW) { + selector.selectNow(); + } else if (selType == SelectionType.SELECT_TIMEOUT) { + selector.select(500); + } else { + new Thread(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(1000); + selector.wakeup(); + } catch (InterruptedException ie) { + throw new RuntimeException(ie); + } + } + }).start(); + + selector.select(); + } + } + + @Override + public void afterRestore(Context context) { + } +} diff --git a/test/jdk/jdk/crac/Selector/Test970/Test.java b/test/jdk/jdk/crac/Selector/Test970/Test.java index e6f7e5c4570..d6946c675c9 100644 --- a/test/jdk/jdk/crac/Selector/Test970/Test.java +++ b/test/jdk/jdk/crac/Selector/Test970/Test.java @@ -18,70 +18,41 @@ // CA 94089 USA or visit www.azul.com if you need additional information or // have any questions. - import java.nio.channels.*; import java.io.IOException; import jdk.crac.*; - -class ChannelResource implements Resource { - - public enum SelectionType {SELECT, SELECT_TIMEOUT, SELECT_NOW}; - - private SocketChannel channel; - private SelectionKey key; - private Selector selector; - - private final SelectionType selType; - - public ChannelResource(SelectionType selType) { - this.selType = selType; - Core.getGlobalContext().register(this); - } - - public void open() throws IOException { - channel = SocketChannel.open(); - channel.configureBlocking(false); - } - - public void register(Selector selector) throws IOException { - key = channel.register(selector, SelectionKey.OP_READ); - this.selector = selector; - } +import jdk.test.lib.crac.CracBuilder; +import jdk.test.lib.crac.CracTest; +import jdk.test.lib.crac.CracTestArg; + +/* + * @test Selector/Test970 + * @summary a regression test for ZE-970 ("a channel deregistration + * is locked depending on mutual order of selector and channel creation") + * @library /test/lib + * @build ChannelResource + * @build Test + * @run driver jdk.test.lib.crac.CracTest SELECT_NOW true + * @run driver jdk.test.lib.crac.CracTest SELECT_NOW false + * @run driver jdk.test.lib.crac.CracTest SELECT true + * @run driver jdk.test.lib.crac.CracTest SELECT false + * @run driver jdk.test.lib.crac.CracTest SELECT_TIMEOUT true + * @run driver jdk.test.lib.crac.CracTest SELECT_TIMEOUT false + */ +public class Test implements CracTest { + @CracTestArg(0) + ChannelResource.SelectionType selType; + + @CracTestArg(1) + boolean openSelectorAtFirst; @Override - public void beforeCheckpoint(Context context) throws IOException { - - channel.socket().close(); - - // causes the channel deregistration - if (selType == SelectionType.SELECT_NOW) { - selector.selectNow(); - } else if (selType == SelectionType.SELECT_TIMEOUT) { - selector.select(500); - } else { - new Thread(new Runnable() { - @Override - public void run() { - try { - Thread.sleep(1000); - selector.wakeup(); - } catch (InterruptedException ie) { throw new RuntimeException(ie); } - } - }).start(); - - selector.select(); - } + public void test() throws Exception { + new CracBuilder().doCheckpointAndRestore(); } @Override - public void afterRestore(Context context) { - } -} - - -public class Test { - - private static void Test(ChannelResource.SelectionType selType, boolean openSelectorAtFirst) throws Exception { + public void exec() throws Exception { if (openSelectorAtFirst) { @@ -106,34 +77,4 @@ private static void Test(ChannelResource.SelectionType selType, boolean openSele selector.close(); } } - - - public static void main(String args[]) throws Exception { - - if (args.length < 1) { throw new RuntimeException("test number is missing"); } - - switch (args[0]) { // 1, 2: ZE-970 - case "1": - Test(ChannelResource.SelectionType.SELECT_NOW, true); - break; - case "2": - Test(ChannelResource.SelectionType.SELECT_NOW, false); - break; - case "3": - Test(ChannelResource.SelectionType.SELECT, true); - break; - case "4": - Test(ChannelResource.SelectionType.SELECT, false); - break; - case "5": - Test(ChannelResource.SelectionType.SELECT_TIMEOUT, true); - break; - case "6": - Test(ChannelResource.SelectionType.SELECT_TIMEOUT, false); - break; - default: - throw new RuntimeException("invalid test number"); - } - - } } diff --git a/test/jdk/jdk/crac/Selector/Test970/Test.sh b/test/jdk/jdk/crac/Selector/Test970/Test.sh deleted file mode 100644 index d1fc390431d..00000000000 --- a/test/jdk/jdk/crac/Selector/Test970/Test.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/sh - -# Copyright 2019-2020 Azul Systems, Inc. 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 Azul Systems, 385 Moffett Park Drive, Suite 115, Sunnyvale, -# CA 94089 USA or visit www.azul.com if you need additional information or -# have any questions. - - -## -## @test Test.sh -## @summary a regression test for ZE-970 ("a channel deregistration -## is locked depending on mutual order of selector and channel creation") -## @compile Test.java -## @run shell/timeout=120 Test.sh -## - -set -x - -for test in `seq 1 6` -do - - IMGDIR="cr$test" - - set +e - ${TESTJAVA}/bin/java -cp ${TESTCLASSPATH} -XX:CRaCCheckpointTo=$IMGDIR Test $test - e=$? - - set -e - [ $e -eq 137 ] - - ${TESTJAVA}/bin/java -XX:CRaCRestoreFrom=$IMGDIR - - echo "PASSED $test" - -done diff --git a/test/jdk/jdk/crac/Selector/interruptedSelection/Test.java b/test/jdk/jdk/crac/Selector/interruptedSelection/Test.java index d6c840c9bfe..25329409641 100644 --- a/test/jdk/jdk/crac/Selector/interruptedSelection/Test.java +++ b/test/jdk/jdk/crac/Selector/interruptedSelection/Test.java @@ -18,15 +18,48 @@ // CA 94089 USA or visit www.azul.com if you need additional information or // have any questions. +import jdk.test.lib.crac.CracBuilder; +import jdk.test.lib.crac.CracTest; +import jdk.test.lib.crac.CracTestArg; import java.nio.channels.Selector; import java.io.IOException; -public class Test { +/* + * @test Selector/interruptedSelection + * @summary check that the thread blocked by Selector.select() could be properly woken up by an interruption + * @library /test/lib + * @build Test + * @run driver/timeout=30 jdk.test.lib.crac.CracTest true true false + * @run driver/timeout=30 jdk.test.lib.crac.CracTest true false false + * @run driver/timeout=30 jdk.test.lib.crac.CracTest false true false + * @run driver/timeout=30 jdk.test.lib.crac.CracTest false false false + * @run driver/timeout=30 jdk.test.lib.crac.CracTest true true true + * @run driver/timeout=30 jdk.test.lib.crac.CracTest false true true + */ +public class Test implements CracTest { + @CracTestArg(0) + boolean setTimeout; + + @CracTestArg(1) + boolean interruptBeforeCheckpoint; + + @CracTestArg(2) + boolean skipCR; + + @Override + public void test() throws Exception { + CracBuilder builder = new CracBuilder(); + if (skipCR) { + builder.doPlain(); + } else { + builder.doCheckpointAndRestore(); + } + } // select(): interrupt before the checkpoint - private static void test(boolean setTimeout, boolean interruptBeforeCheckpoint, boolean skipCR) throws Exception { - + @Override + public void exec() throws Exception { Selector selector = Selector.open(); Runnable r = new Runnable() { @Override @@ -69,34 +102,5 @@ public void run() { try { selector.select(200); selector.close(); } - - - public static void main(String args[]) throws Exception { - - if (args.length < 1) { throw new RuntimeException("test number is missing"); } - - switch (args[0]) { - case "1": - test(true, true, false); - break; - case "2": - test(true, false, false); - break; - case "3": - test(false, true, false); - break; - case "4": - test(false, false, false); - break; - // 5, 6: skip C/R - case "5": - test(true, true, true); - break; - case "6": - test(false, true, true); - break; - default: - throw new RuntimeException("invalid test number"); - } - } } + diff --git a/test/jdk/jdk/crac/Selector/interruptedSelection/Test.sh b/test/jdk/jdk/crac/Selector/interruptedSelection/Test.sh deleted file mode 100644 index 2e0c553045a..00000000000 --- a/test/jdk/jdk/crac/Selector/interruptedSelection/Test.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/sh - -# Copyright 2019-2020 Azul Systems, Inc. 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 Azul Systems, 385 Moffett Park Drive, Suite 115, Sunnyvale, -# CA 94089 USA or visit www.azul.com if you need additional information or -# have any questions. - - -## -## @test Test.sh -## @summary check that the thread blocked by Selector.select() could be properly woken up by an interruption -## @compile Test.java -## @run shell/timeout=120 Test.sh -## - -set -x - -for test in `seq 1 4` -do - - IMGDIR="cr$test" - - set +e - ${TESTJAVA}/bin/java -cp ${TESTCLASSPATH} -XX:CRaCCheckpointTo=$IMGDIR Test $test - e=$? - - set -e - [ $e -eq 137 ] - - ${TESTJAVA}/bin/java -XX:CRaCRestoreFrom=$IMGDIR - - echo "PASSED $test" - -done - - - -${TESTJAVA}/bin/java -cp ${TESTCLASSPATH} Test 5 -echo "PASSED 5" - -${TESTJAVA}/bin/java -cp ${TESTCLASSPATH} Test 6 -echo "PASSED 6" diff --git a/test/jdk/jdk/crac/Selector/keyAfterRestore/ChannelResource.java b/test/jdk/jdk/crac/Selector/keyAfterRestore/ChannelResource.java new file mode 100644 index 00000000000..f38a2314a2d --- /dev/null +++ b/test/jdk/jdk/crac/Selector/keyAfterRestore/ChannelResource.java @@ -0,0 +1,176 @@ +// Copyright 2019-2020 Azul Systems, Inc. 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 Azul Systems, 385 Moffett Park Drive, Suite 115, Sunnyvale, +// CA 94089 USA or visit www.azul.com if you need additional information or +// have any questions. + +import jdk.crac.Context; +import jdk.crac.Core; +import jdk.crac.Resource; + +import java.io.IOException; +import java.nio.channels.CancelledKeyException; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.SocketChannel; + +class ChannelResource implements Resource { + + private SocketChannel channel; + private SelectionKey key; + private Selector selector; + + private Object att = new Integer(123); + + public ChannelResource() { + Core.getGlobalContext().register(this); + } + + public void open() throws IOException { + channel = SocketChannel.open(); + channel.configureBlocking(false); + } + + public void register(Selector selector) throws IOException { + key = channel.register(selector, SelectionKey.OP_CONNECT); + key.attach(att); + this.selector = selector; + } + + @Override + public void beforeCheckpoint(Context context) throws IOException { + + channel.socket().close(); // close the channel => cancel the key + check(!channel.isOpen(), "the channel should not be open"); + selector.select(100); // causes the channel deregistration + } + + @Override + public void afterRestore(Context context) { + + check(key.selector().equals(selector), "invalid key.selector()"); + check(key.channel().equals(channel), "invalid key.channel()"); + + // the key is cancelled + check(!key.isValid(), "expected: key.isValid() == false"); + + boolean caught = false; + try { + key.readyOps(); + } catch (CancelledKeyException e) { + caught = true; + } + check(caught, "expected CancelledKeyException is missing"); + + caught = false; + try { + key.interestOps(); + } catch (CancelledKeyException e) { + caught = true; + } + check(caught, "expected CancelledKeyException is missing"); + + caught = false; + try { + key.interestOps(SelectionKey.OP_CONNECT); + } catch (CancelledKeyException e) { + caught = true; + } + check(caught, "expected CancelledKeyException is missing"); + + caught = false; + try { + key.readyOps(); + } catch (CancelledKeyException e) { + caught = true; + } + check(caught, "expected CancelledKeyException is missing"); + + caught = false; + try { + key.isReadable(); + } catch (CancelledKeyException e) { + caught = true; + } + check(caught, "expected CancelledKeyException is missing"); + + caught = false; + try { + key.isWritable(); + } catch (CancelledKeyException e) { + caught = true; + } + check(caught, "expected CancelledKeyException is missing"); + + caught = false; + try { + key.isConnectable(); + } catch (CancelledKeyException e) { + caught = true; + } + check(caught, "expected CancelledKeyException is missing"); + + caught = false; + try { + key.isAcceptable(); + } catch (CancelledKeyException e) { + caught = true; + } + check(caught, "expected CancelledKeyException is missing"); + + check(att.equals(key.attachment()), "invalid key.attachment()"); + + key.cancel(); // try just in case + + // register again + try { + channel = SocketChannel.open(); + channel.configureBlocking(false); + key = channel.register(selector, SelectionKey.OP_READ); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + // to check after restore + public void checkKey() { + + check(key.isValid(), "key must be valid"); + + check(key.selector().equals(selector), "invalid key.selector()"); + check(key.channel().equals(channel), "invalid key.channel()"); + + key.isReadable(); // just call, cannot set "ready" state manually + check(!key.isWritable(), "invalid key.isWritable()"); + check(!key.isConnectable(), "invalid key.isConnectable()"); + check(!key.isAcceptable(), "invalid key.isAcceptable()"); + + check(key.interestOps() == SelectionKey.OP_READ, "invalid key.interestOps()"); + + System.out.println(">> ready >> " + key.readyOps()); + + check(key.attachment() == null, "key.attachment() expected to be null"); + + key.cancel(); // try just in case + } + + private void check(boolean b, String msg) { + if (!b) { + throw new RuntimeException(msg); + } + } +} diff --git a/test/jdk/jdk/crac/Selector/keyAfterRestore/Test.java b/test/jdk/jdk/crac/Selector/keyAfterRestore/Test.java index 16d67b063b5..62b60ab6c6c 100644 --- a/test/jdk/jdk/crac/Selector/keyAfterRestore/Test.java +++ b/test/jdk/jdk/crac/Selector/keyAfterRestore/Test.java @@ -18,132 +18,33 @@ // CA 94089 USA or visit www.azul.com if you need additional information or // have any questions. - import java.nio.channels.*; import java.io.IOException; import jdk.crac.*; - -class ChannelResource implements Resource { - - private SocketChannel channel; - private SelectionKey key; - private Selector selector; - - private Object att = new Integer(123); - - public ChannelResource() { Core.getGlobalContext().register(this); } - - public void open() throws IOException { - channel = SocketChannel.open(); - channel.configureBlocking(false); - } - - public void register(Selector selector) throws IOException { - key = channel.register(selector, SelectionKey.OP_CONNECT); - key.attach(att); - this.selector = selector; - } +import jdk.test.lib.crac.CracBuilder; +import jdk.test.lib.crac.CracTest; +import jdk.test.lib.crac.CracTestArg; + +/* + * @test Selector/keyAfterRestore + * @summary a trivial test for SelectionKey's state after restore + * @library /test/lib + * @build ChannelResource + * @build Test + * @run driver/timeout=30 jdk.test.lib.crac.CracTest true + * @run driver/timeout=30 jdk.test.lib.crac.CracTest false + */ +public class Test implements CracTest { + @CracTestArg + boolean openSelectorAtFirst; @Override - public void beforeCheckpoint(Context context) throws IOException { - - channel.socket().close(); // close the channel => cancel the key - check(!channel.isOpen(), "the channel should not be open"); - selector.select(100); // causes the channel deregistration + public void test() throws Exception { + new CracBuilder().doCheckpointAndRestore(); } @Override - public void afterRestore(Context context) { - - check(key.selector().equals(selector), "invalid key.selector()"); - check(key.channel().equals(channel), "invalid key.channel()"); - - // the key is cancelled - check(!key.isValid(), "expected: key.isValid() == false"); - - boolean caught = false; - try { key.readyOps(); } - catch (CancelledKeyException e) { caught = true; } - check(caught, "expected CancelledKeyException is missing"); - - caught = false; - try { key.interestOps(); } - catch (CancelledKeyException e) { caught = true; } - check(caught, "expected CancelledKeyException is missing"); - - caught = false; - try { key.interestOps(SelectionKey.OP_CONNECT); } - catch (CancelledKeyException e) { caught = true; } - check(caught, "expected CancelledKeyException is missing"); - - caught = false; - try { key.readyOps(); } - catch (CancelledKeyException e) { caught = true; } - check(caught, "expected CancelledKeyException is missing"); - - caught = false; - try { key.isReadable(); } - catch (CancelledKeyException e) { caught = true; } - check(caught, "expected CancelledKeyException is missing"); - - caught = false; - try { key.isWritable(); } - catch (CancelledKeyException e) { caught = true; } - check(caught, "expected CancelledKeyException is missing"); - - caught = false; - try { key.isConnectable(); } - catch (CancelledKeyException e) { caught = true; } - check(caught, "expected CancelledKeyException is missing"); - - caught = false; - try { key.isAcceptable(); } - catch (CancelledKeyException e) { caught = true; } - check(caught, "expected CancelledKeyException is missing"); - - check(att.equals(key.attachment()), "invalid key.attachment()"); - - key.cancel(); // try just in case - - // register again - try { - channel = SocketChannel.open(); - channel.configureBlocking(false); - key = channel.register(selector, SelectionKey.OP_READ); - } - catch (Exception e) { throw new RuntimeException(e); } - } - - // to check after restore - public void checkKey() { - - check(key.isValid(), "key must be valid"); - - check(key.selector().equals(selector), "invalid key.selector()"); - check(key.channel().equals(channel), "invalid key.channel()"); - - key.isReadable(); // just call, cannot set "ready" state manually - check( !key.isWritable() , "invalid key.isWritable()" ); - check( !key.isConnectable(), "invalid key.isConnectable()"); - check( !key.isAcceptable() , "invalid key.isAcceptable()" ); - - check(key.interestOps() == SelectionKey.OP_READ, "invalid key.interestOps()"); - - System.out.println(">> ready >> " + key.readyOps()); - - check(key.attachment() == null, "key.attachment() expected to be null"); - - key.cancel(); // try just in case - } - - private void check(boolean b, String msg) { if (!b) { throw new RuntimeException(msg); } } -} - - -public class Test { - - private static void test(boolean openSelectorAtFirst) throws Exception { - + public void exec() throws Exception { ChannelResource ch; Selector selector = null; @@ -170,21 +71,4 @@ private static void test(boolean openSelectorAtFirst) throws Exception { selector.close(); } - - public static void main(String args[]) throws Exception { - - if (args.length < 1) { throw new RuntimeException("test number is missing"); } - - switch (args[0]) { - case "1": - test(true); - break; - case "2": - test(false); - break; - default: - throw new RuntimeException("invalid test number"); - } - - } } diff --git a/test/jdk/jdk/crac/Selector/keyAfterRestore/Test.sh b/test/jdk/jdk/crac/Selector/keyAfterRestore/Test.sh deleted file mode 100644 index d9d26fedc81..00000000000 --- a/test/jdk/jdk/crac/Selector/keyAfterRestore/Test.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/sh - -# Copyright 2019-2020 Azul Systems, Inc. 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 Azul Systems, 385 Moffett Park Drive, Suite 115, Sunnyvale, -# CA 94089 USA or visit www.azul.com if you need additional information or -# have any questions. - - -## -## @test Test.sh -## @summary a trivial test for SelectionKey's state after restore -## @compile Test.java -## @run shell/timeout=60 Test.sh -## - -set -x - -for test in `seq 1 2` -do - - IMGDIR="cr$test" - - set +e - ${TESTJAVA}/bin/java -cp ${TESTCLASSPATH} -XX:CRaCCheckpointTo=$IMGDIR Test $test - e=$? - - set -e - [ $e -eq 137 ] - - ${TESTJAVA}/bin/java -XX:CRaCRestoreFrom=$IMGDIR - - echo "PASSED $test" - -done diff --git a/test/jdk/jdk/crac/Selector/multipleSelect/Test.java b/test/jdk/jdk/crac/Selector/multipleSelect/Test.java index 5712bc98208..17edf35e837 100644 --- a/test/jdk/jdk/crac/Selector/multipleSelect/Test.java +++ b/test/jdk/jdk/crac/Selector/multipleSelect/Test.java @@ -18,6 +18,9 @@ // CA 94089 USA or visit www.azul.com if you need additional information or // have any questions. +import jdk.test.lib.crac.CracBuilder; +import jdk.test.lib.crac.CracTest; +import jdk.test.lib.crac.CracTestArg; import java.nio.channels.Selector; import java.io.IOException; @@ -25,24 +28,52 @@ import java.util.concurrent.atomic.AtomicInteger; - -public class Test { +/* + * @test Selector/multipleSelect + * @summary check work of multiple select() + wakeup() + C/R + * @library /test/lib + * @build Test + * @run driver/timeout=30 jdk.test.lib.crac.CracTest ONLY_TIMEOUTS false + * @run driver/timeout=30 jdk.test.lib.crac.CracTest NO_TIMEOUTS false + * @run driver/timeout=30 jdk.test.lib.crac.CracTest MIXED false + * @run driver/timeout=30 jdk.test.lib.crac.CracTest ONLY_TIMEOUTS true + * @run driver/timeout=30 jdk.test.lib.crac.CracTest NO_TIMEOUTS true + * @run driver/timeout=30 jdk.test.lib.crac.CracTest MIXED true + */ +public class Test implements CracTest { private final static Random RND = new Random(); private final static long LONG_TIMEOUT = 3600_000; private final static long SHORT_TIMEOUT = 3_000; - public enum testType { + public enum TestType { NO_TIMEOUTS, // test only select(), wakeup ONLY_TIMEOUTS, // test only select(timeout), do not call wakeup() MIXED}; - private static void test(testType type, boolean skipCR) throws Exception { + @CracTestArg(0) + TestType type; + + @CracTestArg(1) + boolean skipCR; + + @Override + public void test() throws Exception { + CracBuilder builder = new CracBuilder(); + if (skipCR) { + builder.doPlain(); + } else { + builder.doCheckpointAndRestore(); + } + } + + @Override + public void exec() throws Exception { - long dt = (type == testType.ONLY_TIMEOUTS) ? SHORT_TIMEOUT : LONG_TIMEOUT; + long dt = (type == TestType.ONLY_TIMEOUTS) ? SHORT_TIMEOUT : LONG_TIMEOUT; - int nThreads = (type == testType.ONLY_TIMEOUTS) ? 5 : 20; + int nThreads = (type == TestType.ONLY_TIMEOUTS) ? 5 : 20; AtomicInteger nSelected = new AtomicInteger(0); @@ -53,8 +84,8 @@ private static void test(testType type, boolean skipCR) throws Exception { boolean setTimeout[] = new boolean[nThreads]; for (int i = 0; i < nThreads; ++i) { boolean t = false; // NO_TIMEOUTS - if (type == testType.ONLY_TIMEOUTS) { t = true; } - else if (type == testType.MIXED) { t = RND.nextBoolean(); } + if (type == TestType.ONLY_TIMEOUTS) { t = true; } + else if (type == TestType.MIXED) { t = RND.nextBoolean(); } setTimeout[i] = t; } @@ -97,7 +128,7 @@ public void run() { t.join(); Thread.sleep(1000); - if (type == testType.ONLY_TIMEOUTS) { // do not wake threads up, the timeouts must work + if (type == TestType.ONLY_TIMEOUTS) { // do not wake threads up, the timeouts must work while (nSelected.get() > 0) { Thread.sleep(1000); } @@ -138,35 +169,4 @@ public void run() { selector.close(); } - - - - public static void main(String args[]) throws Exception { - - if (args.length < 1) { throw new RuntimeException("test number is missing"); } - - switch (args[0]) { - case "1": - test(testType.ONLY_TIMEOUTS, false); - break; - case "2": - test(testType.NO_TIMEOUTS, false); - break; - case "3": - test(testType.MIXED, false); - break; - // 4-6: no C/R - case "4": - test(testType.ONLY_TIMEOUTS, true); - break; - case "5": - test(testType.NO_TIMEOUTS, true); - break; - case "6": - test(testType.MIXED, true); - break; - default: - throw new RuntimeException("invalid test number"); - } - } } diff --git a/test/jdk/jdk/crac/Selector/multipleSelect/Test.sh b/test/jdk/jdk/crac/Selector/multipleSelect/Test.sh deleted file mode 100644 index 7615520d601..00000000000 --- a/test/jdk/jdk/crac/Selector/multipleSelect/Test.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/sh - -# Copyright 2019-2020 Azul Systems, Inc. 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 Azul Systems, 385 Moffett Park Drive, Suite 115, Sunnyvale, -# CA 94089 USA or visit www.azul.com if you need additional information or -# have any questions. - - -## -## @test Test.sh -## @summary check work of multiple select() + wakeup() + C/R -## @compile Test.java -## @run shell/timeout=240 Test.sh -## - -set -x - -for test in `seq 1 3` -do - - IMGDIR="cr$test" - - set +e - ${TESTJAVA}/bin/java -cp ${TESTCLASSPATH}:$CPAPPEND -XX:CRaCCheckpointTo=$IMGDIR Test $test - e=$? - - set -e - [ $e -eq 137 ] - - ${TESTJAVA}/bin/java -XX:CRaCRestoreFrom=$IMGDIR - - echo "PASSED $test" - -done - -# check conformity (no C/R) - -set -e -for test in `seq 4 6` -do - - ${TESTJAVA}/bin/java -cp ${TESTCLASSPATH} Test $test - echo "PASSED $test" - -done diff --git a/test/jdk/jdk/crac/Selector/multipleSelectNow/Test.java b/test/jdk/jdk/crac/Selector/multipleSelectNow/Test.java index defd3d55eef..96d2adcd62c 100644 --- a/test/jdk/jdk/crac/Selector/multipleSelectNow/Test.java +++ b/test/jdk/jdk/crac/Selector/multipleSelectNow/Test.java @@ -18,17 +18,40 @@ // CA 94089 USA or visit www.azul.com if you need additional information or // have any questions. +import jdk.test.lib.crac.CracBuilder; +import jdk.test.lib.crac.CracTest; +import jdk.test.lib.crac.CracTestArg; import java.nio.channels.Selector; import java.io.IOException; import java.util.concurrent.atomic.AtomicInteger; +/* + * @test Selector/multipleSelectNow + * @summary check work of multiple selectNow() + C/R peaceful coexistence + * @library /test/lib + * @build Test + * @run driver jdk.test.lib.crac.CracTest false + * @run driver jdk.test.lib.crac.CracTest true + */ +public class Test implements CracTest { + + @CracTestArg + boolean skipCR; + + @Override + public void test() throws Exception { + CracBuilder builder = new CracBuilder(); + if (skipCR) { + builder.doPlain(); + } else { + builder.doCheckpointAndRestore(); + } + } -public class Test { - - private static void test(boolean skipCR) throws Exception { - + @Override + public void exec() throws Exception { AtomicInteger nSelected = new AtomicInteger(0); Selector selector = Selector.open(); @@ -85,22 +108,4 @@ public void run() { selector.close(); } - - - - public static void main(String args[]) throws Exception { - - if (args.length < 1) { throw new RuntimeException("test number is missing"); } - - switch (args[0]) { - case "1": - test(false); - break; - case "2": - test(true); - break; - default: - throw new RuntimeException("invalid test number"); - } - } } diff --git a/test/jdk/jdk/crac/Selector/multipleSelectNow/Test.sh b/test/jdk/jdk/crac/Selector/multipleSelectNow/Test.sh deleted file mode 100644 index 34678910732..00000000000 --- a/test/jdk/jdk/crac/Selector/multipleSelectNow/Test.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/sh - -# Copyright 2019-2020 Azul Systems, Inc. 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 Azul Systems, 385 Moffett Park Drive, Suite 115, Sunnyvale, -# CA 94089 USA or visit www.azul.com if you need additional information or -# have any questions. - - -## -## @test Test.sh -## @summary check work of multiple selectNow() + C/R peaceful coexistence -## @compile Test.java -## @run shell/timeout=120 Test.sh -## - -set -x - -set +e -${TESTJAVA}/bin/java -cp ${TESTCLASSPATH} -XX:CRaCCheckpointTo=cr Test 1 -e=$? - -set -e -[ $e -eq 137 ] - -${TESTJAVA}/bin/java -XX:CRaCRestoreFrom=cr -echo "PASSED 1" - - -# check conformity (no C/R) - -${TESTJAVA}/bin/java -cp ${TESTCLASSPATH} Test 2 -echo "PASSED 2" - diff --git a/test/jdk/jdk/crac/Selector/multipleSelectSingleClose/Test.java b/test/jdk/jdk/crac/Selector/multipleSelectSingleClose/Test.java index b93a7785911..ac9daaa9622 100644 --- a/test/jdk/jdk/crac/Selector/multipleSelectSingleClose/Test.java +++ b/test/jdk/jdk/crac/Selector/multipleSelectSingleClose/Test.java @@ -18,6 +18,9 @@ // CA 94089 USA or visit www.azul.com if you need additional information or // have any questions. +import jdk.test.lib.crac.CracBuilder; +import jdk.test.lib.crac.CracTest; +import jdk.test.lib.crac.CracTestArg; import java.nio.channels.Selector; import java.nio.channels.ClosedSelectorException; @@ -26,13 +29,36 @@ import java.util.concurrent.atomic.AtomicInteger; +/* + * @test Selector/multipleSelectSingleClose + * @summary check a coexistence of multiple select() + C/R in case when the selector is finally closed + * @library /test/lib + * @build Test + * @run driver jdk.test.lib.crac.CracTest false false + * @run driver jdk.test.lib.crac.CracTest false true + * @run driver jdk.test.lib.crac.CracTest true true + */ +public class Test implements CracTest { + private final static Random RND = new Random(); -public class Test { + @CracTestArg(0) + boolean skipCR; - private final static Random RND = new Random(); + @CracTestArg(1) + boolean closeBeforeCheckpoint; - private static void test(boolean skipCR, boolean closeBeforeCheckpoint) throws Exception { + @Override + public void test() throws Exception { + CracBuilder builder = new CracBuilder(); + if (skipCR) { + builder.doPlain(); + } else { + builder.doCheckpointAndRestore(); + } + } + @Override + public void exec() throws Exception { int nThreads = 20; AtomicInteger nSelected = new AtomicInteger(0); @@ -98,25 +124,4 @@ public void run() { // just in case... for (Thread t: selectThreads) { t.join(); } } - - - - public static void main(String args[]) throws Exception { - - if (args.length < 1) { throw new RuntimeException("test number is missing"); } - - switch (args[0]) { - case "1": - test(false, false); - break; - case "2": - test(false, true); - break; - case "3": - test(true, true); - break; - default: - throw new RuntimeException("invalid test number"); - } - } } diff --git a/test/jdk/jdk/crac/Selector/multipleSelectSingleClose/Test.sh b/test/jdk/jdk/crac/Selector/multipleSelectSingleClose/Test.sh deleted file mode 100644 index 603dd26febd..00000000000 --- a/test/jdk/jdk/crac/Selector/multipleSelectSingleClose/Test.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/sh - -# Copyright 2019-2020 Azul Systems, Inc. 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 Azul Systems, 385 Moffett Park Drive, Suite 115, Sunnyvale, -# CA 94089 USA or visit www.azul.com if you need additional information or -# have any questions. - - -## -## @test Test.sh -## @summary check a coexistence of multiple select() + C/R in case when the selector is finally closed -## @compile Test.java -## @run shell/timeout=120 Test.sh -## - -set -x - -for test in `seq 1 2` -do - - IMGDIR="cr$test" - - set +e - ${TESTJAVA}/bin/java -cp ${TESTCLASSPATH} -XX:CRaCCheckpointTo=$IMGDIR Test $test - e=$? - - set -e - [ $e -eq 137 ] - - ${TESTJAVA}/bin/java -XX:CRaCRestoreFrom=$IMGDIR - - echo "PASSED $test" - -done - - -# check conformity (no C/R) - -set -e - -${TESTJAVA}/bin/java -cp ${TESTCLASSPATH} Test 3 -echo "PASSED 3" diff --git a/test/jdk/jdk/crac/Selector/selectAfterWakeup/Test.java b/test/jdk/jdk/crac/Selector/selectAfterWakeup/Test.java index 92f31d64304..7623b4638d6 100644 --- a/test/jdk/jdk/crac/Selector/selectAfterWakeup/Test.java +++ b/test/jdk/jdk/crac/Selector/selectAfterWakeup/Test.java @@ -18,15 +18,44 @@ // CA 94089 USA or visit www.azul.com if you need additional information or // have any questions. +import jdk.test.lib.crac.CracBuilder; +import jdk.test.lib.crac.CracTest; +import jdk.test.lib.crac.CracTestArg; +import java.io.IOException; import java.nio.channels.Selector; +/* + * @test Selector/selectAfterWakeup + * @summary check that the Selector's wakeup() makes the subsequent select() call to return immediately + * (see also jdk/test/java/nio/channels/Selector/WakeupSpeed.java); + * covers ZE-983 + * @library /test/lib + * @build Test + * @run driver jdk.test.lib.crac.CracTest true false false + * @run driver jdk.test.lib.crac.CracTest true false true + * @run driver jdk.test.lib.crac.CracTest true true false + * @run driver jdk.test.lib.crac.CracTest true true true + * @run driver jdk.test.lib.crac.CracTest false true false + * @run driver jdk.test.lib.crac.CracTest false true true + */ +public class Test implements CracTest { + @CracTestArg(0) + boolean wakeupBeforeCheckpoint; -public class Test { + @CracTestArg(1) + boolean wakeupAfterRestore; - private static void test(boolean wakeupBeforeCheckpoint, - boolean wakeupAfterRestore, - boolean setSelectTimeout) throws Exception { + @CracTestArg(2) + boolean setSelectTimeout; + + @Override + public void test() throws Exception { + new CracBuilder().doCheckpointAndRestore(); + } + + @Override + public void exec() throws Exception { Selector selector = Selector.open(); @@ -48,33 +77,4 @@ private static void test(boolean wakeupBeforeCheckpoint, selector.close(); } - - public static void main(String args[]) throws Exception { - - if (args.length < 1) { throw new RuntimeException("test number is missing"); } - - switch (args[0]) { - case "1": - test(true, false, false); // ZE-983 - break; - case "2": - test(true, false, true); - break; - case "3": - test(true, true, false); // ZE-983 - break; - case "4": - test(true, true, true); - break; - case "5": - test(false, true, false); - break; - case "6": - test(false, true, true); - break; - - default: - throw new RuntimeException("invalid test number"); - } - } } diff --git a/test/jdk/jdk/crac/Selector/selectAfterWakeup/Test.sh b/test/jdk/jdk/crac/Selector/selectAfterWakeup/Test.sh deleted file mode 100644 index 434e8760832..00000000000 --- a/test/jdk/jdk/crac/Selector/selectAfterWakeup/Test.sh +++ /dev/null @@ -1,51 +0,0 @@ -#!/bin/sh - -# Copyright 2019-2020 Azul Systems, Inc. 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 Azul Systems, 385 Moffett Park Drive, Suite 115, Sunnyvale, -# CA 94089 USA or visit www.azul.com if you need additional information or -# have any questions. - - -## -## @test Test.sh -## @summary check that the Selector's wakeup() makes the subsequent select() call to return immediately -## (see also jdk/test/java/nio/channels/Selector/WakeupSpeed.java); -## covers ZE-983 -## @compile Test.java -## @run shell/timeout=120 Test.sh -## - -set -x - -for test in `seq 1 6` -do - - IMGDIR="cr$test" - - set +e - ${TESTJAVA}/bin/java -cp ${TESTCLASSPATH} -XX:CRaCCheckpointTo=$IMGDIR Test $test - e=$? - - set -e - [ $e -eq 137 ] - - ${TESTJAVA}/bin/java -XX:CRaCRestoreFrom=$IMGDIR - - echo "PASSED $test" - -done diff --git a/test/jdk/jdk/crac/Selector/selectAndWakeupAfterRestore/Test.java b/test/jdk/jdk/crac/Selector/selectAndWakeupAfterRestore/Test.java index 238160830d0..d6bac95ae1c 100644 --- a/test/jdk/jdk/crac/Selector/selectAndWakeupAfterRestore/Test.java +++ b/test/jdk/jdk/crac/Selector/selectAndWakeupAfterRestore/Test.java @@ -18,10 +18,24 @@ // CA 94089 USA or visit www.azul.com if you need additional information or // have any questions. +import jdk.test.lib.crac.CracBuilder; +import jdk.test.lib.crac.CracTest; +import java.io.IOException; import java.nio.channels.Selector; -public class Test { +/* + * @test Selector/selectAndWakeupAfterRestore + * @summary a trivial check that Selector.wakeup() after restore behaves as expected + * @library /test/lib + * @build Test + * @run driver jdk.test.lib.crac.CracTest + */ +public class Test implements CracTest { + @Override + public void test() throws Exception { + new CracBuilder().doCheckpointAndRestore(); + } private static void selectAndWakeup(Selector selector) throws java.io.IOException { @@ -40,7 +54,8 @@ public void run() { selector.select(); } - public static void main(String args[]) throws Exception { + @Override + public void exec() throws Exception { Selector selector = Selector.open(); diff --git a/test/jdk/jdk/crac/Selector/selectAndWakeupAfterRestore/Test.sh b/test/jdk/jdk/crac/Selector/selectAndWakeupAfterRestore/Test.sh deleted file mode 100644 index 4e6147ed936..00000000000 --- a/test/jdk/jdk/crac/Selector/selectAndWakeupAfterRestore/Test.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/sh - -# Copyright 2019-2020 Azul Systems, Inc. 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 Azul Systems, 385 Moffett Park Drive, Suite 115, Sunnyvale, -# CA 94089 USA or visit www.azul.com if you need additional information or -# have any questions. - - -## -## @test Test.sh -## @summary a trivial check that Selector.wakeup() after restore behaves as expected -## @compile Test.java -## @run shell/timeout=60 Test.sh -## - -set -x - -set +e -${TESTJAVA}/bin/java -cp ${TESTCLASSPATH} -XX:CRaCCheckpointTo=cr Test -e=$? - -set -e -[ $e -eq 137 ] - -${TESTJAVA}/bin/java -XX:CRaCRestoreFrom=cr - -echo PASSED diff --git a/test/jdk/jdk/crac/Selector/wakeupAfterRestore/Test.java b/test/jdk/jdk/crac/Selector/wakeupAfterRestore/Test.java index af3f7e28178..730683b153f 100644 --- a/test/jdk/jdk/crac/Selector/wakeupAfterRestore/Test.java +++ b/test/jdk/jdk/crac/Selector/wakeupAfterRestore/Test.java @@ -18,18 +18,37 @@ // CA 94089 USA or visit www.azul.com if you need additional information or // have any questions. +import jdk.test.lib.crac.CracBuilder; +import jdk.test.lib.crac.CracTest; +import jdk.test.lib.crac.CracTestArg; import java.nio.channels.Selector; import java.io.IOException; -public class Test { +/* + * @test Selector/wakeupAfterRestore + * @summary check that the thread blocked by Selector.select() on checkpoint could be properly woken up after restore + * @library /test/lib + * @build Test + * @run driver jdk.test.lib.crac.CracTest true + * @run driver jdk.test.lib.crac.CracTest false + */ +public class Test implements CracTest { private final static long TIMEOUT = 3600_000; // looong timeout static boolean awakened; - private static void test(boolean setTimeout) throws Exception { + @CracTestArg + boolean setTimeout; + @Override + public void test() throws Exception { + new CracBuilder().doCheckpointAndRestore(); + } + + @Override + public void exec() throws Exception { Selector selector = Selector.open(); Runnable r = new Runnable() { @Override @@ -67,23 +86,4 @@ public void run() { selector.select(200); selector.close(); } - - - - - public static void main(String args[]) throws Exception { - - if (args.length < 1) { throw new RuntimeException("test number is missing"); } - - switch (args[0]) { - case "1": - test(true); - break; - case "2": - test(false); - break; - default: - throw new RuntimeException("invalid test number"); - } - } } diff --git a/test/jdk/jdk/crac/Selector/wakeupAfterRestore/Test.sh b/test/jdk/jdk/crac/Selector/wakeupAfterRestore/Test.sh deleted file mode 100644 index 4fcdcd61db5..00000000000 --- a/test/jdk/jdk/crac/Selector/wakeupAfterRestore/Test.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/sh - -# Copyright 2019-2020 Azul Systems, Inc. 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 Azul Systems, 385 Moffett Park Drive, Suite 115, Sunnyvale, -# CA 94089 USA or visit www.azul.com if you need additional information or -# have any questions. - - -## -## @test Test.sh -## @summary check that the thread blocked by Selector.select() on checkpoint could be properly woken up after restore -## @compile Test.java -## @run shell/timeout=120 Test.sh -## - -set -x - -for test in `seq 1 2` -do - - IMGDIR="cr$test" - - set +e - ${TESTJAVA}/bin/java -cp ${TESTCLASSPATH} -XX:CRaCCheckpointTo=$IMGDIR Test $test - e=$? - - set -e - [ $e -eq 137 ] - - ${TESTJAVA}/bin/java -XX:CRaCRestoreFrom=$IMGDIR - - echo "PASSED $test" - -done diff --git a/test/jdk/jdk/crac/Selector/wakeupByClose/Test.java b/test/jdk/jdk/crac/Selector/wakeupByClose/Test.java index 50d8ab89ace..38a755e7d72 100644 --- a/test/jdk/jdk/crac/Selector/wakeupByClose/Test.java +++ b/test/jdk/jdk/crac/Selector/wakeupByClose/Test.java @@ -18,16 +18,45 @@ // CA 94089 USA or visit www.azul.com if you need additional information or // have any questions. +import jdk.test.lib.crac.CracBuilder; +import jdk.test.lib.crac.CracTest; +import jdk.test.lib.crac.CracTestArg; import java.nio.channels.Selector; import java.io.IOException; -public class Test { +/* + * @test Selector/wakeupByClose + * @summary check that the Selector's close() wakes it up after restore + * @library /test/lib + * @build Test + * @run driver jdk.test.lib.crac.CracTest true false + * @run driver jdk.test.lib.crac.CracTest false false + * @run driver jdk.test.lib.crac.CracTest true true + * @run driver jdk.test.lib.crac.CracTest false true + */ +public class Test implements CracTest { static boolean awakened, closed; - private static void test(boolean setTimeout, boolean skipCR) throws Exception { + @CracTestArg(0) + boolean setTimeout; + @CracTestArg(1) + boolean skipCR; + + @Override + public void test() throws Exception { + CracBuilder builder = new CracBuilder(); + if (skipCR) { + builder.doPlain(); + } else { + builder.doCheckpointAndRestore(); + } + } + + @Override + public void exec() throws Exception { Selector selector = Selector.open(); Thread tSelect = new Thread(new Runnable() { @@ -73,27 +102,5 @@ public void run() { throw new RuntimeException("selector did not close"); } } - - public static void main(String[] args) throws Exception { - - if (args.length < 1) { throw new RuntimeException("test number is missing"); } - - switch (args[0]) { - case "1": - test(true, false); - break; - case "2": - test(false, false); - break; - // 3, 4: skip C/R - case "3": - test(true, true); - break; - case "4": - test(false, true); - break; - default: - throw new RuntimeException("invalid test number"); - } - } } + diff --git a/test/jdk/jdk/crac/Selector/wakeupByClose/Test.sh b/test/jdk/jdk/crac/Selector/wakeupByClose/Test.sh deleted file mode 100644 index 30de06a1090..00000000000 --- a/test/jdk/jdk/crac/Selector/wakeupByClose/Test.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/sh - -# Copyright 2019-2020 Azul Systems, Inc. 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 Azul Systems, 385 Moffett Park Drive, Suite 115, Sunnyvale, -# CA 94089 USA or visit www.azul.com if you need additional information or -# have any questions. - - -## -## @test Test.sh -## @summary check that the Selector's close() wakes it up after restore -## @compile Test.java -## @run shell/timeout=60 Test.sh -## - - -set -x - -for test in `seq 1 2` -do - - IMGDIR="cr$test" - - set +e - ${TESTJAVA}/bin/java -cp ${TESTCLASSPATH} -XX:CRaCCheckpointTo=$IMGDIR Test $test - e=$? - - set -e - [ $e -eq 137 ] - - ${TESTJAVA}/bin/java -XX:CRaCRestoreFrom=$IMGDIR - - echo "PASSED $test" - -done - - -${TESTJAVA}/bin/java -cp ${TESTCLASSPATH} Test 3 -echo "PASSED 3" - -${TESTJAVA}/bin/java -cp ${TESTCLASSPATH} Test 4 -echo "PASSED 4" diff --git a/test/jdk/jdk/crac/Selector/wakeupByTimeoutAfterRestore/Test.java b/test/jdk/jdk/crac/Selector/wakeupByTimeoutAfterRestore/Test.java index e94d56d4db0..5b3d8915f05 100644 --- a/test/jdk/jdk/crac/Selector/wakeupByTimeoutAfterRestore/Test.java +++ b/test/jdk/jdk/crac/Selector/wakeupByTimeoutAfterRestore/Test.java @@ -18,18 +18,33 @@ // CA 94089 USA or visit www.azul.com if you need additional information or // have any questions. +import jdk.test.lib.crac.CracBuilder; +import jdk.test.lib.crac.CracTest; import java.nio.channels.Selector; import java.io.IOException; -public class Test { +/* + * @test Selector/wakeupByTimeoutAfterRestore + * @summary check that the Selector selected before the checkpoint, + * will wake up by timeout after the restore + * @library /test/lib + * @build Test + * @run driver jdk.test.lib.crac.CracTest + */ +public class Test implements CracTest { private final static long TIMEOUT = 40_000; // 40 seconds static boolean awakened = false; - public static void main(String args[]) throws Exception { + @Override + public void test() throws Exception { + new CracBuilder().doCheckpointAndRestore(); + } + @Override + public void exec() throws Exception { Selector selector = Selector.open(); Runnable r = new Runnable() { @Override diff --git a/test/jdk/jdk/crac/Selector/wakeupByTimeoutAfterRestore/Test.sh b/test/jdk/jdk/crac/Selector/wakeupByTimeoutAfterRestore/Test.sh deleted file mode 100644 index e55ea143599..00000000000 --- a/test/jdk/jdk/crac/Selector/wakeupByTimeoutAfterRestore/Test.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/sh - -# Copyright 2019-2020 Azul Systems, Inc. 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 Azul Systems, 385 Moffett Park Drive, Suite 115, Sunnyvale, -# CA 94089 USA or visit www.azul.com if you need additional information or -# have any questions. - - -## -## @test Test.sh -## @summary check that the Selector selected before the checkpoint, -## will wake up by timeout after the restore -## @compile Test.java -## @run shell/timeout=120 Test.sh -## - -set -x - -set +e -${TESTJAVA}/bin/java -cp ${TESTCLASSPATH} -XX:CRaCCheckpointTo=cr Test -e=$? - -set -e -[ $e -eq 137 ] - -${TESTJAVA}/bin/java -XX:CRaCRestoreFrom=cr - -echo PASSED diff --git a/test/jdk/jdk/crac/CheckpointRestore.java b/test/jdk/jdk/crac/fileDescriptors/CheckpointWithOpenFdsTest.java similarity index 56% rename from test/jdk/jdk/crac/CheckpointRestore.java rename to test/jdk/jdk/crac/fileDescriptors/CheckpointWithOpenFdsTest.java index 46eef31b8f3..54ca7aad8e4 100644 --- a/test/jdk/jdk/crac/CheckpointRestore.java +++ b/test/jdk/jdk/crac/fileDescriptors/CheckpointWithOpenFdsTest.java @@ -4,9 +4,7 @@ * * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. + * 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 @@ -23,14 +21,31 @@ * questions. */ -import jdk.crac.CheckpointException; import jdk.crac.Core; -import jdk.crac.RestoreException; +import jdk.test.lib.Utils; +import jdk.test.lib.crac.CracBuilder; +import jdk.test.lib.crac.CracTest; +import java.nio.file.Path; +import java.util.*; -class CheckpointRestore { - static final String RESTORED_MESSAGE = "Restored"; +/** + * @test + * @library /test/lib + * @build CheckpointWithOpenFdsTest + * @run driver jdk.test.lib.crac.CracTest + */ +public class CheckpointWithOpenFdsTest implements CracTest { + private static final String EXTRA_FD_WRAPPER = Path.of(Utils.TEST_SRC, "extra_fd_wrapper.sh").toString(); + + @Override + public void test() throws Exception { + CracBuilder builder = new CracBuilder(); + builder.startCheckpoint(Arrays.asList(EXTRA_FD_WRAPPER, CracBuilder.JAVA)).waitForCheckpointed(); + builder.captureOutput(true).doRestore().outputAnalyzer().shouldContain(RESTORED_MESSAGE); + } - public static void main(String[] args) throws CheckpointException, RestoreException { + @Override + public void exec() throws Exception { Core.checkpointRestore(); System.out.println(RESTORED_MESSAGE); } diff --git a/test/jdk/jdk/crac/fileDescriptors/IgnoredFileDescriptorsTest.java b/test/jdk/jdk/crac/fileDescriptors/IgnoredFileDescriptorsTest.java new file mode 100644 index 00000000000..1324e9e7918 --- /dev/null +++ b/test/jdk/jdk/crac/fileDescriptors/IgnoredFileDescriptorsTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2023, Azul Systems, Inc. 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 jdk.crac.Core; +import jdk.test.lib.Utils; +import jdk.test.lib.crac.CracBuilder; +import jdk.test.lib.crac.CracTest; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @test + * @library /test/lib + * @build IgnoredFileDescriptorsTest + * @run driver jdk.test.lib.crac.CracTest + */ +public class IgnoredFileDescriptorsTest implements CracTest { + private static final String EXTRA_FD_WRAPPER = Path.of(Utils.TEST_SRC, "extra_fd_wrapper.sh").toString(); + + @Override + public void test() throws Exception { + List prefix = new ArrayList<>(); + prefix.add(EXTRA_FD_WRAPPER); + prefix.addAll(Arrays.asList("-o", "43", "/dev/stdout")); + prefix.addAll(Arrays.asList("-o", "45", "/dev/urandom")); + prefix.add(CracBuilder.JAVA); + prefix.add("-XX:CRaCIgnoredFileDescriptors=43,/dev/null,44,/dev/urandom"); + + CracBuilder builder = new CracBuilder(); + builder.startCheckpoint(prefix).waitForCheckpointed(); + builder.captureOutput(true).doRestore().outputAnalyzer().shouldContain(RESTORED_MESSAGE); + } + + @Override + public void exec() throws Exception { + try (var stream = Files.list(Path.of("/proc/self/fd"))) { + Map fds = stream.filter(Files::isSymbolicLink) + .collect(Collectors.toMap( + f -> Integer.parseInt(f.toFile().getName()), + f -> { + try { + return Files.readSymbolicLink(f).toFile().getAbsoluteFile().toString(); + } catch (IOException e) { + throw new RuntimeException(e); + } + })); + if (fds.containsKey(42)) { + throw new IllegalStateException("Oh no, 42 was not supposed to be ignored"); + } else if (!fds.containsKey(0) || !fds.containsKey(1) || !fds.containsKey(2)) { + throw new IllegalStateException("Missing standard I/O? Available: " + fds); + } else if (!fds.containsKey(43)) { + throw new IllegalStateException("Missing FD 43"); + } else if (!fds.containsValue("/dev/urandom")) { + throw new IllegalStateException("Missing /dev/urandom"); + } + } + Core.checkpointRestore(); + System.out.println(RESTORED_MESSAGE); + } +} diff --git a/test/jdk/jdk/crac/extra_fd_wrapper.sh b/test/jdk/jdk/crac/fileDescriptors/extra_fd_wrapper.sh similarity index 100% rename from test/jdk/jdk/crac/extra_fd_wrapper.sh rename to test/jdk/jdk/crac/fileDescriptors/extra_fd_wrapper.sh diff --git a/test/jdk/jdk/crac/java/lang/Thread/JoinSleepWaitOnCRPauseTest.java b/test/jdk/jdk/crac/java/lang/Thread/JoinSleepWaitOnCRPauseTest.java index 0245adec558..02a759f5a6d 100644 --- a/test/jdk/jdk/crac/java/lang/Thread/JoinSleepWaitOnCRPauseTest.java +++ b/test/jdk/jdk/crac/java/lang/Thread/JoinSleepWaitOnCRPauseTest.java @@ -21,6 +21,11 @@ * questions. */ +import jdk.test.lib.crac.CracBuilder; +import jdk.test.lib.crac.CracTest; +import jdk.test.lib.crac.CracTestArg; + +import java.util.concurrent.CountDownLatch; /* * @test JoinSleepWaitOnCRPauseTest.java * @requires (os.family == "linux") @@ -31,26 +36,21 @@ * if their end time fell on the CRaC pause period * (i.e. between the checkpoint and restore) * - * @run main/othervm JoinSleepWaitOnCRPauseTest join_ms - * @run main/othervm JoinSleepWaitOnCRPauseTest join_ns - * @run main/othervm JoinSleepWaitOnCRPauseTest sleep_ms - * @run main/othervm JoinSleepWaitOnCRPauseTest sleep_ns - * @run main/othervm JoinSleepWaitOnCRPauseTest wait_ms - * @run main/othervm JoinSleepWaitOnCRPauseTest wait_ns + * @build JoinSleepWaitOnCRPauseTest + * @run driver jdk.test.lib.crac.CracTest join_ms + * @run driver jdk.test.lib.crac.CracTest join_ns + * @run driver jdk.test.lib.crac.CracTest sleep_ms + * @run driver jdk.test.lib.crac.CracTest sleep_ns + * @run driver jdk.test.lib.crac.CracTest wait_ms + * @run driver jdk.test.lib.crac.CracTest wait_ns */ +public class JoinSleepWaitOnCRPauseTest implements CracTest { + private enum TestType { + join_ms, join_ns, sleep_ms, sleep_ns, wait_ms, wait_ns + } - -import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; - -import java.util.concurrent.CountDownLatch; - - -public class JoinSleepWaitOnCRPauseTest { - - private static enum TestType { - join_ms, join_ns, sleep_ms, sleep_ns, wait_ms, wait_ns}; - private final TestType testType; + @CracTestArg + private TestType testType; private final static long EPS_NS = Long.parseLong(System.getProperty( "test.jdk.jdk.crac.java.lang.Thread.crac.JoinSleepWaitOnCRPauseTest.eps", @@ -65,12 +65,8 @@ private static enum TestType { private final CountDownLatch checkpointLatch = new CountDownLatch(1); - - private JoinSleepWaitOnCRPauseTest(TestType testType) { - this.testType = testType; - } - - private void runTest() throws Exception { + @Override + public void exec() throws Exception { String op = testType.name(); op = op.substring(0, op.length() - 3); // remove suffix @@ -166,36 +162,16 @@ private void runTest() throws Exception { } } + @Override + public void test() throws Exception { + CracBuilder builder = new CracBuilder() + .imageDir("cr_" + testType.name()); + builder.doCheckpoint(); - public static void main(String args[]) throws Exception { - - if (args.length > 1) { - - new JoinSleepWaitOnCRPauseTest( - TestType.valueOf(args[0])).runTest(); - - } else if (args.length > 0) { - - String crImg = "cr_" + args[0]; + // sleep a few seconds to ensure the task execution time + // falls within this pause period + Thread.sleep(CRPAUSE_MS); - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( - "-XX:CRaCCheckpointTo=" + crImg, "JoinSleepWaitOnCRPauseTest", - args[0], "runTest"); - OutputAnalyzer out = new OutputAnalyzer(pb.start()); - out.shouldContain("CR: Checkpoint"); - out.shouldHaveExitValue(137); - - // sleep a few seconds to ensure the task execution time - // falls within this pause period - Thread.sleep(CRPAUSE_MS); - - pb = ProcessTools.createJavaProcessBuilder("-XX:CRaCRestoreFrom=" + crImg); - out = new OutputAnalyzer(pb.start()); - out.shouldHaveExitValue(0); - - } else { - - throw new IllegalArgumentException("please provide a test type"); - } + builder.doRestore(); } } diff --git a/test/jdk/jdk/crac/java/net/InetAddress/ResolveInetAddress.java b/test/jdk/jdk/crac/java/net/InetAddress/ResolveInetAddress.java deleted file mode 100644 index ad0783f1970..00000000000 --- a/test/jdk/jdk/crac/java/net/InetAddress/ResolveInetAddress.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2023, Azul Systems, Inc. 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.net.InetAddress; -import java.net.UnknownHostException; -import java.nio.file.Files; -import java.nio.file.Path; - -public class ResolveInetAddress { - public static void main(String[] args) { - if (args.length < 2) { - System.err.println("Args: "); - return; - } - printAddress(args[0]); - while (!Files.exists(Path.of(args[1]))) { - try { - //noinspection BusyWait - Thread.sleep(100); - } catch (InterruptedException e) { - System.err.println("Interrupted!"); - return; - } - } - printAddress(args[0]); - } - - private static void printAddress(String hostname) { - try { - InetAddress address = InetAddress.getByName(hostname); - // we will assume IPv4 address - byte[] bytes = address.getAddress(); - System.out.print(bytes[0] & 0xFF); - for (int i = 1; i < bytes.length; ++i) { - System.out.print('.'); - System.out.print(bytes[i] & 0xFF); - } - System.out.println(); - } catch (UnknownHostException e) { - System.out.println(); - } - } -} diff --git a/test/jdk/jdk/crac/java/net/InetAddress/ResolveTest.java b/test/jdk/jdk/crac/java/net/InetAddress/ResolveTest.java index 1a8766d8b51..921f3a5478b 100644 --- a/test/jdk/jdk/crac/java/net/InetAddress/ResolveTest.java +++ b/test/jdk/jdk/crac/java/net/InetAddress/ResolveTest.java @@ -21,143 +21,108 @@ * questions. */ -import jdk.test.lib.Container; import jdk.test.lib.Utils; import jdk.test.lib.containers.docker.Common; -import jdk.test.lib.containers.docker.DockerRunOptions; import jdk.test.lib.containers.docker.DockerTestUtils; -import jdk.test.lib.process.StreamPumper; +import jdk.test.lib.crac.CracBuilder; +import jdk.test.lib.crac.CracProcess; +import jdk.test.lib.crac.CracTest; +import jdk.test.lib.crac.CracTestArg; -import java.io.IOException; -import java.io.InputStream; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; import java.util.concurrent.*; -import java.util.function.Consumer; /* * @test * @summary Test if InetAddress cache is flushed after checkpoint/restore * @requires docker.support * @library /test/lib - * @modules java.base/jdk.crac - * @build ResolveInetAddress - * @run main/timeout=360 ResolveTest + * @build ResolveTest + * @run driver jdk.test.lib.crac.CracTest */ -public class ResolveTest { +public class ResolveTest implements CracTest { private static final String imageName = Common.imageName("inet-address"); public static final String TEST_HOSTNAME = "some.test.hostname.example.com"; - public static final String CONTAINER_NAME = "test-inet-address"; - public static final String CRAC_CRIU_PATH; - static { - String path = System.getenv("CRAC_CRIU_PATH"); - if (path == null) { - path = Utils.TEST_JDK + "/lib/criu"; - } - CRAC_CRIU_PATH = path; - } + @CracTestArg(value = 0, optional = true) + String ip; + + @CracTestArg(value = 1, optional = true) + String checkFile; - public static void main(String[] args) throws Exception { + @Override + public void test() throws Exception { if (!DockerTestUtils.canTestDocker()) { return; } - if (!Files.exists(Path.of(CRAC_CRIU_PATH))) { - throw new RuntimeException("criu cannot be found in " + CRAC_CRIU_PATH); - } - DockerTestUtils.buildJdkDockerImage(imageName, "Dockerfile-is-ignored", "jdk-docker"); - try { - Future completed = startTestProcess(); - checkpointTestProcess(); - completed.get(5, TimeUnit.SECONDS); - startRestoredProcess(); - } finally { - ensureContainerDead(); - DockerTestUtils.removeDockerImage(imageName); - } - } - - private static Future startTestProcess() throws Exception { - ensureContainerDead(); + CracBuilder builder = new CracBuilder() + .inDockerImage(imageName).dockerOptions("--add-host", TEST_HOSTNAME + ":192.168.12.34") + .captureOutput(true) + .args(CracTest.args(TEST_HOSTNAME, "/second-run")); - List cmd = new ArrayList<>(); - cmd.add(Container.ENGINE_COMMAND); - cmd.addAll(Arrays.asList("run", "--rm", "--add-host", TEST_HOSTNAME + ":192.168.12.34")); - cmd.addAll(Arrays.asList("--volume", Utils.TEST_CLASSES + ":/test-classes/")); - cmd.addAll(Arrays.asList("--volume", "cr:/cr")); - cmd.addAll(Arrays.asList("--volume", CRAC_CRIU_PATH + ":/criu")); - cmd.addAll(Arrays.asList("--env", "CRAC_CRIU_PATH=/criu")); - cmd.addAll(Arrays.asList("--entrypoint", "bash")); - // checkpoint-restore does not work without this: TODO fine-grained --cap-add - cmd.add("--privileged"); - cmd.addAll(Arrays.asList("--name", CONTAINER_NAME)); - cmd.add(imageName); - // Checkpointing does not work for PID 1, therefore we add an intermediary bash process - List javaCmd = new ArrayList<>(); - javaCmd.addAll(Arrays.asList("/jdk/bin/java", "-cp /test-classes/", "-XX:CRaCCheckpointTo=/cr")); - javaCmd.addAll(Arrays.asList(Utils.getTestJavaOpts())); - javaCmd.addAll(Arrays.asList("ResolveInetAddress", TEST_HOSTNAME, "/second-run")); - cmd.addAll(Arrays.asList("-c", String.join(" ", javaCmd) + "; echo i-am-here-to-force-child-process")); - - System.err.println("Running: " + String.join(" ", cmd)); - - CompletableFuture firstOutputFuture = new CompletableFuture(); - Future completed = executeWatching(cmd, line -> { - System.out.println("OUTPUT: " + line); - if (line.equals("192.168.12.34")) { - firstOutputFuture.complete(null); - } - }, error -> { - System.err.println("ERROR: " + error); - firstOutputFuture.cancel(false); - }); - firstOutputFuture.get(10, TimeUnit.SECONDS); - return completed; - } + try { + CompletableFuture firstOutputFuture = new CompletableFuture(); + CracProcess checkpointed = builder.startCheckpoint().watch(line -> { + System.out.println("OUTPUT: " + line); + if (line.equals("192.168.12.34")) { + firstOutputFuture.complete(null); + } + }, error -> { + System.err.println("ERROR: " + error); + firstOutputFuture.cancel(false); + }); + firstOutputFuture.get(10, TimeUnit.SECONDS); + builder.checkpointViaJcmd(); + checkpointed.waitForCheckpointed(); - private static void ensureContainerDead() throws Exception { - // ensure the container is not running, ignore if not present - DockerTestUtils.execute("docker", "kill", CONTAINER_NAME).getExitValue(); - } + builder.recreateContainer(imageName, + "--add-host", TEST_HOSTNAME + ":192.168.56.78", + "--volume", Utils.TEST_CLASSES + ":/second-run"); // any file/dir suffices - private static void checkpointTestProcess() throws Exception { - DockerTestUtils.execute("docker", "exec", CONTAINER_NAME, - "/jdk/bin/jcmd", ResolveInetAddress.class.getName(), "JDK.checkpoint") - .shouldHaveExitValue(0); - } - private static Future executeWatching(List command, Consumer outputConsumer, Consumer errorConsumer) throws IOException, ExecutionException, InterruptedException, TimeoutException { - ProcessBuilder pb = new ProcessBuilder(command); - Process p = pb.start(); - Future outputPumper = pump(p.getInputStream(), outputConsumer); - Future errorPumper = pump(p.getErrorStream(), errorConsumer); - return outputPumper; + builder.startRestore().outputAnalyzer() + .shouldHaveExitValue(0) + .shouldContain("192.168.56.78"); + } finally { + builder.ensureContainerKilled(); + } } - private static Future pump(InputStream stream, Consumer consumer) { - return new StreamPumper(stream).addPump(new StreamPumper.LinePump() { - @Override - protected void processLine(String line) { - consumer.accept(line); + @Override + public void exec() throws Exception { + if (ip == null || checkFile == null) { + System.err.println("Args: "); + return; + } + printAddress(ip); + while (!Files.exists(Path.of(checkFile))) { + try { + //noinspection BusyWait + Thread.sleep(100); + } catch (InterruptedException e) { + System.err.println("Interrupted!"); + return; } - }).process(); + } + printAddress(ip); } - private static void startRestoredProcess() throws Exception { - DockerRunOptions opts = new DockerRunOptions(imageName, "/jdk/bin/java", "ResolveInetAddress"); - opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/"); - opts.addDockerOpts("--volume", "cr:/cr"); - opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/second-run"); // any file suffices - opts.addDockerOpts("--volume", CRAC_CRIU_PATH + ":/criu"); - opts.addDockerOpts("--env", "CRAC_CRIU_PATH=/criu"); - opts.addDockerOpts("--add-host", TEST_HOSTNAME + ":192.168.56.78"); - opts.addDockerOpts("--privileged"); - opts.addJavaOpts("-XX:CRaCRestoreFrom=/cr"); - DockerTestUtils.dockerRunJava(opts) - .shouldHaveExitValue(0) - .shouldContain("192.168.56.78"); + private static void printAddress(String hostname) { + try { + InetAddress address = InetAddress.getByName(hostname); + // we will assume IPv4 address + byte[] bytes = address.getAddress(); + System.out.print(bytes[0] & 0xFF); + for (int i = 1; i < bytes.length; ++i) { + System.out.print('.'); + System.out.print(bytes[i] & 0xFF); + } + System.out.println(); + } catch (UnknownHostException e) { + System.out.println(); + } } } diff --git a/test/jdk/jdk/crac/recursiveCheckpoint/Test.java b/test/jdk/jdk/crac/recursiveCheckpoint/Test.java index 1638e9a4b05..d5f918621c8 100644 --- a/test/jdk/jdk/crac/recursiveCheckpoint/Test.java +++ b/test/jdk/jdk/crac/recursiveCheckpoint/Test.java @@ -18,16 +18,37 @@ // CA 94089 USA or visit www.azul.com if you need additional information or // have any questions. - import jdk.crac.*; -import java.util.concurrent.atomic.AtomicInteger; - +import jdk.test.lib.crac.*; -public class Test implements Resource { +import java.util.concurrent.atomic.AtomicInteger; +/* + * @test + * @summary check that the recursive checkpoint is not allowed + * @library /test/lib + * @build Test + * @run driver/timeout=60 jdk.test.lib.crac.CracTest 10 + */ +public class Test implements Resource, CracTest { private static final AtomicInteger counter = new AtomicInteger(0); private static Exception exception = null; + @CracTestArg + int numThreads; + + @Override + public void test() throws Exception { + CracBuilder builder = new CracBuilder().engine(CracEngine.PAUSE); + CracProcess process = builder.startCheckpoint(); + process.waitForPausePid(); + for (int i = 1; i <= numThreads + 1; ++i) { + System.err.printf("Restore #%d%n", i); + builder.doRestore(); + } + process.waitForSuccess(); + } + private static class TestThread extends Thread { @Override @@ -86,24 +107,17 @@ public void afterRestore(Context context) throws Exception { } } - public static void main(String args[]) throws Exception { - if (args.length < 1) { throw new RuntimeException("number of threads is missing"); } - int numThreads; - try{ - numThreads = Integer.parseInt(args[0]); - } catch (NumberFormatException ex){ - throw new RuntimeException("invalid number of threads"); - } - + @Override + public void exec() throws Exception { Core.getGlobalContext().register(new Test()); TestThread[] threads = new TestThread[numThreads]; - for(int i=0; i CRIU_CANDIDATES = Arrays.asList(Utils.TEST_JDK + "/lib/criu", "/usr/sbin/criu", "/sbin/criu"); + private static final String CRIU_PATH; + + // This dummy field is here as workaround for (possibly) a JTReg bug; + // some tests don't build CracTestArg into their Test.d/ directory + // (not all classes from /test/lib are built!) and the tests would fail. + // This does not always happen when the test is run individually but breaks + // when the whole suite is executed. + private static final Class dummyWorkaround = CracTestArg.class; + + boolean verbose = true; + boolean debug = false; + final List classpathEntries = new ArrayList<>(); + final Map env = new HashMap<>(); + String imageDir = DEFAULT_IMAGE_DIR; + CracEngine engine; + boolean printResources; + Class main; + String[] args; + boolean captureOutput; + String dockerImageName; + private String[] dockerOptions; + + boolean containerStarted; + + static { + String path = System.getenv("CRAC_CRIU_PATH"); + if (path == null) { + for (String candidate : CRIU_CANDIDATES) { + if (new File(candidate).exists()) { + path = candidate; + break; + } + } + } + CRIU_PATH = path; + } + + public CracBuilder() { + } + + public CracBuilder verbose(boolean verbose) { + this.verbose = verbose; + return this; + } + + public CracBuilder debug(boolean debug) { + this.debug = debug; + return this; + } + + public CracBuilder classpathEntry(String cp) { + classpathEntries.add(cp); + return this; + } + + public CracBuilder engine(CracEngine engine) { + assertNull(this.engine); // set once + this.engine = engine; + return this; + } + + public Path imageDir() { + return Path.of(imageDir); + } + + public CracBuilder imageDir(String imageDir) { + assertEquals(DEFAULT_IMAGE_DIR, this.imageDir); // set once + this.imageDir = imageDir; + return this; + } + + public CracBuilder printResources(boolean print) { + this.printResources = print; + return this; + } + + public CracBuilder env(String name, String value) { + env.put(name, value); + return this; + } + + public CracBuilder main(Class mainClass) { + assertNull(this.main); // set once + this.main = mainClass; + return this; + } + + public Class main() { + return main != null ? main : CracTest.class; + } + + public CracBuilder args(String... args) { + assertNull(this.args); // set once + this.args = args; + return this; + } + + public String[] args() { + return args != null ? args : CracTest.args(); + } + + public CracBuilder captureOutput(boolean captureOutput) { + this.captureOutput = captureOutput; + return this; + } + + public CracBuilder inDockerImage(String imageName) { + assertNull(dockerImageName); + this.dockerImageName = imageName; + return this; + } + + public CracBuilder dockerOptions(String... options) { + assertNull(dockerOptions); + this.dockerOptions = options; + return this; + } + + public void doCheckpoint() throws Exception { + startCheckpoint().waitForCheckpointed(); + } + + public CracProcess startCheckpoint() throws Exception { + return startCheckpoint(null); + } + + public CracProcess startCheckpoint(List javaPrefix) throws Exception { + ensureContainerStarted(); + List cmd = prepareCommand(javaPrefix); + cmd.add("-XX:CRaCCheckpointTo=" + imageDir); + cmd.add(main().getName()); + cmd.addAll(Arrays.asList(args())); + log("Starting process to be checkpointed:"); + log(String.join(" ", cmd)); + return new CracProcess(this, cmd); + } + + void log(String fmt, Object... args) { + if (verbose) { + if (args.length == 0) { + System.err.println(fmt); + } else { + System.err.printf(fmt, args); + } + } + } + + private void ensureContainerStarted() throws Exception { + if (dockerImageName == null) { + return; + } + if (CRIU_PATH == null) { + fail("CRAC_CRIU_PATH is not set and cannot find criu executable in any of: " + CRIU_CANDIDATES); + } + if (!containerStarted) { + ensureContainerKilled(); + DockerTestUtils.buildJdkDockerImage(dockerImageName, "Dockerfile-is-ignored", "jdk-docker"); + FileUtils.deleteFileTreeWithRetry(Path.of(".", "jdk-docker")); + // Make sure we start with a clean image directory + DockerTestUtils.execute(Container.ENGINE_COMMAND, "volume", "rm", "cr"); + List cmd = prepareContainerCommand(dockerImageName, dockerOptions); + log("Starting docker container:\n" + String.join(" ", cmd)); + assertEquals(0, new ProcessBuilder().inheritIO().command(cmd).start().waitFor()); + containerStarted = true; + } + } + + private List prepareContainerCommand(String imageName, String[] options) { + List cmd = new ArrayList<>(); + cmd.add(Container.ENGINE_COMMAND); + cmd.addAll(Arrays.asList("run", "--rm", "-d")); + cmd.add("--privileged"); // required to give CRIU sufficient permissions + cmd.add("--init"); // otherwise the checkpointed process would not be reaped (by sleep with PID 1) + int entryCounter = 0; + for (var entry : Utils.TEST_CLASS_PATH.split(File.pathSeparator)) { + cmd.addAll(Arrays.asList("--volume", entry + ":/cp/" + (entryCounter++))); + } + cmd.addAll(Arrays.asList("--volume", "cr:/cr")); + cmd.addAll(Arrays.asList("--volume", CRIU_PATH + ":/criu")); + cmd.addAll(Arrays.asList("--env", "CRAC_CRIU_PATH=/criu")); + cmd.addAll(Arrays.asList("--name", CONTAINER_NAME)); + if (debug) { + cmd.addAll(Arrays.asList("--publish", "5005:5005")); + } + if (options != null) { + cmd.addAll(Arrays.asList(options)); + } + cmd.add(imageName); + cmd.addAll(Arrays.asList("sleep", "3600")); + return cmd; + } + + public void ensureContainerKilled() throws Exception { + DockerTestUtils.execute(Container.ENGINE_COMMAND, "kill", CONTAINER_NAME).getExitValue(); + DockerTestUtils.removeDockerImage(dockerImageName); + } + + public void recreateContainer(String imageName, String... options) throws Exception { + assertTrue(containerStarted); + String minPid = DockerTestUtils.execute(Container.ENGINE_COMMAND, "exec", CONTAINER_NAME, + "cat", "/proc/sys/kernel/ns_last_pid").getStdout().trim(); + DockerTestUtils.execute(Container.ENGINE_COMMAND, "kill", CONTAINER_NAME).getExitValue(); + List cmd = prepareContainerCommand(imageName, options); + log("Recreating docker container:\n" + String.join(" ", cmd)); + assertEquals(0, new ProcessBuilder().inheritIO().command(cmd).start().waitFor()); + // We need to cycle PIDs; had we tried to restore right away the exec would get the + // same PIDs and restore would fail. + log("Cycling PIDs until %s%n", minPid); + DockerTestUtils.execute(Container.ENGINE_COMMAND, "exec", + CONTAINER_NAME, "bash", "-c", + "while [ $(cat /proc/sys/kernel/ns_last_pid) -le " + minPid + " ]; do cat /dev/null; done"); + } + + public CracProcess doRestore() throws Exception { + return startRestore().waitForSuccess(); + } + + public CracProcess startRestore() throws Exception { + return startRestore(null); + } + public CracProcess startRestore(List prefixJava) throws Exception { + ensureContainerStarted(); + List cmd = prepareCommand(prefixJava); + cmd.add("-XX:CRaCRestoreFrom=" + imageDir); + log("Starting restored process:"); + log(String.join(" ", cmd)); + return new CracProcess(this, cmd); + } + + public CracProcess startPlain() throws IOException { + List cmd = new ArrayList<>(); + if (dockerImageName != null) { + cmd.addAll(Arrays.asList(Container.ENGINE_COMMAND, "exec", CONTAINER_NAME)); + } + cmd.add(JAVA); + cmd.add("-ea"); + cmd.add("-cp"); + cmd.add(getClassPath()); + if (debug) { + cmd.add("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=0.0.0.0:5005"); + } + cmd.add(main().getName()); + cmd.addAll(Arrays.asList(args())); + log("Starting process without CRaC:"); + log(String.join(" ", cmd)); + return new CracProcess(this, cmd); + } + + private String getClassPath() { + String classPath = classpathEntries.isEmpty() ? "" : String.join(File.pathSeparator, classpathEntries) + File.pathSeparator; + if (dockerImageName == null) { + classPath += Utils.TEST_CLASS_PATH; + } else { + int numEntries = Utils.TEST_CLASS_PATH.split(File.pathSeparator).length; + for (int i = 0; i < numEntries; ++i) { + classPath += "/cp/" + i + File.pathSeparator; + } + } + return classPath; + } + + public CracProcess doPlain() throws IOException, InterruptedException { + return startPlain().waitForSuccess(); + } + + private List prepareCommand(List javaPrefix) { + List cmd = new ArrayList<>(); + if (javaPrefix != null) { + cmd.addAll(javaPrefix); + } else if (dockerImageName != null) { + cmd.addAll(Arrays.asList(Container.ENGINE_COMMAND, "exec", CONTAINER_NAME)); + cmd.add(DOCKER_JAVA); + } else { + cmd.add(JAVA); + } + cmd.add("-ea"); + cmd.add("-cp"); + cmd.add(getClassPath()); + if (engine != null) { + cmd.add("-XX:CREngine=" + engine.engine); + } + if (printResources) { + cmd.add("-XX:+UnlockDiagnosticVMOptions"); + cmd.add("-XX:+CRPrintResourcesOnCheckpoint"); + } + if (debug) { + cmd.add("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=0.0.0.0:5005"); + cmd.add("-XX:-CRDoThrowCheckpointException"); + } + return cmd; + } + + public void doCheckpointAndRestore() throws Exception { + doCheckpoint(); + doRestore(); + } + + public void checkpointViaJcmd() throws Exception { + List cmd = new ArrayList<>(); + if (dockerImageName != null) { + cmd.addAll(Arrays.asList(Container.ENGINE_COMMAND, "exec", CONTAINER_NAME, "/jdk/bin/jcmd")); + } else { + cmd.add(Utils.TEST_JDK + "/bin/jcmd"); + } + cmd.addAll(Arrays.asList(main().getName(), "JDK.checkpoint")); + // This works for non-docker commands, too + DockerTestUtils.execute(cmd).shouldHaveExitValue(0); + } + +} diff --git a/test/lib/jdk/test/lib/crac/CracEngine.java b/test/lib/jdk/test/lib/crac/CracEngine.java new file mode 100644 index 00000000000..79caef8ff2a --- /dev/null +++ b/test/lib/jdk/test/lib/crac/CracEngine.java @@ -0,0 +1,13 @@ +package jdk.test.lib.crac; + +public enum CracEngine { + CRIU("criuengine"), + PAUSE("pauseengine"), + SIMULATE("simengine"); + + public final String engine; + + CracEngine(String engine) { + this.engine = engine; + } +} diff --git a/test/lib/jdk/test/lib/crac/CracProcess.java b/test/lib/jdk/test/lib/crac/CracProcess.java new file mode 100644 index 00000000000..ae75198f431 --- /dev/null +++ b/test/lib/jdk/test/lib/crac/CracProcess.java @@ -0,0 +1,107 @@ +package jdk.test.lib.crac; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.StreamPumper; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.*; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.stream.Stream; + +import static jdk.test.lib.Asserts.*; + +public class CracProcess { + private final CracBuilder builder; + private final Process process; + + public CracProcess(CracBuilder builder, List cmd) throws IOException { + this.builder = builder; + ProcessBuilder pb = new ProcessBuilder().inheritIO(); + if (builder.captureOutput) { + pb.redirectOutput(ProcessBuilder.Redirect.PIPE); + pb.redirectError(ProcessBuilder.Redirect.PIPE); + } + pb.environment().putAll(builder.env); + this.process = pb.command(cmd).start(); + } + + public int waitFor() throws InterruptedException { + return process.waitFor(); + } + + public void waitForCheckpointed() throws InterruptedException { + if (builder.engine == null || builder.engine == CracEngine.CRIU) { + assertEquals(137, process.waitFor(), "Checkpointed process was not killed as expected."); + // TODO: we could check that "CR: Checkpoint" was written out + } else { + fail("With engine " + builder.engine.engine + " use the async version."); + } + } + + public void waitForPausePid() throws IOException, InterruptedException { + assertEquals(CracEngine.PAUSE, builder.engine, "Pause PID file created only with pauseengine"); + try (WatchService watcher = FileSystems.getDefault().newWatchService()) { + Path imageDir = builder.imageDir().toAbsolutePath(); + waitForFileCreated(watcher, imageDir.getParent(), path -> "cr".equals(path.toFile().getName())); + waitForFileCreated(watcher, imageDir, path -> "pid".equals(path.toFile().getName())); + } + } + + private void waitForFileCreated(WatchService watcher, Path dir, Predicate predicate) throws IOException, InterruptedException { + WatchKey key = dir.register(watcher, StandardWatchEventKinds.ENTRY_CREATE); + assertTrue(key.isValid()); + try { + try (Stream dirContents = Files.list(dir)) { + if (dirContents.anyMatch(predicate)) { + // file already present + return; + } + } + for (; ; ) { + WatchKey key2 = watcher.take(); + for (WatchEvent event : key2.pollEvents()) { + if (event.kind() != StandardWatchEventKinds.ENTRY_CREATE) { + continue; + } + if (predicate.test((Path) event.context())) { + return; + } + } + key2.reset(); + } + } finally { + key.cancel(); + } + } + + public CracProcess waitForSuccess() throws InterruptedException { + int exitValue = process.waitFor(); + assertEquals(0, exitValue, "Process returned unexpected exit code: " + exitValue); + builder.log("Process %d completed with exit value %d%n", process.pid(), exitValue); + return this; + } + + public OutputAnalyzer outputAnalyzer() throws IOException { + assertTrue(builder.captureOutput, "Output must be captured with .captureOutput(true)"); + return new OutputAnalyzer(process); + } + + public CracProcess watch(Consumer outputConsumer, Consumer errorConsumer) { + assertTrue(builder.captureOutput, "Output must be captured with .captureOutput(true)"); + pump(process.getInputStream(), outputConsumer); + pump(process.getErrorStream(), errorConsumer); + return this; + } + + private static void pump(InputStream stream, Consumer consumer) { + new StreamPumper(stream).addPump(new StreamPumper.LinePump() { + @Override + protected void processLine(String line) { + consumer.accept(line); + } + }).process(); + } +} diff --git a/test/lib/jdk/test/lib/crac/CracTest.java b/test/lib/jdk/test/lib/crac/CracTest.java new file mode 100644 index 00000000000..a4b01ec6f7d --- /dev/null +++ b/test/lib/jdk/test/lib/crac/CracTest.java @@ -0,0 +1,210 @@ +package jdk.test.lib.crac; + +import jdk.crac.Core; + +import java.lang.reflect.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Comparator; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Stream; + +import static jdk.test.lib.Asserts.*; + +/** + * CRaC tests usually consists of two parts; the test started by JTreg through the 'run' tag + * and subprocesses started by the test with various VM options. These are represented by the + * {@link #test()} and {@link #exec()} methods. + * CracTest use '@run driver jdk.test.crac.lib.CracTest' as the executable command; the main + * method in this class discovers the executed class from system properties passed by JTReg, + * instantiates the test (public no-arg constructor is needed), populates fields annotated + * with {@link CracTestArg} and executes the {@link #test()} method. + * The test method is expected to use {@link CracBuilder} to start another process. By default, + * CracBuilder invokes the test with arguments that will again instantiate and fill the instance + * and invoke the {@link #exec()} method. + */ +public interface CracTest { + + String RESTORED_MESSAGE = "Restored"; + + /** + * This method is called when JTReg invokes the test; it is supposed to start + * another process (most often using CRaC VM options) and validate its behaviour. + * + * @throws Exception + */ + void test() throws Exception; + + /** + * This method is invoked in the subprocess; this is where you're likely to call + * {@link Core#checkpointRestore()}. + * + * @throws Exception + */ + void exec() throws Exception; + + class ArgsHolder { + private static final String RUN_TEST = "__run_test__"; + private static Class testClass; + private static String[] args; + // This field is present as workaround for @build somehow missing + // the annotation when + private static final Class dummyField = CracTestArg.class; + } + + /** + * Main method for orchestrating the test. This should be called directly by JTReg. + */ + static void main(String[] args) throws Exception { + String testClassName; + if (args.length == 0 || !ArgsHolder.RUN_TEST.equals(args[0])) { + // We will look up the class name (and package) to avoid boilerplate in any @run invocation + String testFile = System.getProperty("test.file"); + String source = Files.readString(Path.of(testFile)).replace('\n', ' '); + Matcher clsMatcher = Pattern.compile("class\\s+(\\S+)\\s+(extends\\s+\\S+\\s+)?implements\\s+(\\S+\\s*,\\s*)*CracTest").matcher(source); + if (!clsMatcher.find()) { + fail("Cannot find test class in " + testFile + ", does it look like class implements CracTest?"); + } + testClassName = clsMatcher.group(1); + Matcher pkgMatcher = Pattern.compile("package\\s+([^;]+);").matcher(source); + if (pkgMatcher.find()) { + testClassName = pkgMatcher.group(1) + "." + testClassName; + } + } else { + testClassName = args[1]; + } + + // When we use CracTest as driver the file with test is not compiled without a @build tag. + // We could compile the class here and load it from a new classloader but since the test library + // is not compiled completely we could be missing some dependencies - this would be just too fragile. + Class testClass; + try { + testClass = Class.forName(testClassName); + } catch (ClassNotFoundException e) { + throw new ClassNotFoundException("Test class " + testClassName + " not found, add jtreg tag @build " + args[0], e); + } + if (CracTest.class.isAssignableFrom(testClass)) { + //noinspection unchecked + run((Class) testClass, args); + } else { + throw new IllegalArgumentException("Class " + testClass.getName() + " does not implement CracTest!"); + } + } + + /** + * This method should be invoked from the public static void main(String[]) method. + * + * @param testClass Class implementing the test. + * @param args Arguments received in the main method. + * @throws Exception + */ + static void run(Class testClass, String[] args) throws Exception { + assertNotNull(args); + ArgsHolder.testClass = testClass; + int argsOffset = 0; + if (args.length == 0 || !args[0].equals(ArgsHolder.RUN_TEST)) { + String[] newArgs = new String[args.length + 2]; + newArgs[0] = ArgsHolder.RUN_TEST; + newArgs[1] = testClass.getName(); + System.arraycopy(args, 0, newArgs, 2, args.length); + ArgsHolder.args = newArgs; + } else { + argsOffset = 2; + } + + try { + Constructor ctor = testClass.getConstructor(); + CracTest testInstance = ctor.newInstance(); + Field[] argFields = getArgFields(testClass); + for (int index = 0; index < argFields.length; index++) { + Field f = argFields[index]; + assertFalse(Modifier.isFinal(f.getModifiers()), "@CracTestArg fields must not be final!"); + Class t = f.getType(); + if (index + argsOffset >= args.length) { + if (f.getAnnotation(CracTestArg.class).optional()) { + break; + } else { + fail("Not enough args for field " + f.getName() + "(" + index + "): have " + (args.length - argsOffset)); + } + } + String arg = args[index + argsOffset]; + Object value = arg; + if (t == boolean.class || t == Boolean.class) { + assertTrue("true".equals(arg) || "false".equals(arg), "Argument " + index + "Boolean arg should be either 'true' or 'false', was: " + arg); + value = Boolean.parseBoolean(arg); + } else if (t == int.class || t == Integer.class) { + try { + value = Integer.parseInt(arg); + } catch (NumberFormatException e) { + fail("Cannot parse argument '" + arg + "' as integer for @CracTestArg(" + index + ") " + f.getName()); + } + } else if (t == long.class || t == Long.class) { + try { + value = Long.parseLong(arg); + } catch (NumberFormatException e) { + fail("Cannot parse argument '" + arg + "' as long for @CracTestArg(" + index + ") " + f.getName()); + } + } else if (t.isEnum()) { + value = Enum.valueOf((Class) t, arg); + } + f.setAccessible(true); + f.set(testInstance, value); + } + if (argsOffset == 0) { + testInstance.test(); + } else { + testInstance.exec(); + } + } catch (NoSuchMethodException e) { + fail("Test class " + testClass.getName() + " is expected to have a public no-arg constructor"); + } + } + + private static Field[] getArgFields(Class testClass) { + // TODO: check superclasses + Field[] sortedFields = Stream.of(testClass.getDeclaredFields()).filter(f -> f.isAnnotationPresent(CracTestArg.class)) + .sorted(Comparator.comparingInt(f -> f.getAnnotation(CracTestArg.class).value())) + .toArray(Field[]::new); + if (sortedFields.length == 0) { + return sortedFields; + } + int firstOptional = -1; + for (int i = 0; i < sortedFields.length; ++i) { + CracTestArg annotation = sortedFields[i].getAnnotation(CracTestArg.class); + int index = annotation.value(); + assertGreaterThanOrEqual(index, 0); + if (i == 0) { + assertEquals(0, index, "@CracTestArg numbers should start with 0"); + } + if (index < i) { + fail("Duplicate @CracTestArg(" + index + "): both fields " + sortedFields[i - 1].getName() + " and " + sortedFields[i].getName()); + } else if (index > i) { + fail("Gap in @CracTestArg indices: missing " + i + ", next is " + index); + } + if (annotation.optional()) { + firstOptional = index; + } else if (firstOptional >= 0) { + fail("Argument " + firstOptional + " is optional; all subsequent arguments must be optional, too."); + } + } + return sortedFields; + } + + /** + * Used as argument for {@link CracBuilder#args(String...)}. + */ + static String[] args(String... extraArgs) { + assertNotNull(ArgsHolder.args, "Args are null; are you trying to access them from test method?"); + if (extraArgs == null || extraArgs.length == 0) { + return ArgsHolder.args; + } else { + return Stream.concat(Stream.of(ArgsHolder.args), Stream.of(extraArgs)).toArray(String[]::new); + } + } + + static Class testClass() { + return ArgsHolder.testClass; + } +} + diff --git a/test/lib/jdk/test/lib/crac/CracTestArg.java b/test/lib/jdk/test/lib/crac/CracTestArg.java new file mode 100644 index 00000000000..158b93dcc88 --- /dev/null +++ b/test/lib/jdk/test/lib/crac/CracTestArg.java @@ -0,0 +1,23 @@ +package jdk.test.lib.crac; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Used to mark fields in {@link CracTest} that should be populated from main method arguments. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface CracTestArg { + /** + * @return The (zero-based) index of the argument used as source of the data. + */ + int value() default 0; + + /** + * @return Can this argument be omitted? + */ + boolean optional() default false; +}