Files
foxhunt/testing/integration/unit/tests/chaos_tests.rs
jgrusewski 9c3d741a08 refactor: restructure repo — crates/, bin/, testing/ layout
Move 17 library crates into crates/, CLI binary into bin/fxt,
consolidate 10 test crates into testing/, split config crate
from deployment config files.

Root directory reduced from 38+ to ~17 directories.
All Cargo.toml paths and build.rs proto refs updated.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 11:56:00 +01:00

101 lines
3.0 KiB
Rust

//! Chaos engineering tests for Foxhunt HFT system.
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::Duration;
use tokio::time::sleep;
use rand::{Rng, SeedableRng};
use rand::rngs::StdRng;
/// Test system behavior under random failures
#[tokio::test]
async fn test_random_service_failures() {
let success_count = Arc::new(AtomicUsize::new(0));
let failure_count = Arc::new(AtomicUsize::new(0));
let mut handles = vec![];
// Spawn multiple concurrent tasks that randomly fail
for i in 0..10 {
let success_count = Arc::clone(&success_count);
let failure_count = Arc::clone(&failure_count);
let handle = tokio::spawn(async move {
let mut rng = StdRng::from_entropy();
sleep(Duration::from_millis(rng.gen_range(1..100))).await;
// Randomly fail 30% of the time
if rng.gen_bool(0.3) {
failure_count.fetch_add(1, Ordering::Relaxed);
panic!("Simulated chaos failure in task {}", i);
} else {
success_count.fetch_add(1, Ordering::Relaxed);
}
});
handles.push(handle);
}
// Wait for all tasks to complete
for handle in handles {
let _ = handle.await; // Ignore panics
}
let successes = success_count.load(Ordering::Relaxed);
let failures = failure_count.load(Ordering::Relaxed);
// Verify we had both successes and failures (chaos)
println!("Chaos test results: {} successes, {} failures", successes, failures);
assert!(successes + failures == 10);
}
/// Test system resilience under high load
#[tokio::test]
async fn test_load_resilience() {
let request_count = Arc::new(AtomicUsize::new(0));
let mut handles = vec![];
// Simulate high concurrent load
for _ in 0..50 {
let request_count = Arc::clone(&request_count);
let handle = tokio::spawn(async move {
// Simulate work
let mut rng = StdRng::from_entropy();
sleep(Duration::from_millis(rng.gen_range(1..20))).await;
request_count.fetch_add(1, Ordering::Relaxed);
});
handles.push(handle);
}
// Wait for all requests to complete
for handle in handles {
handle.await.expect("Task should not panic under load");
}
assert_eq!(request_count.load(Ordering::Relaxed), 50);
}
/// Test resource exhaustion scenarios
#[tokio::test]
async fn test_resource_limits() {
// Simulate memory pressure by creating many allocations
let mut allocations = Vec::new();
for i in 0..1000 {
let data = vec![i; 1000]; // 1KB allocation
allocations.push(data);
// Add some delay to prevent overwhelming the system
if i % 100 == 0 {
tokio::task::yield_now().await;
}
}
// Verify we can still function under memory pressure
assert_eq!(allocations.len(), 1000);
// Clean up
allocations.clear();
}