416 lines
12 KiB
Plaintext
Raw Normal View History

2025-10-07 10:32:04 +01:00
# 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)"
}
}