- DAG architecture: `dag show/validate/export` (nulib/main_provisioning/dag.nu),
config loader (lib_provisioning/config/loader/dag.nu), taskserv dag-executor.
Backed by schemas/lib/dag/*.ncl; orchestrator emits NATS events via
WorkspaceComposition::into_workflow. See ADR-020, ADR-021.
- Unified Component Architecture: components/mod.nu, main_provisioning/
{components,workflow,extensions,ontoref-queries}.nu. Full workflow engine with
topological sort and NATS subject emission. Blocks A-H complete (libre-daoshi).
- Commands-registry: nulib/commands-registry.ncl (Nickel source, 314 lines) +
JSON cache at ~/.cache/provisioning/commands-registry.json rebuilt on source
change. cli/provisioning fast-path alias expansion avoids cold Nu startup.
ADDING_COMMANDS.md documents new-command workflow.
- Platform service manager: service-manager.nu (+573), startup.nu (+611),
service-check.nu (+255); autostart/bootstrap/health/target refactored.
- Nushell 0.112.2 migration: removed all try/catch and bash redirections;
external commands prefixed with ^; type signatures enforced. Driven by
scripts/refactor-try-catch{,-simplified}.nu.
- TTY stack: removed shlib/*-tty.sh; replaced by cli/tty-dispatch.sh,
tty-filter.sh, tty-commands.conf.
- New domain modules: images/ (golden image lifecycle), workspace/{state,sync}.nu,
main_provisioning/{bootstrap,cluster-deploy,fip,state}.nu, commands/{state,
build,integrations/auth,utilities/alias}.nu, platform.nu expanded (+874).
- Config loader overhaul: loader/core.nu slimmed (-759), cache/core.nu
refactored (-454), removed legacy loaders/file_loader.nu (-330).
- Thirteen new provisioning-<domain>.nu top-level modules for bash dispatcher.
- Tests: test_workspace_state.nu (+351); updates to test_oci_registry,
test_services.
- README + CHANGELOG updated.
390 lines
11 KiB
Text
390 lines
11 KiB
Text
#!/usr/bin/env nu
|
|
|
|
# Service Management System Tests
|
|
|
|
use ../lib_provisioning/services/mod.nu *
|
|
|
|
# Test service registry loading
|
|
export def test-service-registry-loading [] {
|
|
print "Testing: Service registry loading"
|
|
|
|
# Load and validate registry (no try-catch)
|
|
let result = (do {
|
|
let registry = (load-service-registry)
|
|
|
|
assert ($registry | is-not-empty) "Registry should not be empty"
|
|
assert ("orchestrator" in ($registry | columns)) "Orchestrator should be in registry"
|
|
|
|
print "✅ Service registry loads correctly"
|
|
true
|
|
} | complete)
|
|
|
|
if $result.exit_code == 0 {
|
|
$result.stdout
|
|
} else {
|
|
print "❌ Failed to load service registry"
|
|
false
|
|
}
|
|
}
|
|
|
|
# Test service definition retrieval
|
|
export def test-service-definition [] {
|
|
print "Testing: Service definition retrieval"
|
|
|
|
# Get and validate service definition (no try-catch)
|
|
let result = (do {
|
|
let orchestrator = (get-service-definition "orchestrator")
|
|
|
|
assert ($orchestrator.name == "orchestrator") "Service name should match"
|
|
assert ($orchestrator.type == "platform") "Service type should be platform"
|
|
assert ($orchestrator.deployment.mode == "binary") "Deployment mode should be binary"
|
|
|
|
print "✅ Service definition retrieval works"
|
|
true
|
|
} | complete)
|
|
|
|
if $result.exit_code == 0 {
|
|
$result.stdout
|
|
} else {
|
|
print "❌ Failed to get service definition"
|
|
false
|
|
}
|
|
}
|
|
|
|
# Test dependency resolution
|
|
export def test-dependency-resolution [] {
|
|
print "Testing: Dependency resolution"
|
|
|
|
# Resolve and validate dependencies (no try-catch)
|
|
let result = (do {
|
|
let deps = (resolve-dependencies "control-center")
|
|
|
|
assert ("orchestrator" in $deps) "Should resolve orchestrator dependency"
|
|
|
|
print "✅ Dependency resolution works"
|
|
true
|
|
} | complete)
|
|
|
|
if $result.exit_code == 0 {
|
|
$result.stdout
|
|
} else {
|
|
print "❌ Dependency resolution failed"
|
|
false
|
|
}
|
|
}
|
|
|
|
# Test dependency graph validation
|
|
export def test-dependency-graph [] {
|
|
print "Testing: Dependency graph validation"
|
|
|
|
# Validate dependency graph (no try-catch)
|
|
let result = (do {
|
|
let validation = (validate-dependency-graph)
|
|
|
|
assert ($validation.valid) "Dependency graph should be valid"
|
|
assert (not $validation.has_cycles) "Should not have cycles"
|
|
|
|
print "✅ Dependency graph is valid"
|
|
true
|
|
} | complete)
|
|
|
|
if $result.exit_code == 0 {
|
|
$result.stdout
|
|
} else {
|
|
print "❌ Dependency graph validation failed"
|
|
false
|
|
}
|
|
}
|
|
|
|
# Test startup order calculation
|
|
export def test-startup-order [] {
|
|
print "Testing: Startup order calculation"
|
|
|
|
# Calculate and validate startup order (no try-catch)
|
|
let result = (do {
|
|
let services = ["control-center", "orchestrator"]
|
|
let order = (get-startup-order $services)
|
|
|
|
let orchestrator_idx = ($order | enumerate | where item == "orchestrator" | get index | get 0)
|
|
let control_center_idx = ($order | enumerate | where item == "control-center" | get index | get 0)
|
|
|
|
assert ($orchestrator_idx < $control_center_idx) "Orchestrator should start before control-center"
|
|
|
|
print "✅ Startup order calculation works"
|
|
true
|
|
} | complete)
|
|
|
|
if $result.exit_code == 0 {
|
|
$result.stdout
|
|
} else {
|
|
print "❌ Startup order calculation failed"
|
|
false
|
|
}
|
|
}
|
|
|
|
# Test service prerequisites validation
|
|
export def test-prerequisites-validation [] {
|
|
print "Testing: Prerequisites validation"
|
|
|
|
# Validate prerequisites (no try-catch)
|
|
let result = (do {
|
|
let validation = (validate-service-prerequisites "orchestrator")
|
|
|
|
assert ("valid" in $validation) "Validation should have valid field"
|
|
assert ("can_start" in $validation) "Validation should have can_start field"
|
|
|
|
print "✅ Prerequisites validation works"
|
|
true
|
|
} | complete)
|
|
|
|
if $result.exit_code == 0 {
|
|
$result.stdout
|
|
} else {
|
|
print "❌ Prerequisites validation failed"
|
|
false
|
|
}
|
|
}
|
|
|
|
# Test conflict detection
|
|
export def test-conflict-detection [] {
|
|
print "Testing: Conflict detection"
|
|
|
|
# Check for service conflicts (no try-catch)
|
|
let result = (do {
|
|
let conflicts = (check-service-conflicts "coredns")
|
|
|
|
assert ("has_conflicts" in $conflicts) "Should have has_conflicts field"
|
|
|
|
print "✅ Conflict detection works"
|
|
true
|
|
} | complete)
|
|
|
|
if $result.exit_code == 0 {
|
|
$result.stdout
|
|
} else {
|
|
print "❌ Conflict detection failed"
|
|
false
|
|
}
|
|
}
|
|
|
|
# Test required services check
|
|
export def test-required-services-check [] {
|
|
print "Testing: Required services check"
|
|
|
|
# Check required services (no try-catch)
|
|
let result = (do {
|
|
let check = (check-required-services "server")
|
|
|
|
assert ("required_services" in $check) "Should have required_services field"
|
|
assert ("all_running" in $check) "Should have all_running field"
|
|
assert ("can_auto_start" in $check) "Should have can_auto_start field"
|
|
|
|
assert ("orchestrator" in $check.required_services) "Orchestrator should be required for server ops"
|
|
|
|
print "✅ Required services check works"
|
|
true
|
|
} | complete)
|
|
|
|
if $result.exit_code == 0 {
|
|
$result.stdout
|
|
} else {
|
|
print "❌ Required services check failed"
|
|
false
|
|
}
|
|
}
|
|
|
|
# Test all services validation
|
|
export def test-all-services-validation [] {
|
|
print "Testing: All services validation"
|
|
|
|
# Validate all services (no try-catch)
|
|
let result = (do {
|
|
let validation = (validate-all-services)
|
|
|
|
assert ($validation.total_services > 0) "Should have services"
|
|
assert ("valid_services" in $validation) "Should have valid_services count"
|
|
|
|
print "✅ All services validation works"
|
|
true
|
|
} | complete)
|
|
|
|
if $result.exit_code == 0 {
|
|
$result.stdout
|
|
} else {
|
|
print "❌ All services validation failed"
|
|
false
|
|
}
|
|
}
|
|
|
|
# Test readiness report
|
|
export def test-readiness-report [] {
|
|
print "Testing: Readiness report"
|
|
|
|
# Get and validate readiness report (no try-catch)
|
|
let result = (do {
|
|
let report = (get-readiness-report)
|
|
|
|
assert ($report.total_services > 0) "Should have services"
|
|
assert ("running_services" in $report) "Should have running count"
|
|
assert ("services" in $report) "Should have services list"
|
|
|
|
print "✅ Readiness report works"
|
|
true
|
|
} | complete)
|
|
|
|
if $result.exit_code == 0 {
|
|
$result.stdout
|
|
} else {
|
|
print "❌ Readiness report failed"
|
|
false
|
|
}
|
|
}
|
|
|
|
# Test dependency tree
|
|
export def test-dependency-tree [] {
|
|
print "Testing: Dependency tree generation"
|
|
|
|
# Generate and validate dependency tree (no try-catch)
|
|
let result = (do {
|
|
let tree = (get-dependency-tree "control-center")
|
|
|
|
assert ($tree.service == "control-center") "Root should be control-center"
|
|
assert ("dependencies" in $tree) "Should have dependencies field"
|
|
|
|
print "✅ Dependency tree generation works"
|
|
true
|
|
} | complete)
|
|
|
|
if $result.exit_code == 0 {
|
|
$result.stdout
|
|
} else {
|
|
print "❌ Dependency tree generation failed"
|
|
false
|
|
}
|
|
}
|
|
|
|
# Test reverse dependencies
|
|
export def test-reverse-dependencies [] {
|
|
print "Testing: Reverse dependencies"
|
|
|
|
# Get and validate reverse dependencies (no try-catch)
|
|
let result = (do {
|
|
let reverse_deps = (get-reverse-dependencies "orchestrator")
|
|
|
|
assert ("control-center" in $reverse_deps) "Control-center should depend on orchestrator"
|
|
|
|
print "✅ Reverse dependencies work"
|
|
true
|
|
} | complete)
|
|
|
|
if $result.exit_code == 0 {
|
|
$result.stdout
|
|
} else {
|
|
print "❌ Reverse dependencies failed"
|
|
false
|
|
}
|
|
}
|
|
|
|
# Test can-stop-service
|
|
export def test-can-stop-service [] {
|
|
print "Testing: Can-stop-service check"
|
|
|
|
# Check if service can be stopped (no try-catch)
|
|
let result = (do {
|
|
let can_stop = (can-stop-service "orchestrator")
|
|
|
|
assert ("can_stop" in $can_stop) "Should have can_stop field"
|
|
assert ("dependent_services" in $can_stop) "Should have dependent_services field"
|
|
|
|
print "✅ Can-stop-service check works"
|
|
true
|
|
} | complete)
|
|
|
|
if $result.exit_code == 0 {
|
|
$result.stdout
|
|
} else {
|
|
print "❌ Can-stop-service check failed"
|
|
false
|
|
}
|
|
}
|
|
|
|
# Test service state initialization
|
|
export def test-service-state-init [] {
|
|
print "Testing: Service state initialization"
|
|
|
|
# Initialize and validate service state (no try-catch)
|
|
let result = (do {
|
|
init-service-state
|
|
|
|
let state_dir = $"($env.HOME)/.provisioning/services/state"
|
|
let pid_dir = $"($env.HOME)/.provisioning/services/pids"
|
|
let log_dir = $"($env.HOME)/.provisioning/services/logs"
|
|
|
|
assert ($state_dir | path exists) "State directory should exist"
|
|
assert ($pid_dir | path exists) "PID directory should exist"
|
|
assert ($log_dir | path exists) "Log directory should exist"
|
|
|
|
print "✅ Service state initialization works"
|
|
true
|
|
} | complete)
|
|
|
|
if $result.exit_code == 0 {
|
|
$result.stdout
|
|
} else {
|
|
print "❌ Service state initialization failed"
|
|
false
|
|
}
|
|
}
|
|
|
|
# Run all tests
|
|
export def main [] {
|
|
print "=== Service Management System Tests ===\n"
|
|
|
|
let tests = [
|
|
test-service-registry-loading
|
|
test-service-definition
|
|
test-dependency-resolution
|
|
test-dependency-graph
|
|
test-startup-order
|
|
test-prerequisites-validation
|
|
test-conflict-detection
|
|
test-required-services-check
|
|
test-all-services-validation
|
|
test-readiness-report
|
|
test-dependency-tree
|
|
test-reverse-dependencies
|
|
test-can-stop-service
|
|
test-service-state-init
|
|
]
|
|
|
|
mut passed = 0
|
|
mut failed = 0
|
|
|
|
for test in $tests {
|
|
# Run test with error handling (no try-catch)
|
|
let result = (do { do $test } | complete)
|
|
if $result.exit_code == 0 {
|
|
if ($result.stdout) {
|
|
$passed = $passed + 1
|
|
} else {
|
|
$failed = $failed + 1
|
|
}
|
|
} else {
|
|
print $"❌ Test ($test) threw an error"
|
|
$failed = $failed + 1
|
|
}
|
|
|
|
print ""
|
|
}
|
|
|
|
print $"=== Test Results ==="
|
|
print $"Passed: ($passed)"
|
|
print $"Failed: ($failed)"
|
|
print $"Total: (($tests | length))"
|
|
|
|
if $failed == 0 {
|
|
print "\n✅ All tests passed!"
|
|
} else {
|
|
print $"\n❌ ($failed) tests failed"
|
|
}
|
|
}
|