provisioning-platform/prov-ecosystem/crates/daemon-cli/tests/integration_tests.rs

293 lines
8.3 KiB
Rust
Raw Normal View History

//! Integration tests for daemon-cli
//!
//! Tests interaction between multiple components
use std::sync::Arc;
use daemon_cli::orchestration::{EncryptOperation, RuntimeOperation, ValidaOperation};
use daemon_cli::{
Event, EventBus, EventPayload, EventType, HealthProbe, OperationRegistry, ProbeStatus,
};
#[tokio::test]
async fn test_operation_registry_workflow() {
// Create cache (shared across operations)
let cache = Arc::new(daemon_cli::core::HierarchicalCache::new().unwrap());
// Create registry and register operations
let mut registry = OperationRegistry::default();
registry.register("valida", Arc::new(ValidaOperation::new(cache.clone())));
registry.register("runtime", Arc::new(RuntimeOperation::new(cache.clone())));
registry.register("encrypt", Arc::new(EncryptOperation::new(cache.clone())));
// Verify all operations registered
assert_eq!(registry.len(), 3);
assert!(registry.contains("valida"));
assert!(registry.contains("runtime"));
assert!(registry.contains("encrypt"));
// Verify list operation
let ops = registry.list();
assert_eq!(ops.len(), 3);
}
#[tokio::test]
async fn test_event_bus_workflow() {
let bus = EventBus::new(100);
// Create publisher and subscriber
let mut subscriber = bus.subscribe();
// Publish event
let payload = EventPayload::new("test-op", true).with_target("config.yaml");
let event = daemon_cli::Event::new(EventType::ValidationCompleted, payload);
let result = bus.publish(event.clone());
assert!(result.is_ok());
assert_eq!(result.unwrap(), 1); // One subscriber
// Receive event
let received = subscriber.recv().await.unwrap();
assert_eq!(received.event_type, EventType::ValidationCompleted);
assert!(received.payload.success);
assert_eq!(received.payload.target, Some("config.yaml".to_string()));
drop(received); // Drop to use it
}
#[tokio::test]
async fn test_event_filtering() {
let bus = EventBus::new(100);
let mut subscriber = bus.subscribe();
// Publish multiple events of different types
let payload1 = EventPayload::new("valida", true);
let event1 = Event::new(EventType::ValidationCompleted, payload1);
bus.publish(event1).ok();
let payload2 = EventPayload::new("runtime", true);
let event2 = Event::new(EventType::RuntimeDetected, payload2);
bus.publish(event2).ok();
// Receive and filter
let mut validation_count = 0;
let mut runtime_count = 0;
for _ in 0..2 {
if let Ok(event) = subscriber.recv().await {
match event.event_type {
EventType::ValidationCompleted => validation_count += 1,
EventType::RuntimeDetected => runtime_count += 1,
_ => {}
}
}
}
assert_eq!(validation_count, 1);
assert_eq!(runtime_count, 1);
}
#[test]
fn test_health_probe_lifecycle() {
let probe = HealthProbe::new();
// Check initial state
assert_eq!(probe.is_alive(), ProbeStatus::Healthy);
assert_eq!(probe.is_ready(), ProbeStatus::Healthy);
assert_eq!(probe.operation_count(), 0);
// Simulate operations
for _ in 0..5 {
probe.increment_operations();
}
assert_eq!(probe.operation_count(), 5);
let _ = probe.uptime_secs();
// Verify probe responses
let liveness = probe.liveness_response();
assert_eq!(liveness.status, ProbeStatus::Healthy);
let readiness = probe.readiness_response();
assert_eq!(readiness.status, ProbeStatus::Healthy);
}
#[test]
fn test_operation_registry_complete_workflow() {
let mut registry = OperationRegistry::default();
// Start with empty registry
assert_eq!(registry.len(), 0);
assert!(!registry.contains("test-op"));
// Register operations - not implementing actual operations for this test
// In real scenario, we'd register actual operation implementations
// For this test, we just verify the registry behavior
// List operations
let list = registry.list();
assert_eq!(list.len(), 0); // Still empty since we can't mock without trait objects
// Verify unregister
assert!(!registry.unregister("nonexistent"));
}
#[tokio::test]
async fn test_multiple_subscribers_event_delivery() {
let bus = EventBus::new(100);
// Create multiple subscribers
let mut sub1 = bus.subscribe();
let mut sub2 = bus.subscribe();
let mut sub3 = bus.subscribe();
assert_eq!(bus.subscriber_count(), 3);
// Publish event
let payload = EventPayload::new("multi-sub-test", true);
let event = Event::new(EventType::Custom, payload);
let result = bus.publish(event);
assert_eq!(result.unwrap(), 3); // All 3 subscribers receive event
// Verify all subscribers got the event
for _ in 0..3 {
if let Ok(_e1) = sub1.try_recv() {
break;
}
if let Ok(_e2) = sub2.try_recv() {
break;
}
if let Ok(_e3) = sub3.try_recv() {
break;
}
}
}
#[tokio::test]
async fn test_cache_performance_basic() {
use std::time::Instant;
let cache = daemon_cli::core::HierarchicalCache::new().unwrap();
// Measure cache set performance
let start = Instant::now();
let mut count = 0;
for i in 0..100 {
let key = format!("test-key-{}", i);
let value = format!("test-value-{}", i);
let _ = cache.set_command(key, value).await;
count += 1;
}
let elapsed = start.elapsed();
assert_eq!(count, 100);
println!(
"Cache 100 sets: {:?} ({:.2} ops/sec)",
elapsed,
100.0 / elapsed.as_secs_f64()
);
}
#[tokio::test]
async fn test_webhook_event_creation() {
use daemon_cli::webhooks::{WebHookEvent, WebHookPayload, WebHookType};
let payload = WebHookPayload::new()
.with_repository("test-repo")
.with_branch("main")
.with_message("Test commit");
let event = WebHookEvent::new(WebHookType::Push, payload);
assert_eq!(event.hook_type, WebHookType::Push);
assert_eq!(event.payload.repository, Some("test-repo".to_string()));
assert_eq!(event.attempt, 1);
assert!(!event.webhook_id.is_empty());
}
#[test]
fn test_rendering_context_builder() {
use daemon_cli::rendering::template::OutputFormat;
use daemon_cli::rendering::RenderContext;
use serde_json::json;
let ctx = RenderContext::new()
.with_variable("name", json!("test"))
.with_variable("version", json!("1.0.0"))
.with_output_format(OutputFormat::Json)
.with_config_file("/etc/config.toml");
assert_eq!(ctx.variables.len(), 2);
assert_eq!(ctx.output_format, OutputFormat::Json);
assert_eq!(ctx.config_file, Some("/etc/config.toml".to_string()));
}
#[tokio::test]
async fn test_concurrent_event_bus_subscribers() {
use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::Arc as StdArc;
let bus = EventBus::new(1000);
let counter = StdArc::new(AtomicU32::new(0));
// Spawn multiple subscribers
let mut handles = vec![];
for _i in 0..5 {
let mut rx = bus.subscribe();
let counter_clone = counter.clone();
let handle = tokio::spawn(async move {
if let Ok(_event) = rx.recv().await {
counter_clone.fetch_add(1, Ordering::SeqCst);
}
});
handles.push(handle);
}
// Publish event
let payload = EventPayload::new("concurrent-test", true);
let event = Event::new(EventType::Custom, payload);
bus.publish(event).ok();
// Wait for subscribers
for handle in handles {
let _ = handle.await;
}
assert_eq!(counter.load(Ordering::SeqCst), 5);
}
#[test]
fn test_health_metrics_calculations() {
use daemon_cli::HealthMetrics;
let metrics = HealthMetrics::new();
// Record operations
for _ in 0..100 {
metrics.record_operation();
}
for _ in 0..75 {
metrics.record_success();
}
for _ in 0..25 {
metrics.record_failure();
}
// Record cache hits
for _ in 0..800 {
metrics.record_cache_hit();
}
for _ in 0..200 {
metrics.record_cache_miss();
}
// Verify calculations
assert_eq!(metrics.operations_executed(), 100);
assert_eq!(metrics.operations_succeeded(), 75);
assert_eq!(metrics.operations_failed(), 25);
assert_eq!(metrics.success_rate(), 75.0);
assert_eq!(metrics.cache_hit_rate(), 80.0);
}