- Add Kubernetes examples demonstrating deployment of various applications (PostgreSQL, Redis, generic). This improves the documentation and provides practical usage examples. - Add `tokio` dependency for async examples. This enables the use of asynchronous operations in the examples. - Add `once_cell` dependency for improved resource management in Kubernetes module. This allows efficient management of singletons and other resources.
385 lines
12 KiB
Rust
385 lines
12 KiB
Rust
//! 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<String, String> = 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<String> = 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<String, String> = 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;
|
|
}
|