diff --git a/proxy/src/telemetry/metrics/histogram.rs b/proxy/src/telemetry/metrics/histogram.rs index f151637c2..467374532 100644 --- a/proxy/src/telemetry/metrics/histogram.rs +++ b/proxy/src/telemetry/metrics/histogram.rs @@ -123,3 +123,133 @@ impl cmp::Ord for Bucket { } } } + +#[cfg(test)] +mod tests { + use super::*; + + use std::collections::HashMap; + use std::u64; + + const NUM_BUCKETS: usize = 47; + static BOUNDS: &'static Bounds = &Bounds(&[ + Bucket::Le(10), + Bucket::Le(20), + Bucket::Le(30), + Bucket::Le(40), + Bucket::Le(50), + Bucket::Le(60), + Bucket::Le(70), + Bucket::Le(80), + Bucket::Le(90), + Bucket::Le(100), + Bucket::Le(200), + Bucket::Le(300), + Bucket::Le(400), + Bucket::Le(500), + Bucket::Le(600), + Bucket::Le(700), + Bucket::Le(800), + Bucket::Le(900), + Bucket::Le(1_000), + Bucket::Le(2_000), + Bucket::Le(3_000), + Bucket::Le(4_000), + Bucket::Le(5_000), + Bucket::Le(6_000), + Bucket::Le(7_000), + Bucket::Le(8_000), + Bucket::Le(9_000), + Bucket::Le(10_000), + Bucket::Le(20_000), + Bucket::Le(30_000), + Bucket::Le(40_000), + Bucket::Le(50_000), + Bucket::Le(60_000), + Bucket::Le(70_000), + Bucket::Le(80_000), + Bucket::Le(90_000), + Bucket::Le(100_000), + Bucket::Le(200_000), + Bucket::Le(300_000), + Bucket::Le(400_000), + Bucket::Le(500_000), + Bucket::Le(600_000), + Bucket::Le(700_000), + Bucket::Le(800_000), + Bucket::Le(900_000), + Bucket::Le(1_000_000), + Bucket::Inf, + ]); + + quickcheck! { + fn bucket_incremented(obs: u64) -> bool { + let mut hist = Histogram::new(&BOUNDS); + hist.add(obs); + let incremented_bucket = &BOUNDS.0.iter() + .position(|bucket| match *bucket { + Bucket::Le(ceiling) => obs <= ceiling, + Bucket::Inf => true, + }) + .unwrap(); + for i in 0..NUM_BUCKETS { + let expected = if i == *incremented_bucket { 1 } else { 0 }; + let count: u64 = hist.buckets[i].into(); + assert_eq!(count, expected, "(for bucket <= {})", BOUNDS.0[i]); + } + true + } + + fn sum_equals_total_of_observations(observations: Vec) -> bool { + let mut hist = Histogram::new(&BOUNDS); + + let mut expected_sum = Wrapping(0u64); + for obs in observations { + expected_sum += Wrapping(obs); + hist.add(obs); + } + + hist.sum == expected_sum + } + + fn count_equals_number_of_observations(observations: Vec) -> bool { + let mut hist = Histogram::new(&BOUNDS); + + for obs in &observations { + hist.add(*obs); + } + + let count: u64 = hist.buckets.iter().map(|&c| { + let count: u64 = c.into(); + count + }).sum(); + count as usize == observations.len() + } + + fn multiple_observations_increment_buckets(observations: Vec) -> bool { + let mut buckets_and_counts: HashMap = HashMap::new(); + let mut hist = Histogram::new(&BOUNDS); + + for obs in observations { + let incremented_bucket = &BOUNDS.0.iter() + .position(|bucket| match *bucket { + Bucket::Le(ceiling) => obs <= ceiling, + Bucket::Inf => true, + }) + .unwrap(); + *buckets_and_counts + .entry(*incremented_bucket) + .or_insert(0) += 1; + + hist.add(obs); + } + + for (i, count) in hist.buckets.iter().enumerate() { + let count: u64 = (*count).into(); + assert_eq!(buckets_and_counts.get(&i).unwrap_or(&0), &count); + } + true + } + } +} +