The goal of Simulation is to provide a set of low level components which can be used to write applications amenable to FoundationDB style simulation testing.
Simulation is an abstraction over [Tokio], allowing application developers to write applications which are generic over sources of nondeterminism. Additionally, Simulation provides deterministic analogues to time, scheduling, network and IO.
Simulation provides a mock source of time. Mock time will only advance when the executor has no more work to do. This can be used to force deterministic reordering of task execution.
When time is advanced, it is advanced instantly to a value which allows the executor to make progress. Applications which rely on timeouts can then be tested in a fraction of the time it would normally take to test a particular execution ordering.
Simulation includes an in-memory network. Applications can use Environment::bind
and Environment::connect
to create in-memory connections between components. The in-memory connections will automatically have delays
and disconnect faults injected, dependent on an initial seed value.
Faults are injected based on a seedable RNG, causing IO delays and disconnects. This is sufficient to trigger bugs in higher level components, such as message reordering.
By eliminating sources of nondeterminism, and basing fault injection on a seedable RNG, it's possible to run many thousands of tests in the span of a few seconds with different fault injections. This allows testing different execution orderings. If a particular seed causes a failing execution ordering, developers can use the seed value to debug and fix their applications.
Once the error is fixed, the seed value can be used to setup a regression test to ensure that the issue stays fixed.
```rust use simulation::{Environment, TcpListener}; use futures::{SinkExt, StreamExt}; use std::{io, net, time}; use tokio::codec::{Framed, LinesCodec};
/// Start a client request handler which will write greetings to clients.
async fn handle
/// Start a server which will bind to the provided addr and repyl to clients.
async fn server
while let Ok((socket, addr)) = listener.accept().await {
let request = handle(env.clone(), socket, addr);
env.spawn(request)
}
Ok(())
}
/// Create a client which will read a message from the server
async fn client
License: MIT