// Integration tests for platform-config multi-source schema resolution use std::fs; use std::path::PathBuf; use platform_config::{deployment::load_deployment_mode, ExtensionSchemaCache, PlatformStartup}; use tempfile::TempDir; #[test] fn test_deployment_mode_load() { // This test requires deployment-mode.ncl to exist match load_deployment_mode() { Ok(config) => { assert!( config.config.is_object(), "Deployment config should be a JSON object" ); println!("✓ Deployment mode loaded successfully"); } Err(e) => { eprintln!("ℹ Deployment mode not found (expected in CI): {}", e); } } } #[test] fn test_platform_startup_initialization() { match load_deployment_mode() { Ok(config) => { let startup = PlatformStartup::new(&config.config); assert!( startup.is_ok(), "PlatformStartup initialization should succeed" ); let startup = startup.unwrap(); let enabled = startup.enabled_services(); println!("✓ Enabled services: {:?}", enabled); // Should have at least vault_service and orchestrator assert!( !enabled.is_empty(), "At least one service should be enabled" ); } Err(e) => { eprintln!("ℹ Deployment mode not found (expected in CI): {}", e); } } } #[test] fn test_service_dependencies_validation() { match load_deployment_mode() { Ok(config) => { let startup = PlatformStartup::new(&config.config); assert!(startup.is_ok(), "PlatformStartup should initialize"); let startup = startup.unwrap(); // Validate orchestrator dependencies (should depend on vault_service) let result = startup.validate_dependencies("orchestrator"); // This will pass if vault_service is enabled, or fail if not // Both are valid outcomes depending on deployment config match result { Ok(()) => println!("✓ Orchestrator dependencies validated"), Err(e) => println!("ℹ Orchestrator dependency check: {}", e), } } Err(e) => { eprintln!("ℹ Deployment mode not found (expected in CI): {}", e); } } } #[test] fn test_startup_order_calculation() { match load_deployment_mode() { Ok(config) => { let startup = PlatformStartup::new(&config.config); assert!(startup.is_ok(), "PlatformStartup should initialize"); let startup = startup.unwrap(); let order = startup.get_startup_order(); assert!(order.is_ok(), "Startup order calculation should succeed"); let order = order.unwrap(); println!("✓ Startup order: {:?}", order); // vault_service should come before orchestrator (if both enabled) let vault_idx = order.iter().position(|s| s == "vault_service"); let orch_idx = order.iter().position(|s| s == "orchestrator"); if let (Some(v), Some(o)) = (vault_idx, orch_idx) { assert!(v < o, "vault_service should start before orchestrator"); } } Err(e) => { eprintln!("ℹ Deployment mode not found (expected in CI): {}", e); } } } #[test] fn test_extension_schema_cache_creation() { let temp_dir = TempDir::new().unwrap(); let cache = ExtensionSchemaCache::new(temp_dir.path().to_path_buf()); assert!( cache.is_ok(), "ExtensionSchemaCache should create successfully" ); println!("✓ Extension schema cache created"); } #[test] fn test_extension_discovery_and_import_paths() { let temp_dir = TempDir::new().unwrap(); let cache = ExtensionSchemaCache::new(temp_dir.path().to_path_buf()).unwrap(); // Create mock extension structure let ext_dir = temp_dir.path().join("hetzner@1.0.0"); let schemas_dir = ext_dir.join("schemas"); fs::create_dir_all(&schemas_dir).unwrap(); fs::write(schemas_dir.join("main.ncl"), "{}").unwrap(); // List extensions let extensions = cache.list_cached_extensions().unwrap(); assert_eq!(extensions.len(), 1, "Should find hetzner extension"); assert_eq!(extensions[0].name, "hetzner"); assert_eq!(extensions[0].version, "1.0.0"); // Get import paths let import_paths = cache.build_import_paths().unwrap(); assert_eq!(import_paths.len(), 1, "Should have one import path"); assert!(import_paths[0].exists(), "Import path should exist"); println!("✓ Extension discovery successful"); } #[test] fn test_multiple_extension_versions() { let temp_dir = TempDir::new().unwrap(); let cache = ExtensionSchemaCache::new(temp_dir.path().to_path_buf()).unwrap(); // Create multiple versions of same extension for version in &["1.0.0", "1.1.0", "2.0.0"] { let ext_dir = temp_dir.path().join(format!("aws@{}", version)); let schemas_dir = ext_dir.join("schemas"); fs::create_dir_all(&schemas_dir).unwrap(); fs::write(schemas_dir.join("main.ncl"), "{}").unwrap(); } let extensions = cache.list_cached_extensions().unwrap(); assert_eq!(extensions.len(), 3, "Should find all AWS versions"); // Test exact version matching let path = cache.get_extension_path("aws", Some("1.1.0")); assert!(path.is_some(), "Should find exact version"); assert!(path.unwrap().ends_with("aws@1.1.0/schemas")); // Test latest version (first found) let path = cache.get_extension_path("aws", None); assert!(path.is_some(), "Should find at least one version"); println!("✓ Multiple extension versions handled correctly"); } #[test] fn test_multi_extension_import_paths() { let temp_dir = TempDir::new().unwrap(); let cache = ExtensionSchemaCache::new(temp_dir.path().to_path_buf()).unwrap(); // Create multiple extensions for (name, version) in &[("hetzner", "1.0.0"), ("aws", "2.1.0"), ("upcloud", "1.5.0")] { let ext_dir = temp_dir.path().join(format!("{}@{}", name, version)); let schemas_dir = ext_dir.join("schemas"); fs::create_dir_all(&schemas_dir).unwrap(); fs::write(schemas_dir.join("main.ncl"), "{}").unwrap(); } let extensions = cache.list_cached_extensions().unwrap(); assert_eq!(extensions.len(), 3, "Should find all extensions"); let import_paths = cache.build_import_paths().unwrap(); assert_eq!(import_paths.len(), 3, "Should have three import paths"); // All paths should exist for path in &import_paths { assert!(path.exists(), "Import path should exist: {:?}", path); } println!("✓ Multi-extension import paths: {:?}", import_paths); } #[test] fn test_git_repo_structure_in_startup() { match load_deployment_mode() { Ok(config) => { // Just verify that the git config is present in deployment-mode let git_config = config.config.get("git"); assert!( git_config.is_some(), "Git configuration should be in deployment-mode.ncl" ); let schemas = git_config.unwrap().get("schemas_repo"); let configs = git_config.unwrap().get("configs_repo"); assert!(schemas.is_some(), "schemas_repo should be defined"); assert!(configs.is_some(), "configs_repo should be defined"); // Verify essential fields let schemas = schemas.unwrap(); assert!(schemas.get("url").is_some(), "URL should be defined"); assert!( schemas.get("cache_dir").is_some(), "cache_dir should be defined" ); println!("✓ Git repo structure validated"); } Err(e) => { eprintln!("ℹ Deployment mode not found (expected in CI): {}", e); } } } #[test] fn test_nickel_import_path_priority() { // This test verifies that the NICKEL_IMPORT_PATH priority system works // (actual priority order is tested via functional tests, not unit tests) let home = std::env::var("HOME").unwrap_or_else(|_| "/tmp".to_string()); // Priority 1: Extension schemas let ext_cache = PathBuf::from(format!("{}/.cache/provisioning/extensions", home)); if ext_cache.exists() { println!("✓ Extension cache dir exists: {:?}", ext_cache); } // Priority 2: Git schemas let schemas_cache = PathBuf::from(format!("{}/.cache/provisioning/schemas", home)); if schemas_cache.exists() { println!("✓ Schemas cache dir exists: {:?}", schemas_cache); } // Priority 3: Git configs let configs_cache = PathBuf::from(format!("{}/.cache/provisioning/configs", home)); if configs_cache.exists() { println!("✓ Configs cache dir exists: {:?}", configs_cache); } // Priority 4: Local provisioning/schemas if PathBuf::from("provisioning/schemas").exists() { println!("✓ Local schemas dir exists"); } println!("✓ NICKEL_IMPORT_PATH cache structure verified"); } #[test] fn test_service_enabled_checking() { match load_deployment_mode() { Ok(config) => { let startup = PlatformStartup::new(&config.config); assert!(startup.is_ok()); let startup = startup.unwrap(); // Core services should be checkable for service in &["orchestrator", "vault_service"] { let enabled = startup.is_service_enabled(service); println!( " • {}: {}", service, if enabled { "enabled" } else { "disabled" } ); } println!("✓ Service enablement checking works"); } Err(e) => { eprintln!("ℹ Deployment mode not found (expected in CI): {}", e); } } }