@@ -242,12 +242,14 @@ mod tests {
242242 use std:: time:: Duration ;
243243
244244 use axum_server:: tls_rustls:: RustlsConfig ;
245+ use opentelemetry_sdk:: metrics:: { InMemoryMetricExporter , PeriodicReader , SdkMeterProvider } ;
245246 use payjoin_test_utils:: { http_agent, local_cert_key, wait_for_service_ready} ;
246247 use rustls:: pki_types:: CertificateDer ;
247248 use rustls:: RootCertStore ;
248249 use tempfile:: tempdir;
249250
250251 use super :: * ;
252+ use crate :: metrics:: { ACTIVE_CONNECTIONS , HTTP_REQUESTS , TOTAL_CONNECTIONS } ;
251253
252254 async fn start_service (
253255 cert_der : Vec < u8 > ,
@@ -336,4 +338,48 @@ mod tests {
336338 "cross-instance request should not be rejected as forbidden"
337339 ) ;
338340 }
341+
342+ #[ tokio:: test]
343+ async fn middleware_records_metrics ( ) {
344+ use axum:: body:: Body ;
345+ use axum:: http:: Request ;
346+ use tower:: ServiceExt ;
347+
348+ let exporter = InMemoryMetricExporter :: default ( ) ;
349+ let reader = PeriodicReader :: builder ( exporter. clone ( ) ) . build ( ) ;
350+ let provider = SdkMeterProvider :: builder ( ) . with_reader ( reader) . build ( ) ;
351+
352+ let tempdir = tempdir ( ) . unwrap ( ) ;
353+ let config = Config :: new (
354+ "[::]:0" . parse ( ) . expect ( "valid listener address" ) ,
355+ tempdir. path ( ) . to_path_buf ( ) ,
356+ Duration :: from_secs ( 2 ) ,
357+ ) ;
358+
359+ let sentinel_tag = generate_sentinel_tag ( ) ;
360+ let services = Services {
361+ directory : init_directory ( & config, sentinel_tag) . await . unwrap ( ) ,
362+ relay : ohttp_relay:: Service :: new ( sentinel_tag) . await ,
363+ metrics : MetricsService :: new ( Some ( provider. clone ( ) ) ) ,
364+ } ;
365+
366+ let app = build_app ( services) ;
367+
368+ let request = Request :: builder ( ) . method ( "GET" ) . uri ( "/health" ) . body ( Body :: empty ( ) ) . unwrap ( ) ;
369+ let response = ServiceExt :: < Request < Body > > :: oneshot ( app, request) . await . unwrap ( ) ;
370+ assert_eq ! ( response. status( ) , 200 ) ;
371+
372+ provider. force_flush ( ) . expect ( "flush failed" ) ;
373+
374+ let finished = exporter. get_finished_metrics ( ) . expect ( "metrics" ) ;
375+ let metric_names: Vec < & str > = finished
376+ . iter ( )
377+ . flat_map ( |rm| rm. scope_metrics ( ) )
378+ . flat_map ( |sm| sm. metrics ( ) )
379+ . map ( |m| m. name ( ) )
380+ . collect ( ) ;
381+ assert ! ( metric_names. contains( & HTTP_REQUESTS ) , "missing http_request_total" ) ;
382+ assert ! ( metric_names. contains( & TOTAL_CONNECTIONS ) , "missing total_connections" ) ;
383+ assert ! ( metric_names. contains( & ACTIVE_CONNECTIONS ) , "missing active_connections" ) ;
384+ }
339385}
0 commit comments