416 lines
12 KiB
Plaintext
416 lines
12 KiB
Plaintext
# 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)"
|
||
}
|
||
}
|