Files
foxhunt/services/api_gateway/tests/metrics_integration_test.rs
jgrusewski 32e33d3d19 🎯 Waves 82-99: Complete compilation fix + warning reduction
## Final Metrics (Wave 99)
- Compilation errors: 672 → 0  (100% resolution)
- Test compilation: 489 → 0  (100% resolution)
- Warnings: 313 → 124 (60% reduction, target was <50)

## Wave Timeline
Wave 82-87: Source code errors (183→0)
Wave 88-94: Test compilation (489→0)
Wave 95: Import cleanup experiment
Wave 96: Import restoration (26 errors fixed)
Wave 97: Warning phase 1 (313→188, -40%)
Wave 98: Warning phase 2 (188→124, -34%)
Wave 99: Warning phase 3 (124→124, target not met)

## Major API Migrations (73+ files)
- NewsEvent: 18-field structure with full metadata
- ExecutionReport: filled_quantity→executed_quantity
- Position: 16-field modernization (avg_cost, market_value, etc)
- TradingOrder: account_id field added
- TimeInForce: Abbreviated variants (GTC, IOC, FOK)

## Remaining Work
- 124 warnings (non-critical: unused variables, dead code, deprecated APIs)
- Most are cleanup/style issues, not correctness problems
- Recommendation: Accept current state, prioritize test coverage (95% target)

## Production Status
 Wave 79 certified: 87.8% production ready
 Zero compilation errors maintained
 All services compile and tests runnable
🔄 Next: Test coverage measurement (95% target - CLAUDE.md requirement)

Co-authored-by: Wave 82-99 Agents (40+ parallel agents deployed)
2025-10-04 12:14:46 +02:00

299 lines
9.7 KiB
Rust

