|
|
@ -195,301 +195,3 @@ mod tests { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
|
fn test_database_metrics_collection() { |
|
|
|
|
|
<<<<<<< HEAD |
|
|
|
|
|
update_db_connections("sqlite", 5, 10); |
|
|
|
|
|
update_db_connections("postgresql", 8, 2); |
|
|
|
|
|
observe_db_query_duration("select", 0.025); |
|
|
|
|
|
observe_db_query_duration("insert", 0.045); |
|
|
|
|
|
observe_db_query_duration("update", 0.030); |
|
|
|
|
|
|
|
|
|
|
|
let metrics = gather_metrics().expect("Failed to gather metrics"); |
|
|
|
|
|
assert!(metrics.contains("vaultwarden_db_connections_active")); |
|
|
|
|
|
assert!(metrics.contains("vaultwarden_db_connections_idle")); |
|
|
|
|
|
assert!(metrics.contains("vaultwarden_db_query_duration_seconds")); |
|
|
|
|
|
======= |
|
|
|
|
|
// Test database connection metrics
|
|
|
|
|
|
update_db_connections("sqlite", 5, 10); |
|
|
|
|
|
update_db_connections("postgresql", 8, 2); |
|
|
|
|
|
|
|
|
|
|
|
// Test database query duration metrics
|
|
|
|
|
|
observe_db_query_duration("select", 0.025); |
|
|
|
|
|
observe_db_query_duration("insert", 0.045); |
|
|
|
|
|
observe_db_query_duration("update", 0.030); |
|
|
|
|
|
>>>>>>> dfe102f5 (feat: add comprehensive Prometheus metrics support) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
|
fn test_authentication_metrics() { |
|
|
|
|
|
<<<<<<< HEAD |
|
|
|
|
|
======= |
|
|
|
|
|
// Test authentication attempt metrics
|
|
|
|
|
|
>>>>>>> dfe102f5 (feat: add comprehensive Prometheus metrics support) |
|
|
|
|
|
increment_auth_attempts("password", "success"); |
|
|
|
|
|
increment_auth_attempts("password", "failed"); |
|
|
|
|
|
increment_auth_attempts("webauthn", "success"); |
|
|
|
|
|
increment_auth_attempts("2fa", "failed"); |
|
|
|
|
|
<<<<<<< HEAD |
|
|
|
|
|
update_user_sessions("authenticated", 150); |
|
|
|
|
|
update_user_sessions("anonymous", 5); |
|
|
|
|
|
|
|
|
|
|
|
let metrics = gather_metrics().expect("Failed to gather metrics"); |
|
|
|
|
|
assert!(metrics.contains("vaultwarden_auth_attempts_total")); |
|
|
|
|
|
assert!(metrics.contains("vaultwarden_user_sessions_active")); |
|
|
|
|
|
======= |
|
|
|
|
|
|
|
|
|
|
|
// Test user session metrics
|
|
|
|
|
|
update_user_sessions("authenticated", 150); |
|
|
|
|
|
update_user_sessions("anonymous", 5); |
|
|
|
|
|
>>>>>>> dfe102f5 (feat: add comprehensive Prometheus metrics support) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
|
fn test_build_info_initialization() { |
|
|
|
|
|
<<<<<<< HEAD |
|
|
|
|
|
init_build_info(); |
|
|
|
|
|
let start_time = std::time::SystemTime::now(); |
|
|
|
|
|
update_uptime(start_time); |
|
|
|
|
|
|
|
|
|
|
|
let metrics = gather_metrics().expect("Failed to gather metrics"); |
|
|
|
|
|
assert!(metrics.contains("vaultwarden_build_info")); |
|
|
|
|
|
assert!(metrics.contains("vaultwarden_uptime_seconds")); |
|
|
|
|
|
======= |
|
|
|
|
|
// Test build info metrics initialization
|
|
|
|
|
|
init_build_info(); |
|
|
|
|
|
|
|
|
|
|
|
// Test uptime metrics
|
|
|
|
|
|
let start_time = std::time::SystemTime::now(); |
|
|
|
|
|
update_uptime(start_time); |
|
|
|
|
|
>>>>>>> dfe102f5 (feat: add comprehensive Prometheus metrics support) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
|
fn test_metrics_gathering() { |
|
|
|
|
|
<<<<<<< HEAD |
|
|
|
|
|
======= |
|
|
|
|
|
// Initialize some metrics
|
|
|
|
|
|
>>>>>>> dfe102f5 (feat: add comprehensive Prometheus metrics support) |
|
|
|
|
|
increment_http_requests("GET", "/api/sync", 200); |
|
|
|
|
|
update_db_connections("sqlite", 1, 5); |
|
|
|
|
|
init_build_info(); |
|
|
|
|
|
|
|
|
|
|
|
<<<<<<< HEAD |
|
|
|
|
|
let metrics_output = gather_metrics(); |
|
|
|
|
|
assert!(metrics_output.is_ok(), "gather_metrics should succeed"); |
|
|
|
|
|
|
|
|
|
|
|
let metrics_text = metrics_output.unwrap(); |
|
|
|
|
|
assert!(!metrics_text.is_empty(), "metrics output should not be empty"); |
|
|
|
|
|
assert!(metrics_text.contains("# HELP"), "metrics should have HELP lines"); |
|
|
|
|
|
assert!(metrics_text.contains("# TYPE"), "metrics should have TYPE lines"); |
|
|
|
|
|
assert!(metrics_text.contains("vaultwarden_"), "metrics should contain vaultwarden prefix"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[tokio::test] |
|
|
|
|
|
async fn test_business_metrics_collection_noop() { |
|
|
|
|
|
// Business metrics require database access, which cannot be easily mocked in unit tests.
|
|
|
|
|
|
// This test verifies that the async function exists and can be called without panicking.
|
|
|
|
|
|
// Integration tests would provide database access and verify metrics are actually updated.
|
|
|
|
|
|
init_build_info(); |
|
|
|
|
|
let metrics = gather_metrics().expect("Failed to gather metrics"); |
|
|
|
|
|
assert!(metrics.contains("vaultwarden_"), "Business metrics should be accessible"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
|
fn test_path_normalization() { |
|
|
|
|
|
======= |
|
|
|
|
|
// Test gathering all metrics
|
|
|
|
|
|
let metrics_output = gather_metrics(); |
|
|
|
|
|
assert!(metrics_output.is_ok()); |
|
|
|
|
|
|
|
|
|
|
|
let metrics_text = metrics_output.unwrap(); |
|
|
|
|
|
assert!(!metrics_text.is_empty()); |
|
|
|
|
|
|
|
|
|
|
|
// Should contain Prometheus format headers
|
|
|
|
|
|
assert!(metrics_text.contains("# HELP")); |
|
|
|
|
|
assert!(metrics_text.contains("# TYPE")); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[tokio::test] |
|
|
|
|
|
async fn test_business_metrics_collection() { |
|
|
|
|
|
// This test would require a mock database connection
|
|
|
|
|
|
// For now, we just test that the function doesn't panic
|
|
|
|
|
|
|
|
|
|
|
|
// In a real test, you would:
|
|
|
|
|
|
// 1. Create a test database
|
|
|
|
|
|
// 2. Insert test data (users, organizations, ciphers)
|
|
|
|
|
|
// 3. Call update_business_metrics
|
|
|
|
|
|
// 4. Verify the metrics were updated correctly
|
|
|
|
|
|
|
|
|
|
|
|
// Placeholder test - in production this would use a mock DbConn
|
|
|
|
|
|
assert!(true); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
|
fn test_path_normalization() { |
|
|
|
|
|
// Test that path normalization works for metric cardinality control
|
|
|
|
|
|
>>>>>>> dfe102f5 (feat: add comprehensive Prometheus metrics support) |
|
|
|
|
|
increment_http_requests("GET", "/api/sync", 200); |
|
|
|
|
|
increment_http_requests("GET", "/api/accounts/123/profile", 200); |
|
|
|
|
|
increment_http_requests("POST", "/api/organizations/456/users", 201); |
|
|
|
|
|
increment_http_requests("PUT", "/api/ciphers/789", 200); |
|
|
|
|
|
<<<<<<< HEAD |
|
|
|
|
|
|
|
|
|
|
|
let result = gather_metrics(); |
|
|
|
|
|
assert!(result.is_ok(), "gather_metrics should succeed with various paths"); |
|
|
|
|
|
|
|
|
|
|
|
let metrics_text = result.unwrap(); |
|
|
|
|
|
assert!(!metrics_text.is_empty(), "metrics output should not be empty"); |
|
|
|
|
|
assert!(metrics_text.contains("vaultwarden_http_requests_total"), "should have http request metrics"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
|
fn test_concurrent_metrics_collection() { |
|
|
|
|
|
use std::thread; |
|
|
|
|
|
|
|
|
|
|
|
======= |
|
|
|
|
|
|
|
|
|
|
|
// Test that gather_metrics works
|
|
|
|
|
|
let result = gather_metrics(); |
|
|
|
|
|
assert!(result.is_ok()); |
|
|
|
|
|
|
|
|
|
|
|
let metrics_text = result.unwrap(); |
|
|
|
|
|
// Paths should be normalized in the actual implementation
|
|
|
|
|
|
// This test verifies the collection doesn't panic
|
|
|
|
|
|
assert!(!metrics_text.is_empty()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
|
fn test_concurrent_metrics_collection() { |
|
|
|
|
|
use std::sync::Arc; |
|
|
|
|
|
use std::thread; |
|
|
|
|
|
|
|
|
|
|
|
// Test concurrent access to metrics
|
|
|
|
|
|
>>>>>>> dfe102f5 (feat: add comprehensive Prometheus metrics support) |
|
|
|
|
|
let handles: Vec<_> = (0..10).map(|i| { |
|
|
|
|
|
thread::spawn(move || { |
|
|
|
|
|
increment_http_requests("GET", "/api/sync", 200); |
|
|
|
|
|
observe_http_request_duration("GET", "/api/sync", 0.1 + (i as f64 * 0.01)); |
|
|
|
|
|
update_db_connections("sqlite", i, 10 - i); |
|
|
|
|
|
}) |
|
|
|
|
|
}).collect(); |
|
|
|
|
|
<<<<<<< HEAD |
|
|
|
|
|
|
|
|
|
|
|
for handle in handles { |
|
|
|
|
|
handle.join().expect("Thread panicked"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
let result = gather_metrics(); |
|
|
|
|
|
assert!(result.is_ok(), "metrics collection should be thread-safe"); |
|
|
|
|
|
assert!(!result.unwrap().is_empty(), "concurrent access should not corrupt metrics"); |
|
|
|
|
|
======= |
|
|
|
|
|
|
|
|
|
|
|
// Wait for all threads to complete
|
|
|
|
|
|
for handle in handles { |
|
|
|
|
|
handle.join().unwrap(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Verify metrics collection still works
|
|
|
|
|
|
let result = gather_metrics(); |
|
|
|
|
|
assert!(result.is_ok()); |
|
|
|
|
|
>>>>>>> dfe102f5 (feat: add comprehensive Prometheus metrics support) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[cfg(not(feature = "enable_metrics"))] |
|
|
|
|
|
mod metrics_disabled_tests { |
|
|
|
|
|
use super::*; |
|
|
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
|
fn test_no_op_implementations() { |
|
|
|
|
|
<<<<<<< HEAD |
|
|
|
|
|
======= |
|
|
|
|
|
// When metrics are disabled, all functions should be no-ops
|
|
|
|
|
|
>>>>>>> dfe102f5 (feat: add comprehensive Prometheus metrics support) |
|
|
|
|
|
increment_http_requests("GET", "/api/sync", 200); |
|
|
|
|
|
observe_http_request_duration("GET", "/api/sync", 0.150); |
|
|
|
|
|
update_db_connections("sqlite", 5, 10); |
|
|
|
|
|
observe_db_query_duration("select", 0.025); |
|
|
|
|
|
increment_auth_attempts("password", "success"); |
|
|
|
|
|
update_user_sessions("authenticated", 150); |
|
|
|
|
|
init_build_info(); |
|
|
|
|
|
<<<<<<< HEAD |
|
|
|
|
|
|
|
|
|
|
|
let start_time = std::time::SystemTime::now(); |
|
|
|
|
|
update_uptime(start_time); |
|
|
|
|
|
|
|
|
|
|
|
let result = gather_metrics(); |
|
|
|
|
|
assert!(result.is_ok(), "disabled metrics should return ok"); |
|
|
|
|
|
assert_eq!(result.unwrap(), "Metrics not enabled", "should return disabled message"); |
|
|
|
|
|
======= |
|
|
|
|
|
|
|
|
|
|
|
let start_time = std::time::SystemTime::now(); |
|
|
|
|
|
update_uptime(start_time); |
|
|
|
|
|
|
|
|
|
|
|
// Test that gather_metrics returns a disabled message
|
|
|
|
|
|
let result = gather_metrics(); |
|
|
|
|
|
assert!(result.is_ok()); |
|
|
|
|
|
assert_eq!(result.unwrap(), "Metrics not enabled"); |
|
|
|
|
|
>>>>>>> dfe102f5 (feat: add comprehensive Prometheus metrics support) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[tokio::test] |
|
|
|
|
|
async fn test_business_metrics_no_op() { |
|
|
|
|
|
<<<<<<< HEAD |
|
|
|
|
|
let result = gather_metrics(); |
|
|
|
|
|
assert!(result.is_ok(), "disabled metrics should not panic"); |
|
|
|
|
|
assert_eq!(result.unwrap(), "Metrics not enabled", "should return disabled message"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
|
fn test_concurrent_no_op_calls() { |
|
|
|
|
|
use std::thread; |
|
|
|
|
|
|
|
|
|
|
|
======= |
|
|
|
|
|
// This should also be a no-op when metrics are disabled
|
|
|
|
|
|
// We can't test with a real DbConn without significant setup,
|
|
|
|
|
|
// but we can verify it doesn't panic
|
|
|
|
|
|
|
|
|
|
|
|
// In a real implementation, you'd mock DbConn
|
|
|
|
|
|
assert!(true); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
|
fn test_concurrent_no_op_calls() { |
|
|
|
|
|
use std::thread; |
|
|
|
|
|
|
|
|
|
|
|
// Test that concurrent calls to disabled metrics don't cause issues
|
|
|
|
|
|
>>>>>>> dfe102f5 (feat: add comprehensive Prometheus metrics support) |
|
|
|
|
|
let handles: Vec<_> = (0..5).map(|i| { |
|
|
|
|
|
thread::spawn(move || { |
|
|
|
|
|
increment_http_requests("GET", "/test", 200); |
|
|
|
|
|
observe_http_request_duration("GET", "/test", 0.1); |
|
|
|
|
|
update_db_connections("test", i, 5 - i); |
|
|
|
|
|
increment_auth_attempts("password", "success"); |
|
|
|
|
|
}) |
|
|
|
|
|
}).collect(); |
|
|
|
|
|
<<<<<<< HEAD |
|
|
|
|
|
|
|
|
|
|
|
for handle in handles { |
|
|
|
|
|
handle.join().expect("Thread panicked"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
let result = gather_metrics(); |
|
|
|
|
|
assert!(result.is_ok(), "disabled metrics should be thread-safe"); |
|
|
|
|
|
assert_eq!(result.unwrap(), "Metrics not enabled", "disabled metrics should always return same message"); |
|
|
|
|
|
======= |
|
|
|
|
|
|
|
|
|
|
|
for handle in handles { |
|
|
|
|
|
handle.join().unwrap(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// All calls should be no-ops
|
|
|
|
|
|
let result = gather_metrics(); |
|
|
|
|
|
assert!(result.is_ok()); |
|
|
|
|
|
assert_eq!(result.unwrap(), "Metrics not enabled"); |
|
|
|
|
|
>>>>>>> dfe102f5 (feat: add comprehensive Prometheus metrics support) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|