diff --git a/raft/src/test/java/org/apache/kafka/raft/RaftEventSimulationTest.java b/raft/src/test/java/org/apache/kafka/raft/RaftEventSimulationTest.java index 223c2694c767d..94a1a9601737b 100644 --- a/raft/src/test/java/org/apache/kafka/raft/RaftEventSimulationTest.java +++ b/raft/src/test/java/org/apache/kafka/raft/RaftEventSimulationTest.java @@ -61,7 +61,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; - /** * The simulation testing framework provides a way to verify quorum behavior under * different conditions. It is similar to system testing in that the test involves @@ -83,19 +82,11 @@ * period, followed by some cluster event (such as a node failure), and then some * logic to validate behavior after recovery. * - * If any of the tests fail on a particular seed, the easiest way to reproduce - * the failure is to change the `@Property` annotation to specify the failing seed. - * For example: - * - *
- * {@code
- * @Property(tries = 1, seed = "-590031835267299290", shrinking = ShrinkingMode.OFF)
- * }
- *
- *
- * (Note that we disable parameter shrinking since it is not too useful for simulation
- * failures and this allows us to isolate a single execution, which makes the logging
- * more useful if enabled.)
+ * If any of the tests fail, the output will indicate the arguments that failed.
+ * The easiest way to reproduce the failure for debugging is to create a separate
+ * `@Test` case which invokes the `@Property` method with those arguments directly.
+ * This ensures that logging output will only include output from a single
+ * simulation execution.
*/
@Tag("integration")
public class RaftEventSimulationTest {
@@ -110,10 +101,11 @@ public class RaftEventSimulationTest {
@Property(tries = 100)
void canElectInitialLeader(
- @ForAll Random random,
+ @ForAll int seed,
@ForAll @IntRange(min = 1, max = 5) int numVoters,
@ForAll @IntRange(min = 0, max = 5) int numObservers
) {
+ Random random = new Random(seed);
Cluster cluster = new Cluster(numVoters, numObservers, random);
MessageRouter router = new MessageRouter(cluster);
EventScheduler scheduler = schedulerWithDefaultInvariants(cluster);
@@ -128,11 +120,12 @@ void canElectInitialLeader(
@Property(tries = 100)
void canElectNewLeaderAfterOldLeaderFailure(
- @ForAll Random random,
+ @ForAll int seed,
@ForAll @IntRange(min = 3, max = 5) int numVoters,
@ForAll @IntRange(min = 0, max = 5) int numObservers,
@ForAll boolean isGracefulShutdown
) {
+ Random random = new Random(seed);
Cluster cluster = new Cluster(numVoters, numObservers, random);
MessageRouter router = new MessageRouter(cluster);
EventScheduler scheduler = schedulerWithDefaultInvariants(cluster);
@@ -167,10 +160,11 @@ void canElectNewLeaderAfterOldLeaderFailure(
@Property(tries = 100)
void canRecoverAfterAllNodesKilled(
- @ForAll Random random,
+ @ForAll int seed,
@ForAll @IntRange(min = 1, max = 5) int numVoters,
@ForAll @IntRange(min = 0, max = 5) int numObservers
) {
+ Random random = new Random(seed);
Cluster cluster = new Cluster(numVoters, numObservers, random);
MessageRouter router = new MessageRouter(cluster);
EventScheduler scheduler = schedulerWithDefaultInvariants(cluster);
@@ -199,10 +193,11 @@ void canRecoverAfterAllNodesKilled(
@Property(tries = 100)
void canElectNewLeaderAfterOldLeaderPartitionedAway(
- @ForAll Random random,
+ @ForAll int seed,
@ForAll @IntRange(min = 3, max = 5) int numVoters,
@ForAll @IntRange(min = 0, max = 5) int numObservers
) {
+ Random random = new Random(seed);
Cluster cluster = new Cluster(numVoters, numObservers, random);
MessageRouter router = new MessageRouter(cluster);
EventScheduler scheduler = schedulerWithDefaultInvariants(cluster);
@@ -230,10 +225,11 @@ void canElectNewLeaderAfterOldLeaderPartitionedAway(
@Property(tries = 100)
void canMakeProgressIfMajorityIsReachable(
- @ForAll Random random,
+ @ForAll int seed,
@ForAll @IntRange(min = 0, max = 3) int numObservers
) {
int numVoters = 5;
+ Random random = new Random(seed);
Cluster cluster = new Cluster(numVoters, numObservers, random);
MessageRouter router = new MessageRouter(cluster);
EventScheduler scheduler = schedulerWithDefaultInvariants(cluster);
@@ -274,10 +270,11 @@ void canMakeProgressIfMajorityIsReachable(
@Property(tries = 100)
void canMakeProgressAfterBackToBackLeaderFailures(
- @ForAll Random random,
+ @ForAll int seed,
@ForAll @IntRange(min = 3, max = 5) int numVoters,
@ForAll @IntRange(min = 0, max = 5) int numObservers
) {
+ Random random = new Random(seed);
Cluster cluster = new Cluster(numVoters, numObservers, random);
MessageRouter router = new MessageRouter(cluster);
EventScheduler scheduler = schedulerWithDefaultInvariants(cluster);
@@ -306,13 +303,14 @@ void canMakeProgressAfterBackToBackLeaderFailures(
@Property(tries = 100)
void canRecoverFromSingleNodeCommittedDataLoss(
- @ForAll Random random,
+ @ForAll int seed,
@ForAll @IntRange(min = 3, max = 5) int numVoters,
@ForAll @IntRange(min = 0, max = 2) int numObservers
) {
// We run this test without the `MonotonicEpoch` and `MajorityReachedHighWatermark`
// invariants since the loss of committed data on one node can violate them.
+ Random random = new Random(seed);
Cluster cluster = new Cluster(numVoters, numObservers, random);
EventScheduler scheduler = new EventScheduler(cluster.random, cluster.time);
scheduler.addInvariant(new MonotonicHighWatermark(cluster));