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
use std::time::Duration;
use rand::{random, Closed01};

fn apply_jitter(duration: Duration, jitter: f64) -> Duration {
    let secs = (duration.as_secs() as f64) * jitter;
    let nanos = (duration.subsec_nanos() as f64) * jitter;
    let millis = (secs * 1000f64) + (nanos / 1000000f64);
    Duration::from_millis(millis as u64)
}

pub fn jitter(duration: Duration) -> Duration {
    let Closed01(jitter) = random();
    apply_jitter(duration, jitter)
}

#[test]
fn apply_jitter_quickcheck() {
    extern crate quickcheck;

    #[derive(Clone, Debug)]
    struct ArbitraryJitter(f64);

    impl quickcheck::Arbitrary for ArbitraryJitter {
        fn arbitrary<G: quickcheck::Gen>(g: &mut G) -> Self {
            let Closed01(jitter) = g.gen();
            ArbitraryJitter(jitter)
        }
    }

    fn rounds_correctly(millis: u64, arb_jitter: ArbitraryJitter) -> bool {
        let ArbitraryJitter(jitter) = arb_jitter;

        let millis_with_jitter = ((millis as f64) * jitter) as u64;
        let duration_with_jitter = apply_jitter(Duration::from_millis(millis), jitter);

        duration_with_jitter == Duration::from_millis(millis_with_jitter)
    }

    quickcheck::quickcheck(rounds_correctly as fn(u64, ArbitraryJitter) -> bool)
}