#![cfg(feature = "observability")]
use std::collections::HashMap;
use std::time::Duration;
use things3_core::observability::{
CheckResult, HealthStatus, ObservabilityConfig, ObservabilityManager,
};
#[test]
fn test_observability_config_with_all_features_enabled() {
let config = ObservabilityConfig {
log_level: "debug".to_string(),
json_logs: true,
enable_tracing: true,
jaeger_endpoint: Some("http://localhost:14268/api/traces".to_string()),
otlp_endpoint: Some("http://localhost:4317".to_string()),
enable_metrics: true,
metrics_port: 9090,
health_port: 8080,
service_name: "things3-test".to_string(),
service_version: "1.0.0".to_string(),
};
assert_eq!(config.log_level, "debug");
assert!(config.json_logs);
assert!(config.enable_tracing);
assert!(config.jaeger_endpoint.is_some());
assert!(config.otlp_endpoint.is_some());
assert!(config.enable_metrics);
assert_eq!(config.metrics_port, 9090);
assert_eq!(config.health_port, 8080);
}
#[test]
fn test_observability_config_with_minimal_features() {
let config = ObservabilityConfig {
log_level: "error".to_string(),
json_logs: false,
enable_tracing: false,
jaeger_endpoint: None,
otlp_endpoint: None,
enable_metrics: false,
metrics_port: 9090,
health_port: 8080,
service_name: "things3-minimal".to_string(),
service_version: "0.1.0".to_string(),
};
assert_eq!(config.log_level, "error");
assert!(!config.json_logs);
assert!(!config.enable_tracing);
assert!(config.jaeger_endpoint.is_none());
assert!(config.otlp_endpoint.is_none());
assert!(!config.enable_metrics);
}
#[test]
fn test_observability_config_log_levels() {
let levels = vec!["trace", "debug", "info", "warn", "error"];
for level in levels {
let config = ObservabilityConfig {
log_level: level.to_string(),
..Default::default()
};
assert_eq!(config.log_level, level);
}
}
#[test]
fn test_observability_config_custom_ports() {
let config = ObservabilityConfig {
metrics_port: 3000,
health_port: 3001,
..Default::default()
};
assert_eq!(config.metrics_port, 3000);
assert_eq!(config.health_port, 3001);
}
#[test]
fn test_observability_config_with_jaeger_only() {
let config = ObservabilityConfig {
jaeger_endpoint: Some("http://jaeger:14268/api/traces".to_string()),
otlp_endpoint: None,
..Default::default()
};
assert!(config.jaeger_endpoint.is_some());
assert!(config.otlp_endpoint.is_none());
}
#[test]
fn test_observability_config_with_otlp_only() {
let config = ObservabilityConfig {
jaeger_endpoint: None,
otlp_endpoint: Some("http://otel-collector:4317".to_string()),
..Default::default()
};
assert!(config.jaeger_endpoint.is_none());
assert!(config.otlp_endpoint.is_some());
}
#[test]
fn test_observability_manager_creation_with_default_config() {
let config = ObservabilityConfig::default();
let manager = ObservabilityManager::new(config);
assert!(manager.is_ok());
}
#[test]
fn test_observability_manager_creation_with_custom_config() {
let config = ObservabilityConfig {
log_level: "debug".to_string(),
json_logs: true,
enable_tracing: true,
enable_metrics: true,
..Default::default()
};
let manager = ObservabilityManager::new(config);
assert!(manager.is_ok());
}
#[test]
fn test_observability_manager_initialization() {
let config = ObservabilityConfig::default();
let manager = ObservabilityManager::new(config).unwrap();
assert!(manager.health_status().status == "healthy");
}
#[test]
fn test_observability_manager_with_tracing_disabled() {
let config = ObservabilityConfig {
enable_tracing: false,
..Default::default()
};
let manager = ObservabilityManager::new(config).unwrap();
assert!(manager.health_status().status == "healthy");
}
#[test]
fn test_observability_manager_with_metrics_disabled() {
let config = ObservabilityConfig {
enable_metrics: false,
..Default::default()
};
let manager = ObservabilityManager::new(config).unwrap();
assert!(manager.health_status().status == "healthy");
}
#[test]
fn test_observability_manager_with_all_features_disabled() {
let config = ObservabilityConfig {
enable_tracing: false,
enable_metrics: false,
..Default::default()
};
let manager = ObservabilityManager::new(config).unwrap();
assert!(manager.health_status().status == "healthy");
}
#[test]
fn test_metrics_record_database_operations() {
let config = ObservabilityConfig::default();
let manager = ObservabilityManager::new(config).unwrap();
for i in 0..5 {
let result = manager.record_db_operation("test_query", || {
i * 2
});
assert_eq!(result, i * 2);
}
}
#[test]
fn test_metrics_record_task_operations() {
let config = ObservabilityConfig::default();
let manager = ObservabilityManager::new(config).unwrap();
manager.record_task_operation("create", 1);
manager.record_task_operation("update", 1);
manager.record_task_operation("delete", 1);
manager.record_task_operation("complete", 1);
}
#[test]
fn test_metrics_record_search_operations() {
let config = ObservabilityConfig::default();
let manager = ObservabilityManager::new(config).unwrap();
let result1 = manager.record_search_operation("test query 1", || vec![1, 2, 3, 4, 5]);
assert_eq!(result1.len(), 5);
let result2 = manager.record_search_operation("test query 2", || vec![1, 2, 3]);
assert_eq!(result2.len(), 3);
}
#[test]
fn test_metrics_record_errors() {
let config = ObservabilityConfig::default();
let manager = ObservabilityManager::new(config).unwrap();
for i in 0..3 {
manager.record_error(&format!("error_type_{}", i), "Test error message");
}
}
#[test]
fn test_health_status_creation() {
let config = ObservabilityConfig::default();
let manager = ObservabilityManager::new(config).unwrap();
let health = manager.health_status();
assert_eq!(health.status, "healthy");
assert_eq!(health.version, env!("CARGO_PKG_VERSION"));
assert!(!health.checks.is_empty());
}
#[test]
fn test_health_status_with_checks() {
let mut checks = HashMap::new();
checks.insert(
"database".to_string(),
CheckResult {
status: "healthy".to_string(),
message: Some("Connection OK".to_string()),
duration_ms: 5,
},
);
checks.insert(
"cache".to_string(),
CheckResult {
status: "healthy".to_string(),
message: None,
duration_ms: 1,
},
);
let health = HealthStatus {
status: "healthy".to_string(),
timestamp: chrono::Utc::now(),
version: "1.0.0".to_string(),
uptime: Duration::from_secs(3600),
checks,
};
assert_eq!(health.checks.len(), 2);
assert!(health.checks.contains_key("database"));
assert!(health.checks.contains_key("cache"));
}
#[test]
fn test_health_status_degraded() {
let mut checks = HashMap::new();
checks.insert(
"database".to_string(),
CheckResult {
status: "healthy".to_string(),
message: None,
duration_ms: 5,
},
);
checks.insert(
"cache".to_string(),
CheckResult {
status: "degraded".to_string(),
message: Some("High latency".to_string()),
duration_ms: 100,
},
);
let health = HealthStatus {
status: "degraded".to_string(),
timestamp: chrono::Utc::now(),
version: "1.0.0".to_string(),
uptime: Duration::from_secs(3600),
checks,
};
assert_eq!(health.status, "degraded");
assert_eq!(health.checks["cache"].status, "degraded");
}
#[test]
fn test_logging_with_json_format() {
let config = ObservabilityConfig {
json_logs: true,
log_level: "info".to_string(),
..Default::default()
};
let manager = ObservabilityManager::new(config).unwrap();
assert!(manager.health_status().status == "healthy");
}
#[test]
fn test_logging_with_text_format() {
let config = ObservabilityConfig {
json_logs: false,
log_level: "debug".to_string(),
..Default::default()
};
let manager = ObservabilityManager::new(config).unwrap();
assert!(manager.health_status().status == "healthy");
}
#[test]
fn test_logging_with_different_levels() {
let levels = vec!["trace", "debug", "info", "warn", "error"];
for level in levels {
let config = ObservabilityConfig {
log_level: level.to_string(),
..Default::default()
};
let manager = ObservabilityManager::new(config).unwrap();
assert!(manager.health_status().status == "healthy");
}
}
#[test]
fn test_full_observability_stack() {
let config = ObservabilityConfig {
log_level: "debug".to_string(),
json_logs: false,
enable_tracing: true,
enable_metrics: true,
jaeger_endpoint: Some("http://localhost:14268/api/traces".to_string()),
otlp_endpoint: Some("http://localhost:4317".to_string()),
metrics_port: 9090,
health_port: 8080,
service_name: "things3-integration-test".to_string(),
service_version: "1.0.0".to_string(),
};
let manager = ObservabilityManager::new(config).unwrap();
manager.record_db_operation("test_op", || 42);
manager.record_task_operation("create", 1);
manager.record_search_operation("test query", || vec![1, 2, 3, 4, 5]);
manager.record_error("test_error", "Test error message");
let health = manager.health_status();
assert_eq!(health.status, "healthy");
}
#[test]
fn test_observability_with_multiple_operations() {
let config = ObservabilityConfig::default();
let manager = ObservabilityManager::new(config).unwrap();
for i in 0..10 {
manager.record_db_operation(&format!("operation_{}", i), || i);
if i % 2 == 0 {
manager.record_task_operation("create", 1);
} else {
manager.record_task_operation("update", 1);
}
}
manager.record_search_operation("test query", || {
vec![1; 50] });
manager.record_error("test_error", "Simulated error");
}
#[test]
fn test_observability_config_round_trip_serialization() {
let original_config = ObservabilityConfig {
log_level: "debug".to_string(),
json_logs: true,
enable_tracing: true,
jaeger_endpoint: Some("http://jaeger:14268".to_string()),
otlp_endpoint: Some("http://otel:4317".to_string()),
enable_metrics: true,
metrics_port: 9091,
health_port: 8081,
service_name: "test-service".to_string(),
service_version: "2.0.0".to_string(),
};
let json = serde_json::to_string(&original_config).unwrap();
let deserialized_config: ObservabilityConfig = serde_json::from_str(&json).unwrap();
assert_eq!(original_config.log_level, deserialized_config.log_level);
assert_eq!(original_config.json_logs, deserialized_config.json_logs);
assert_eq!(
original_config.enable_tracing,
deserialized_config.enable_tracing
);
assert_eq!(
original_config.jaeger_endpoint,
deserialized_config.jaeger_endpoint
);
assert_eq!(
original_config.otlp_endpoint,
deserialized_config.otlp_endpoint
);
assert_eq!(
original_config.enable_metrics,
deserialized_config.enable_metrics
);
assert_eq!(
original_config.metrics_port,
deserialized_config.metrics_port
);
assert_eq!(original_config.health_port, deserialized_config.health_port);
assert_eq!(
original_config.service_name,
deserialized_config.service_name
);
assert_eq!(
original_config.service_version,
deserialized_config.service_version
);
}