Expand description
Rusty-fork provides a way to “fork” unit tests into separate processes.
There are a number of reasons to want to run some tests in isolated processes:
-
When tests share a process, if any test causes the process to abort, segfault, overflow the stack, etc., the entire test runner process dies. If the test is in a subprocess, only the subprocess dies and the test runner simply fails the test.
-
Isolating a test to a subprocess makes it possible to add a timeout to the test and forcibly terminate it and produce a normal test failure.
-
Tests which need to interact with some inherently global property, such as the current working directory, can do so without interfering with other tests.
This crate itself provides two things:
-
The
rusty_fork_test!
macro, which is a simple way to wrap standard Rust tests to be run in subprocesses with optional timeouts. -
The
fork
function which can be used as a building block to make other types of process isolation strategies.
§Quick Start
If you just want to run normal Rust tests in isolated processes, getting started is pretty quick.
In Cargo.toml
, add
[dev-dependencies]
rusty-fork = "*"
Then, you can simply wrap any test(s) to be isolated with the
rusty_fork_test!
macro.
use rusty_forkfork::rusty_fork_test;
rusty_fork_test! {
#[test]
fn my_test() {
assert_eq!(2, 1 + 1);
}
// more tests...
}
For more advanced usage, have a look at the fork
function.
§How rusty-fork works
Unix-style process forking isn’t really viable within the standard Rust test environment for a number of reasons.
-
While true process forking can be done on Windows, it’s neither fast nor reliable.
-
The Rust test environment is multi-threaded, so attempting to do anything non-trivial after a process fork would result in undefined behaviour.
Rusty-fork instead works by spawning a fresh instance of the current process, after adjusting the command-line to ensure that only the desired test is entered. Some additional coordination establishes the parent/child branches and (not quite seamlessly) integrates the child’s output with the test output capture system.
Coordination between the processes is performed via environment variables, since there is otherwise no way to pass parameters to a test.
Since it needs to spawn new copies of the test runner executable, rusty-fork does need to know about the meaning of every flag passed by the user. If any unknown flags are encountered, forking will fail. Please do not hesitate to file issues if rusty-fork fails to recognise any valid flags passed to the test runner.
It is possible to inform rusty-fork of new flags without patching by
setting environment variables. For example, if a new --frob-widgets
flag
were added to the test runner, you could set RUSTY_FORK_FLAG_FROB_WIDGETS
to one of the following:
pass
— Pass the flag (just the flag) to the child processpass-arg
— Pass the flag and its following argument to the child processdrop
— Don’t pass the flag to the child processdrop-arg
— Don’t pass the flag to the child process, and ignore whatever argument follows.
In general, arguments that affect which tests are run should be dropped, and others should be passed.
Modules§
- Support code for the
rusty_fork_test!
macro and similar.
Macros§
- Produce a hashable identifier unique to the particular macro invocation which is stable across processes of the same executable.
- Run Rust tests in subprocesses.
- Given the unqualified name of a
#[test]
function, produce a&'static str
corresponding to the name of the test as filtered by the standard test harness.
Structs§
- Wraps a
std::process::Child
to coordinate state betweenstd
andwait_timeout
. - Wraps
std::process::ExitStatus
. Historically, this was due to thewait_timeout
crate having its ownExitStatus
type. - The type of the value produced by
rusty_fork_id!
.
Enums§
- Enum for errors produced by the rusty-fork crate.
Functions§
- Simulate a process fork.
Type Aliases§
- General
Result
type for rusty-fork.