# Taskserv Testing Framework # Provides sandbox testing capabilities for taskservs use lib_provisioning * use utils.nu * use validate.nu * use deps_validator.nu * use ../lib_provisioning/config/accessor.nu * # Test taskserv in local container sandbox export def "main test" [ taskserv_name: string --infra (-i): string --settings (-s): string --runtime: string = "docker" # docker, podman, or native --verbose (-v) --keep # Keep container after test --out: string ]: nothing -> nothing { if ($out | is-not-empty) { set-provisioning-out $out set-provisioning-no-terminal true } # Load settings let curr_settings = try { find_get_settings --infra $infra --settings $settings } catch { _print $"🛑 Failed to load settings" return } _print $"\n(_ansi cyan_bold)Taskserv Sandbox Testing(_ansi reset)" _print $"Taskserv: (_ansi yellow_bold)($taskserv_name)(_ansi reset)" _print $"Runtime: ($runtime)\n" # Check runtime availability let runtime_check = (check-runtime $runtime) if not $runtime_check.available { _print $"🛑 Runtime ($runtime) not available: ($runtime_check.error)" return } if $verbose { _print $"(_ansi green)✓ Runtime ($runtime) available(_ansi reset)" } # Run validation first _print $"\n(_ansi yellow)→ Running pre-test validation...(_ansi reset)" let validation = (validate-dependencies $taskserv_name $curr_settings --verbose=$verbose) if not $validation.valid { _print $"(_ansi red)✗ Validation failed, cannot proceed with testing(_ansi reset)" print-validation-report $validation return } if $verbose { _print $"(_ansi green)✓ Validation passed(_ansi reset)" } # Prepare sandbox environment _print $"\n(_ansi yellow)→ Preparing sandbox environment...(_ansi reset)" let sandbox = (prepare-sandbox $taskserv_name $runtime $verbose) if not $sandbox.success { _print $"🛑 Failed to prepare sandbox: ($sandbox.error)" return } _print $"(_ansi green)✓ Sandbox prepared: ($sandbox.container_id)(_ansi reset)" # Run tests in sandbox _print $"\n(_ansi yellow)→ Running tests in sandbox...(_ansi reset)" let test_result = (run-sandbox-tests $taskserv_name $sandbox $curr_settings $verbose) # Cleanup if requested if not $keep { _print $"\n(_ansi yellow)→ Cleaning up sandbox...(_ansi reset)" cleanup-sandbox $sandbox $runtime } else { _print $"\n(_ansi blue)ℹ Sandbox container kept: ($sandbox.container_id)(_ansi reset)" _print $" Connect with: ($runtime) exec -it ($sandbox.container_id) bash" } # Print summary print-test-summary $test_result } # Check if runtime is available def check-runtime [ runtime: string ]: nothing -> record { match $runtime { "docker" => { let available = (which docker | length) > 0 if $available { let running = try { ^docker ps | complete | get exit_code } catch { 1 } if $running == 0 { { available: true, error: "" } } else { { available: false, error: "Docker daemon not running" } } } else { { available: false, error: "Docker not installed" } } } "podman" => { let available = (which podman | length) > 0 if $available { { available: true, error: "" } } else { { available: false, error: "Podman not installed" } } } "native" => { { available: true, error: "" } } _ => { { available: false, error: $"Unknown runtime: ($runtime)" } } } } # Prepare sandbox environment def prepare-sandbox [ taskserv_name: string runtime: string verbose: bool ]: nothing -> record { if $runtime == "native" { return { success: true container_id: "native" runtime: "native" error: "" } } # Select appropriate base image based on taskserv requirements let base_image = "ubuntu:22.04" # Default, could be made configurable if $verbose { _print $" Using base image: ($base_image)" } # Create container let container_result = try { match $runtime { "docker" => { ^docker run -d --rm --name $"taskserv-test-($taskserv_name)" $base_image sleep 3600 | complete } "podman" => { ^podman run -d --rm --name $"taskserv-test-($taskserv_name)" $base_image sleep 3600 | complete } } } catch { return { success: false container_id: "" runtime: $runtime error: $"Failed to create container: ($in)" } } if $container_result.exit_code != 0 { return { success: false container_id: "" runtime: $runtime error: $"Container creation failed: ($container_result.stderr)" } } let container_id = ($container_result.stdout | str trim) return { success: true container_id: $container_id runtime: $runtime base_image: $base_image error: "" } } # Run tests in sandbox def run-sandbox-tests [ taskserv_name: string sandbox: record settings: record verbose: bool ]: nothing -> record { mut test_results = [] # Test 1: Check if required packages can be installed _print $" Test 1: Package prerequisites..." let pkg_test = (test-package-prerequisites $taskserv_name $sandbox $verbose) $test_results = ($test_results | append $pkg_test) # Test 2: Check if configuration files are valid _print $" Test 2: Configuration validity..." let config_test = (test-configuration-validity $taskserv_name $sandbox $verbose) $test_results = ($test_results | append $config_test) # Test 3: Check if scripts can be executed _print $" Test 3: Script execution..." let script_test = (test-script-execution $taskserv_name $sandbox $verbose) $test_results = ($test_results | append $script_test) # Test 4: Health check simulation (if available) _print $" Test 4: Health check simulation..." let health_test = (test-health-check $taskserv_name $sandbox $settings $verbose) $test_results = ($test_results | append $health_test) let total_passed = ($test_results | where status == "passed" | length) let total_failed = ($test_results | where status == "failed" | length) let total_skipped = ($test_results | where status == "skipped" | length) return { taskserv: $taskserv_name tests: $test_results summary: { total: ($test_results | length) passed: $total_passed failed: $total_failed skipped: $total_skipped } overall_passed: ($total_failed == 0) } } # Test package prerequisites def test-package-prerequisites [ taskserv_name: string sandbox: record verbose: bool ]: nothing -> record { if $sandbox.runtime == "native" { return { test: "Package prerequisites" status: "skipped" message: "Skipped in native mode" } } # This is a simplified test - would need expansion let result = try { match $sandbox.runtime { "docker" => { ^docker exec $sandbox.container_id apt-get update | complete } "podman" => { ^podman exec $sandbox.container_id apt-get update | complete } } } catch { return { test: "Package prerequisites" status: "failed" message: $"Failed to update package list: ($in)" } } if $result.exit_code == 0 { { test: "Package prerequisites" status: "passed" message: "Package manager accessible" } } else { { test: "Package prerequisites" status: "failed" message: $"Package update failed: ($result.stderr)" } } } # Test configuration validity def test-configuration-validity [ taskserv_name: string sandbox: record verbose: bool ]: nothing -> record { # Run KCL validation let kcl_result = (validate-kcl-schemas $taskserv_name --verbose=false) if $kcl_result.valid { { test: "Configuration validity" status: "passed" message: $"($kcl_result.files_checked) configuration files validated" } } else { { test: "Configuration validity" status: "failed" message: $"KCL validation failed: (($kcl_result.errors | str join ', '))" } } } # Test script execution def test-script-execution [ taskserv_name: string sandbox: record verbose: bool ]: nothing -> record { # Run script validation let script_result = (validate-scripts $taskserv_name --verbose=false) if $script_result.valid { { test: "Script execution" status: "passed" message: $"($script_result.files_checked) scripts validated" } } else { { test: "Script execution" status: "failed" message: $"Script validation failed: (($script_result.errors | str join ', '))" } } } # Test health check def test-health-check [ taskserv_name: string sandbox: record settings: record verbose: bool ]: nothing -> record { let health_validation = (validate-health-check $taskserv_name $settings --verbose=false) if not $health_validation.has_health_check { return { test: "Health check" status: "skipped" message: "No health check defined" } } if $health_validation.valid { { test: "Health check" status: "passed" message: $"Health check configuration valid: ($health_validation.endpoint)" } } else { { test: "Health check" status: "failed" message: $"Health check validation failed: (($health_validation.errors | str join ', '))" } } } # Cleanup sandbox def cleanup-sandbox [ sandbox: record runtime: string ]: nothing -> nothing { if $sandbox.runtime == "native" { return } try { match $runtime { "docker" => { ^docker stop $sandbox.container_id } "podman" => { ^podman stop $sandbox.container_id } } _print $"(_ansi green)✓ Sandbox cleaned up(_ansi reset)" } catch { _print $"(_ansi yellow)⚠ Warning: Failed to cleanup sandbox: ($in)(_ansi reset)" } } # Print test summary def print-test-summary [ results: record ]: nothing -> nothing { _print $"\n(_ansi cyan_bold)Test Summary(_ansi reset)" _print $"Total tests: ($results.summary.total)" _print $"(_ansi green)Passed: ($results.summary.passed)(_ansi reset)" _print $"(_ansi red)Failed: ($results.summary.failed)(_ansi reset)" _print $"(_ansi yellow)Skipped: ($results.summary.skipped)(_ansi reset)" _print $"\n(_ansi cyan)Detailed Results:(_ansi reset)" for test in $results.tests { let icon = match $test.status { "passed" => $"(_ansi green)✓(_ansi reset)" "failed" => $"(_ansi red)✗(_ansi reset)" "skipped" => $"(_ansi yellow)⊘(_ansi reset)" _ => "•" } _print $" ($icon) ($test.test): ($test.message)" } if $results.overall_passed { _print $"\n(_ansi green_bold)✓ All tests passed(_ansi reset)" } else { _print $"\n(_ansi red_bold)✗ Some tests failed(_ansi reset)" } }