|
| 1 | +///! Integration test for Issue #34 - Complete Provider Configuration Integration |
| 2 | +///! |
| 3 | +///! Tests the complete end-to-end flow: |
| 4 | +///! 1. App starts in WaitingForConfig state |
| 5 | +///! 2. Settings modal shows provider configuration |
| 6 | +///! 3. Async validation works |
| 7 | +///! 4. State transitions correctly |
| 8 | +///! 5. UI components integrate properly |
| 9 | +use agentic::{ |
| 10 | + events::{AppEvent, AppState}, |
| 11 | + settings::{AsyncValidationResult, ProviderType, Settings, ValidationEvent, ValidationStatus}, |
| 12 | + theme::{Theme, ThemeVariant}, |
| 13 | + ui::app::App, |
| 14 | +}; |
| 15 | +use std::time::Duration; |
| 16 | + |
| 17 | +#[tokio::main] |
| 18 | +async fn main() -> Result<(), Box<dyn std::error::Error>> { |
| 19 | + println!("🧪 Integration Test: Complete Provider Configuration"); |
| 20 | + println!("=================================================="); |
| 21 | + |
| 22 | + // Test 1: App starts in correct state |
| 23 | + test_initial_app_state().await?; |
| 24 | + |
| 25 | + // Test 2: Settings integration |
| 26 | + test_settings_integration().await?; |
| 27 | + |
| 28 | + // Test 3: Provider validation result handling |
| 29 | + test_provider_validation_handling().await?; |
| 30 | + |
| 31 | + // Test 4: State transitions |
| 32 | + test_state_transitions().await?; |
| 33 | + |
| 34 | + // Test 5: Provider configuration components |
| 35 | + test_provider_configuration_components().await?; |
| 36 | + |
| 37 | + println!("\n✅ All integration tests passed!"); |
| 38 | + println!("🎯 Issue #34 Provider Configuration Integration: COMPLETE"); |
| 39 | + |
| 40 | + Ok(()) |
| 41 | +} |
| 42 | + |
| 43 | +async fn test_initial_app_state() -> Result<(), Box<dyn std::error::Error>> { |
| 44 | + println!("\n📋 Test 1: Initial App State"); |
| 45 | + println!("-----------------------------"); |
| 46 | + |
| 47 | + let theme = Theme::new(ThemeVariant::EverforestDark); |
| 48 | + let app = App::new(theme); |
| 49 | + |
| 50 | + // App should start in WaitingForConfig since no providers are configured |
| 51 | + assert_eq!(app.state(), &AppState::WaitingForConfig); |
| 52 | + println!("✅ App correctly starts in WaitingForConfig state"); |
| 53 | + |
| 54 | + // Provider readiness should be false |
| 55 | + assert!(!app.settings().has_valid_provider()); |
| 56 | + println!("✅ Provider readiness check works correctly"); |
| 57 | + |
| 58 | + // Available providers should be empty |
| 59 | + assert!(app.settings().get_available_providers().is_empty()); |
| 60 | + println!("✅ Available providers list is correctly empty"); |
| 61 | + |
| 62 | + Ok(()) |
| 63 | +} |
| 64 | + |
| 65 | +async fn test_settings_integration() -> Result<(), Box<dyn std::error::Error>> { |
| 66 | + println!("\n⚙️ Test 2: Settings Integration"); |
| 67 | + println!("-------------------------------------"); |
| 68 | + |
| 69 | + let theme = Theme::new(ThemeVariant::EverforestDark); |
| 70 | + let mut app = App::new(theme); |
| 71 | + |
| 72 | + // Test opening settings |
| 73 | + app.enter_settings(); |
| 74 | + assert_eq!(app.state(), &AppState::Settings); |
| 75 | + println!("✅ Settings modal opens correctly"); |
| 76 | + |
| 77 | + // Check that provider sections exist |
| 78 | + let provider_sections = app.settings().get_provider_sections(); |
| 79 | + assert!(!provider_sections.is_empty()); |
| 80 | + println!("✅ Provider sections are available in settings"); |
| 81 | + |
| 82 | + // Check that both LOCAL and OPENROUTER sections exist |
| 83 | + let section_names: Vec<&str> = provider_sections.iter().map(|s| s.title.as_str()).collect(); |
| 84 | + assert!(section_names.contains(&"LOCAL Provider")); |
| 85 | + assert!(section_names.contains(&"OPENROUTER Provider")); |
| 86 | + println!("✅ Both LOCAL and OPENROUTER provider sections exist"); |
| 87 | + |
| 88 | + // Test closing settings |
| 89 | + app.exit_settings(); |
| 90 | + assert_eq!(app.state(), &AppState::WaitingForConfig); |
| 91 | + println!("✅ Settings modal closes correctly, returns to WaitingForConfig"); |
| 92 | + |
| 93 | + Ok(()) |
| 94 | +} |
| 95 | + |
| 96 | +async fn test_provider_validation_handling() -> Result<(), Box<dyn std::error::Error>> { |
| 97 | + println!("\n🔄 Test 3: Provider Validation Result Handling"); |
| 98 | + println!("---------------------------------------------"); |
| 99 | + |
| 100 | + let mut settings = Settings::new(); |
| 101 | + |
| 102 | + // Check initial state |
| 103 | + assert_eq!( |
| 104 | + settings.local_provider.validation_status, |
| 105 | + ValidationStatus::Unchecked |
| 106 | + ); |
| 107 | + assert_eq!( |
| 108 | + settings.openrouter_provider.validation_status, |
| 109 | + ValidationStatus::Unchecked |
| 110 | + ); |
| 111 | + println!("✅ Initial provider status is Unchecked"); |
| 112 | + |
| 113 | + // Test validation event handling |
| 114 | + let validation_event = ValidationEvent::ValidationComplete { |
| 115 | + provider: ProviderType::Local, |
| 116 | + result: AsyncValidationResult { |
| 117 | + status: ValidationStatus::Valid, |
| 118 | + message: Some("Connection successful".to_string()), |
| 119 | + response_time: Some(Duration::from_millis(250)), |
| 120 | + }, |
| 121 | + }; |
| 122 | + |
| 123 | + settings.handle_validation_event(validation_event); |
| 124 | + assert_eq!( |
| 125 | + settings.local_provider.validation_status, |
| 126 | + ValidationStatus::Valid |
| 127 | + ); |
| 128 | + println!("✅ Validation event correctly updates provider status"); |
| 129 | + |
| 130 | + // Test provider readiness after validation |
| 131 | + assert!(settings.has_valid_provider()); |
| 132 | + println!("✅ Provider readiness correctly reflects valid provider"); |
| 133 | + |
| 134 | + let available = settings.get_available_providers(); |
| 135 | + assert!(available.contains(&ProviderType::Local)); |
| 136 | + assert!(!available.contains(&ProviderType::OpenRouter)); |
| 137 | + println!("✅ Available providers list correctly reflects valid providers"); |
| 138 | + |
| 139 | + Ok(()) |
| 140 | +} |
| 141 | + |
| 142 | +async fn test_state_transitions() -> Result<(), Box<dyn std::error::Error>> { |
| 143 | + println!("\n🔄 Test 4: State Transitions"); |
| 144 | + println!("-----------------------------"); |
| 145 | + |
| 146 | + let theme = Theme::new(ThemeVariant::EverforestDark); |
| 147 | + let mut app = App::new(theme); |
| 148 | + |
| 149 | + // Initial state should be WaitingForConfig |
| 150 | + assert_eq!(app.state(), &AppState::WaitingForConfig); |
| 151 | + println!("✅ Initial state: WaitingForConfig"); |
| 152 | + |
| 153 | + // Simulate a provider becoming valid |
| 154 | + let validation_event = ValidationEvent::ValidationComplete { |
| 155 | + provider: ProviderType::Local, |
| 156 | + result: AsyncValidationResult { |
| 157 | + status: ValidationStatus::Valid, |
| 158 | + message: Some("Connection successful".to_string()), |
| 159 | + response_time: Some(Duration::from_millis(150)), |
| 160 | + }, |
| 161 | + }; |
| 162 | + |
| 163 | + app.update_provider_status(validation_event); |
| 164 | + // State should transition to Main |
| 165 | + assert_eq!(app.state(), &AppState::Main); |
| 166 | + println!("✅ State correctly transitions to Main when provider becomes valid"); |
| 167 | + |
| 168 | + // Simulate provider becoming invalid |
| 169 | + let invalid_event = ValidationEvent::ValidationComplete { |
| 170 | + provider: ProviderType::Local, |
| 171 | + result: AsyncValidationResult { |
| 172 | + status: ValidationStatus::Invalid, |
| 173 | + message: Some("Connection failed".to_string()), |
| 174 | + response_time: Some(Duration::from_millis(5000)), |
| 175 | + }, |
| 176 | + }; |
| 177 | + |
| 178 | + app.update_provider_status(invalid_event); |
| 179 | + // State should transition back to WaitingForConfig |
| 180 | + assert_eq!(app.state(), &AppState::WaitingForConfig); |
| 181 | + println!( |
| 182 | + "✅ State correctly transitions back to WaitingForConfig when provider becomes invalid" |
| 183 | + ); |
| 184 | + |
| 185 | + Ok(()) |
| 186 | +} |
| 187 | + |
| 188 | +async fn test_provider_configuration_components() -> Result<(), Box<dyn std::error::Error>> { |
| 189 | + println!("\n🎯 Test 5: Provider Configuration Components"); |
| 190 | + println!("--------------------------------------------"); |
| 191 | + |
| 192 | + let settings = Settings::new(); |
| 193 | + |
| 194 | + // Test provider status summary |
| 195 | + let status_summary = settings.get_provider_status_summary(); |
| 196 | + assert_eq!(status_summary.len(), 2); // LOCAL and OPENROUTER |
| 197 | + println!("✅ Provider status summary includes both providers"); |
| 198 | + |
| 199 | + // Check initial status icons in provider sections |
| 200 | + let provider_sections = settings.get_provider_sections(); |
| 201 | + for section in &provider_sections { |
| 202 | + assert_eq!(section.status_icon, "⚪"); // Unchecked |
| 203 | + } |
| 204 | + println!("✅ Initial status icons show unchecked state (⚪)"); |
| 205 | + |
| 206 | + // Test field structure for LOCAL provider |
| 207 | + let local_section = provider_sections |
| 208 | + .iter() |
| 209 | + .find(|s| s.title == "LOCAL Provider") |
| 210 | + .expect("LOCAL Provider section should exist"); |
| 211 | + |
| 212 | + assert!(!local_section.fields.is_empty()); |
| 213 | + let _endpoint_field = local_section |
| 214 | + .fields |
| 215 | + .iter() |
| 216 | + .find(|f| f.label.contains("Endpoint")) |
| 217 | + .expect("Endpoint field should exist"); |
| 218 | + |
| 219 | + println!("✅ LOCAL provider has endpoint configuration field"); |
| 220 | + |
| 221 | + // Test field structure for OPENROUTER provider |
| 222 | + let openrouter_section = provider_sections |
| 223 | + .iter() |
| 224 | + .find(|s| s.title == "OPENROUTER Provider") |
| 225 | + .expect("OPENROUTER Provider section should exist"); |
| 226 | + |
| 227 | + assert!(!openrouter_section.fields.is_empty()); |
| 228 | + let _api_key_field = openrouter_section |
| 229 | + .fields |
| 230 | + .iter() |
| 231 | + .find(|f| f.label.contains("API Key")) |
| 232 | + .expect("API Key field should exist"); |
| 233 | + |
| 234 | + println!("✅ OPENROUTER provider has API key configuration field"); |
| 235 | + |
| 236 | + // Test API key masking functionality |
| 237 | + let test_key = "sk-or-v1-1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef00e"; |
| 238 | + let masked = agentic::settings::mask_api_key(test_key); |
| 239 | + assert!(masked.starts_with("sk-or-v1-")); |
| 240 | + assert!(masked.ends_with("00e")); |
| 241 | + assert!(masked.contains("***")); |
| 242 | + println!("✅ API key masking works correctly"); |
| 243 | + |
| 244 | + println!("\n🎉 All provider configuration components verified!"); |
| 245 | + |
| 246 | + Ok(()) |
| 247 | +} |
0 commit comments