[go: up one dir, main page]

kaos/
lib.rs

1
2//! ####  Chaotic testing harness
3//!
4//! Kaos is a chaotic testing test harness to test your services against random failures.
5//! It allows you to add failpoints that panic randomly inside your code and randomizes
6//! asserts availability and tolerance for resiliency for these faults.
7//!
8//! # Kaos Tests
9//!
10//! Create a directory that will hold all chaos tests called `kaos-tests`.
11//!
12//! A minimal launcher for kaos setup looks like this:
13//!
14//! ```
15//! #[test]
16//! fn kaos() {
17//!     let k = kaos::Runs::new();
18//!
19//!     for entry in fs::read_dir("kaos-tests").unwrap() {
20//!         let entry = entry.unwrap();
21//!         let path = entry.path();
22//!
23//!         // Every service run should be available at least 2 seconds
24//!         k.available(path, Duration::from_secs(2));
25//!     }
26//! }
27//! ```
28//!
29//! and in your Cargo.toml
30//!
31//! ```toml
32//! [[test]]
33//! name = "kaos"
34//! path = "kaos-tests/launcher.rs"
35//! ```
36//!
37//! That's all, now what you have to do is run with `cargo test`.
38//!
39//! Kaos is using the same approach that [https://docs.rs/trybuild] has.
40//! Instead of being compiler-like test harness, it has diverged to be chaos engineering
41//! oriented harness.
42
43#![doc(
44    html_logo_url = "https://raw.githubusercontent.com/vertexclique/kaos/master/img/achaos.gif"
45)]
46
47extern crate humantime;
48
49#[macro_use]
50mod term;
51
52#[macro_use]
53mod path;
54
55mod cargo;
56mod dependencies;
57mod diff;
58mod env;
59mod error;
60mod features;
61mod manifest;
62mod message;
63mod normalize;
64mod run;
65mod rustflags;
66
67use std::cell::RefCell;
68use std::path::{Path, PathBuf};
69use std::{time::Duration, thread};
70
71
72///
73/// Chaotic runs test setup
74#[derive(Debug)]
75pub struct Runs {
76    runner: RefCell<Runner>,
77}
78
79#[derive(Debug)]
80struct Runner {
81    tests: Vec<Test>,
82}
83
84#[derive(Clone, Debug)]
85struct Test {
86    path: PathBuf,
87    duration: Option<Duration>,
88    max_surge: isize,
89    expected: Expected,
90}
91
92#[derive(Copy, Clone, Debug)]
93enum Expected {
94    Available,
95    Chaotic
96}
97
98impl Runs {
99    #[allow(clippy::new_without_default)]
100    pub fn new() -> Self {
101        Runs {
102            runner: RefCell::new(Runner { tests: Vec::new() }),
103        }
104    }
105
106    pub fn available<P: AsRef<Path>>(&self, path: P, duration: Duration) {
107        self.runner.borrow_mut().tests.push(Test {
108            path: path.as_ref().to_owned(),
109            duration: Some(duration),
110            max_surge: !0,
111            expected: Expected::Available,
112        });
113    }
114
115    pub fn chaotic<P: AsRef<Path>>(&self, path: P, run_count: usize, max_surge: usize) {
116        (0..run_count).into_iter().for_each(|_| {
117            self.runner.borrow_mut().tests.push(Test {
118                path: path.as_ref().to_owned(),
119                duration: None,
120                max_surge: max_surge as isize,
121                expected: Expected::Chaotic,
122            });
123        });
124    }
125}
126
127#[doc(hidden)]
128impl Drop for Runs {
129    fn drop(&mut self) {
130        if !thread::panicking() {
131            self.runner.borrow_mut().run();
132        }
133    }
134}