//! Integration tests for API Gateway metrics system
//!
//! Verifies that all metrics are correctly registered and recorded
use api_gateway::metrics::{AuthMetrics, ConfigMetrics, GatewayMetrics, ProxyMetrics};
use prometheus::Registry;
use std::sync::Arc;
#[test]
fn test_gateway_metrics_initialization() {
let metrics = GatewayMetrics::new().expect("Failed to create metrics");
// Verify all subsystems initialized
assert!(Arc::strong_count(&metrics.auth) >= 1);
assert!(Arc::strong_count(&metrics.proxy) >= 1);
assert!(Arc::strong_count(&metrics.config) >= 1);
assert!(Arc::strong_count(&metrics.registry) >= 1);
}
#[test]
fn test_auth_metrics_registration() {
let registry = Registry::new();
let auth_metrics = AuthMetrics::new(&registry).expect("Failed to create auth metrics");
// Record some events
auth_metrics.auth_requests_total.inc();
auth_metrics.record_success(5.5);
auth_metrics.record_failure("expired_jwt", Some("test_user"));
auth_metrics.record_user_request("test_user");
auth_metrics.record_rate_limit("rate_limited_user");
// Verify metrics can be gathered
let metrics = registry.gather();
assert!(!metrics.is_empty(), "No metrics gathered");
// Check specific metrics exist
let metric_names: Vec<String> = metrics.iter().map(|m| m.name().to_string()).collect();
assert!(
metric_names.contains(&"api_gateway_auth_requests_total".to_string()),
"Missing auth_requests_total metric"
);
assert!(
metric_names.contains(&"api_gateway_auth_requests_success".to_string()),
"Missing auth_requests_success metric"
);
assert!(
metric_names.contains(&"api_gateway_auth_sla_met".to_string()),
"Missing auth_sla_met metric"
);
}
#[test]
fn test_proxy_metrics_registration() {
let registry = Registry::new();
let proxy_metrics = ProxyMetrics::new(&registry).expect("Failed to create proxy metrics");
// Record backend events
proxy_metrics.record_backend_success("trading", "ExecuteTrade", 15.5);
proxy_metrics.record_backend_failure("backtesting", "timeout");
proxy_metrics.update_circuit_breaker_state("trading", 0); // closed
proxy_metrics.update_health_status("trading", true);
proxy_metrics.update_connection_pool("trading", 10, 5, 50);
// Verify metrics can be gathered
let metrics = registry.gather();
assert!(!metrics.is_empty(), "No metrics gathered");
let metric_names: Vec<String> = metrics.iter().map(|m| m.name().to_string()).collect();
assert!(
metric_names.contains(&"api_gateway_backend_requests_total".to_string()),
"Missing backend_requests_total metric"
);
assert!(
metric_names.contains(&"api_gateway_circuit_breaker_state".to_string()),
"Missing circuit_breaker_state metric"
);
assert!(
metric_names.contains(&"api_gateway_health_status".to_string()),
"Missing health_status metric"
);
}
#[test]
fn test_config_metrics_registration() {
let registry = Registry::new();
let config_metrics = ConfigMetrics::new(&registry).expect("Failed to create config metrics");
// Record config events
config_metrics.record_notify_event(true);
config_metrics.record_config_reload("auth", 25.0);
config_metrics.update_listener_status(true);
config_metrics.record_reconnection();
// Verify metrics can be gathered
let metrics = registry.gather();
assert!(!metrics.is_empty(), "No metrics gathered");
let metric_names: Vec<String> = metrics.iter().map(|m| m.name().to_string()).collect();
assert!(
metric_names.contains(&"api_gateway_notify_events_total".to_string()),
"Missing notify_events_total metric"
);
assert!(
metric_names.contains(&"api_gateway_config_reload_duration_milliseconds".to_string()),
"Missing config_reload_duration metric"
);
assert!(
metric_names.contains(&"api_gateway_notify_listener_connected".to_string()),
"Missing notify_listener_connected metric"
);
}
#[test]
fn test_auth_sla_tracking() {
let registry = Registry::new();
let auth_metrics = AuthMetrics::new(&registry).expect("Failed to create auth metrics");
// Record requests meeting SLA (<10μs)
auth_metrics.record_success(5.0);
auth_metrics.record_success(8.5);
auth_metrics.record_success(9.9);
// Record requests exceeding SLA (>10μs)
auth_metrics.record_success(15.0);
auth_metrics.record_success(25.5);
let metrics = registry.gather();
let sla_met = metrics
.iter()
.find(|m| m.name() == "api_gateway_auth_sla_met")
.expect("SLA met metric not found");
let sla_exceeded = metrics
.iter()
.find(|m| m.name() == "api_gateway_auth_sla_exceeded")
.expect("SLA exceeded metric not found");
// Verify counts (3 met, 2 exceeded)
assert_eq!(sla_met.metric[0].counter.value, Some(3.0));
assert_eq!(sla_exceeded.metric[0].counter.value, Some(2.0));
}
#[test]
fn test_cache_hit_rate_tracking() {
let registry = Registry::new();
let auth_metrics = AuthMetrics::new(&registry).expect("Failed to create auth metrics");
// Simulate 95% cache hit rate
auth_metrics.jwt_cache_hits.inc_by(95.0);
auth_metrics.jwt_cache_misses.inc_by(5.0);
auth_metrics.rbac_cache_hits.inc_by(98.0);
auth_metrics.rbac_cache_misses.inc_by(2.0);
let metrics = registry.gather();
let jwt_hits = metrics
.iter()
.find(|m| m.name() == "api_gateway_jwt_cache_hits")
.expect("JWT cache hits not found");
let jwt_misses = metrics
.iter()
.find(|m| m.name() == "api_gateway_jwt_cache_misses")
.expect("JWT cache misses not found");
assert_eq!(jwt_hits.metric[0].counter.value, Some(95.0));
assert_eq!(jwt_misses.metric[0].counter.value, Some(5.0));
// Verify hit rate calculation
let hit_rate = 100.0 * 95.0 / (95.0 + 5.0);
assert_eq!(hit_rate, 95.0, "JWT cache hit rate should be 95%");
}
#[test]
fn test_circuit_breaker_state_transitions() {
let registry = Registry::new();
let proxy_metrics = ProxyMetrics::new(&registry).expect("Failed to create proxy metrics");
// Initial state: closed (0)
proxy_metrics.update_circuit_breaker_state("trading", 0);
// Trip circuit breaker (open = 2)
proxy_metrics.record_circuit_breaker_trip("trading");
let metrics = registry.gather();
let cb_state = metrics
.iter()
.find(|m| m.name() == "api_gateway_circuit_breaker_state")
.expect("Circuit breaker state not found");
// Verify state is open (2)
let trading_state = cb_state
.metric
.iter()
.find(|m| {
m.label
.iter()
.any(|l| l.name() == "service" && l.value() == "trading")
})
.expect("Trading service state not found");
assert_eq!(trading_state.gauge.value, Some(2.0));
// Recover circuit breaker (closed = 0)
proxy_metrics.record_circuit_breaker_recovery("trading");
let metrics = registry.gather();
let cb_state = metrics
.iter()
.find(|m| m.name() == "api_gateway_circuit_breaker_state")
.expect("Circuit breaker state not found");
let trading_state = cb_state
.metric
.iter()
.find(|m| {
m.label
.iter()
.any(|l| l.name() == "service" && l.value() == "trading")
})
.expect("Trading service state not found");
assert_eq!(trading_state.gauge.value, Some(0.0));
}
#[test]
fn test_per_user_metrics() {
let registry = Registry::new();
let auth_metrics = AuthMetrics::new(&registry).expect("Failed to create auth metrics");
// Record requests for different users
auth_metrics.record_user_request("user_1");
auth_metrics.record_user_request("user_1");
auth_metrics.record_user_request("user_2");
// Record failures per user
auth_metrics.record_failure("expired_jwt", Some("user_1"));
auth_metrics.record_failure("permission_denied", Some("user_2"));
// Record rate limits
auth_metrics.record_rate_limit("user_3");
auth_metrics.record_rate_limit("user_3");
let metrics = registry.gather();
// Verify per-user request counts
let requests_by_user = metrics
.iter()
.find(|m| m.name() == "api_gateway_requests_by_user")
.expect("Requests by user not found");
assert_eq!(requests_by_user.metric.len(), 2); // user_1 and user_2
// Verify per-user rate limits
let rate_limits_by_user = metrics
.iter()
.find(|m| m.name() == "api_gateway_rate_limits_by_user")
.expect("Rate limits by user not found");
let user_3_limits = rate_limits_by_user
.metric
.iter()
.find(|m| {
m.label
.iter()
.any(|l| l.name() == "user_id" && l.value() == "user_3")
})
.expect("User 3 rate limits not found");
assert_eq!(user_3_limits.counter.value, Some(2.0));
}
#[test]
fn test_metrics_exporter_format() {
use api_gateway::metrics::PrometheusExporter;
let metrics = GatewayMetrics::new().expect("Failed to create metrics");
// Record some events
metrics.auth.record_success(5.0);
metrics.proxy.record_backend_success("trading", "ExecuteTrade", 15.0);
metrics.config.record_notify_event(true);
let exporter = PrometheusExporter::new(metrics.registry());
let output = exporter
.gather_metrics()
.expect("Failed to gather metrics");
// Verify Prometheus text format
assert!(output.contains("# HELP"));
assert!(output.contains("# TYPE"));
assert!(output.contains("api_gateway_auth_requests_success"));
assert!(output.contains("api_gateway_backend_requests_success"));
assert!(output.contains("api_gateway_notify_events_success"));
}