2025-10-07 10:32:04 +01:00

416 lines
12 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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)"
}
}