Rewrite README to reflect the current state of Shuttle - #326
Conversation
The README had drifted a long way from the library it describes. It was largely a copy of the crate-level docs in shuttle/src/lib.rs, covering check_random and the Loom comparison and little else, with a single sentence about the wrappers. Rewrite it around what Shuttle can test today and how a failure gets debugged: * A dedicated section on testing tokio code, covering the dependency-swap setup, #[tokio::test], which tokio modules are actually modeled, how time and timeouts work (timeouts fire via trigger_timeouts rather than elapsing), what is re-exported from real tokio and therefore unsafe to use under Shuttle, and the environment variables the tokio harness reads. * The replay workflow, which was previously only in the crate docs. * A table of all eight built-in schedulers and their entry points. * Config knobs and the SHUTTLE_* environment variables. * Coverage of the std replacements, including the known gaps: Arc is std's, atomics are unsound, no OnceLock/LazyLock/mpmc, time is not modeled. * The other wrappers, Shuttle Explorer, and a repository layout table covering the 0.9.2 split into shuttle-engine/schedulers/std. No code changes; shuttle/src/lib.rs docs are left alone.
shuttle-tokio is being republished as 1.0.0 so that it mirrors the version of the crate it wraps, matching the other wrappers. Point the tokio setup and companion crate examples at `1`, which also makes them agree with the examples in wrappers/README.md.
| [A Randomized Scheduler with Probabilistic Guarantees of Finding Bugs](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/asplos277-pct.pdf). | ||
| Shuttle is a library for testing concurrent Rust code. It takes control of the scheduler, so that | ||
| thread interleavings are chosen by Shuttle rather than by the OS. That gives you two things a normal | ||
| concurrency test cannot: interleavings are explored deliberately instead of by luck, and any failure |
There was a problem hiding this comment.
Not a fan of this luck term
|
|
||
| This repository also houses a collection of [wrappers](/wrappers) and their implementations. These make it easier to test code using popular libraries such as `tokio` and `rand`, as well as synchronization primitives from `std::sync` and collections from `std::collections`. For more information on how to use these wrappers, see the [wrappers/README.md](/wrappers/README.md). | ||
| Shuttle implements a number of *randomized concurrency testing* techniques, including | ||
| [A Randomized Scheduler with Probabilistic Guarantees of Finding Bugs](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/asplos277-pct.pdf) |
There was a problem hiding this comment.
This should be moved down to the section with schedulers
| [A Randomized Scheduler with Probabilistic Guarantees of Finding Bugs](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/asplos277-pct.pdf) | ||
| (PCT). | ||
|
|
||
| Shuttle is inspired by [Loom](https://github.com/tokio-rs/loom), but focuses on randomized testing |
There was a problem hiding this comment.
Mention that Shuttle has seen more love than Loom in recent years? Also mention that Shuttle can also be run exhaustively? (though without any POR)
| than Loom. Empirically, randomized testing is successful at finding most concurrency bugs, which | ||
| tend not to be adversarial. | ||
|
|
||
| Beyond the core library, this repository houses a collection of drop-in |
There was a problem hiding this comment.
I think it should be explicit that the core philosophy of Shuttle is to require minimal changes to the code
|
|
||
| ```rust | ||
| #[cfg(all(feature = "shuttle", test))] | ||
| use shuttle::{sync::*, thread}; |
There was a problem hiding this comment.
This is not how we want people to swap imports. Use the wrapper crates instead
|
|
||
| ## Reproducing a failure | ||
|
|
||
| When a Shuttle test fails, it prints the schedule that caused the failure: |
There was a problem hiding this comment.
Note that schedulers like the random scheduler will also print the seed ?
| - Vector clocks, which power the causality tracking exposed through `shuttle::current`, are behind | ||
| the `vector-clocks` feature. | ||
|
|
||
| ## Choosing a scheduler |
There was a problem hiding this comment.
I wonder if the uncontrolled nondeterminism check scheduler should have its own little section
- Drop the "by luck" framing in the opening paragraph. - Move the PCT citation down into the scheduler section. - Note that Shuttle can run exhaustively via check_dfs, with no POR. - State the minimal-changes-to-the-code goal explicitly. - Recommend the shuttle-sync wrapper instead of hand-rolled cfg import swapping, and note the std::sync superset and missing thread wrapper. - Document that check_random prints the failing seed, and how a seed differs from a schedule as a reproducer. - Give the uncontrolled nondeterminism check scheduler its own section.
This CR is borderline draft (because it is AI slop), but I'm leaving it open because I do think it or a version of it will want to be merged. I have yet to review this CR properly.
My opinions:
AI SLOP BELOW
The README had drifted a long way from the library it describes. It was 82 lines, roughly 60 of which were a near-verbatim copy of the crate-level docs in
shuttle/src/lib.rs(the samestdMutexexample, the samecheck_randomrewrite, the same Loom paragraph), plus badges and a single sentence about the wrappers.Nothing in it was wrong. But it said nothing about async, the replay workflow, seven of the eight schedulers,
Config, theSHUTTLE_*environment variables, labels, thevector-clocksorannotationfeatures, Shuttle Explorer, the 0.9.2 split intoshuttle-engine/shuttle-schedulers/shuttle-std, or tokio beyond one passing mention.Since
shuttle/Cargo.tomlsetsreadme = "../README.md", this is also the crates.io landing page.What changed
Reordered around "what can I test, and how do I debug a failure", and pulled the useful onboarding content that only existed in
lib.rsinto the README.package = "shuttle-tokio"setup,#[tokio::test], which tokio modules are actually modeled, time and timeouts, what is re-exported from real tokio and therefore unsafe under Shuttle, the environment variables the harness reads, and the companion crates.Configknobs and theSHUTTLE_*environment variables.stdreplacements, with the caveats stated rather than left to be discovered:Arcis std's, theatomicimplementation is unsound,fence(Relaxed)panics, time is not modeled, noOnceLock/LazyLock/mpmc.## License.No code changes.
shuttle/src/lib.rsdocs are deliberately untouched.Two things called out as design decisions
Some of this is judgement, so flagging it explicitly rather than burying it:
lib.rsdoc block are still independent near-duplicates. There is noinclude_str!anywhere, which is why they drifted. This PR does not address that; it treats the README as the pitch-and-orientation document and leaveslib.rsas the API narrative. If you would rather have a single source of truth via#![doc = include_str!("../README.md")], that is a bigger change (every code fence becomes a doctest and needs annotating, and intra-doc links become URLs) and probably its own PR.timeoutignores its duration entirely and only fires viatrigger_timeouts, and thattask_local!currently gives shared storage across all Shuttle tasks. Happy to trim it down to a pointer atwrappers/tokio/README.mdif you'd prefer the README stay short.Verification
Every technical claim was checked against the source rather than carried over from the old text. Specifically avoided documenting
shuttle::check(#[doc(hidden)]) and the tokio crate'scheck/default_shuttle_config(both#[deprecated]and slated to move).Relation to other open PRs
The tokio examples here say
version = "1"forshuttle-tokio, which is what #327 republishes it as, and which matches whatwrappers/README.mdalready tells users to write. The rest of the README stands alone.This PR touches only
README.md, so it does not conflict with #325 or #327 and can merge in any order; merging it before #327 would just mean the documented requirement lands slightly ahead of the release.Not included
wrappers/README.mddocuments atokio-version-importer-do-not-use-directlycrate that does not exist in the tree. Left alone here. (Theshuttle_enablergap in that file is addressed in #325.)By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.