//! Unit tests for client::trading_client module //! //! Tests trading client configuration, creation, and security validation. use tli::client::trading_client::{TradingClient, TradingClientConfig}; /// Test TradingClientConfig default values #[test] fn test_trading_client_config_default() { let config = TradingClientConfig::default(); assert_eq!(config.endpoint, "https://localhost:50050"); assert_eq!(config.timeout_ms, 30_000); } /// Test TradingClientConfig with custom values #[test] fn test_trading_client_config_custom() { let config = TradingClientConfig { endpoint: "https://trading-service:50051".to_string(), timeout_ms: 10_000, }; assert_eq!(config.endpoint, "https://trading-service:50051"); assert_eq!(config.timeout_ms, 10_000); } /// Test TradingClientConfig clone #[test] fn test_trading_client_config_clone() { let config = TradingClientConfig { endpoint: "https://test:8080".to_string(), timeout_ms: 5000, }; let cloned = config.clone(); assert_eq!(cloned.endpoint, config.endpoint); assert_eq!(cloned.timeout_ms, config.timeout_ms); } /// Test TradingClientConfig serialization #[test] fn test_trading_client_config_serialization() { let config = TradingClientConfig { endpoint: "https://test:8080".to_string(), timeout_ms: 5000, }; let json = serde_json::to_string(&config).unwrap(); assert!(json.contains("https://test:8080")); assert!(json.contains("5000")); let deserialized: TradingClientConfig = serde_json::from_str(&json).unwrap(); assert_eq!(deserialized.endpoint, config.endpoint); assert_eq!(deserialized.timeout_ms, config.timeout_ms); } /// Test TradingClientConfig debug formatting #[test] fn test_trading_client_config_debug() { let config = TradingClientConfig::default(); let debug_str = format!("{:?}", config); assert!(debug_str.contains("TradingClientConfig")); } /// Test TradingClient creation #[test] fn test_trading_client_creation() { let config = TradingClientConfig::default(); let client = TradingClient::new(config); // Client should be created successfully assert!(format!("{:?}", client).contains("TradingClient")); } /// Test TradingClient with custom config #[test] fn test_trading_client_custom_config() { let config = TradingClientConfig { endpoint: "https://custom-trading:9000".to_string(), timeout_ms: 15000, }; let client = TradingClient::new(config); assert!(format!("{:?}", client).contains("TradingClient")); } /// Test TradingClient debug formatting #[test] fn test_trading_client_debug() { let config = TradingClientConfig::default(); let client = TradingClient::new(config); let debug_str = format!("{:?}", client); assert!(debug_str.contains("TradingClient")); } /// Test TradingClient shutdown #[tokio::test] async fn test_trading_client_shutdown() { let config = TradingClientConfig::default(); let mut client = TradingClient::new(config); // Shutdown should complete without error client.shutdown().await; } /// Test TradingClientConfig with zero timeout #[test] fn test_trading_client_config_zero_timeout() { let config = TradingClientConfig { endpoint: "https://test:8080".to_string(), timeout_ms: 0, }; assert_eq!(config.timeout_ms, 0); } /// Test TradingClientConfig with very long timeout #[test] fn test_trading_client_config_long_timeout() { let config = TradingClientConfig { endpoint: "https://test:8080".to_string(), timeout_ms: u64::MAX, }; assert_eq!(config.timeout_ms, u64::MAX); } /// Test TradingClientConfig with various endpoint formats #[test] fn test_trading_client_config_endpoint_formats() { let endpoints = vec![ "https://localhost:50050", "https://trading-service.example.com:443", "https://10.0.0.1:8080", "https://[::1]:50051", ]; for endpoint in endpoints { let config = TradingClientConfig { endpoint: endpoint.to_string(), timeout_ms: 5000, }; assert_eq!(config.endpoint, endpoint); } } /// Test TradingClientConfig with empty endpoint #[test] fn test_trading_client_config_empty_endpoint() { let config = TradingClientConfig { endpoint: "".to_string(), timeout_ms: 5000, }; assert!(config.endpoint.is_empty()); } /// Test TradingClientConfig with very long endpoint #[test] fn test_trading_client_config_very_long_endpoint() { let long_hostname = "a".repeat(1000); let endpoint = format!("https://{}.example.com:50051", long_hostname); let config = TradingClientConfig { endpoint: endpoint.clone(), timeout_ms: 5000, }; assert_eq!(config.endpoint, endpoint); } /// Test multiple TradingClient instances #[test] fn test_multiple_trading_clients() { let config1 = TradingClientConfig { endpoint: "https://service1:50051".to_string(), timeout_ms: 5000, }; let config2 = TradingClientConfig { endpoint: "https://service2:50052".to_string(), timeout_ms: 10000, }; let client1 = TradingClient::new(config1); let client2 = TradingClient::new(config2); assert!(format!("{:?}", client1).contains("TradingClient")); assert!(format!("{:?}", client2).contains("TradingClient")); } /// Test TradingClientConfig deserialization from JSON #[test] fn test_trading_client_config_from_json() { let json = r#"{"endpoint":"https://test:8080","timeout_ms":15000}"#; let config: TradingClientConfig = serde_json::from_str(json).unwrap(); assert_eq!(config.endpoint, "https://test:8080"); assert_eq!(config.timeout_ms, 15000); } /// Test TradingClientConfig with different timeout values #[test] fn test_trading_client_config_timeout_values() { let timeouts = vec![100, 1_000, 10_000, 30_000, 60_000, 300_000]; for timeout in timeouts { let config = TradingClientConfig { endpoint: "https://test:8080".to_string(), timeout_ms: timeout, }; assert_eq!(config.timeout_ms, timeout); } } /// Test TradingClient creation with default config #[test] fn test_trading_client_with_default_config() { let client = TradingClient::new(TradingClientConfig::default()); assert!(format!("{:?}", client).contains("TradingClient")); } /// Test TradingClientConfig equality after clone #[test] fn test_trading_client_config_clone_equality() { let config = TradingClientConfig { endpoint: "https://test:8080".to_string(), timeout_ms: 5000, }; let cloned = config.clone(); // Verify all fields match assert_eq!(config.endpoint, cloned.endpoint); assert_eq!(config.timeout_ms, cloned.timeout_ms); } /// Test TradingClientConfig round-trip serialization #[test] fn test_trading_client_config_roundtrip() { let original = TradingClientConfig { endpoint: "https://roundtrip:7777".to_string(), timeout_ms: 12345, }; let json = serde_json::to_string(&original).unwrap(); let deserialized: TradingClientConfig = serde_json::from_str(&json).unwrap(); assert_eq!(original.endpoint, deserialized.endpoint); assert_eq!(original.timeout_ms, deserialized.timeout_ms); } /// Test TradingClient concurrent shutdown #[tokio::test] async fn test_trading_client_concurrent_shutdown() { use std::sync::Arc; use tokio::sync::Mutex; let config = TradingClientConfig::default(); let client = Arc::new(Mutex::new(TradingClient::new(config))); // Spawn multiple shutdown attempts let mut handles = vec![]; for _ in 0..5 { let client_clone = client.clone(); let handle = tokio::spawn(async move { let mut client = client_clone.lock().await; client.shutdown().await; }); handles.push(handle); } // All shutdowns should complete for handle in handles { handle.await.unwrap(); } } /// Test TradingClientConfig with port numbers #[test] fn test_trading_client_config_port_numbers() { let ports = vec![80, 443, 8080, 50050, 50051, 65535]; for port in ports { let config = TradingClientConfig { endpoint: format!("https://test:{}", port), timeout_ms: 5000, }; assert!(config.endpoint.contains(&port.to_string())); } }