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>
101 lines
3.0 KiB
Rust
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();
|
|
} |