rusty_fork/
lib.rs

1//-
2// Copyright 2018 Jason Lingle
3//
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7// option. This file may not be copied, modified, or distributed
8// except according to those terms.
9
10#![deny(missing_docs, unsafe_code)]
11
12//! Rusty-fork provides a way to "fork" unit tests into separate processes.
13//!
14//! There are a number of reasons to want to run some tests in isolated
15//! processes:
16//!
17//! - When tests share a process, if any test causes the process to abort,
18//! segfault, overflow the stack, etc., the entire test runner process dies. If
19//! the test is in a subprocess, only the subprocess dies and the test runner
20//! simply fails the test.
21//!
22//! - Isolating a test to a subprocess makes it possible to add a timeout to
23//! the test and forcibly terminate it and produce a normal test failure.
24//!
25//! - Tests which need to interact with some inherently global property, such
26//! as the current working directory, can do so without interfering with other
27//! tests.
28//!
29//! This crate itself provides two things:
30//!
31//! - The [`rusty_fork_test!`](macro.rusty_fork_test.html) macro, which is a
32//! simple way to wrap standard Rust tests to be run in subprocesses with
33//! optional timeouts.
34//!
35//! - The [`fork`](fn.fork.html) function which can be used as a building block
36//! to make other types of process isolation strategies.
37//!
38//! ## Quick Start
39//!
40//! If you just want to run normal Rust tests in isolated processes, getting
41//! started is pretty quick.
42//!
43//! In `Cargo.toml`, add
44//!
45//! ```toml
46//! [dev-dependencies]
47//! rusty-fork = "0.3.0"
48//! ```
49//!
50//! Then, you can simply wrap any test(s) to be isolated with the
51//! [`rusty_fork_test!`](macro.rusty_fork_test.html) macro.
52//!
53//! ```rust
54//! use rusty_fork::rusty_fork_test;
55//!
56//! rusty_fork_test! {
57//! # /* NOREADME
58//!     #[test]
59//! # NOREADME */
60//!     fn my_test() {
61//!         assert_eq!(2, 1 + 1);
62//!     }
63//!
64//!     // more tests...
65//! }
66//! # // NOREADME
67//! # fn main() { my_test(); } // NOREADME
68//! ```
69//!
70//! For more advanced usage, have a look at the [`fork`](fn.fork.html)
71//! function.
72//!
73//! ## How rusty-fork works
74//!
75//! Unix-style process forking isn't really viable within the standard Rust
76//! test environment for a number of reasons.
77//!
78//! - While true process forking can be done on Windows, it's neither fast nor
79//! reliable.
80//!
81//! - The Rust test environment is multi-threaded, so attempting to do anything
82//! non-trivial after a process fork would result in undefined behaviour.
83//!
84//! Rusty-fork instead works by _spawning_ a fresh instance of the current
85//! process, after adjusting the command-line to ensure that only the desired
86//! test is entered. Some additional coordination establishes the parent/child
87//! branches and (not quite seamlessly) integrates the child's output with the
88//! test output capture system.
89//!
90//! Coordination between the processes is performed via environment variables,
91//! since there is otherwise no way to pass parameters to a test.
92//!
93//! Since it needs to spawn new copies of the test runner executable,
94//! rusty-fork does need to know about the meaning of every flag passed by the
95//! user. If any unknown flags are encountered, forking will fail. Please do
96//! not hesitate to file
97//! [issues](https://github.com/AltSysrq/rusty-fork/issues) if rusty-fork fails
98//! to recognise any valid flags passed to the test runner.
99//!
100//! It is possible to inform rusty-fork of new flags without patching by
101//! setting environment variables. For example, if a new `--frob-widgets` flag
102//! were added to the test runner, you could set `RUSTY_FORK_FLAG_FROB_WIDGETS`
103//! to one of the following:
104//!
105//! - `pass` — Pass the flag (just the flag) to the child process
106//! - `pass-arg` — Pass the flag and its following argument to the child process
107//! - `drop` — Don't pass the flag to the child process
108//! - `drop-arg` — Don't pass the flag to the child process, and ignore whatever
109//!   argument follows.
110//!
111//! In general, arguments that affect which tests are run should be dropped,
112//! and others should be passed.
113//!
114//! <!-- ENDREADME -->
115
116#[macro_use] extern crate quick_error;
117
118#[macro_use] mod sugar;
119#[macro_use] pub mod fork_test;
120mod error;
121mod cmdline;
122mod fork;
123mod child_wrapper;
124
125pub use crate::sugar::RustyForkId;
126pub use crate::error::{Error, Result};
127pub use crate::fork::fork;
128pub use crate::child_wrapper::{ChildWrapper, ExitStatusWrapper};