//! Integration tests for daemon-cli //! //! Tests interaction between multiple components use daemon_cli::orchestration::{EncryptOperation, RuntimeOperation, ValidaOperation}; use daemon_cli::{ Event, EventBus, EventPayload, EventType, HealthProbe, OperationRegistry, ProbeStatus, }; use std::sync::Arc; #[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); }