moonpool-sim 0.2.0

Simulation engine for the moonpool framework
docs.rs failed to build moonpool-sim-0.2.0
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Visit the last successful build: moonpool-sim-0.2.2

Moonpool Simulation Framework

Deterministic simulation for testing distributed systems, inspired by FoundationDB's simulation testing.

Why Deterministic Simulation?

FoundationDB's insight: bugs hide in error paths. Production code rarely exercises timeout handlers, retry logic, or failure recovery. Deterministic simulation with fault injection finds these bugs before production does.

Key properties:

  • Reproducible: Same seed produces identical execution
  • Comprehensive: Tests all failure modes (network, timing, corruption)
  • Fast: Logical time skips idle periods

Core Components

  • [SimWorld]: The simulation runtime managing events and time
  • [SimulationBuilder]: Configure and run simulations
  • [chaos]: Fault injection (buggify, assertions, invariants)

Quick Start

use moonpool_sim::{SimulationBuilder, WorkloadTopology};

SimulationBuilder::new()
    .topology(WorkloadTopology::ClientServer { clients: 2, servers: 1 })
    .run(|ctx| async move {
        // Your distributed system workload
    });

Fault Injection Overview

See [chaos] module for detailed documentation.

Mechanism Default What it tests
TCP latencies 1-11ms connect Async scheduling
Random connection close 0.001% Reconnection, redelivery
Bit flip corruption 0.01% Checksum validation
Connect failure 50% probabilistic Timeout handling, retries
Clock drift 100ms max Leases, heartbeats
Buggified delays 25% Race conditions
Partial writes 1000 bytes max Message fragmentation
Packet loss disabled At-least-once delivery
Network partitions disabled Split-brain handling

Multi-Seed Testing

Tests run across multiple seeds to explore the state space:

SimulationBuilder::new()
    .run_count(IterationControl::UntilAllSometimesReached(1000))
    .run(workload);

Debugging a failing seed:

SimulationBuilder::new()
    .set_seed(failing_seed)
    .run_count(IterationControl::FixedCount(1))
    .run(workload);