You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

231 lines
8.4 KiB

#[cfg(feature = "enable_metrics")]
mod metrics_integration_tests {
use rocket::local::blocking::Client;
use rocket::http::{Status, Header, ContentType};
use rocket::serde::json;
use vaultwarden::api::core::routes as core_routes;
use vaultwarden::api::metrics::routes as metrics_routes;
use vaultwarden::CONFIG;
use vaultwarden::metrics;
fn create_test_rocket() -> rocket::Rocket<rocket::Build> {
// Initialize metrics for testing
metrics::init_build_info();
rocket::build()
.mount("/", core_routes())
.mount("/", metrics_routes())
.attach(vaultwarden::api::middleware::MetricsFairing)
}
#[test]
fn test_metrics_endpoint_without_auth() {
let client = Client::tracked(create_test_rocket()).expect("valid rocket instance");
// Test without authorization header
let response = client.get("/metrics").dispatch();
// Should return 401 Unauthorized when metrics token is required
if CONFIG.metrics_token().is_some() {
assert_eq!(response.status(), Status::Unauthorized);
} else {
// If no token is configured, it should work
assert_eq!(response.status(), Status::Ok);
}
}
#[test]
fn test_metrics_endpoint_with_bearer_token() {
let client = Client::tracked(create_test_rocket()).expect("valid rocket instance");
// Test with Bearer token
if let Some(token) = CONFIG.metrics_token() {
let auth_header = Header::new("Authorization", format!("Bearer {}", token));
let response = client.get("/metrics").header(auth_header).dispatch();
assert_eq!(response.status(), Status::Ok);
let body = response.into_string().expect("response body");
assert!(body.contains("# HELP"));
assert!(body.contains("# TYPE"));
assert!(body.contains("vaultwarden_"));
}
}
#[test]
fn test_metrics_endpoint_with_query_parameter() {
let client = Client::tracked(create_test_rocket()).expect("valid rocket instance");
// Test with query parameter
if let Some(token) = CONFIG.metrics_token() {
let response = client.get(format!("/metrics?token={}", token)).dispatch();
assert_eq!(response.status(), Status::Ok);
let body = response.into_string().expect("response body");
assert!(body.contains("# HELP"));
assert!(body.contains("# TYPE"));
}
}
#[test]
fn test_metrics_endpoint_with_invalid_token() {
let client = Client::tracked(create_test_rocket()).expect("valid rocket instance");
// Test with invalid Bearer token
let auth_header = Header::new("Authorization", "Bearer invalid-token");
let response = client.get("/metrics").header(auth_header).dispatch();
assert_eq!(response.status(), Status::Unauthorized);
}
#[test]
fn test_metrics_content_format() {
let client = Client::tracked(create_test_rocket()).expect("valid rocket instance");
// Setup authorization if needed
let mut request = client.get("/metrics");
if let Some(token) = CONFIG.metrics_token() {
let auth_header = Header::new("Authorization", format!("Bearer {}", token));
request = request.header(auth_header);
}
let response = request.dispatch();
if response.status() == Status::Ok {
let body = response.into_string().expect("response body");
// Verify Prometheus format
assert!(body.contains("# HELP"));
assert!(body.contains("# TYPE"));
// Verify expected metrics exist
assert!(body.contains("vaultwarden_build_info"));
assert!(body.contains("vaultwarden_uptime_seconds"));
// Verify metric types
assert!(body.contains("TYPE vaultwarden_build_info gauge"));
assert!(body.contains("TYPE vaultwarden_uptime_seconds gauge"));
}
}
#[test]
fn test_metrics_instrumentation() {
let client = Client::tracked(create_test_rocket()).expect("valid rocket instance");
// Make some requests to generate HTTP metrics
let _response1 = client.get("/alive").dispatch();
let _response2 = client.post("/api/accounts/register")
.header(ContentType::JSON)
.body(r#"{"email":"test@example.com"}"#)
.dispatch();
// Now check metrics
let mut metrics_request = client.get("/metrics");
if let Some(token) = CONFIG.metrics_token() {
let auth_header = Header::new("Authorization", format!("Bearer {}", token));
metrics_request = metrics_request.header(auth_header);
}
let response = metrics_request.dispatch();
if response.status() == Status::Ok {
let body = response.into_string().expect("response body");
// Should contain HTTP request metrics
assert!(body.contains("vaultwarden_http_requests_total"));
assert!(body.contains("vaultwarden_http_request_duration_seconds"));
}
}
#[test]
fn test_multiple_concurrent_requests() {
use std::thread;
use std::sync::Arc;
let client = Arc::new(Client::tracked(create_test_rocket()).expect("valid rocket instance"));
// Spawn multiple threads making requests
let handles: Vec<_> = (0..5).map(|_| {
let client = Arc::clone(&client);
thread::spawn(move || {
client.get("/alive").dispatch();
})
}).collect();
// Wait for all requests to complete
for handle in handles {
handle.join().unwrap();
}
// Check that metrics were collected
let mut metrics_request = client.get("/metrics");
if let Some(token) = CONFIG.metrics_token() {
let auth_header = Header::new("Authorization", format!("Bearer {}", token));
metrics_request = metrics_request.header(auth_header);
}
let response = metrics_request.dispatch();
assert!(response.status() == Status::Ok || response.status() == Status::Unauthorized);
}
#[test]
fn test_metrics_performance() {
let client = Client::tracked(create_test_rocket()).expect("valid rocket instance");
let start = std::time::Instant::now();
let mut metrics_request = client.get("/metrics");
if let Some(token) = CONFIG.metrics_token() {
let auth_header = Header::new("Authorization", format!("Bearer {}", token));
metrics_request = metrics_request.header(auth_header);
}
let response = metrics_request.dispatch();
let duration = start.elapsed();
// Metrics endpoint should respond quickly (under 1 second)
assert!(duration.as_secs() < 1);
if response.status() == Status::Ok {
let body = response.into_string().expect("response body");
// Should return meaningful content
assert!(body.len() > 100);
}
}
}
#[cfg(not(feature = "enable_metrics"))]
mod metrics_disabled_tests {
use rocket::local::blocking::Client;
use rocket::http::Status;
use vaultwarden::api::core::routes as core_routes;
fn create_test_rocket() -> rocket::Rocket<rocket::Build> {
rocket::build()
.mount("/", core_routes())
// Note: metrics routes should not be mounted when feature is disabled
}
#[test]
fn test_metrics_endpoint_not_available() {
let client = Client::tracked(create_test_rocket()).expect("valid rocket instance");
// Metrics endpoint should not exist when feature is disabled
let response = client.get("/metrics").dispatch();
assert_eq!(response.status(), Status::NotFound);
}
#[test]
fn test_normal_endpoints_still_work() {
let client = Client::tracked(create_test_rocket()).expect("valid rocket instance");
// Normal endpoints should still work
let response = client.get("/alive").dispatch();
assert_eq!(response.status(), Status::Ok);
}
}