//! Common test utilities for Foxhunt HFT System //! //! This module provides shared testing infrastructure to eliminate duplication //! across the 80+ test files in the project. //! //! # Usage //! ```rust //! use common::*; use common::test_config::*; use common::mock_data::*; //! ``` pub mod database_helper; // Test Configuration Module pub mod test_config { /// Unified test configuration for all test types #[derive(Debug, Clone)] pub struct UnifiedTestConfig { pub environment_name: String, pub docker_compose_file: Option, pub cleanup_on_exit: bool, pub persist_data: bool, pub log_level: String, pub test_database_url: String, pub test_redis_url: String, pub test_influxdb_url: String, pub parallel_tests: bool, pub timeout_seconds: u64, pub max_retries: u32, } impl Default for UnifiedTestConfig { fn default() -> Self { Self { environment_name: "test".to_string(), docker_compose_file: Some("docker-compose.test.yml".to_string()), cleanup_on_exit: true, persist_data: false, log_level: "debug".to_string(), test_database_url: std::env::var("TEST_DATABASE_URL") .unwrap_or_else(|_| "postgresql://localhost:5432/hft_testing".to_string()), test_redis_url: std::env::var("TEST_REDIS_URL") .unwrap_or_else(|_| "redis://localhost:6379/0".to_string()), test_influxdb_url: std::env::var("TEST_INFLUXDB_URL") .unwrap_or_else(|_| "http://localhost:8086".to_string()), parallel_tests: true, timeout_seconds: 30, max_retries: 3, } } } } // Mock Data Generation Module pub mod mock_data { // Note: These imports are commented out as they require the common crate // Tests using these should import from the actual crates directly // use ::common::error::CommonError; // use ::common::error::CommonResult; // use ::common::database::DatabaseConfig; // use ::common::database::DatabasePool; // use ::common::Order; // use ::common::Position; // use ::common::Symbol; // use ::common::Price; // use ::common::Quantity; // use ::common::HftTimestamp; /// Generate mock order using canonical types /// /// Note: This is a placeholder - actual tests should create orders using the proper types pub fn create_mock_order_data() -> MockOrderData { MockOrderData { symbol: "BTCUSD".to_string(), side: "Buy".to_string(), quantity: 1.0, price: 50000.0, } } /// Mock order data for tests #[derive(Debug, Clone)] pub struct MockOrderData { pub symbol: String, pub side: String, pub quantity: f64, pub price: f64, } /// Generate mock market data pub fn create_mock_market_tick(symbol: &str) -> MockMarketTick { MockMarketTick { symbol: symbol.to_string(), price: 50000.0, volume: 100.0, timestamp: chrono::Utc::now().timestamp_millis(), } } /// Mock market tick for tests #[derive(Debug, Clone)] pub struct MockMarketTick { pub symbol: String, pub price: f64, pub volume: f64, pub timestamp: i64, } } // Test Utilities Module pub mod test_utils { use std::time::Duration; use tokio::time::timeout; /// Async test helper with timeout pub async fn run_with_timeout(future: F, timeout_secs: u64) -> Result where F: std::future::Future, { timeout(Duration::from_secs(timeout_secs), future) .await .map_err(|_| "Test timed out") } /// Setup tracing for tests pub fn setup_test_tracing() { use tracing_subscriber::EnvFilter; let _ = tracing_subscriber::fmt() .with_test_writer() .with_env_filter(EnvFilter::from_default_env()) .try_init(); } /// Generate test symbol name pub fn test_symbol(name: &str) -> String { name.to_string() } /// Generate test price value pub fn test_price(value: f64) -> f64 { value } /// Generate test quantity value pub fn test_quantity(value: f64) -> f64 { value } /// Common test assertions pub mod assertions { use std::time::Duration; /// Assert that a value is within a percentage tolerance pub fn assert_within_percent(actual: f64, expected: f64, percent: f64) { let tolerance = expected * (percent / 100.0); let diff = (actual - expected).abs(); assert!( diff <= tolerance, "Value {} is not within {}% of expected {}, difference: {}", actual, percent, expected, diff ); } /// Assert that latency is within `HFT` requirements pub fn assert_hft_latency(duration: Duration, max_microseconds: u64) { let micros = duration.as_micros() as u64; assert!( micros <= max_microseconds, "Latency {}μs exceeds HFT requirement of {}μs", micros, max_microseconds ); } } } // Async Test Patterns Module pub mod async_patterns { use tokio::sync::broadcast; /// Proper broadcast receiver pattern for tests pub struct TestBroadcastReceiver { receiver: broadcast::Receiver, } impl TestBroadcastReceiver where T: Clone + Send + 'static, { pub fn new(receiver: broadcast::Receiver) -> Self { Self { receiver } } pub async fn wait_for_shutdown(mut self) -> Result<(), broadcast::error::RecvError> { loop { tokio::select! { msg = self.receiver.recv() => { match msg { Ok(_) => return Ok(()), Err(e) => return Err(e), } } } } } } } // REMOVED: All pub use statements eliminated per cleanup requirements // Tests must import from canonical sources: // - tests::test_common::database_helper::* // - tests::test_common::test_config::UnifiedTestConfig // - tests::test_common::mock_data::* // - tests::test_common::test_utils::* // - tests::test_common::async_patterns::TestBroadcastReceiver // Re-export canonical types for test convenience