Expand description

Code for deterministic and/or reproducible use of PRNGs in tests.

Often in testing we want to test a random scenario, but we want to be sure of our ability to reproduce the scenario if the test fails.

To achieve this, just have your test use testing_rng() in place of rand::thread_rng(). Then the test will (by default) choose a new random seed for every run, and print that seed to standard output. If the test fails, the seed will be displayed as part of the failure message, and you will be able to use it to recreate the same PRNG seed as the one that caused the failure.

If you’re running your tests in a situation where deterministic behavior is key, you can also enable this via the environment.

The run-time behavior is controlled using the ARTI_TEST_PRNG variable; you can set it to any of the following:

  • random for a randomly seeded PRNG. (This is the default).
  • deterministic for an arbitrary seed that is the same on every run of the program. (You can use this in cases where even a tiny chance of stochastic behavior in your tests is unacceptable.)
  • A hexadecimal string, to specify a given seed to re-use from a previous test run.

WARNING

This is for testing only! Never ever use it in non-testing code. Doing so may compromise your security.

You may wish to use clippy’s disallowed-methods lint to ensure you aren’t using it outside of your tests.

Examples

Here’s a simple example, of a test that verifies that integer sorting works correctly by shuffling a short sequence and then re-sorting it.

use tor_basic_utils::test_rng::testing_rng;
use rand::{seq::SliceRandom};
let mut rng = testing_rng();

let mut v = vec![-10, -3, 0, 1, 2, 3];
v.shuffle(&mut rng);
v.sort();
assert_eq!(&v, &[-10, -3, 0, 1, 2, 3])

Here’s a trickier example of how you might write a test to override the default behavior. (For example, you might want to do this if the test is unreliable and you don’t have time to hunt down the issues.)

use tor_basic_utils::test_rng::Config;
let mut rng = Config::from_env()
    .unwrap_or(Config::Deterministic)
    .into_rng();

Enums

Type describing a testing_rng configuration.

Functions

Return a new, possibly deterministic, RNG for use in tests.