#![allow(unused_crate_dependencies)] use std::collections::HashMap; use std::sync::Arc; use std::time::{Duration, Instant}; use tokio::time::timeout; use crate::framework::{TestOrchestrator, TestFrameworkConfig, PerformanceThresholds, IntegrationTestResult}; use crate::framework::mocks::MockServiceRegistry; use config::{ConfigManager, TLIConfig}; use tli::client::{TLIClient, ConnectionManager, ServiceConnection}; use tli::ui::{Dashboard, Terminal, CommandInterface}; use tli::commands::{Command, CommandResult, CommandType}; /// TLI Client Integration Tests /// /// Tests the Terminal Line Interface client functionality including: /// - gRPC connections to all three services /// /// - Command execution and response handling /// - Real-time data streaming and display /// /// - Configuration management interface /// - Performance monitoring dashboard /// /// - Error handling and recovery pub struct TLIClientTests { orchestrator: TestOrchestrator, mock_registry: MockServiceRegistry, tli_config: TLIConfig, } impl TLIClientTests { /// Initialize TLI Client test suite pub async fn new() -> Result> { let config = TestFrameworkConfig { performance_thresholds: PerformanceThresholds { max_e2e_latency_us: 50, // 50μs end-to-end max_order_latency_us: 20, // 20μs order processing max_risk_latency_us: 10, // 10μs risk validation max_ml_latency_ms: 50, // 50ms ML inference max_config_reload_ms: 100, // 100ms config reload min_throughput_ops_sec: 10000, // 10k ops/sec minimum }, database_url: std::env::var("TEST_DATABASE_URL") .unwrap_or_else(|_| "postgresql://test:test@localhost:5432/foxhunt_test".to_string()), service_ports: { let mut ports = HashMap::new(); ports.insert("trading".to_string(), 50051); ports.insert("backtesting".to_string(), 50052); ports.insert("ml_training".to_string(), 50053); ports }, test_timeout_secs: 30, }; let orchestrator = TestOrchestrator::new(config).await?; let mock_registry = MockServiceRegistry::new().await?; // Load TLI configuration let config_manager = ConfigManager::new().await?; let tli_config = config_manager.get_tli_config().await?; Ok(Self { orchestrator, mock_registry, tli_config, }) } /// Test Suite 1: Service Connection Management /// /// Validates TLI's ability to connect and manage connections to services: /// - gRPC connection establishment /// /// - Connection health monitoring /// - Automatic reconnection on failures /// /// - Service discovery and failover pub async fn test_service_connection_management(&self) -> IntegrationTestResult { println!("🔗 Testing TLI Client - Service Connection Management"); let start_time = Instant::now(); let mut test_results = IntegrationTestResult::new("TLI Client Service Connection Management"); // Start all required services for service_name in ["trading", "backtesting", "ml_training"] { match self.orchestrator.start_service(service_name).await { Ok(_) => { test_results.add_success(&format!("Started {} service for TLI testing", service_name)); } Err(e) => { test_results.add_failure(&format!("Failed to start {} service: {}", service_name, e)); } } } // Allow services to initialize tokio::time::sleep(Duration::from_millis(2000)).await; // Test Case 1: TLI Client Initialization let tli_client_config = TLIClientConfig { service_endpoints: { let mut endpoints = HashMap::new(); endpoints.insert("trading".to_string(), "http://localhost:50051".to_string()); endpoints.insert("backtesting".to_string(), "http://localhost:50052".to_string()); endpoints.insert("ml_training".to_string(), "http://localhost:50053".to_string()); endpoints }, connection_timeout_ms: 5000, retry_attempts: 3, retry_delay_ms: 1000, keepalive_interval_s: 30, }; let tli_init_start = Instant::now(); let tli_client_result = TLIClient::new(tli_client_config.clone()).await; let tli_init_duration = tli_init_start.elapsed(); match tli_client_result { Ok(mut tli_client) => { test_results.add_success("TLI client initialized successfully"); if tli_init_duration.as_millis() <= 5000 { test_results.add_success(&format!( "TLI initialization time acceptable: {}ms", tli_init_duration.as_millis() )); } else { test_results.add_failure(&format!( "TLI initialization time too long: {}ms", tli_init_duration.as_millis() )); } // Test Case 2: Service Connection Tests for service_name in ["trading", "backtesting", "ml_training"] { let connection_start = Instant::now(); match tli_client.connect_to_service(service_name).await { Ok(_) => { let connection_duration = connection_start.elapsed(); test_results.add_success(&format!("Connected to {} service", service_name)); if connection_duration.as_millis() <= 2000 { test_results.add_success(&format!( "{} connection time acceptable: {}ms", service_name, connection_duration.as_millis() )); } else { test_results.add_failure(&format!( "{} connection time too long: {}ms", service_name, connection_duration.as_millis() )); } // Test health check for each service match tli_client.check_service_health(service_name).await { Ok(health_status) => { if health_status.is_healthy { test_results.add_success(&format!("{} service health check passed", service_name)); } else { test_results.add_failure(&format!("{} service reports unhealthy: {}", service_name, health_status.status_message)); } } Err(e) => { test_results.add_failure(&format!("Failed {} service health check: {}", service_name, e)); } } } Err(e) => { test_results.add_failure(&format!("Failed to connect to {} service: {}", service_name, e)); } } } // Test Case 3: Connection Resilience // Simulate a service disconnection and reconnection println!("Testing connection resilience by restarting trading service..."); // Stop trading service temporarily match self.orchestrator.stop_service("trading").await { Ok(_) => { test_results.add_success("Trading service stopped for resilience test"); // Wait a moment for connection to detect failure tokio::time::sleep(Duration::from_millis(1000)).await; // Check if TLI detects the disconnection match tli_client.check_service_health("trading").await { Ok(health_status) => { if !health_status.is_healthy { test_results.add_success("TLI correctly detected service disconnection"); } else { test_results.add_failure("TLI failed to detect service disconnection"); } } Err(_) => { test_results.add_success("TLI correctly detected service unavailability"); } } // Restart trading service match self.orchestrator.start_service("trading").await { Ok(_) => { test_results.add_success("Trading service restarted"); // Allow time for reconnection tokio::time::sleep(Duration::from_millis(2000)).await; // Test automatic reconnection let reconnect_start = Instant::now(); match tli_client.reconnect_to_service("trading").await { Ok(_) => { let reconnect_duration = reconnect_start.elapsed(); test_results.add_success("TLI reconnected to trading service"); if reconnect_duration.as_millis() <= 3000 { test_results.add_success(&format!( "Reconnection time acceptable: {}ms", reconnect_duration.as_millis() )); } else { test_results.add_failure(&format!( "Reconnection time too long: {}ms", reconnect_duration.as_millis() )); } // Verify reconnection works match tli_client.check_service_health("trading").await { Ok(health_status) => { if health_status.is_healthy { test_results.add_success("Trading service health confirmed after reconnection"); } else { test_results.add_failure("Trading service still unhealthy after reconnection"); } } Err(e) => { test_results.add_failure(&format!("Failed to verify reconnection: {}", e)); } } } Err(e) => { test_results.add_failure(&format!("Failed to reconnect to trading service: {}", e)); } } } Err(e) => { test_results.add_failure(&format!("Failed to restart trading service: {}", e)); } } } Err(e) => { test_results.add_failure(&format!("Failed to stop trading service for resilience test: {}", e)); } } // Test Case 4: Concurrent Connection Management let concurrent_test_start = Instant::now(); let mut concurrent_tasks = Vec::new(); for i in 0..5 { let mut client_clone = tli_client.clone(); let task = tokio::spawn(async move { // Test concurrent health checks let health_results = futures::join!( client_clone.check_service_health("trading"), client_clone.check_service_health("backtesting"), client_clone.check_service_health("ml_training") ); (i, health_results) }); concurrent_tasks.push(task); } let mut concurrent_success = 0; let mut concurrent_failures = 0; for task in concurrent_tasks { match task.await { Ok((task_id, (trading_health, backtesting_health, ml_health))) => { let mut task_success = true; if trading_health.is_err() || backtesting_health.is_err() || ml_health.is_err() { task_success = false; } if task_success { concurrent_success += 1; } else { concurrent_failures += 1; } } Err(_) => { concurrent_failures += 1; } } } let concurrent_duration = concurrent_test_start.elapsed(); if concurrent_failures == 0 { test_results.add_success(&format!( "All {} concurrent connection tests passed in {}ms", concurrent_success, concurrent_duration.as_millis() )); } else { test_results.add_failure(&format!( "Concurrent connection test failures: {} success, {} failures", concurrent_success, concurrent_failures )); } } Err(e) => { test_results.add_failure(&format!("Failed to initialize TLI client: {}", e)); } } test_results.duration = start_time.elapsed(); test_results.finalize(); Ok(test_results) } /// Test Suite 2: Command Execution Interface /// /// Validates TLI's command processing and execution: /// - Command parsing and validation /// /// - Service command routing /// - Response formatting and display /// /// - Error handling and user feedback pub async fn test_command_execution_interface(&self) -> IntegrationTestResult { println!("⌨️ Testing TLI Client - Command Execution Interface"); let start_time = Instant::now(); let mut test_results = IntegrationTestResult::new("TLI Client Command Execution Interface"); // Initialize TLI client for command testing let tli_client_config = TLIClientConfig { service_endpoints: { let mut endpoints = HashMap::new(); endpoints.insert("trading".to_string(), "http://localhost:50051".to_string()); endpoints.insert("backtesting".to_string(), "http://localhost:50052".to_string()); endpoints.insert("ml_training".to_string(), "http://localhost:50053".to_string()); endpoints }, connection_timeout_ms: 5000, retry_attempts: 3, retry_delay_ms: 1000, keepalive_interval_s: 30, }; match TLIClient::new(tli_client_config).await { Ok(mut tli_client) => { test_results.add_success("TLI client initialized for command testing"); // Ensure connections are established tokio::time::sleep(Duration::from_millis(1000)).await; // Test Case 1: Basic Command Parsing let test_commands = vec![ ("help", CommandType::Help, "Display help information"), ("status", CommandType::Status, "Show system status"), ("list orders", CommandType::ListOrders, "List active orders"), ("list positions", CommandType::ListPositions, "List open positions"), ("start backtest --strategy SMA --symbol EURUSD", CommandType::StartBacktest, "Start backtesting"), ("train model --type MAMBA --symbol EURUSD", CommandType::TrainModel, "Train ML model"), ("config get trading.max_position_size", CommandType::ConfigGet, "Get configuration value"), ("config set trading.max_position_size 1000000", CommandType::ConfigSet, "Set configuration value"), ]; for (command_str, expected_type, description) in &test_commands { let parse_start = Instant::now(); match tli_client.parse_command(command_str).await { Ok(parsed_command) => { let parse_duration = parse_start.elapsed(); test_results.add_success(&format!("Parsed command: {} - {}", command_str, description)); if parsed_command.command_type == *expected_type { test_results.add_success(&format!("Command type correctly identified: {:?}", expected_type)); } else { test_results.add_failure(&format!( "Command type mismatch for '{}': expected {:?}, got {:?}", command_str, expected_type, parsed_command.command_type )); } if parse_duration.as_micros() <= 1000 { // < 1ms for parsing test_results.add_success(&format!( "Command parsing time acceptable: {}μs", parse_duration.as_micros() )); } else { test_results.add_failure(&format!( "Command parsing time too long: {}μs", parse_duration.as_micros() )); } } Err(e) => { test_results.add_failure(&format!("Failed to parse command '{}': {}", command_str, e)); } } } // Test Case 2: Service Command Execution let service_commands = vec![ ( "status", CommandType::Status, "System status", None, // No specific service ), ( "list orders", CommandType::ListOrders, "List orders from trading service", Some("trading"), ), ( "list positions", CommandType::ListPositions, "List positions from trading service", Some("trading"), ), ]; for (command_str, command_type, description, target_service) in &service_commands { let execute_start = Instant::now(); match tli_client.execute_command(command_str).await { Ok(command_result) => { let execute_duration = execute_start.elapsed(); test_results.add_success(&format!("Executed command: {} - {}", command_str, description)); // Validate command result structure if command_result.success { test_results.add_success(&format!("Command '{}' executed successfully", command_str)); } else { test_results.add_failure(&format!( "Command '{}' failed: {}", command_str, command_result.error_message.unwrap_or_else(|| "No error message".to_string()) )); } if command_result.response_data.is_some() { test_results.add_success(&format!("Command '{}' returned data", command_str)); } // Validate execution time based on command type let max_duration = match command_type { CommandType::Status => Duration::from_millis(500), CommandType::ListOrders | CommandType::ListPositions => Duration::from_millis(1000), _ => Duration::from_millis(2000), }; if execute_duration <= max_duration { test_results.add_success(&format!( "Command '{}' execution time acceptable: {}ms", command_str, execute_duration.as_millis() )); } else { test_results.add_failure(&format!( "Command '{}' execution time too long: {}ms > {}ms", command_str, execute_duration.as_millis(), max_duration.as_millis() )); } } Err(e) => { test_results.add_failure(&format!("Failed to execute command '{}': {}", command_str, e)); } } } // Test Case 3: Invalid Command Handling let invalid_commands = vec![ "invalid_command", "list unknown_entity", "config set invalid.path value", "train model --invalid-flag value", "", // Empty command ]; for invalid_command in &invalid_commands { match tli_client.execute_command(invalid_command).await { Ok(result) => { if !result.success { test_results.add_success(&format!( "Invalid command '{}' properly rejected", invalid_command )); } else { test_results.add_failure(&format!( "Invalid command '{}' was incorrectly accepted", invalid_command )); } } Err(_) => { test_results.add_success(&format!( "Invalid command '{}' properly raised error", invalid_command )); } } } // Test Case 4: Concurrent Command Execution let concurrent_commands = vec![ "status", "list orders", "list positions", ]; let concurrent_start = Instant::now(); let mut concurrent_tasks = Vec::new(); for (i, command) in concurrent_commands.into_iter().enumerate() { let mut client_clone = tli_client.clone(); let command_str = command.to_string(); let task = tokio::spawn(async move { let result = client_clone.execute_command(&command_str).await; (i, command_str, result) }); concurrent_tasks.push(task); } let mut concurrent_success = 0; let mut concurrent_failures = 0; for task in concurrent_tasks { match task.await { Ok((task_id, command_str, result)) => { match result { Ok(command_result) => { if command_result.success { concurrent_success += 1; } else { concurrent_failures += 1; } } Err(_) => { concurrent_failures += 1; } } } Err(_) => { concurrent_failures += 1; } } } let concurrent_duration = concurrent_start.elapsed(); if concurrent_failures == 0 { test_results.add_success(&format!( "All {} concurrent commands executed successfully in {}ms", concurrent_success, concurrent_duration.as_millis() )); } else { test_results.add_failure(&format!( "Concurrent command execution had failures: {} success, {} failures", concurrent_success, concurrent_failures )); } } Err(e) => { test_results.add_failure(&format!("Failed to initialize TLI client for command testing: {}", e)); } } test_results.duration = start_time.elapsed(); test_results.finalize(); Ok(test_results) } /// Test Suite 3: Real-time Data Streaming /// /// Validates TLI's real-time data display capabilities: /// - Market data streaming and display /// /// - Order status updates /// - Performance metrics streaming /// /// - Dashboard refresh and updates pub async fn test_realtime_data_streaming(&self) -> IntegrationTestResult { println!("📊 Testing TLI Client - Real-time Data Streaming"); let start_time = Instant::now(); let mut test_results = IntegrationTestResult::new("TLI Client Real-time Data Streaming"); // Initialize TLI client for streaming tests let tli_client_config = TLIClientConfig { service_endpoints: { let mut endpoints = HashMap::new(); endpoints.insert("trading".to_string(), "http://localhost:50051".to_string()); endpoints.insert("backtesting".to_string(), "http://localhost:50052".to_string()); endpoints.insert("ml_training".to_string(), "http://localhost:50053".to_string()); endpoints }, connection_timeout_ms: 5000, retry_attempts: 3, retry_delay_ms: 1000, keepalive_interval_s: 30, }; match TLIClient::new(tli_client_config).await { Ok(mut tli_client) => { test_results.add_success("TLI client initialized for streaming tests"); // Test Case 1: Market Data Streaming let market_symbols = vec!["EURUSD", "GBPUSD", "USDJPY"]; for symbol in &market_symbols { let stream_start = Instant::now(); match tli_client.subscribe_market_data(symbol).await { Ok(mut stream) => { test_results.add_success(&format!("Subscribed to {} market data stream", symbol)); // Collect some streaming data let mut tick_count = 0; let max_ticks = 10; let timeout_duration = Duration::from_secs(5); while tick_count < max_ticks { match timeout(Duration::from_millis(500), stream.next()).await { Ok(Some(tick_data)) => { tick_count += 1; // Validate tick data structure if tick_data.symbol == *symbol { test_results.add_success(&format!( "Received valid {} tick: bid={:.5}, ask={:.5}", symbol, tick_data.bid, tick_data.ask )); } else { test_results.add_failure(&format!( "Tick data symbol mismatch: expected {}, got {}", symbol, tick_data.symbol )); } // Validate tick data freshness let tick_age = chrono::Utc::now().signed_duration_since(tick_data.timestamp); if tick_age.num_seconds() <= 2 { test_results.add_success(&format!("{} tick data is fresh", symbol)); } else { test_results.add_failure(&format!( "{} tick data is stale: {} seconds old", symbol, tick_age.num_seconds() )); } } Ok(None) => { test_results.add_failure(&format!("Market data stream for {} ended unexpectedly", symbol)); break; } Err(_) => { // Timeout - continue waiting continue; } } if stream_start.elapsed() > timeout_duration { break; } } if tick_count > 0 { test_results.add_success(&format!( "Received {} ticks for {} in streaming test", tick_count, symbol )); } else { test_results.add_failure(&format!( "No ticks received for {} within timeout", symbol )); } // Unsubscribe match tli_client.unsubscribe_market_data(symbol).await { Ok(_) => { test_results.add_success(&format!("Unsubscribed from {} market data", symbol)); } Err(e) => { test_results.add_failure(&format!("Failed to unsubscribe from {}: {}", symbol, e)); } } } Err(e) => { test_results.add_failure(&format!("Failed to subscribe to {} market data: {}", symbol, e)); } } } // Test Case 2: Order Status Streaming match tli_client.subscribe_order_updates().await { Ok(mut order_stream) => { test_results.add_success("Subscribed to order status updates"); // Place a test order to generate updates let test_order = TestOrder { symbol: "EURUSD".to_string(), side: "buy".to_string(), quantity: 100000.0, order_type: "market".to_string(), }; match tli_client.execute_command(&format!( "place order --symbol {} --side {} --quantity {} --type {}", test_order.symbol, test_order.side, test_order.quantity, test_order.order_type )).await { Ok(order_result) => { if order_result.success { test_results.add_success("Test order placed for streaming validation"); // Listen for order updates let mut update_count = 0; let max_updates = 3; let update_timeout = Duration::from_secs(10); let update_start = Instant::now(); while update_count < max_updates && update_start.elapsed() < update_timeout { match timeout(Duration::from_millis(1000), order_stream.next()).await { Ok(Some(order_update)) => { update_count += 1; test_results.add_success(&format!( "Received order update #{}: status={}", update_count, order_update.status )); // Validate update structure if order_update.order_id.is_some() { test_results.add_success("Order update contains order ID"); } else { test_results.add_failure("Order update missing order ID"); } if order_update.timestamp.is_some() { test_results.add_success("Order update contains timestamp"); } else { test_results.add_failure("Order update missing timestamp"); } } Ok(None) => { test_results.add_failure("Order update stream ended unexpectedly"); break; } Err(_) => { // Timeout - continue waiting continue; } } } if update_count > 0 { test_results.add_success(&format!("Received {} order updates", update_count)); } else { test_results.add_failure("No order updates received"); } } else { test_results.add_failure("Failed to place test order for streaming"); } } Err(e) => { test_results.add_failure(&format!("Failed to execute order command: {}", e)); } } // Unsubscribe from order updates match tli_client.unsubscribe_order_updates().await { Ok(_) => { test_results.add_success("Unsubscribed from order updates"); } Err(e) => { test_results.add_failure(&format!("Failed to unsubscribe from order updates: {}", e)); } } } Err(e) => { test_results.add_failure(&format!("Failed to subscribe to order updates: {}", e)); } } // Test Case 3: Performance Metrics Streaming match tli_client.subscribe_performance_metrics().await { Ok(mut metrics_stream) => { test_results.add_success("Subscribed to performance metrics stream"); let mut metrics_count = 0; let max_metrics = 5; let metrics_timeout = Duration::from_secs(15); let metrics_start = Instant::now(); while metrics_count < max_metrics && metrics_start.elapsed() < metrics_timeout { match timeout(Duration::from_millis(2000), metrics_stream.next()).await { Ok(Some(performance_metrics)) => { metrics_count += 1; test_results.add_success(&format!( "Received performance metrics #{}", metrics_count )); // Validate metrics structure if performance_metrics.latency_stats.is_some() { let latency = performance_metrics.latency_stats.unwrap(); test_results.add_success(&format!( "Latency metrics: avg={}μs, p99={}μs", latency.average_us, latency.p99_us )); } if performance_metrics.throughput_stats.is_some() { let throughput = performance_metrics.throughput_stats.unwrap(); test_results.add_success(&format!( "Throughput metrics: {}ops/s", throughput.operations_per_second )); } if performance_metrics.system_stats.is_some() { test_results.add_success("System stats included in performance metrics"); } } Ok(None) => { test_results.add_failure("Performance metrics stream ended unexpectedly"); break; } Err(_) => { // Timeout - continue waiting continue; } } } if metrics_count > 0 { test_results.add_success(&format!("Received {} performance metric updates", metrics_count)); } else { test_results.add_failure("No performance metrics received"); } // Unsubscribe match tli_client.unsubscribe_performance_metrics().await { Ok(_) => { test_results.add_success("Unsubscribed from performance metrics"); } Err(e) => { test_results.add_failure(&format!("Failed to unsubscribe from performance metrics: {}", e)); } } } Err(e) => { test_results.add_failure(&format!("Failed to subscribe to performance metrics: {}", e)); } } // Test Case 4: Multiple Stream Management let multi_stream_start = Instant::now(); let mut active_streams = 0; // Subscribe to multiple streams simultaneously let eurusd_stream = tli_client.subscribe_market_data("EURUSD").await; let gbpusd_stream = tli_client.subscribe_market_data("GBPUSD").await; let performance_stream = tli_client.subscribe_performance_metrics().await; if eurusd_stream.is_ok() { active_streams += 1; } if gbpusd_stream.is_ok() { active_streams += 1; } if performance_stream.is_ok() { active_streams += 1; } test_results.add_success(&format!("Successfully started {} simultaneous streams", active_streams)); // Let streams run for a short time tokio::time::sleep(Duration::from_secs(3)).await; // Clean up all streams let _ = tli_client.unsubscribe_market_data("EURUSD").await; let _ = tli_client.unsubscribe_market_data("GBPUSD").await; let _ = tli_client.unsubscribe_performance_metrics().await; let multi_stream_duration = multi_stream_start.elapsed(); test_results.add_success(&format!( "Multiple stream test completed in {}s", multi_stream_duration.as_secs() )); } Err(e) => { test_results.add_failure(&format!("Failed to initialize TLI client for streaming tests: {}", e)); } } test_results.duration = start_time.elapsed(); test_results.finalize(); Ok(test_results) } /// Execute complete TLI Client test suite pub async fn run_all_tests(&self) -> Result, Box> { println!("🚀 Starting TLI Client Integration Test Suite"); let mut results = Vec::new(); // Test Suite 1: Service Connection Management match timeout(Duration::from_secs(self.orchestrator.config.test_timeout_secs), self.test_service_connection_management()).await { Ok(Ok(result)) => results.push(result), Ok(Err(e)) => { let mut failed_result = IntegrationTestResult::new("TLI Client Service Connection Management"); failed_result.add_failure(&format!("Test suite failed: {}", e)); failed_result.finalize(); results.push(failed_result); }, Err(_) => { let mut timeout_result = IntegrationTestResult::new("TLI Client Service Connection Management"); timeout_result.add_failure("Test suite timed out"); timeout_result.finalize(); results.push(timeout_result); } } // Test Suite 2: Command Execution Interface match timeout(Duration::from_secs(self.orchestrator.config.test_timeout_secs), self.test_command_execution_interface()).await { Ok(Ok(result)) => results.push(result), Ok(Err(e)) => { let mut failed_result = IntegrationTestResult::new("TLI Client Command Execution Interface"); failed_result.add_failure(&format!("Test suite failed: {}", e)); failed_result.finalize(); results.push(failed_result); }, Err(_) => { let mut timeout_result = IntegrationTestResult::new("TLI Client Command Execution Interface"); timeout_result.add_failure("Test suite timed out"); timeout_result.finalize(); results.push(timeout_result); } } // Test Suite 3: Real-time Data Streaming match timeout(Duration::from_secs(self.orchestrator.config.test_timeout_secs * 2), self.test_realtime_data_streaming()).await { Ok(Ok(result)) => results.push(result), Ok(Err(e)) => { let mut failed_result = IntegrationTestResult::new("TLI Client Real-time Data Streaming"); failed_result.add_failure(&format!("Test suite failed: {}", e)); failed_result.finalize(); results.push(failed_result); }, Err(_) => { let mut timeout_result = IntegrationTestResult::new("TLI Client Real-time Data Streaming"); timeout_result.add_failure("Test suite timed out"); timeout_result.finalize(); results.push(timeout_result); } } // Print summary let total_tests = results.len(); let passed_tests = results.iter().filter(|r| r.passed).count(); let failed_tests = total_tests - passed_tests; println!("📊 TLI Client Integration Test Summary:"); println!(" Total Test Suites: {}", total_tests); println!(" Passed: {} ✅", passed_tests); println!(" Failed: {} ❌", failed_tests); if failed_tests == 0 { println!("🎉 All TLI Client integration tests passed!"); } else { println!("⚠️ {} TLI Client integration test suite(s) failed", failed_tests); } Ok(results) } } // Supporting types for TLI client tests #[derive(Debug, Clone)] pub struct TLIClientConfig { pub service_endpoints: HashMap, pub connection_timeout_ms: u64, pub retry_attempts: usize, pub retry_delay_ms: u64, pub keepalive_interval_s: u64, } #[derive(Debug, Clone)] pub struct TestOrder { pub symbol: String, pub side: String, pub quantity: f64, pub order_type: String, } #[cfg(test)] mod tests { use super::*; use tokio; #[tokio::test] async fn integration_test_tli_client_complete() { let test_suite = TLIClientTests::new().await .expect("Failed to initialize TLI Client test suite"); let results = test_suite.run_all_tests().await .expect("Failed to run TLI Client test suite"); // Ensure all tests passed for result in &results { assert!(result.passed, "Test suite '{}' failed: {:?}", result.test_name, result.failures); } // Validate performance requirements met for result in &results { assert!( result.duration.as_secs() <= 120, // 2 minutes max for TLI tests "Test suite '{}' took too long: {}s", result.test_name, result.duration.as_secs() ); } } }