From ca1dca902c1d4c42c9a36c8f0de12290f1174edb Mon Sep 17 00:00:00 2001 From: Maxim Muzafarov Date: Thu, 31 Jul 2025 00:14:46 +0200 Subject: [PATCH] Fix ShortPaxosSimulationTest and AccordSimulationRunner do not execute from the cli patch by Maxim Muzafarov; reviewed by Ariel Weisberg for CASSANDRA-20805 --- CHANGES.txt | 1 + .../cassandra/simulator/SimulationRunner.java | 2 ++ .../cassandra/simulator/SimulatorUtils.java | 34 +++++++++++++++++-- .../paxos/AccordSimulationRunner.java | 19 +++++++---- .../paxos/PaxosSimulationRunner.java | 21 +++++++----- .../simulator/systems/SimulatedTime.java | 2 +- .../test/ShortAccordSimulationTest.java | 11 +++--- ...axosMigrationFromAccordSimulationTest.java | 22 ++++++------ ...tPaxosMigrationToAccordSimulationTest.java | 16 ++++----- .../test/ShortPaxosSimulationTest.java | 22 ++++++++---- 10 files changed, 100 insertions(+), 50 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index bc3fa7b424..6a23d410e3 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 5.1 + * Fix ShortPaxosSimulationTest and AccordSimulationRunner do not execute from the cli (CASSANDRA-20805) * Allow overriding arbitrary settings via environment variables (CASSANDRA-20749) * Optimize MessagingService.getVersionOrdinal (CASSANDRA-20816) * Optimize TrieMemtable#getFlushSet (CASSANDRA-20760) diff --git a/test/simulator/main/org/apache/cassandra/simulator/SimulationRunner.java b/test/simulator/main/org/apache/cassandra/simulator/SimulationRunner.java index d1d8a6c8b6..11aa42c88d 100644 --- a/test/simulator/main/org/apache/cassandra/simulator/SimulationRunner.java +++ b/test/simulator/main/org/apache/cassandra/simulator/SimulationRunner.java @@ -498,6 +498,8 @@ public class SimulationRunner public static void checkArgumentAllowed(List values, int... allowed) { + if (values == null || values.isEmpty()) + return; values.forEach(v -> checkArgumentAllowed(v, allowed)); } diff --git a/test/simulator/main/org/apache/cassandra/simulator/SimulatorUtils.java b/test/simulator/main/org/apache/cassandra/simulator/SimulatorUtils.java index 64747093f0..805cc4badc 100644 --- a/test/simulator/main/org/apache/cassandra/simulator/SimulatorUtils.java +++ b/test/simulator/main/org/apache/cassandra/simulator/SimulatorUtils.java @@ -21,15 +21,17 @@ package org.apache.cassandra.simulator; import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; import java.util.stream.Collectors; import org.slf4j.Logger; import io.netty.util.concurrent.FastThreadLocal; import org.apache.cassandra.utils.concurrent.Threads; +import picocli.CommandLine; public class SimulatorUtils { @@ -51,12 +53,12 @@ public class SimulatorUtils FastThreadLocal.destroy(); } - public static void verifyAndlogSimulatorArgs(String[] args) + private static void verifyAndlogSimulatorArgs(List args) { RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean(); final List jvmArgs = runtimeMxBean.getInputArguments(); System.err.printf("JVM Args: %s%n", jvmArgs.stream().collect(Collectors.joining("\" \"", "\"", "\""))); - System.err.printf("Command Args: %s%n", Arrays.stream(args).collect(Collectors.joining("\" \"", "\"", "\""))); + System.err.printf("Command Args: %s%n", args.stream().collect(Collectors.joining("\" \"", "\"", "\""))); assert jvmArgs.stream().anyMatch(arg -> arg.startsWith("-Xbootclasspath/a") && arg.endsWith("simulator-bootstrap.jar")) : "must launch JVM with -Xbootclasspath/a:simulator-bootstrap.jar"; @@ -81,4 +83,30 @@ public class SimulatorUtils if (!jvmArgs.stream().anyMatch(arg -> arg.equals("-Dcassandra.simulator.skiplog4jreload=true"))) System.err.println("JVM Argument -Dcassandra.simulator.skiplog4jreload=true not set, non-determinism possible"); } + + public static CommandLine prepareRunner(Object command, CommandLine.IFactory factory, Consumer exceptionHandler) + { + CommandLine cli = new CommandLine(command, factory); + cli.setExecutionStrategy(parseResult -> { + verifyAndlogSimulatorArgs(parseResult.originalArgs()); + return new CommandLine.RunLast().execute(parseResult); + }); + return exceptionHandler == null ? cli : + cli.setExecutionExceptionHandler((ex, commandLine, fullParseResult) -> { + if (ex != null) exceptionHandler.accept(ex); + return commandLine.getCommandSpec().exitCodeOnExecutionException(); + }); + } + + public static void executeWithExceptionThrowing(Object command, CommandLine.IFactory factory, String[] args) + { + AtomicReference cause = new AtomicReference<>(); + int exitCode; + if ((exitCode = prepareRunner(command, factory, cause::set).execute(args)) == 0) + return; + if (cause.get() == null) + throw new RuntimeException("Simulation failed with exit code: " + exitCode); + else + throw new RuntimeException("Simulation failed with exit code: " + exitCode, cause.get()); + } } diff --git a/test/simulator/main/org/apache/cassandra/simulator/paxos/AccordSimulationRunner.java b/test/simulator/main/org/apache/cassandra/simulator/paxos/AccordSimulationRunner.java index 162aa45b2f..b2417c7f20 100644 --- a/test/simulator/main/org/apache/cassandra/simulator/paxos/AccordSimulationRunner.java +++ b/test/simulator/main/org/apache/cassandra/simulator/paxos/AccordSimulationRunner.java @@ -33,7 +33,6 @@ import picocli.CommandLine.Command; @Command(name = "accord", description = "Run an Accord simulation", - helpCommand = true, subcommands = { CommandLine.HelpCommand.class, AccordSimulationRunner.Run.class, AccordSimulationRunner.Record.class, @@ -94,16 +93,22 @@ public class AccordSimulationRunner extends SimulationRunner // for simple unit tests so we can simply invoke main() private static final AtomicInteger uniqueNum = new AtomicInteger(); + private static CommandLine.IFactory simulationFactory() + { + return new PaxosSimulationRunner.InjectPaxosClusterSimulationFactory(new AccordClusterSimulation.Builder() + .unique(uniqueNum.getAndIncrement())); + } + + public static void executeWithExceptionThrowing(String[] args) + { + SimulatorUtils.executeWithExceptionThrowing(AccordSimulationRunner.class, simulationFactory(), args); + } + /** * See {@link org.apache.cassandra.simulator} package info for execution tips */ public static void main(String[] args) throws IOException { - SimulatorUtils.verifyAndlogSimulatorArgs(args); - AccordClusterSimulation.Builder builder = new AccordClusterSimulation.Builder(); - builder.unique(uniqueNum.getAndIncrement()); - - CommandLine commandLine = new CommandLine(AccordSimulationRunner.class, new PaxosSimulationRunner.InjectPaxosClusterSimulationFactory(builder)); - commandLine.execute(args); + System.exit(SimulatorUtils.prepareRunner(AccordSimulationRunner.class, simulationFactory(), null).execute(args)); } } diff --git a/test/simulator/main/org/apache/cassandra/simulator/paxos/PaxosSimulationRunner.java b/test/simulator/main/org/apache/cassandra/simulator/paxos/PaxosSimulationRunner.java index 83f33a5a56..5e19bda1bb 100644 --- a/test/simulator/main/org/apache/cassandra/simulator/paxos/PaxosSimulationRunner.java +++ b/test/simulator/main/org/apache/cassandra/simulator/paxos/PaxosSimulationRunner.java @@ -22,7 +22,6 @@ import java.io.IOException; import java.lang.reflect.Field; import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; - import javax.inject.Inject; import org.apache.cassandra.config.Config; @@ -30,14 +29,12 @@ import org.apache.cassandra.distributed.api.ConsistencyLevel; import org.apache.cassandra.simulator.ClusterSimulation; import org.apache.cassandra.simulator.SimulationRunner; import org.apache.cassandra.simulator.SimulatorUtils; - import picocli.CommandLine; import picocli.CommandLine.Command; import picocli.CommandLine.Option; @Command(name = "paxos", description = "Run a paxos simulation", - helpCommand = true, subcommands = { CommandLine.HelpCommand.class, PaxosSimulationRunner.Run.class, PaxosSimulationRunner.VersionCommand.class, @@ -201,16 +198,22 @@ public class PaxosSimulationRunner extends SimulationRunner implements Runnable } } + private static CommandLine.IFactory simulationFactory() + { + return new InjectPaxosClusterSimulationFactory(new PaxosClusterSimulation.Builder() + .unique(uniqueNum.getAndIncrement())); + } + + public static void executeWithExceptionThrowing(String[] args) + { + SimulatorUtils.executeWithExceptionThrowing(PaxosSimulationRunner.class, simulationFactory(), args); + } + /** * See {@link org.apache.cassandra.simulator} package info for execution tips */ public static void main(String[] args) throws IOException { - SimulatorUtils.verifyAndlogSimulatorArgs(args); - PaxosClusterSimulation.Builder builder = new PaxosClusterSimulation.Builder(); - builder.unique(uniqueNum.getAndIncrement()); - - CommandLine commandLine = new CommandLine(PaxosSimulationRunner.class, new InjectPaxosClusterSimulationFactory(builder)); - commandLine.execute(args); + System.exit(SimulatorUtils.prepareRunner(PaxosSimulationRunner.class, simulationFactory(), null).execute(args)); } } diff --git a/test/simulator/main/org/apache/cassandra/simulator/systems/SimulatedTime.java b/test/simulator/main/org/apache/cassandra/simulator/systems/SimulatedTime.java index df4fa90403..55cd832ff5 100644 --- a/test/simulator/main/org/apache/cassandra/simulator/systems/SimulatedTime.java +++ b/test/simulator/main/org/apache/cassandra/simulator/systems/SimulatedTime.java @@ -49,7 +49,7 @@ import static org.apache.cassandra.simulator.RandomSource.Choices.uniform; // TODO (cleanup): when we encounter an exception and unwind the simulation, we should restore normal time to go with normal waits etc. public class SimulatedTime { - private static final Pattern PERMITTED_TIME_THREADS = Pattern.compile("(logback|SimulationLiveness|Reconcile)[-:][0-9]+"); + private static final Pattern PERMITTED_TIME_THREADS = Pattern.compile("(logback|SimulationLiveness|Reconcile)[-:][0-9]+|RMI Scheduler\\(\\d+\\)"); @Shared(scope = Shared.Scope.SIMULATION) public interface Listener diff --git a/test/simulator/test/org/apache/cassandra/simulator/test/ShortAccordSimulationTest.java b/test/simulator/test/org/apache/cassandra/simulator/test/ShortAccordSimulationTest.java index fdf53fd3e2..7367b77b98 100644 --- a/test/simulator/test/org/apache/cassandra/simulator/test/ShortAccordSimulationTest.java +++ b/test/simulator/test/org/apache/cassandra/simulator/test/ShortAccordSimulationTest.java @@ -18,8 +18,6 @@ package org.apache.cassandra.simulator.test; -import java.io.IOException; - import org.junit.Test; import org.apache.cassandra.simulator.paxos.AccordSimulationRunner; @@ -94,8 +92,13 @@ import org.apache.cassandra.simulator.paxos.AccordSimulationRunner; public class ShortAccordSimulationTest { @Test - public void simulationTest() throws IOException + public void simulationTest() { - AccordSimulationRunner.main(new String[] { "run", "-n", "3..6", "-t", "1000", "--cluster-action-limit", "-1", "-c", "2", "-s", "30"}); + AccordSimulationRunner.executeWithExceptionThrowing(new String[]{ "run", + "-n", "3..6", + "-t", "1000", + "--cluster-action-limit", "-1", + "-c", "2", + "-s", "30" }); } } diff --git a/test/simulator/test/org/apache/cassandra/simulator/test/ShortPaxosMigrationFromAccordSimulationTest.java b/test/simulator/test/org/apache/cassandra/simulator/test/ShortPaxosMigrationFromAccordSimulationTest.java index 97fb59dc61..78e994dff9 100644 --- a/test/simulator/test/org/apache/cassandra/simulator/test/ShortPaxosMigrationFromAccordSimulationTest.java +++ b/test/simulator/test/org/apache/cassandra/simulator/test/ShortPaxosMigrationFromAccordSimulationTest.java @@ -18,8 +18,6 @@ package org.apache.cassandra.simulator.test; -import java.io.IOException; - import org.junit.Ignore; import org.junit.Test; @@ -97,17 +95,17 @@ public class ShortPaxosMigrationFromAccordSimulationTest { @Test @Ignore - public void casOnAccordSimulationTestAccordStart() throws IOException + public void casOnAccordSimulationTestAccordStart() { - PaxosSimulationRunner.main(new String[] { "run", - "--transactional-mode", "full", - "--seed", "0x2b091cc62b96a2eb", - "-n", "3..6", - "-t", "1000", - "--cluster-action-limit", "-1", - "--consensus-action-limit", "1", - "--consensus-actions", "ACCORD_MIGRATE", - "-c", "2"}); + PaxosSimulationRunner.executeWithExceptionThrowing(new String[]{ "run", + "--transactional-mode", "full", + "--seed", "0x2b091cc62b96a2eb", + "-n", "3..6", + "-t", "1000", + "--cluster-action-limit", "-1", + "--consensus-action-limit", "1", + "--consensus-actions", "ACCORD_MIGRATE", + "-c", "2" }); } } diff --git a/test/simulator/test/org/apache/cassandra/simulator/test/ShortPaxosMigrationToAccordSimulationTest.java b/test/simulator/test/org/apache/cassandra/simulator/test/ShortPaxosMigrationToAccordSimulationTest.java index dab2482f36..99aba3d715 100644 --- a/test/simulator/test/org/apache/cassandra/simulator/test/ShortPaxosMigrationToAccordSimulationTest.java +++ b/test/simulator/test/org/apache/cassandra/simulator/test/ShortPaxosMigrationToAccordSimulationTest.java @@ -98,14 +98,14 @@ public class ShortPaxosMigrationToAccordSimulationTest @Ignore public void casOnAccordSimulationTestPaxosStart() throws IOException { - PaxosSimulationRunner.main(new String[] { "run", - "--transactional-mode", "off", - "-n", "3..6", - "-t", "1000", - "--cluster-action-limit", "-1", - "--consensus-action-limit", "1", - "--consensus-actions", "ACCORD_MIGRATE", - "-c", "2"}); + PaxosSimulationRunner.executeWithExceptionThrowing(new String[]{ "run", + "--transactional-mode", "off", + "-n", "3..6", + "-t", "1000", + "--cluster-action-limit", "-1", + "--consensus-action-limit", "1", + "--consensus-actions", "ACCORD_MIGRATE", + "-c", "2" }); } } diff --git a/test/simulator/test/org/apache/cassandra/simulator/test/ShortPaxosSimulationTest.java b/test/simulator/test/org/apache/cassandra/simulator/test/ShortPaxosSimulationTest.java index d726c25e94..bd2e26e595 100644 --- a/test/simulator/test/org/apache/cassandra/simulator/test/ShortPaxosSimulationTest.java +++ b/test/simulator/test/org/apache/cassandra/simulator/test/ShortPaxosSimulationTest.java @@ -18,8 +18,6 @@ package org.apache.cassandra.simulator.test; -import java.io.IOException; - import org.junit.Ignore; import org.junit.Test; @@ -95,16 +93,28 @@ import org.apache.cassandra.simulator.paxos.PaxosSimulationRunner; public class ShortPaxosSimulationTest { @Test - public void simulationTest() throws IOException + public void simulationTest() { - PaxosSimulationRunner.main(new String[] { "run", "--variant", "v2", "-n", "3..6", "-t", "1000", "-c", "2", "--cluster-action-limit", "2", "-s", "30" }); + PaxosSimulationRunner.executeWithExceptionThrowing(new String[] { "run", + "--variant", "v2", + "-n", "3..6", + "-t", "1000", + "-c", "2", + "--cluster-action-limit", "2", + "-s", "30" }); } @Test @Ignore("fails due to OOM DirectMemory - unclear why") - public void selfReconcileTest() throws IOException + public void selfReconcileTest() { - PaxosSimulationRunner.main(new String[] { "reconcile", "-n", "3..6", "-t", "1000", "-c", "2", "--cluster-action-limit", "2", "-s", "30", "--with-self" }); + PaxosSimulationRunner.executeWithExceptionThrowing(new String[] { "reconcile", + "-n", "3..6", + "-t", "1000", + "-c", "2", + "--cluster-action-limit", "2", + "-s", "30", + "--with-self" }); } }