@@ -851,30 +851,96 @@ pub fn exploration_error_to_metric_label(error: &EndpointExplorationError) -> St
851851
852852#[ cfg( test) ]
853853mod 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