...
This commit is contained in:
385
packages/system/kubernetes/tests/integration_tests.rs
Normal file
385
packages/system/kubernetes/tests/integration_tests.rs
Normal file
@@ -0,0 +1,385 @@
|
||||
//! Integration tests for SAL Kubernetes
|
||||
//!
|
||||
//! These tests require a running Kubernetes cluster and appropriate credentials.
|
||||
//! Set KUBERNETES_TEST_ENABLED=1 to run these tests.
|
||||
|
||||
use sal_kubernetes::KubernetesManager;
|
||||
|
||||
/// 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_kubernetes_manager_creation() {
|
||||
if !should_run_k8s_tests() {
|
||||
println!("Skipping Kubernetes integration tests. Set KUBERNETES_TEST_ENABLED=1 to enable.");
|
||||
return;
|
||||
}
|
||||
|
||||
let result = KubernetesManager::new("default").await;
|
||||
match result {
|
||||
Ok(_) => println!("Successfully created KubernetesManager"),
|
||||
Err(e) => println!("Failed to create KubernetesManager: {}", e),
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_namespace_operations() {
|
||||
if !should_run_k8s_tests() {
|
||||
return;
|
||||
}
|
||||
|
||||
let km = match KubernetesManager::new("default").await {
|
||||
Ok(km) => km,
|
||||
Err(_) => return, // Skip if can't connect
|
||||
};
|
||||
|
||||
// Test namespace creation (should be idempotent)
|
||||
let test_namespace = "sal-test-namespace";
|
||||
let result = km.namespace_create(test_namespace).await;
|
||||
assert!(result.is_ok(), "Failed to create namespace: {:?}", result);
|
||||
|
||||
// Test creating the same namespace again (should not error)
|
||||
let result = km.namespace_create(test_namespace).await;
|
||||
assert!(
|
||||
result.is_ok(),
|
||||
"Failed to create namespace idempotently: {:?}",
|
||||
result
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_pods_list() {
|
||||
if !should_run_k8s_tests() {
|
||||
return;
|
||||
}
|
||||
|
||||
let km = match KubernetesManager::new("default").await {
|
||||
Ok(km) => km,
|
||||
Err(_) => return, // Skip if can't connect
|
||||
};
|
||||
|
||||
let result = km.pods_list().await;
|
||||
match result {
|
||||
Ok(pods) => {
|
||||
println!("Found {} pods in default namespace", pods.len());
|
||||
|
||||
// Verify pod structure
|
||||
for pod in pods.iter().take(3) {
|
||||
// Check first 3 pods
|
||||
assert!(pod.metadata.name.is_some());
|
||||
assert!(pod.metadata.namespace.is_some());
|
||||
println!(
|
||||
"Pod: {} in namespace: {}",
|
||||
pod.metadata.name.as_ref().unwrap(),
|
||||
pod.metadata.namespace.as_ref().unwrap()
|
||||
);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Failed to list pods: {}", e);
|
||||
// Don't fail the test if we can't list pods due to permissions
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_services_list() {
|
||||
if !should_run_k8s_tests() {
|
||||
return;
|
||||
}
|
||||
|
||||
let km = match KubernetesManager::new("default").await {
|
||||
Ok(km) => km,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
let result = km.services_list().await;
|
||||
match result {
|
||||
Ok(services) => {
|
||||
println!("Found {} services in default namespace", services.len());
|
||||
|
||||
// Verify service structure
|
||||
for service in services.iter().take(3) {
|
||||
assert!(service.metadata.name.is_some());
|
||||
println!("Service: {}", service.metadata.name.as_ref().unwrap());
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Failed to list services: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_deployments_list() {
|
||||
if !should_run_k8s_tests() {
|
||||
return;
|
||||
}
|
||||
|
||||
let km = match KubernetesManager::new("default").await {
|
||||
Ok(km) => km,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
let result = km.deployments_list().await;
|
||||
match result {
|
||||
Ok(deployments) => {
|
||||
println!(
|
||||
"Found {} deployments in default namespace",
|
||||
deployments.len()
|
||||
);
|
||||
|
||||
// Verify deployment structure
|
||||
for deployment in deployments.iter().take(3) {
|
||||
assert!(deployment.metadata.name.is_some());
|
||||
println!("Deployment: {}", deployment.metadata.name.as_ref().unwrap());
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Failed to list deployments: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_resource_counts() {
|
||||
if !should_run_k8s_tests() {
|
||||
return;
|
||||
}
|
||||
|
||||
let km = match KubernetesManager::new("default").await {
|
||||
Ok(km) => km,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
let result = km.resource_counts().await;
|
||||
match result {
|
||||
Ok(counts) => {
|
||||
println!("Resource counts: {:?}", counts);
|
||||
|
||||
// Verify expected resource types are present
|
||||
assert!(counts.contains_key("pods"));
|
||||
assert!(counts.contains_key("services"));
|
||||
assert!(counts.contains_key("deployments"));
|
||||
assert!(counts.contains_key("configmaps"));
|
||||
assert!(counts.contains_key("secrets"));
|
||||
|
||||
// Verify counts are reasonable (counts are usize, so always non-negative)
|
||||
for (resource_type, count) in counts {
|
||||
// Verify we got a count for each resource type
|
||||
println!("Resource type '{}' has {} items", resource_type, count);
|
||||
// Counts should be reasonable (not impossibly large)
|
||||
assert!(
|
||||
count < 10000,
|
||||
"Count for {} seems unreasonably high: {}",
|
||||
resource_type,
|
||||
count
|
||||
);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Failed to get resource counts: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_namespaces_list() {
|
||||
if !should_run_k8s_tests() {
|
||||
return;
|
||||
}
|
||||
|
||||
let km = match KubernetesManager::new("default").await {
|
||||
Ok(km) => km,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
let result = km.namespaces_list().await;
|
||||
match result {
|
||||
Ok(namespaces) => {
|
||||
println!("Found {} namespaces", namespaces.len());
|
||||
|
||||
// Should have at least default namespace
|
||||
let namespace_names: Vec<String> = namespaces
|
||||
.iter()
|
||||
.filter_map(|ns| ns.metadata.name.as_ref())
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
println!("Namespaces: {:?}", namespace_names);
|
||||
assert!(namespace_names.contains(&"default".to_string()));
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Failed to list namespaces: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_pattern_matching_dry_run() {
|
||||
if !should_run_k8s_tests() {
|
||||
return;
|
||||
}
|
||||
|
||||
let km = match KubernetesManager::new("default").await {
|
||||
Ok(km) => km,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
// Test pattern matching without actually deleting anything
|
||||
// We'll just verify that the regex patterns work correctly
|
||||
let test_patterns = vec![
|
||||
"test-.*", // Should match anything starting with "test-"
|
||||
".*-temp$", // Should match anything ending with "-temp"
|
||||
"nonexistent-.*", // Should match nothing (hopefully)
|
||||
];
|
||||
|
||||
for pattern in test_patterns {
|
||||
println!("Testing pattern: {}", pattern);
|
||||
|
||||
// Get all pods first
|
||||
if let Ok(pods) = km.pods_list().await {
|
||||
let regex = regex::Regex::new(pattern).unwrap();
|
||||
let matching_pods: Vec<_> = pods
|
||||
.iter()
|
||||
.filter_map(|pod| pod.metadata.name.as_ref())
|
||||
.filter(|name| regex.is_match(name))
|
||||
.collect();
|
||||
|
||||
println!(
|
||||
"Pattern '{}' would match {} pods: {:?}",
|
||||
pattern,
|
||||
matching_pods.len(),
|
||||
matching_pods
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_namespace_exists_functionality() {
|
||||
if !should_run_k8s_tests() {
|
||||
return;
|
||||
}
|
||||
|
||||
let km = match KubernetesManager::new("default").await {
|
||||
Ok(km) => km,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
// Test that default namespace exists
|
||||
let result = km.namespace_exists("default").await;
|
||||
match result {
|
||||
Ok(exists) => {
|
||||
assert!(exists, "Default namespace should exist");
|
||||
println!("Default namespace exists: {}", exists);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Failed to check if default namespace exists: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Test that a non-existent namespace doesn't exist
|
||||
let result = km.namespace_exists("definitely-does-not-exist-12345").await;
|
||||
match result {
|
||||
Ok(exists) => {
|
||||
assert!(!exists, "Non-existent namespace should not exist");
|
||||
println!("Non-existent namespace exists: {}", exists);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Failed to check if non-existent namespace exists: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_manager_namespace_property() {
|
||||
if !should_run_k8s_tests() {
|
||||
return;
|
||||
}
|
||||
|
||||
let test_namespace = "test-namespace";
|
||||
let km = match KubernetesManager::new(test_namespace).await {
|
||||
Ok(km) => km,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
// Verify the manager knows its namespace
|
||||
assert_eq!(km.namespace(), test_namespace);
|
||||
println!("Manager namespace: {}", km.namespace());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_error_handling() {
|
||||
if !should_run_k8s_tests() {
|
||||
return;
|
||||
}
|
||||
|
||||
let km = match KubernetesManager::new("default").await {
|
||||
Ok(km) => km,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
// Test getting a non-existent pod
|
||||
let result = km.pod_get("definitely-does-not-exist-12345").await;
|
||||
assert!(result.is_err(), "Getting non-existent pod should fail");
|
||||
|
||||
if let Err(e) = result {
|
||||
println!("Expected error for non-existent pod: {}", e);
|
||||
// Verify it's the right kind of error
|
||||
match e {
|
||||
sal_kubernetes::KubernetesError::ApiError(_) => {
|
||||
println!("Correctly got API error for non-existent resource");
|
||||
}
|
||||
_ => {
|
||||
println!("Got unexpected error type: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_configmaps_and_secrets() {
|
||||
if !should_run_k8s_tests() {
|
||||
return;
|
||||
}
|
||||
|
||||
let km = match KubernetesManager::new("default").await {
|
||||
Ok(km) => km,
|
||||
Err(_) => return,
|
||||
};
|
||||
|
||||
// Test configmaps listing
|
||||
let result = km.configmaps_list().await;
|
||||
match result {
|
||||
Ok(configmaps) => {
|
||||
println!("Found {} configmaps in default namespace", configmaps.len());
|
||||
for cm in configmaps.iter().take(3) {
|
||||
if let Some(name) = &cm.metadata.name {
|
||||
println!("ConfigMap: {}", name);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Failed to list configmaps: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Test secrets listing
|
||||
let result = km.secrets_list().await;
|
||||
match result {
|
||||
Ok(secrets) => {
|
||||
println!("Found {} secrets in default namespace", secrets.len());
|
||||
for secret in secrets.iter().take(3) {
|
||||
if let Some(name) = &secret.metadata.name {
|
||||
println!("Secret: {}", name);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Failed to list secrets: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user