//! Saturation stress tests - find where the runtime breaks. //! //! These tests intentionally push past limits to document failure modes. use super::{BlackHole, Counter, Msg, Stress, StressResult}; use std::time::Duration; use swactor::runtime::{Runtime, RuntimeConfig}; /// Blast the transfer queue (replaces router_inbox_overflow) #[test] #[cfg(feature = "stress")] fn transfer_queue_overflow() { println!("\n>>> STRESS: Transfer Queue Overflow"); let config = RuntimeConfig { max_actors: 10, actor_max_messages: 100, // Tiny buffer num_threads: 1, ..Default::default() }; let runtime = Runtime::new(config); let sink = runtime.spawn(BlackHole).unwrap(); // Process spawn runtime.tick(); // Blast messages without processing let mut result = StressResult::new("transfer_queue_overflow"); let start = std::time::Instant::now(); for _ in 0..10_000 { result.operations += 1; if runtime.send_to::(sink, Msg).is_ok() { result.successes += 1; } else { result.failures += 1; } } result.duration = start.elapsed(); result.note(format!("Transfer buffer: 100, Messages sent: 10,000")); // With hybrid channel, no failures expected assert_eq!(result.failures, 0, "Hybrid channel should not reject"); result.print(); println!(">>> PASS: Hybrid channel prevented transfer queue overflow\n"); } /// Blast a single actor's mailbox via transfer queue #[test] #[cfg(feature = "stress")] fn actor_inbox_overflow() { println!("\n>>> STRESS: Actor Inbox Overflow"); let config = RuntimeConfig { max_actors: 10, actor_max_messages: 100_000, // Large transfer buffer num_threads: 1, ..Default::default() }; let runtime = Runtime::new(config); let sink = runtime.spawn(Counter::new()).unwrap(); // Process spawn runtime.tick(); // Now blast messages let mut sent = 0u64; let mut failed = 0u64; for _ in 0..10_000 { if runtime.send_to::(sink, Msg).is_ok() { sent += 1; } else { failed += 1; } // Tick occasionally to let worker deliver if sent % 100 == 0 { runtime.tick(); } } // Process all remaining messages for _ in 0..5000 { runtime.tick(); } println!(" Sent: {}", sent); println!(" Failed: {}", failed); assert_eq!(failed, 0, "Transfer queue rejected message under load"); println!(">>> PASS: No message loss with hybrid channel\n"); } /// Blast the runtime with actor spawns #[test] #[cfg(feature = "stress")] fn actor_queue_overflow() { println!("\n>>> STRESS: Actor Queue Overflow"); let config = RuntimeConfig { max_actors: 100, // Small actor queue actor_max_messages: 100, num_threads: 1, ..Default::default() }; let runtime = Runtime::new(config); let mut result = StressResult::new("actor_queue_overflow"); let start = std::time::Instant::now(); // Try to spawn 500 actors into 100-slot queue for _ in 0..500 { result.operations += 1; match runtime.spawn(BlackHole) { Ok(_) => result.successes += 1, Err(_) => result.failures += 1, } } result.duration = start.elapsed(); result.note(format!("Queue capacity: 100, Spawn attempts: 500")); result.print(); // Note: With hybrid channel (overflow to SegQueue), we expect no failures assert_eq!( result.failures, 0, "Spawned more actors than queue capacity" ); println!(">>> PASS: Actor queue correctly handles overflow\n"); } /// Sustained overload - run at 2x capacity for extended period. /// Documents: Does the system degrade gracefully or crash? #[test] #[cfg(feature = "stress")] fn sustained_overload() { println!("\n>>> STRESS: Sustained Overload"); let config = RuntimeConfig { max_actors: 100, actor_max_messages: 1000, num_threads: 1, ..Default::default() }; let runtime = Runtime::new(config); // Spawn some actors let mut actors = Vec::new(); for _ in 0..50 { if let Ok(addr) = runtime.spawn(Counter::new()) { actors.push(addr); } } // Process spawn registrations for _ in 0..200 { runtime.tick(); } let result = Stress::new("sustained_overload") .for_duration(Duration::from_secs(2)) .run(|| { // Send to random actor let idx = (std::time::Instant::now().elapsed().as_nanos() as usize) % actors.len(); let success = runtime.send_to::(actors[idx], Msg).is_ok(); // Process some (but not all) - simulating overload runtime.tick(); success }); result.print(); println!(">>> System survived sustained overload without panic\n"); }