Name Description Size
lib.rs 9054
testing.rs Allows testing code to enable and disable failspots When testing a crate, failspots can be enabled through a [Client] object. This can be retrieved by using the `fn testing_client() -> Client<'static, Self>` method that exists as part of every enum that was declared using the [`failspot_name!()`][crate::failspot_name] macro. The [`Client::set_enabled()`][Client::set_enabled] method can be used to set or unset a failspot. [`Client::reset()`][Client::reset] will unset all failspots. Example usage: ``` # failspot::failspot_name! { pub enum FailSpotName { Name1 } } # fn run_tests() {} let mut client = FailSpotName::testing_client(); client.set_enabled(FailSpotName::Name1, true); // When the `Client` object drops, all the failspots will be reset to disabled // Must ensure it stays alive while tests are running. run_tests(); ``` # Concurrency -- Important!!! **TL;DR -- Put all your integration tests that use failspot in a separate source file!** ## The problem In Rust, **tests are run concurrently by default**. Since the configuration for the failspots is a global variable that will be shared by all threads, that would create a problem -- Tests that don't use failspots will suddenly start failing because another concurrent test enabled them, and tests that do use failspots would clobber each other's configuration. To prevent this, the [Client] returned by `testing_client()` is **protected by a mutex** -- Only one test at a time can configure the failspots through the `Client` methods. When the client is dropped, all the failspots are reset to disabled state and the mutex is released so the next test can start with a fresh state. This means **every test that may run concurrently with a failspot test must hold the [Client] object the entire time the test is running**, even if that test doesn't actually use failspots. If there are multiple enums declared with [`failspot_name!()`][crate::failspot_name] then a [Client] object for each enum must be held by every test that may run concurrently. For tests that use failspots, this is intuitive -- Most tests that use failspots will create a [Client] as part of their setup. ## Stopping regular tests from breaking For tests that don't use failspots, there are 2 choices: 1. **Put failspot tests in their own source file (recommended)** Integration tests in different source files are run in different processes, so separating failspot and non failspot tests eliminates the concurrency issue. 2. **Force tests to run serially** By setting `RUST_TEST_THREADS=1` in the enviroment, the tests will run one-at-a-time and there will be no interference. Obviously, the first one should be preferred unless there is a good reason not to. 6315