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
//! Buggify allows you to cooperate with the simulator to inject failures.
//!
//! Learn more: <https://transactional.blog/simulation/buggify>

use tracing::info;

/// Returns true with a probability of 25% if buggify is enabled.
pub fn buggify() -> bool {
    crate::rand::thread_rng().buggify()
}

/// Buggify with given probability.
pub fn buggify_with_prob(probability: f64) -> bool {
    crate::rand::thread_rng().buggify_with_prob(probability)
}

/// Enable buggify.
pub fn enable() {
    info!("buggify enabled");
    crate::rand::thread_rng().enable_buggify()
}

/// Disable buggify.
pub fn disable() {
    info!("buggify disabled");
    crate::rand::thread_rng().disable_buggify()
}

/// Returns if buggify is enabled.
pub fn is_enabled() -> bool {
    crate::rand::thread_rng().is_buggify_enabled()
}

#[cfg(test)]
mod tests {
    use crate::runtime::Runtime;

    #[test]
    fn buggify() {
        let runtime = Runtime::new();
        runtime.block_on(async move {
            assert!(
                !crate::buggify::is_enabled(),
                "buggify should be disabled by default"
            );

            crate::buggify::enable();
            assert!(crate::buggify::is_enabled());

            let count = (0..1000).filter(|_| crate::buggify::buggify()).count();
            assert!((200..300).contains(&count)); // 25%

            let count = (0..1000)
                .filter(|_| crate::buggify::buggify_with_prob(0.1))
                .count();
            assert!((50..150).contains(&count)); // 10%

            crate::buggify::disable();
            assert!(!crate::buggify::is_enabled());

            for _ in 0..10 {
                assert!(!crate::buggify::buggify());
                assert!(!crate::buggify::buggify_with_prob(1.0));
            }
        });
    }
}