//! Edge case and error scenario tests for Kubernetes module //! //! These tests verify proper error handling and edge case behavior. use sal_kubernetes::KubernetesManager; use std::collections::HashMap; /// Check if Kubernetes integration tests should run fn should_run_k8s_tests() -> bool { std::env::var("KUBERNETES_TEST_ENABLED").unwrap_or_default() == "1" } #[tokio::test] async fn test_deployment_with_invalid_image() { if !should_run_k8s_tests() { println!("Skipping Kubernetes integration tests. Set KUBERNETES_TEST_ENABLED=1 to enable."); return; } let km = match KubernetesManager::new("default").await { Ok(km) => km, Err(_) => return, }; // Clean up any existing test deployment let _ = km.deployment_delete("test-invalid-image").await; // Try to create deployment with invalid image name let result = km .deployment_create( "test-invalid-image", "invalid/image/name/that/does/not/exist:latest", 1, None, None, ) .await; // The deployment creation should succeed (Kubernetes validates images at runtime) assert!(result.is_ok(), "Deployment creation should succeed even with invalid image"); // Clean up let _ = km.deployment_delete("test-invalid-image").await; } #[tokio::test] async fn test_deployment_with_empty_name() { if !should_run_k8s_tests() { return; } let km = match KubernetesManager::new("default").await { Ok(km) => km, Err(_) => return, }; // Try to create deployment with empty name let result = km .deployment_create("", "nginx:latest", 1, None, None) .await; // Should fail due to invalid name assert!(result.is_err(), "Deployment with empty name should fail"); } #[tokio::test] async fn test_deployment_with_invalid_replicas() { if !should_run_k8s_tests() { return; } let km = match KubernetesManager::new("default").await { Ok(km) => km, Err(_) => return, }; // Clean up any existing test deployment let _ = km.deployment_delete("test-invalid-replicas").await; // Try to create deployment with negative replicas let result = km .deployment_create("test-invalid-replicas", "nginx:latest", -1, None, None) .await; // Should fail due to invalid replica count assert!(result.is_err(), "Deployment with negative replicas should fail"); } #[tokio::test] async fn test_deployment_with_large_env_vars() { if !should_run_k8s_tests() { return; } let km = match KubernetesManager::new("default").await { Ok(km) => km, Err(_) => return, }; // Clean up any existing test deployment let _ = km.deployment_delete("test-large-env").await; // Create deployment with many environment variables let mut env_vars = HashMap::new(); for i in 0..50 { env_vars.insert(format!("TEST_VAR_{}", i), format!("value_{}", i)); } let result = km .deployment_create("test-large-env", "nginx:latest", 1, None, Some(env_vars)) .await; assert!(result.is_ok(), "Deployment with many env vars should succeed: {:?}", result); // Verify the deployment was created let deployment = km.deployment_get("test-large-env").await; assert!(deployment.is_ok(), "Should be able to get deployment with many env vars"); // Verify environment variables count let deployment = deployment.unwrap(); if let Some(spec) = &deployment.spec { if let Some(template) = &spec.template.spec { if let Some(container) = template.containers.first() { if let Some(env) = &container.env { assert_eq!(env.len(), 50, "Should have 50 environment variables"); } } } } // Clean up let _ = km.deployment_delete("test-large-env").await; } #[tokio::test] async fn test_deployment_with_special_characters_in_env_vars() { if !should_run_k8s_tests() { return; } let km = match KubernetesManager::new("default").await { Ok(km) => km, Err(_) => return, }; // Clean up any existing test deployment let _ = km.deployment_delete("test-special-env").await; // Create deployment with special characters in environment variables let mut env_vars = HashMap::new(); env_vars.insert("DATABASE_URL".to_string(), "postgres://user:pass@host:5432/db?ssl=true".to_string()); env_vars.insert("JSON_CONFIG".to_string(), r#"{"key": "value", "number": 123}"#.to_string()); env_vars.insert("MULTILINE_VAR".to_string(), "line1\nline2\nline3".to_string()); env_vars.insert("SPECIAL_CHARS".to_string(), "!@#$%^&*()_+-=[]{}|;:,.<>?".to_string()); let result = km .deployment_create("test-special-env", "nginx:latest", 1, None, Some(env_vars)) .await; assert!(result.is_ok(), "Deployment with special chars in env vars should succeed: {:?}", result); // Verify the deployment was created and env vars are preserved let deployment = km.deployment_get("test-special-env").await; assert!(deployment.is_ok(), "Should be able to get deployment"); let deployment = deployment.unwrap(); if let Some(spec) = &deployment.spec { if let Some(template) = &spec.template.spec { if let Some(container) = template.containers.first() { if let Some(env) = &container.env { let env_map: HashMap = env .iter() .filter_map(|e| e.value.as_ref().map(|v| (e.name.clone(), v.clone()))) .collect(); assert_eq!( env_map.get("DATABASE_URL"), Some(&"postgres://user:pass@host:5432/db?ssl=true".to_string()) ); assert_eq!( env_map.get("JSON_CONFIG"), Some(&r#"{"key": "value", "number": 123}"#.to_string()) ); assert_eq!( env_map.get("SPECIAL_CHARS"), Some(&"!@#$%^&*()_+-=[]{}|;:,.<>?".to_string()) ); } } } } // Clean up let _ = km.deployment_delete("test-special-env").await; } #[tokio::test] async fn test_deploy_application_with_invalid_port() { if !should_run_k8s_tests() { return; } let km = match KubernetesManager::new("default").await { Ok(km) => km, Err(_) => return, }; // Try to deploy application with invalid port (negative) let result = km .deploy_application("test-invalid-port", "nginx:latest", 1, -80, None, None) .await; // Should fail due to invalid port assert!(result.is_err(), "Deploy application with negative port should fail"); // Try with port 0 let result = km .deploy_application("test-zero-port", "nginx:latest", 1, 0, None, None) .await; // Should fail due to invalid port assert!(result.is_err(), "Deploy application with port 0 should fail"); } #[tokio::test] async fn test_get_nonexistent_deployment() { if !should_run_k8s_tests() { return; } let km = match KubernetesManager::new("default").await { Ok(km) => km, Err(_) => return, }; // Try to get a deployment that doesn't exist let result = km.deployment_get("nonexistent-deployment-12345").await; // Should fail with appropriate error assert!(result.is_err(), "Getting nonexistent deployment should fail"); } #[tokio::test] async fn test_delete_nonexistent_deployment() { if !should_run_k8s_tests() { return; } let km = match KubernetesManager::new("default").await { Ok(km) => km, Err(_) => return, }; // Try to delete a deployment that doesn't exist let result = km.deployment_delete("nonexistent-deployment-12345").await; // Should fail gracefully assert!(result.is_err(), "Deleting nonexistent deployment should fail"); } #[tokio::test] async fn test_deployment_with_zero_replicas() { if !should_run_k8s_tests() { return; } let km = match KubernetesManager::new("default").await { Ok(km) => km, Err(_) => return, }; // Clean up any existing test deployment let _ = km.deployment_delete("test-zero-replicas").await; // Create deployment with zero replicas (should be valid) let result = km .deployment_create("test-zero-replicas", "nginx:latest", 0, None, None) .await; assert!(result.is_ok(), "Deployment with zero replicas should succeed: {:?}", result); // Verify the deployment was created with 0 replicas let deployment = km.deployment_get("test-zero-replicas").await; assert!(deployment.is_ok(), "Should be able to get deployment with zero replicas"); let deployment = deployment.unwrap(); if let Some(spec) = &deployment.spec { assert_eq!(spec.replicas, Some(0), "Should have 0 replicas"); } // Clean up let _ = km.deployment_delete("test-zero-replicas").await; }