futures-testing
Every leaf future in Rust must manage its own waker. Forget to store it, cache a stale one, or fail to handle a spurious poll, and your future silently deadlocks. These bugs are hard to write deterministic tests for because they depend on poll ordering.
This crate fuzzes the poll ordering. It randomly interleaves polling, driving, cancellation, spurious wakeups, and waker swaps, then asserts that the waker contract is upheld after every step.
What it catches
- Lost wakers -- returning
Pendingwithout retaining or waking theWaker. - Stale wakers -- caching the first waker instead of accepting a fresh one each poll.
- Spurious poll intolerance -- panicking or producing wrong results when polled without a prior wakeup.
- Cancel-safety violations -- state corruption when a future is dropped mid-await and retried.
How it works
You provide two things:
- A driver -- the other side of the leaf future (e.g. a channel sender for a receiver future).
- A factory -- an async closure that produces the future under test.
The runner calls the factory multiple times per test, randomly choosing when to poll, drive,
swap wakers, inject spurious polls, or cancel. When the driver reports progress, the runner
asserts the future's waker was called. Under the hood it uses arbtest
to fuzz the interleaving, so failing seeds are reproducible with .seed().
use ControlFlow;
use ;
use StreamExt;
Features
tracing-- emit trace-level logs for each action the runner takes, useful for debugging failures.