Skip to content

Commit 1f81242

Browse files
committed
test(site-explorer): assert histogram buckets beyond 10s
Replace the hand-rolled view-build loop with carbide-test-support scenarios and add a Prometheus round-trip test that records a 30s observation and verifies it lands in the extended bucket range.
1 parent 3cf1774 commit 1f81242

3 files changed

Lines changed: 91 additions & 18 deletions

File tree

Cargo.lock

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/site-explorer/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ thiserror = { workspace = true }
5454
version-compare = { workspace = true }
5555

5656
[dev-dependencies]
57+
opentelemetry-prometheus = { workspace = true }
58+
prometheus = { workspace = true }
59+
5760
bmc-vendor = { path = "../bmc-vendor" }
5861
carbide-api-model = { path = "../api-model", default-features = false, features = [
5962
"test-support",

crates/site-explorer/src/metrics.rs

Lines changed: 84 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -851,30 +851,96 @@ pub fn exploration_error_to_metric_label(error: &EndpointExplorationError) -> St
851851

852852
#[cfg(test)]
853853
mod tests {
854+
use carbide_test_support::Outcome::*;
855+
use carbide_test_support::scenarios;
856+
use opentelemetry::metrics::MeterProvider;
857+
use opentelemetry_sdk::metrics::SdkMeterProvider;
858+
use prometheus::{Encoder, TextEncoder};
859+
854860
use super::*;
855861

862+
struct LatencyHistogramTestMeter {
863+
meter_provider: SdkMeterProvider,
864+
registry: prometheus::Registry,
865+
}
866+
867+
impl LatencyHistogramTestMeter {
868+
fn new(name_filter: &'static str) -> Self {
869+
let registry = prometheus::Registry::new();
870+
let metrics_exporter = opentelemetry_prometheus::exporter()
871+
.with_registry(registry.clone())
872+
.without_scope_info()
873+
.without_target_info()
874+
.build()
875+
.unwrap();
876+
877+
let meter_provider = SdkMeterProvider::builder()
878+
.with_reader(metrics_exporter)
879+
.with_view(site_explorer_latency_histogram_view(name_filter).unwrap())
880+
.build();
881+
882+
Self {
883+
meter_provider,
884+
registry,
885+
}
886+
}
887+
888+
fn export_metrics(&self) -> String {
889+
let mut buffer = vec![];
890+
let encoder = TextEncoder::new();
891+
let metric_families = self.registry.gather();
892+
encoder.encode(&metric_families, &mut buffer).unwrap();
893+
String::from_utf8(buffer).unwrap()
894+
}
895+
}
896+
856897
#[test]
857898
fn site_explorer_latency_histogram_views_build() {
858-
let cases = [
859-
(
860-
"carbide_site_explorer_iteration_latency",
861-
"iteration latency",
862-
),
863-
(
864-
"carbide_site_explorer_*_latency",
865-
"carbide site explorer latency glob",
899+
scenarios!(
900+
run = |name_filter: &'static str| {
901+
site_explorer_latency_histogram_view(name_filter)
902+
.map(|_| ())
903+
.map_err(drop)
904+
};
905+
"iteration latency" {
906+
"carbide_site_explorer_iteration_latency" => Yields(()),
907+
}
908+
909+
"carbide site explorer latency glob" {
910+
"carbide_site_explorer_*_latency" => Yields(()),
911+
}
912+
913+
"endpoint exploration duration" {
914+
"carbide_endpoint_exploration_duration" => Yields(()),
915+
}
916+
);
917+
}
918+
919+
#[test]
920+
fn site_explorer_latency_histogram_redistributes_observations_above_ten_seconds() {
921+
let test_meter =
922+
LatencyHistogramTestMeter::new("carbide_site_explorer_iteration_latency");
923+
let meter = test_meter.meter_provider.meter("site-explorer-test");
924+
let histogram = meter
925+
.f64_histogram("carbide_site_explorer_iteration_latency")
926+
.with_unit("ms")
927+
.build();
928+
929+
histogram.record(30_000.0, &[]);
930+
931+
let encoded = test_meter.export_metrics();
932+
assert!(
933+
encoded.contains(
934+
r#"carbide_site_explorer_iteration_latency_milliseconds_bucket{le="30000"} 1"#
866935
),
867-
(
868-
"carbide_endpoint_exploration_duration",
869-
"endpoint exploration duration",
936+
"expected 30s observation in the 30000ms bucket, got:\n{encoded}"
937+
);
938+
assert!(
939+
!encoded.contains(
940+
r#"carbide_site_explorer_iteration_latency_milliseconds_bucket{le="10000"} 1"#
870941
),
871-
];
872-
873-
for (name_filter, label) in cases {
874-
site_explorer_latency_histogram_view(name_filter).unwrap_or_else(|error| {
875-
panic!("{label} view must build: {error}");
876-
});
877-
}
942+
"30s observation should not land in the 10000ms bucket:\n{encoded}"
943+
);
878944
}
879945
}
880946

0 commit comments

Comments
 (0)