//! Test Harness for Foxhunt HFT Integration Testing //! //! Provides utilities for comprehensive end-to-end testing including: //! - gRPC service clients //! - Test data generation //! - Database fixtures //! - Performance monitoring //! - Service orchestration pub mod grpc_clients; pub mod test_data; pub mod fixtures; pub mod performance; pub mod docker_compose; pub mod proto; use std::sync::Arc; use std::time::Duration; use tokio::time::timeout; use anyhow::Result; /// Core test harness for managing service lifecycles and test execution pub struct TestHarness { pub grpc_clients: grpc_clients::GrpcClients, pub test_data: test_data::TestDataGenerator, pub fixtures: fixtures::TestFixtures, pub performance: performance::PerformanceMonitor, } impl TestHarness { /// Initialize test harness with all required components pub async fn new() -> Result { let grpc_clients = grpc_clients::GrpcClients::new().await?; let test_data = test_data::TestDataGenerator::new(); let fixtures = fixtures::TestFixtures::new().await?; let performance = performance::PerformanceMonitor::new(); Ok(Self { grpc_clients, test_data, fixtures, performance, }) } /// Setup test environment with all services pub async fn setup(&mut self) -> Result<()> { // Start database fixtures self.fixtures.setup().await?; // Wait for services to be ready self.wait_for_services().await?; // Generate test data self.test_data.generate_synthetic_data().await?; Ok(()) } /// Cleanup test environment pub async fn cleanup(&mut self) -> Result<()> { self.fixtures.cleanup().await?; Ok(()) } /// Wait for all services to be healthy async fn wait_for_services(&self) -> Result<()> { let timeout_duration = Duration::from_secs(60); timeout(timeout_duration, async { loop { if self.grpc_clients.are_all_healthy().await? { break; } tokio::time::sleep(Duration::from_millis(500)).await; } Ok::<(), anyhow::Error>(()) }).await??; Ok(()) } /// Execute end-to-end test scenario with performance monitoring pub async fn execute_scenario(&mut self, name: &str, test_fn: F) -> Result where F: FnOnce(&mut TestHarness) -> Fut, Fut: std::future::Future>, { let start_time = std::time::Instant::now(); self.performance.start_scenario(name); let result = match test_fn(self).await { Ok(()) => TestResult::Success { duration: start_time.elapsed(), metrics: self.performance.get_metrics(name), }, Err(e) => TestResult::Failure { duration: start_time.elapsed(), error: e.to_string(), metrics: self.performance.get_metrics(name), }, }; self.performance.end_scenario(name); Ok(result) } } /// Test execution result with performance metrics #[derive(Debug)] pub enum TestResult { Success { duration: Duration, metrics: performance::ScenarioMetrics, }, Failure { duration: Duration, error: String, metrics: performance::ScenarioMetrics, }, } impl TestResult { pub fn is_success(&self) -> bool { matches!(self, TestResult::Success { .. }) } pub fn duration(&self) -> Duration { match self { TestResult::Success { duration, .. } => *duration, TestResult::Failure { duration, .. } => *duration, } } pub fn metrics(&self) -> &performance::ScenarioMetrics { match self { TestResult::Success { metrics, .. } => metrics, TestResult::Failure { metrics, .. } => metrics, } } } /// Test environment configuration #[derive(Debug, Clone)] pub struct TestConfig { pub tli_endpoint: String, pub ml_training_endpoint: String, pub trading_service_endpoint: String, pub database_url: String, pub influxdb_url: String, pub enable_gpu_tests: bool, pub performance_baseline_file: Option, } impl Default for TestConfig { fn default() -> Self { Self { tli_endpoint: "http://localhost:50051".to_string(), ml_training_endpoint: "http://localhost:50052".to_string(), trading_service_endpoint: "http://localhost:50053".to_string(), database_url: "postgresql://test:test@localhost:5432/foxhunt_test".to_string(), influxdb_url: "http://localhost:8086".to_string(), enable_gpu_tests: false, performance_baseline_file: None, } } } /// Load test configuration from environment or config file pub fn load_test_config() -> Result { let mut config = TestConfig::default(); // Override with environment variables if present if let Ok(endpoint) = std::env::var("TLI_ENDPOINT") { config.tli_endpoint = endpoint; } if let Ok(endpoint) = std::env::var("ML_TRAINING_ENDPOINT") { config.ml_training_endpoint = endpoint; } if let Ok(endpoint) = std::env::var("TRADING_SERVICE_ENDPOINT") { config.trading_service_endpoint = endpoint; } if let Ok(url) = std::env::var("DATABASE_URL") { config.database_url = url; } if let Ok(url) = std::env::var("INFLUXDB_URL") { config.influxdb_url = url; } if let Ok(_) = std::env::var("ENABLE_GPU_TESTS") { config.enable_gpu_tests = true; } Ok(config) }