//! Tests for deployment creation with environment variables //! //! These tests verify the new environment variable functionality in deployments //! and the enhanced deploy_application method. 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_create_with_env_vars() { 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, // Skip if can't connect }; // Clean up any existing test deployment let _ = km.deployment_delete("test-env-deployment").await; // Create deployment with environment variables let mut labels = HashMap::new(); labels.insert("app".to_string(), "test-env-app".to_string()); labels.insert("test".to_string(), "env-vars".to_string()); let mut env_vars = HashMap::new(); env_vars.insert("TEST_VAR_1".to_string(), "value1".to_string()); env_vars.insert("TEST_VAR_2".to_string(), "value2".to_string()); env_vars.insert("NODE_ENV".to_string(), "test".to_string()); let result = km .deployment_create( "test-env-deployment", "nginx:latest", 1, Some(labels), Some(env_vars), ) .await; assert!( result.is_ok(), "Failed to create deployment with env vars: {:?}", result ); // Verify the deployment was created let deployment = km.deployment_get("test-env-deployment").await; assert!(deployment.is_ok(), "Failed to get created deployment"); let deployment = deployment.unwrap(); // Verify environment variables are set in the container spec 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 { // Check that our environment variables are present 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("TEST_VAR_1"), Some(&"value1".to_string())); assert_eq!(env_map.get("TEST_VAR_2"), Some(&"value2".to_string())); assert_eq!(env_map.get("NODE_ENV"), Some(&"test".to_string())); } else { panic!("No environment variables found in container spec"); } } } } // Clean up let _ = km.deployment_delete("test-env-deployment").await; } #[tokio::test] async fn test_pod_create_with_env_vars() { 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, // Skip if can't connect }; // Clean up any existing test pod let _ = km.pod_delete("test-env-pod").await; // Create pod with environment variables let mut env_vars = HashMap::new(); env_vars.insert("NODE_ENV".to_string(), "test".to_string()); env_vars.insert( "DATABASE_URL".to_string(), "postgres://localhost:5432/test".to_string(), ); env_vars.insert("API_KEY".to_string(), "test-api-key-12345".to_string()); let mut labels = HashMap::new(); labels.insert("app".to_string(), "test-env-pod-app".to_string()); labels.insert("test".to_string(), "environment-variables".to_string()); let result = km .pod_create("test-env-pod", "nginx:latest", Some(labels), Some(env_vars)) .await; assert!( result.is_ok(), "Failed to create pod with env vars: {:?}", result ); if let Ok(pod) = result { let pod_name = pod .metadata .name .as_ref() .unwrap_or(&"".to_string()) .clone(); assert_eq!(pod_name, "test-env-pod"); println!("✅ Created pod with environment variables: {}", pod_name); // Verify the pod has the expected environment variables if let Some(spec) = &pod.spec { if let Some(container) = spec.containers.first() { if let Some(env) = &container.env { let env_names: Vec = env.iter().map(|e| e.name.clone()).collect(); assert!(env_names.contains(&"NODE_ENV".to_string())); assert!(env_names.contains(&"DATABASE_URL".to_string())); assert!(env_names.contains(&"API_KEY".to_string())); println!("✅ Pod has expected environment variables"); } } } } // Clean up let _ = km.pod_delete("test-env-pod").await; } #[tokio::test] async fn test_deployment_create_without_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-no-env-deployment").await; // Create deployment without environment variables let mut labels = HashMap::new(); labels.insert("app".to_string(), "test-no-env-app".to_string()); let result = km .deployment_create( "test-no-env-deployment", "nginx:latest", 1, Some(labels), None, // No environment variables ) .await; assert!( result.is_ok(), "Failed to create deployment without env vars: {:?}", result ); // Verify the deployment was created let deployment = km.deployment_get("test-no-env-deployment").await; assert!(deployment.is_ok(), "Failed to get created deployment"); let deployment = deployment.unwrap(); // Verify no environment variables are set if let Some(spec) = &deployment.spec { if let Some(template) = &spec.template.spec { if let Some(container) = template.containers.first() { // Environment variables should be None or empty assert!( container.env.is_none() || container.env.as_ref().unwrap().is_empty(), "Expected no environment variables, but found some" ); } } } // Clean up let _ = km.deployment_delete("test-no-env-deployment").await; } #[tokio::test] async fn test_deploy_application_with_env_vars() { if !should_run_k8s_tests() { return; } let km = match KubernetesManager::new("default").await { Ok(km) => km, Err(_) => return, }; // Clean up any existing resources let _ = km.deployment_delete("test-app-env").await; let _ = km.service_delete("test-app-env").await; // Deploy application with both labels and environment variables let mut labels = HashMap::new(); labels.insert("app".to_string(), "test-app-env".to_string()); labels.insert("tier".to_string(), "backend".to_string()); let mut env_vars = HashMap::new(); env_vars.insert( "DATABASE_URL".to_string(), "postgres://localhost:5432/test".to_string(), ); env_vars.insert("API_KEY".to_string(), "test-api-key".to_string()); env_vars.insert("LOG_LEVEL".to_string(), "debug".to_string()); let result = km .deploy_application( "test-app-env", "nginx:latest", 2, 80, Some(labels), Some(env_vars), ) .await; assert!( result.is_ok(), "Failed to deploy application with env vars: {:?}", result ); // Verify both deployment and service were created let deployment = km.deployment_get("test-app-env").await; assert!(deployment.is_ok(), "Deployment should be created"); let service = km.service_get("test-app-env").await; assert!(service.is_ok(), "Service should be created"); // Verify environment variables in 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://localhost:5432/test".to_string()) ); assert_eq!(env_map.get("API_KEY"), Some(&"test-api-key".to_string())); assert_eq!(env_map.get("LOG_LEVEL"), Some(&"debug".to_string())); } } } } // Clean up let _ = km.deployment_delete("test-app-env").await; let _ = km.service_delete("test-app-env").await; } #[tokio::test] async fn test_deploy_application_cleanup_existing_resources() { if !should_run_k8s_tests() { return; } let km = match KubernetesManager::new("default").await { Ok(km) => km, Err(_) => { println!("Skipping test - no Kubernetes cluster available"); return; } }; let app_name = "test-cleanup-app"; // Clean up any existing resources first to ensure clean state let _ = km.deployment_delete(app_name).await; let _ = km.service_delete(app_name).await; // Wait a moment for cleanup to complete tokio::time::sleep(tokio::time::Duration::from_secs(2)).await; // First deployment let result = km .deploy_application(app_name, "nginx:latest", 1, 80, None, None) .await; if result.is_err() { println!("Skipping test - cluster connection unstable: {:?}", result); return; } // Verify resources exist (with graceful handling) let deployment_exists = km.deployment_get(app_name).await.is_ok(); let service_exists = km.service_get(app_name).await.is_ok(); if !deployment_exists || !service_exists { println!("Skipping test - resources not created properly"); let _ = km.deployment_delete(app_name).await; let _ = km.service_delete(app_name).await; return; } // Second deployment with different configuration (should replace the first) let mut env_vars = HashMap::new(); env_vars.insert("VERSION".to_string(), "2.0".to_string()); let result = km .deploy_application(app_name, "nginx:alpine", 2, 80, None, Some(env_vars)) .await; if result.is_err() { println!( "Skipping verification - second deployment failed: {:?}", result ); let _ = km.deployment_delete(app_name).await; let _ = km.service_delete(app_name).await; return; } // Verify resources still exist (replaced, not duplicated) let deployment = km.deployment_get(app_name).await; if deployment.is_err() { println!("Skipping verification - deployment not found after replacement"); let _ = km.deployment_delete(app_name).await; let _ = km.service_delete(app_name).await; return; } // Verify the new configuration let deployment = deployment.unwrap(); if let Some(spec) = &deployment.spec { assert_eq!(spec.replicas, Some(2), "Replicas should be updated to 2"); if let Some(template) = &spec.template.spec { if let Some(container) = template.containers.first() { assert_eq!( container.image, Some("nginx:alpine".to_string()), "Image should be updated" ); if let Some(env) = &container.env { let has_version = env .iter() .any(|e| e.name == "VERSION" && e.value == Some("2.0".to_string())); assert!(has_version, "Environment variable VERSION should be set"); } } } } // Clean up let _ = km.deployment_delete(app_name).await; let _ = km.service_delete(app_name).await; }