// Integration tests for Swarm API endpoints // Tests verify swarm statistics and health monitoring endpoints use std::sync::Arc; use vapora_swarm::{AgentProfile, SwarmCoordinator}; /// Helper to create a test agent profile fn create_test_profile(id: &str, success_rate: f64, load: f64) -> AgentProfile { AgentProfile { id: id.to_string(), roles: vec!["developer".to_string()], capabilities: vec!["coding".to_string(), "testing".to_string()], current_load: load, success_rate, availability: true, } } #[tokio::test] async fn test_swarm_coordinator_initialization() { // Create a SwarmCoordinator let swarm = Arc::new(SwarmCoordinator::new()); // Register test profiles let profile1 = create_test_profile("agent-1", 0.95, 0.3); let profile2 = create_test_profile("agent-2", 0.85, 0.5); swarm.register_agent(profile1).ok(); swarm.register_agent(profile2).ok(); // Get statistics let stats = swarm.get_swarm_stats(); // Verify statistics assert_eq!(stats.total_agents, 2); assert_eq!(stats.available_agents, 2); assert!(stats.avg_load > 0.0); assert!(stats.active_tasks == 0); // No tasks assigned yet } #[tokio::test] async fn test_swarm_health_status_healthy() { // Create swarm with available agents let swarm = Arc::new(SwarmCoordinator::new()); let profile1 = create_test_profile("agent-1", 0.95, 0.3); let profile2 = create_test_profile("agent-2", 0.90, 0.2); swarm.register_agent(profile1).ok(); swarm.register_agent(profile2).ok(); let stats = swarm.get_swarm_stats(); // Verify health calculation assert_eq!(stats.total_agents, 2); assert_eq!(stats.available_agents, 2); // All agents available = healthy let is_healthy = stats.total_agents > 0 && stats.available_agents > 0; assert!(is_healthy); } #[tokio::test] async fn test_swarm_health_status_degraded() { // Create swarm with some unavailable agents let swarm = Arc::new(SwarmCoordinator::new()); let available_profile = create_test_profile("agent-1", 0.95, 0.3); let mut unavailable_profile = create_test_profile("agent-2", 0.85, 0.5); unavailable_profile.availability = false; swarm.register_agent(available_profile).ok(); swarm.register_agent(unavailable_profile).ok(); let stats = swarm.get_swarm_stats(); // Verify health calculation assert_eq!(stats.total_agents, 2); assert_eq!(stats.available_agents, 1); // Some unavailable = degraded let is_degraded = stats.total_agents > 0 && stats.available_agents < stats.total_agents; assert!(is_degraded); } #[tokio::test] async fn test_swarm_health_status_no_agents() { // Create empty swarm let swarm = Arc::new(SwarmCoordinator::new()); let stats = swarm.get_swarm_stats(); // Verify no agents assert_eq!(stats.total_agents, 0); assert_eq!(stats.available_agents, 0); } #[tokio::test] async fn test_swarm_statistics_load_calculation() { // Create swarm with varied load profiles let swarm = Arc::new(SwarmCoordinator::new()); let light_load = create_test_profile("agent-1", 0.95, 0.1); let medium_load = create_test_profile("agent-2", 0.85, 0.5); let high_load = create_test_profile("agent-3", 0.80, 0.9); swarm.register_agent(light_load).ok(); swarm.register_agent(medium_load).ok(); swarm.register_agent(high_load).ok(); let stats = swarm.get_swarm_stats(); // Verify load calculation (average of 0.1, 0.5, 0.9 = 0.5) assert_eq!(stats.total_agents, 3); assert!(stats.avg_load > 0.4 && stats.avg_load < 0.6); } #[tokio::test] async fn test_swarm_statistics_success_rate_variance() { // Create swarm with different success rates let swarm = Arc::new(SwarmCoordinator::new()); let high_success = create_test_profile("agent-1", 0.99, 0.2); let medium_success = create_test_profile("agent-2", 0.50, 0.3); let low_success = create_test_profile("agent-3", 0.10, 0.1); swarm.register_agent(high_success).ok(); swarm.register_agent(medium_success).ok(); swarm.register_agent(low_success).ok(); let stats = swarm.get_swarm_stats(); // Verify all agents registered despite variance assert_eq!(stats.total_agents, 3); assert_eq!(stats.available_agents, 3); } #[tokio::test] async fn test_swarm_agent_availability_transitions() { // Create swarm with available agent let swarm = Arc::new(SwarmCoordinator::new()); let mut profile = create_test_profile("agent-1", 0.95, 0.3); swarm.register_agent(profile.clone()).ok(); // Verify initial state let mut stats = swarm.get_swarm_stats(); assert_eq!(stats.available_agents, 1); // Mark agent unavailable profile.availability = false; swarm.register_agent(profile).ok(); // Verify transition stats = swarm.get_swarm_stats(); assert_eq!(stats.available_agents, 0); } #[tokio::test] async fn test_swarm_unregister_agent() { // Create swarm with agent let swarm = Arc::new(SwarmCoordinator::new()); let profile = create_test_profile("agent-1", 0.95, 0.3); swarm.register_agent(profile).ok(); let mut stats = swarm.get_swarm_stats(); assert_eq!(stats.total_agents, 1); // Unregister agent swarm.unregister_agent("agent-1").ok(); // Verify removal stats = swarm.get_swarm_stats(); assert_eq!(stats.total_agents, 0); } #[tokio::test] async fn test_swarm_task_assignment_selects_best_agent() { // Create swarm with agents of different quality let swarm = Arc::new(SwarmCoordinator::new()); let poor_agent = create_test_profile("agent-poor", 0.50, 0.9); // Low success, high load let good_agent = create_test_profile("agent-good", 0.95, 0.2); // High success, low load swarm.register_agent(poor_agent).ok(); swarm.register_agent(good_agent).ok(); // Score: success_rate / (1.0 + load) // agent-poor: 0.50 / (1.0 + 0.9) = 0.50 / 1.9 ≈ 0.26 // agent-good: 0.95 / (1.0 + 0.2) = 0.95 / 1.2 ≈ 0.79 // agent-good should be selected // Verify agent-good has better score let poor_score = 0.50 / (1.0 + 0.9); let good_score = 0.95 / (1.0 + 0.2); assert!(good_score > poor_score); } #[tokio::test] async fn test_swarm_statistics_consistency() { // Test that statistics remain consistent with multiple operations let swarm = Arc::new(SwarmCoordinator::new()); // Initial state let mut stats = swarm.get_swarm_stats(); assert_eq!(stats.total_agents, 0); // Add agents for i in 0..5 { let profile = create_test_profile(&format!("agent-{}", i), 0.85, 0.3); swarm.register_agent(profile).ok(); } stats = swarm.get_swarm_stats(); assert_eq!(stats.total_agents, 5); assert_eq!(stats.available_agents, 5); // Update one agent to unavailable let mut profile = create_test_profile("agent-0", 0.85, 0.3); profile.availability = false; swarm.register_agent(profile).ok(); stats = swarm.get_swarm_stats(); assert_eq!(stats.total_agents, 5); assert_eq!(stats.available_agents, 4); // Remove one agent swarm.unregister_agent("agent-1").ok(); stats = swarm.get_swarm_stats(); assert_eq!(stats.total_agents, 4); assert_eq!(stats.available_agents, 3); } #[tokio::test] async fn test_swarm_large_agent_pool() { // Test swarm behavior with larger agent pool let swarm = Arc::new(SwarmCoordinator::new()); // Register 50 agents with varied metrics for i in 0..50 { let success_rate = if i % 3 == 0 { 0.95 } else if i % 3 == 1 { 0.75 } else { 0.55 }; let load = (i as f64 % 10.0) / 10.0; let profile = create_test_profile(&format!("agent-{}", i), success_rate, load); swarm.register_agent(profile).ok(); } let stats = swarm.get_swarm_stats(); // Verify all registered assert_eq!(stats.total_agents, 50); assert_eq!(stats.available_agents, 50); // Verify average load is reasonable assert!(stats.avg_load > 0.0 && stats.avg_load < 1.0); } #[tokio::test] async fn test_swarm_empty_after_unregister_all() { // Create swarm with agents let swarm = Arc::new(SwarmCoordinator::new()); for i in 0..3 { let profile = create_test_profile(&format!("agent-{}", i), 0.85, 0.3); swarm.register_agent(profile).ok(); } let mut stats = swarm.get_swarm_stats(); assert_eq!(stats.total_agents, 3); // Unregister all for i in 0..3 { swarm.unregister_agent(&format!("agent-{}", i)).ok(); } stats = swarm.get_swarm_stats(); assert_eq!(stats.total_agents, 0); assert_eq!(stats.available_agents, 0); }