//! Rhai integration tests for SAL Kubernetes //! //! These tests verify that the Rhai wrappers work correctly and can execute //! the Rhai test scripts in the tests/rhai/ directory. #[cfg(feature = "rhai")] mod rhai_tests { use rhai::Engine; use sal_kubernetes::rhai::*; use std::fs; use std::path::Path; /// Check if Kubernetes integration tests should run fn should_run_k8s_tests() -> bool { std::env::var("KUBERNETES_TEST_ENABLED").unwrap_or_default() == "1" } #[test] fn test_register_kubernetes_module() { let mut engine = Engine::new(); let result = register_kubernetes_module(&mut engine); assert!( result.is_ok(), "Failed to register Kubernetes module: {:?}", result ); } #[test] fn test_kubernetes_functions_registered() { let mut engine = Engine::new(); register_kubernetes_module(&mut engine).unwrap(); // Test that the constructor function is registered let script = r#" let result = ""; try { let km = kubernetes_manager_new("test"); result = "constructor_exists"; } catch(e) { result = "constructor_exists_but_failed"; } result "#; let result = engine.eval::(script); assert!(result.is_ok()); let result_value = result.unwrap(); assert!( result_value == "constructor_exists" || result_value == "constructor_exists_but_failed", "Expected constructor to be registered, got: {}", result_value ); } #[test] fn test_rhai_function_signatures() { let mut engine = Engine::new(); register_kubernetes_module(&mut engine).unwrap(); // Test that the new object-oriented API methods work correctly // These will fail without a cluster, but should not fail due to missing methods let test_scripts = vec![ // List methods (still function-based for listing) ("pods_list", "let km = kubernetes_manager_new(\"test\"); km.pods_list();"), ("services_list", "let km = kubernetes_manager_new(\"test\"); km.services_list();"), ("deployments_list", "let km = kubernetes_manager_new(\"test\"); km.deployments_list();"), ("namespaces_list", "let km = kubernetes_manager_new(\"test\"); km.namespaces_list();"), ("resource_counts", "let km = kubernetes_manager_new(\"test\"); km.resource_counts();"), // Create methods (object-oriented) ("create_namespace", "let km = kubernetes_manager_new(\"test\"); km.create_namespace(\"test-ns\");"), ("create_pod", "let km = kubernetes_manager_new(\"test\"); km.create_pod(\"test-pod\", \"nginx\", #{});"), ("create_service", "let km = kubernetes_manager_new(\"test\"); km.create_service(\"test-svc\", #{}, 80, 80);"), // Get methods (object-oriented) ("get_pod", "let km = kubernetes_manager_new(\"test\"); km.get_pod(\"test-pod\");"), ("get_service", "let km = kubernetes_manager_new(\"test\"); km.get_service(\"test-svc\");"), // Delete methods (object-oriented) ("delete_pod", "let km = kubernetes_manager_new(\"test\"); km.delete_pod(\"test-pod\");"), ("delete_service", "let km = kubernetes_manager_new(\"test\"); km.delete_service(\"test-service\");"), ("delete_deployment", "let km = kubernetes_manager_new(\"test\"); km.delete_deployment(\"test-deployment\");"), ("delete_namespace", "let km = kubernetes_manager_new(\"test\"); km.delete_namespace(\"test-ns\");"), // Utility methods ("namespace_exists", "let km = kubernetes_manager_new(\"test\"); km.namespace_exists(\"test-ns\");"), ("namespace", "let km = kubernetes_manager_new(\"test\"); namespace(km);"), ("delete_pattern", "let km = kubernetes_manager_new(\"test\"); km.delete(\"test-.*\");"), ]; for (function_name, script) in test_scripts { println!("Testing function: {}", function_name); let result = engine.eval::(script); // The function should be registered (not get a "function not found" error) // It may fail due to no Kubernetes cluster, but that's expected match result { Ok(_) => { println!("Function {} executed successfully", function_name); } Err(e) => { let error_msg = e.to_string(); // Should not be a "function not found" error assert!( !error_msg.contains("Function not found") && !error_msg.contains("Unknown function"), "Function {} not registered: {}", function_name, error_msg ); println!( "Function {} failed as expected (no cluster): {}", function_name, error_msg ); } } } } #[tokio::test] async fn test_rhai_with_real_cluster() { if !should_run_k8s_tests() { println!("Skipping Rhai Kubernetes integration tests. Set KUBERNETES_TEST_ENABLED=1 to enable."); return; } let mut engine = Engine::new(); register_kubernetes_module(&mut engine).unwrap(); // Test basic functionality with a real cluster let script = r#" let km = kubernetes_manager_new("default"); let ns = namespace(km); ns "#; let result = engine.eval::(script); match result { Ok(namespace) => { assert_eq!(namespace, "default"); println!("Successfully got namespace from Rhai: {}", namespace); } Err(e) => { println!("Failed to execute Rhai script with real cluster: {}", e); // Don't fail the test if we can't connect to cluster } } } #[tokio::test] async fn test_rhai_pods_list() { if !should_run_k8s_tests() { return; } let mut engine = Engine::new(); register_kubernetes_module(&mut engine).unwrap(); let script = r#" let km = kubernetes_manager_new("default"); let pods = pods_list(km); pods.len() "#; let result = engine.eval::(script); match result { Ok(count) => { assert!(count >= 0); println!("Successfully listed {} pods from Rhai", count); } Err(e) => { println!("Failed to list pods from Rhai: {}", e); // Don't fail the test if we can't connect to cluster } } } #[tokio::test] async fn test_rhai_resource_counts() { if !should_run_k8s_tests() { return; } let mut engine = Engine::new(); register_kubernetes_module(&mut engine).unwrap(); let script = r#" let km = kubernetes_manager_new("default"); let counts = resource_counts(km); counts "#; let result = engine.eval::(script); match result { Ok(counts) => { println!("Successfully got resource counts from Rhai: {:?}", counts); // Verify expected keys are present assert!(counts.contains_key("pods")); assert!(counts.contains_key("services")); assert!(counts.contains_key("deployments")); } Err(e) => { println!("Failed to get resource counts from Rhai: {}", e); // Don't fail the test if we can't connect to cluster } } } #[tokio::test] async fn test_rhai_namespace_operations() { if !should_run_k8s_tests() { return; } let mut engine = Engine::new(); register_kubernetes_module(&mut engine).unwrap(); // Test namespace existence check let script = r#" let km = kubernetes_manager_new("default"); let exists = namespace_exists(km, "default"); exists "#; let result = engine.eval::(script); match result { Ok(exists) => { assert!(exists, "Default namespace should exist"); println!( "Successfully checked namespace existence from Rhai: {}", exists ); } Err(e) => { println!("Failed to check namespace existence from Rhai: {}", e); // Don't fail the test if we can't connect to cluster } } } #[test] fn test_rhai_error_handling() { let mut engine = Engine::new(); register_kubernetes_module(&mut engine).unwrap(); // Test that errors are properly converted to Rhai errors let script = r#" let km = kubernetes_manager_new("invalid-namespace-name-that-should-fail"); pods_list(km) "#; let result = engine.eval::(script); assert!(result.is_err(), "Expected error for invalid configuration"); if let Err(e) = result { let error_msg = e.to_string(); println!("Got expected error: {}", error_msg); assert!(error_msg.contains("Kubernetes error") || error_msg.contains("error")); } } #[test] fn test_rhai_script_files_exist() { // Test that our Rhai test files exist and are readable let test_files = [ "tests/rhai/basic_kubernetes.rhai", "tests/rhai/namespace_operations.rhai", "tests/rhai/resource_management.rhai", "tests/rhai/run_all_tests.rhai", ]; for test_file in test_files { let path = Path::new(test_file); assert!(path.exists(), "Rhai test file should exist: {}", test_file); // Try to read the file to ensure it's valid let content = fs::read_to_string(path) .unwrap_or_else(|e| panic!("Failed to read {}: {}", test_file, e)); assert!( !content.is_empty(), "Rhai test file should not be empty: {}", test_file ); assert!( content.contains("print("), "Rhai test file should contain print statements: {}", test_file ); } } #[test] fn test_basic_rhai_script_syntax() { // Test that we can at least parse our basic Rhai script let mut engine = Engine::new(); register_kubernetes_module(&mut engine).unwrap(); // Simple script that should parse without errors let script = r#" print("Testing Kubernetes Rhai integration"); let functions = ["kubernetes_manager_new", "pods_list", "namespace"]; for func in functions { print("Function: " + func); } print("Basic syntax test completed"); "#; let result = engine.eval::<()>(script); assert!( result.is_ok(), "Basic Rhai script should parse and execute: {:?}", result ); } #[tokio::test] async fn test_rhai_script_execution_with_cluster() { if !should_run_k8s_tests() { println!( "Skipping Rhai script execution test. Set KUBERNETES_TEST_ENABLED=1 to enable." ); return; } let mut engine = Engine::new(); register_kubernetes_module(&mut engine).unwrap(); // Try to execute a simple script that creates a manager let script = r#" let km = kubernetes_manager_new("default"); let ns = namespace(km); print("Created manager for namespace: " + ns); ns "#; let result = engine.eval::(script); match result { Ok(namespace) => { assert_eq!(namespace, "default"); println!("Successfully executed Rhai script with cluster"); } Err(e) => { println!( "Rhai script execution failed (expected if no cluster): {}", e ); // Don't fail the test if we can't connect to cluster } } } }