#![allow( clippy::all, unused_imports, unused_variables, dead_code, unused_mut, unused_assignments, non_camel_case_types, clippy::approx_constant, unexpected_cfgs, unused_must_use, unused_parens )] //! Integration tests for SONA (Self-Optimizing Neural Architecture) //! //! Tests the three-tier learning loop: instant adaptation, background consolidation, //! and deep loop processing. use ruvllm::{ error::Result, sona::{ LearningLoop, RoutingRecommendation, SonaConfig, SonaIntegration, SonaStats, Trajectory, }, }; use std::time::Duration; /// Create a test SONA configuration fn create_test_sona_config() -> SonaConfig { SonaConfig { hidden_dim: 64, embedding_dim: 128, micro_lora_rank: 2, base_lora_rank: 4, instant_learning_rate: 0.01, background_learning_rate: 0.001, ewc_lambda: 0.1, pattern_capacity: 100, background_interval_secs: 3600, deep_interval_secs: 604800, quality_threshold: 0.5, } } /// Create a test trajectory fn create_test_trajectory(request_id: &str, quality: f32) -> Trajectory { Trajectory { request_id: request_id.to_string(), session_id: "test-session".to_string(), query_embedding: vec![0.1; 128], response_embedding: vec![0.2; 128], quality_score: quality, routing_features: vec![0.7, 0.9, 0.5, 0.5], model_index: 1, timestamp: chrono::Utc::now(), } } #[test] fn test_sona_config_default() { let config = SonaConfig::default(); assert_eq!(config.hidden_dim, 256); assert_eq!(config.embedding_dim, 768); assert_eq!(config.micro_lora_rank, 2); assert_eq!(config.base_lora_rank, 8); assert!(config.instant_learning_rate > 0.0); assert!(config.ewc_lambda > 0.0); assert!(config.quality_threshold > 0.0); } #[test] fn test_sona_integration_creation() { let config = create_test_sona_config(); let sona = SonaIntegration::new(config); let stats = sona.stats(); assert_eq!(stats.total_trajectories, 0); assert_eq!(stats.instant_updates, 0); assert_eq!(stats.background_updates, 0); assert_eq!(stats.deep_updates, 0); } #[test] fn test_learning_loop_variants() { assert!(matches!(LearningLoop::Instant, LearningLoop::Instant)); assert!(matches!(LearningLoop::Background, LearningLoop::Background)); assert!(matches!(LearningLoop::Deep, LearningLoop::Deep)); } #[test] fn test_trajectory_creation() { let trajectory = create_test_trajectory("req-001", 0.8); assert_eq!(trajectory.request_id, "req-001"); assert_eq!(trajectory.session_id, "test-session"); assert_eq!(trajectory.quality_score, 0.8); assert_eq!(trajectory.query_embedding.len(), 128); assert_eq!(trajectory.response_embedding.len(), 128); assert_eq!(trajectory.routing_features.len(), 4); } #[test] fn test_sona_record_trajectory() { let config = SonaConfig { quality_threshold: 0.0, // Accept all trajectories ..create_test_sona_config() }; let sona = SonaIntegration::new(config); let trajectory = create_test_trajectory("req-001", 0.8); sona.record_trajectory(trajectory).unwrap(); let stats = sona.stats(); assert_eq!(stats.total_trajectories, 1); assert_eq!(stats.instant_updates, 1); // Should run instant loop } #[test] fn test_sona_quality_threshold() { let config = SonaConfig { quality_threshold: 0.7, ..create_test_sona_config() }; let sona = SonaIntegration::new(config); // High quality - should trigger instant loop let high_quality = create_test_trajectory("req-001", 0.9); sona.record_trajectory(high_quality).unwrap(); let stats = sona.stats(); assert_eq!(stats.total_trajectories, 1); assert_eq!(stats.instant_updates, 1); // Low quality - should not trigger instant loop let low_quality = create_test_trajectory("req-002", 0.5); sona.record_trajectory(low_quality).unwrap(); let stats = sona.stats(); assert_eq!(stats.total_trajectories, 2); assert_eq!(stats.instant_updates, 1); // Still 1 } #[test] fn test_sona_multiple_trajectories() { let config = SonaConfig { quality_threshold: 0.0, ..create_test_sona_config() }; let sona = SonaIntegration::new(config); for i in 0..10 { let trajectory = create_test_trajectory(&format!("req-{:03}", i), 0.8); sona.record_trajectory(trajectory).unwrap(); } let stats = sona.stats(); assert_eq!(stats.total_trajectories, 10); assert_eq!(stats.instant_updates, 10); } #[test] fn test_sona_routing_recommendation_no_patterns() { let config = create_test_sona_config(); let sona = SonaIntegration::new(config); let query = vec![0.1; 128]; let rec = sona.get_routing_recommendation(&query); // With no patterns, should return defaults assert_eq!(rec.based_on_patterns, 0); } #[test] fn test_routing_recommendation_default() { let rec = RoutingRecommendation::default(); assert_eq!(rec.suggested_model, 0); assert_eq!(rec.confidence, 0.0); assert_eq!(rec.based_on_patterns, 0); assert_eq!(rec.average_quality, 0.0); } #[test] fn test_sona_search_patterns_empty() { let config = create_test_sona_config(); let sona = SonaIntegration::new(config); let query = vec![0.1; 128]; let patterns = sona.search_patterns(&query, 5); assert!(patterns.is_empty()); } #[test] fn test_sona_apply_transform() { let config = create_test_sona_config(); let sona = SonaIntegration::new(config); let input = vec![0.1; 64]; // Must match hidden_dim let output = sona.apply_transform(&input); assert_eq!(output.len(), input.len()); assert!(output.iter().all(|&v| v.is_finite())); } #[test] fn test_sona_stats() { let config = create_test_sona_config(); let sona = SonaIntegration::new(config); let stats = sona.stats(); assert_eq!(stats.total_trajectories, 0); assert_eq!(stats.instant_updates, 0); assert_eq!(stats.background_updates, 0); assert_eq!(stats.deep_updates, 0); assert_eq!(stats.patterns_learned, 0); assert_eq!(stats.buffer_size, 0); } #[test] fn test_sona_stats_after_learning() { let config = SonaConfig { quality_threshold: 0.0, ..create_test_sona_config() }; let sona = SonaIntegration::new(config); // Record some trajectories for i in 0..5 { let trajectory = create_test_trajectory(&format!("req-{}", i), 0.8); sona.record_trajectory(trajectory).unwrap(); } let stats = sona.stats(); assert_eq!(stats.total_trajectories, 5); assert!(stats.buffer_size > 0); } #[test] fn test_sona_trigger_background_loop() { let config = SonaConfig { quality_threshold: 0.0, background_interval_secs: 0, // Allow immediate trigger ..create_test_sona_config() }; let sona = SonaIntegration::new(config); // Record trajectories for i in 0..5 { let trajectory = create_test_trajectory(&format!("req-{}", i), 0.8); sona.record_trajectory(trajectory).unwrap(); } // Trigger background loop sona.trigger_background_loop().unwrap(); let stats = sona.stats(); assert!(stats.background_updates >= 1); } #[test] fn test_sona_trigger_deep_loop() { let config = SonaConfig { quality_threshold: 0.0, ..create_test_sona_config() }; let sona = SonaIntegration::new(config); // Record trajectories (this may trigger deep loop automatically if interval elapsed) for i in 0..5 { let trajectory = create_test_trajectory(&format!("req-{}", i), 0.8); sona.record_trajectory(trajectory).unwrap(); } let stats_before = sona.stats(); let deep_updates_before = stats_before.deep_updates; // Trigger background loop first (to populate patterns) sona.trigger_background_loop().unwrap(); // Trigger deep loop explicitly sona.trigger_deep_loop().unwrap(); let stats = sona.stats(); // At least one more deep update after explicit trigger assert!( stats.deep_updates >= deep_updates_before + 1, "Expected at least {} deep updates, got {}", deep_updates_before + 1, stats.deep_updates ); } #[test] fn test_trajectory_timestamp() { let trajectory = create_test_trajectory("req-001", 0.8); let now = chrono::Utc::now(); // Timestamp should be recent let diff = now - trajectory.timestamp; assert!(diff.num_seconds() < 1); } #[test] fn test_sona_varying_quality_trajectories() { let config = SonaConfig { quality_threshold: 0.5, ..create_test_sona_config() }; let sona = SonaIntegration::new(config); // Record trajectories with varying quality let qualities = [0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1]; for (i, &quality) in qualities.iter().enumerate() { let trajectory = create_test_trajectory(&format!("req-{}", i), quality); sona.record_trajectory(trajectory).unwrap(); } let stats = sona.stats(); assert_eq!(stats.total_trajectories, 9); // Only 5 have quality >= 0.5 threshold assert_eq!(stats.instant_updates, 5); } #[test] fn test_sona_empty_background_loop() { let config = create_test_sona_config(); let sona = SonaIntegration::new(config); // Trigger background loop with no trajectories // Note: The implementation returns early without incrementing counter // if there are no high-quality trajectories to process let result = sona.trigger_background_loop(); assert!(result.is_ok()); let stats = sona.stats(); // With no trajectories meeting quality threshold, background_updates is 0 assert_eq!( stats.background_updates, 0, "Background loop with no trajectories should not count as an update" ); } #[test] fn test_sona_empty_deep_loop() { let config = create_test_sona_config(); let sona = SonaIntegration::new(config); // Trigger deep loop with no patterns let result = sona.trigger_deep_loop(); assert!(result.is_ok()); let stats = sona.stats(); assert_eq!(stats.deep_updates, 1); } #[test] fn test_sona_large_embedding() { let config = SonaConfig { embedding_dim: 768, hidden_dim: 256, quality_threshold: 0.0, ..SonaConfig::default() }; let sona = SonaIntegration::new(config); let trajectory = Trajectory { request_id: "large-001".to_string(), session_id: "test".to_string(), query_embedding: vec![0.1; 768], response_embedding: vec![0.2; 768], quality_score: 0.9, routing_features: vec![0.5; 4], model_index: 0, timestamp: chrono::Utc::now(), }; sona.record_trajectory(trajectory).unwrap(); let stats = sona.stats(); assert_eq!(stats.total_trajectories, 1); } #[test] fn test_sona_model_index_mapping() { let config = SonaConfig { quality_threshold: 0.0, ..create_test_sona_config() }; let sona = SonaIntegration::new(config); // Test different model indices for model_idx in 0..4 { let trajectory = Trajectory { request_id: format!("model-{}", model_idx), session_id: "test".to_string(), query_embedding: vec![0.1; 128], response_embedding: vec![0.2; 128], quality_score: 0.8, routing_features: vec![0.5; 4], model_index: model_idx, timestamp: chrono::Utc::now(), }; sona.record_trajectory(trajectory).unwrap(); } let stats = sona.stats(); assert_eq!(stats.total_trajectories, 4); } #[test] fn test_sona_concurrent_safe() { use std::sync::Arc; use std::thread; let config = SonaConfig { quality_threshold: 0.0, ..create_test_sona_config() }; let sona = Arc::new(SonaIntegration::new(config)); let mut handles = vec![]; // Spawn multiple threads recording trajectories for thread_id in 0..4 { let sona_clone = Arc::clone(&sona); let handle = thread::spawn(move || { for i in 0..10 { let trajectory = Trajectory { request_id: format!("thread-{}-req-{}", thread_id, i), session_id: format!("thread-{}", thread_id), query_embedding: vec![0.1; 128], response_embedding: vec![0.2; 128], quality_score: 0.8, routing_features: vec![0.5; 4], model_index: 0, timestamp: chrono::Utc::now(), }; sona_clone.record_trajectory(trajectory).unwrap(); } }); handles.push(handle); } for handle in handles { handle.join().unwrap(); } let stats = sona.stats(); assert_eq!(stats.total_trajectories, 40); } #[test] fn test_sona_stats_struct() { let stats = SonaStats { total_trajectories: 100, instant_updates: 80, background_updates: 5, deep_updates: 1, patterns_learned: 50, buffer_size: 20, last_background_secs_ago: 3600, last_deep_secs_ago: 86400, }; assert_eq!(stats.total_trajectories, 100); assert_eq!(stats.instant_updates, 80); assert_eq!(stats.background_updates, 5); assert_eq!(stats.deep_updates, 1); assert_eq!(stats.patterns_learned, 50); assert_eq!(stats.buffer_size, 20); } #[test] fn test_sona_routing_features() { let trajectory = Trajectory { request_id: "routing-test".to_string(), session_id: "test".to_string(), query_embedding: vec![0.1; 128], response_embedding: vec![0.2; 128], quality_score: 0.9, routing_features: vec![0.7, 0.9, 0.8, 0.5], // temperature, top_p, confidence, context_ratio model_index: 1, timestamp: chrono::Utc::now(), }; assert_eq!(trajectory.routing_features.len(), 4); assert_eq!(trajectory.routing_features[0], 0.7); // temperature assert_eq!(trajectory.routing_features[1], 0.9); // top_p } #[test] fn test_sona_boundary_quality() { let config = SonaConfig { quality_threshold: 0.5, ..create_test_sona_config() }; let sona = SonaIntegration::new(config); // Exactly at threshold let trajectory = create_test_trajectory("boundary", 0.5); sona.record_trajectory(trajectory).unwrap(); let stats = sona.stats(); assert_eq!(stats.instant_updates, 1); // Should still trigger } #[test] fn test_sona_zero_quality() { let config = SonaConfig { quality_threshold: 0.0, ..create_test_sona_config() }; let sona = SonaIntegration::new(config); let trajectory = create_test_trajectory("zero-quality", 0.0); sona.record_trajectory(trajectory).unwrap(); let stats = sona.stats(); assert_eq!(stats.total_trajectories, 1); // With threshold 0.0, even quality 0.0 should trigger (0.0 >= 0.0) assert_eq!(stats.instant_updates, 1); } #[test] fn test_sona_negative_quality_handling() { let config = create_test_sona_config(); let sona = SonaIntegration::new(config); // Negative quality should still be recorded but not trigger learning let trajectory = Trajectory { request_id: "negative".to_string(), session_id: "test".to_string(), query_embedding: vec![0.1; 128], response_embedding: vec![0.2; 128], quality_score: -0.5, // Negative routing_features: vec![0.5; 4], model_index: 0, timestamp: chrono::Utc::now(), }; sona.record_trajectory(trajectory).unwrap(); let stats = sona.stats(); assert_eq!(stats.total_trajectories, 1); assert_eq!(stats.instant_updates, 0); // Should not trigger }