- 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.
294 lines
9.0 KiB
Rust
294 lines
9.0 KiB
Rust
//! 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<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://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;
|
|
}
|