use crate::metrics; use crate::security::AuthInterceptor; use tonic::service::Interceptor; use tonic::Request; // Since counters are lazy statics, we can get their values directly for testing use std::thread::sleep; use std::time::Duration; #[test] fn test_metrics_request_timer_ok() { let method = "test_method_ok"; let timer = metrics::RequestTimer::new(method); // Simulate some work sleep(Duration::from_millis(10)); timer.finish_ok(); // Check counters let started = metrics::GRPC_REQUESTS_TOTAL .with_label_values(&[method, "started"]) .get(); let ok = metrics::GRPC_REQUESTS_TOTAL .with_label_values(&[method, "ok"]) .get(); assert_eq!(started, 1.0); assert_eq!(ok, 1.0); } #[test] fn test_metrics_request_timer_err() { let method = "test_method_err"; let timer = metrics::RequestTimer::new(method); // Simulate some work sleep(Duration::from_millis(5)); timer.finish_err(); // Check counters let started = metrics::GRPC_REQUESTS_TOTAL .with_label_values(&[method, "started"]) .get(); let err = metrics::GRPC_REQUESTS_TOTAL .with_label_values(&[method, "error"]) .get(); assert_eq!(started, 1.0); assert_eq!(err, 1.0); } #[test] fn test_metrics_render() { // Just trigger a metric to ensure the registry isn't empty metrics::BYTES_READ_TOTAL.inc_by(4096.0); let rendered = metrics::render_metrics(); assert!(rendered.contains("furumi_bytes_read_total")); assert!(rendered.contains("4096")); } #[test] fn test_server_auth_interceptor_valid() { let mut interceptor = AuthInterceptor::new("supersecret".to_string()); let mut req = Request::new(()); req.metadata_mut() .insert("authorization", "Bearer supersecret".parse().unwrap()); let res = interceptor.call(req); assert!(res.is_ok(), "Valid token should be accepted"); } #[test] fn test_server_auth_interceptor_invalid() { let mut interceptor = AuthInterceptor::new("supersecret".to_string()); let mut req = Request::new(()); req.metadata_mut() .insert("authorization", "Bearer wrongtoken".parse().unwrap()); let res = interceptor.call(req); assert!(res.is_err(), "Invalid token should be rejected"); assert_eq!(res.unwrap_err().code(), tonic::Code::Unauthenticated); } #[test] fn test_server_auth_interceptor_missing() { let mut interceptor = AuthInterceptor::new("supersecret".to_string()); let req = Request::new(()); // Missing metadata entirely let res = interceptor.call(req); assert!( res.is_err(), "Missing token should be rejected when auth is enabled" ); assert_eq!(res.unwrap_err().code(), tonic::Code::Unauthenticated); } #[test] fn test_server_auth_interceptor_disabled() { // Empty string means auth is disabled let mut interceptor = AuthInterceptor::new("".to_string()); let req = Request::new(()); let res = interceptor.call(req); assert!( res.is_ok(), "Request should pass if auth is disabled on server" ); }