#![allow(unused_crate_dependencies)] //! Integration tests for TLOB model integration //! Tests the complete TLOB functionality within adaptive-strategy use adaptive_strategy::models::{ModelConfig, ModelFactory}; use std::time::Instant; /// Create test order book features matching TLOB requirements fn create_test_tlob_features() -> Vec { let mut features = Vec::with_capacity(51); // Bid prices (10 levels, decreasing) for i in 0..10 { features.push(100.0 - (i as f64 * 0.01)); } // Ask prices (10 levels, increasing) for i in 0..10 { features.push(100.01 + (i as f64 * 0.01)); } // Bid volumes (10 levels) for i in 0..10 { features.push(1000.0 + (i as f64 * 100.0)); } // Ask volumes (10 levels) for i in 0..10 { features.push(1100.0 + (i as f64 * 100.0)); } // Market data: last_price, volume, volatility, momentum features.extend_from_slice(&[100.005, 5000.0, 0.02, 0.001]); // Microstructure features (7 values) features.extend_from_slice(&[0.1, 0.2, 0.15, 0.3, 0.25, 0.05, 0.08]); assert_eq!(features.len(), 51); features } #[tokio::test] async fn test_tlob_model_creation() { let config = ModelConfig::default(); let result = ModelFactory::create_model("tlob", "test_tlob_integration".to_string(), config).await; assert!(result.is_ok(), "Should be able to create TLOB model"); let model = result.unwrap(); assert_eq!(model.name(), "test_tlob_integration"); assert_eq!(model.model_type(), "tlob"); assert!(model.is_ready()); } #[tokio::test] async fn test_tlob_prediction_functionality() { let config = ModelConfig::default(); let model = ModelFactory::create_model("tlob", "test_prediction".to_string(), config) .await .unwrap(); let features = create_test_tlob_features(); let result = model.predict(&features).await; assert!(result.is_ok(), "TLOB prediction should succeed"); let prediction = result.unwrap(); // Validate prediction structure assert!(prediction.confidence >= 0.0 && prediction.confidence <= 1.0); assert!(!prediction.features_used.is_empty()); // Check metadata if let Some(metadata) = prediction.metadata { assert!(metadata.contains_key("model_type")); assert_eq!(metadata["model_type"], "tlob"); assert!(metadata.contains_key("extraction_time_ns")); } } #[tokio::test] async fn test_tlob_performance_target() { let config = ModelConfig::default(); let model = ModelFactory::create_model("tlob", "test_performance".to_string(), config) .await .unwrap(); let features = create_test_tlob_features(); // Warm up the model for _ in 0..5 { let _ = model.predict(&features).await.unwrap(); } // Measure performance over multiple predictions let mut total_time_ns = 0u64; let iterations = 100; for _ in 0..iterations { let start = Instant::now(); let _result = model.predict(&features).await.unwrap(); total_time_ns += start.elapsed().as_nanos() as u64; } let avg_time_ns = total_time_ns / iterations; let avg_time_us = avg_time_ns as f64 / 1000.0; println!("Average prediction time: {:.2}μs", avg_time_us); // Verify sub-50μs target (with some tolerance for test environment) assert!( avg_time_us < 100.0, "Average prediction time {:.2}μs should be reasonable (target <50μs)", avg_time_us ); } #[tokio::test] async fn test_tlob_model_metadata() { let config = ModelConfig::default(); let model = ModelFactory::create_model("tlob", "test_metadata".to_string(), config) .await .unwrap(); let metadata = model.get_metadata(); assert_eq!(metadata.model_type, "tlob"); assert_eq!(metadata.input_dimensions, 51); assert!(metadata.description.is_some()); assert!(metadata.description.unwrap().contains("TLOB")); // Check parameters assert!(metadata.parameters.contains_key("feature_dim")); assert!(metadata.parameters.contains_key("prediction_horizon")); } #[tokio::test] async fn test_tlob_model_performance_metrics() { let config = ModelConfig::default(); let model = ModelFactory::create_model("tlob", "test_metrics".to_string(), config) .await .unwrap(); let features = create_test_tlob_features(); // Make some predictions for _ in 0..10 { let _ = model.predict(&features).await.unwrap(); } let performance = model.get_performance().await.unwrap(); assert!(performance.accuracy >= 0.0 && performance.accuracy <= 1.0); assert!(performance.prediction_count >= 10); } #[tokio::test] async fn test_tlob_invalid_features() { let config = ModelConfig::default(); let model = ModelFactory::create_model("tlob", "test_invalid".to_string(), config) .await .unwrap(); // Test with insufficient features let invalid_features = vec![1.0; 30]; // Only 30 features instead of 51 let result = model.predict(&invalid_features).await; assert!(result.is_err(), "Should fail with insufficient features"); } #[tokio::test] async fn test_tlob_model_memory_usage() { let config = ModelConfig::default(); let model = ModelFactory::create_model("tlob", "test_memory".to_string(), config) .await .unwrap(); let memory_usage = model.memory_usage(); assert!( memory_usage > 0, "Model should report non-zero memory usage" ); assert!( memory_usage < 100 * 1024 * 1024, "Memory usage should be reasonable (<100MB)" ); } #[tokio::test] async fn test_tlob_model_configuration() { let mut config = ModelConfig::default(); config.batch_size = 16; config.custom_parameters.insert( "prediction_horizon".to_string(), serde_json::Value::Number(serde_json::Number::from(5)), ); let model = ModelFactory::create_model("tlob", "test_config".to_string(), config) .await .unwrap(); let metadata = model.get_metadata(); assert_eq!( metadata.parameters["prediction_horizon"].as_u64().unwrap(), 5 ); } #[tokio::test] async fn test_tlob_concurrent_predictions() { let config = ModelConfig::default(); let model = std::sync::Arc::new( ModelFactory::create_model("tlob", "test_concurrent".to_string(), config) .await .unwrap(), ); let features = create_test_tlob_features(); let mut tasks = Vec::new(); // Launch concurrent prediction tasks for _i in 0..4 { let model_clone = model.clone(); let features_clone = features.clone(); let task = tokio::spawn(async move { model_clone.predict(&features_clone).await.unwrap() }); tasks.push(task); } // Wait for all predictions to complete let results = futures::future::join_all(tasks).await; assert_eq!(results.len(), 4); for result in results { assert!(result.is_ok(), "Concurrent prediction should succeed"); } } #[tokio::test] async fn test_model_factory_available_models() { let available = ModelFactory::available_models(); assert!( available.contains(&"tlob"), "TLOB should be in available models" ); } // Performance stress test #[tokio::test] async fn test_tlob_sustained_load() { let config = ModelConfig::default(); let model = ModelFactory::create_model("tlob", "test_sustained".to_string(), config) .await .unwrap(); let features = create_test_tlob_features(); // Sustained prediction load let start_time = Instant::now(); let prediction_count = 1000; for _ in 0..prediction_count { let result = model.predict(&features).await; assert!(result.is_ok(), "Sustained predictions should not fail"); } let elapsed = start_time.elapsed(); let avg_per_prediction = elapsed.as_nanos() as f64 / prediction_count as f64 / 1000.0; println!( "Sustained load: {} predictions in {:.2}ms (avg {:.2}μs per prediction)", prediction_count, elapsed.as_millis(), avg_per_prediction ); // Verify reasonable performance under sustained load assert!( avg_per_prediction < 200.0, "Average prediction time under sustained load should be reasonable" ); }