void withCurrentLeader(Consumer<RaftNode> action) {
            for (RaftNode node : running.values()) {
                if (node.client.quorum().isLeader()) {
                    action.accept(node);
                }
            }
        }
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
independently executing nodes, but there are several important differences:

1. Simulation behavior is deterministic provided an initial random seed. This
   makes it easy to reproduce and debug test failures.
2. The simulation uses an in-memory message router instead of a real network.
   Not only is this much cheaper and faster, it provides an easy way to create
   flaky network conditions or even network partitions without losing the
   simulation determinism.
3. Similarly, persistent state is stored in memory. We can nevertheless simulate
   different kinds of failures, such as the loss of unflushed data after a hard
   node restart using {@link MockLog}.

The framework uses a single event scheduler in order to provide deterministic
executions. Each test is setup as a specific scenario with a variable number of
voters and observers. Much like system tests, there is typically a warmup
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, 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.
raft/src/test/java/org/apache/kafka/raft/RaftEventSimulationTest.java