1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//-
// Copyright 2018 Jason Lingle
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![deny(missing_docs, unsafe_code)]

//! 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.rusty_fork_test.html) macro, which is a
//! simple way to wrap standard Rust tests to be run in subprocesses with
//! optional timeouts.
//!
//! - The [`fork`](fn.fork.html) 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
//!
//! ```toml
//! [dev-dependencies]
//! rusty-fork = "0.2.1"
//! ```
//!
//! and to your crate root add
//!
//! ```rust,ignore
//! #[macro_use] extern crate rusty_fork;
//! ```
//!
//! Then, you can simply wrap any test(s) to be isolated with the
//! [`rusty_fork_test!`](macro.rusty_fork_test.html) macro.
//!
//! ```rust
//! #[macro_use] extern crate rusty_fork;
//!
//! rusty_fork_test! {
//! # /* NOREADME
//!     #[test]
//! # NOREADME */
//!     fn my_test() {
//!         assert_eq!(2, 1 + 1);
//!     }
//!
//!     // more tests...
//! }
//! # // NOREADME
//! # fn main() { my_test(); } // NOREADME
//! ```
//!
//! For more advanced usage, have a look at the [`fork`](fn.fork.html)
//! 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](https://github.com/AltSysrq/rusty-fork/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 process
//! - `pass-arg` — Pass the flag and its following argument to the child process
//! - `drop` — Don't pass the flag to the child process
//! - `drop-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.
//!
//! <!-- ENDREADME -->

extern crate fnv;
#[macro_use] extern crate quick_error;
extern crate tempfile;
#[cfg(feature = "timeout")] extern crate wait_timeout;

#[macro_use] mod sugar;
#[macro_use] pub mod fork_test;
mod error;
mod cmdline;
mod fork;
mod child_wrapper;

pub use sugar::RustyForkId;
pub use error::{Error, Result};
pub use fork::fork;
pub use child_wrapper::{ChildWrapper, ExitStatusWrapper};