mirror of
https://github.com/rubenhensen/k8scd.git
synced 2026-09-18 18:42:56 +02:00
Add nix-infra-machine
This commit is contained in:
@@ -0,0 +1,480 @@
|
||||
#!/usr/bin/env bash
|
||||
# Assertion library for nix-infra-machine tests
|
||||
# Provides reusable assertion functions with consistent output formatting
|
||||
#
|
||||
# All assertions follow this pattern:
|
||||
# assert_* "label" [args...]
|
||||
# Returns 0 on pass, 1 on fail
|
||||
# Prints colored pass/fail message
|
||||
#
|
||||
# Requires: Colors (GREEN, RED, YELLOW, NC) from shared.sh
|
||||
# Requires: cmd, cmd_value, cmd_clean functions from shared.sh
|
||||
|
||||
# ============================================================================
|
||||
# Service Assertions
|
||||
# ============================================================================
|
||||
|
||||
# Check if a systemd service is active
|
||||
# Usage: assert_service_active "$node" "service-name" ["optional label"]
|
||||
assert_service_active() {
|
||||
local node="$1"
|
||||
local service="$2"
|
||||
local label="${3:-$service}"
|
||||
|
||||
local status
|
||||
status=$(cmd_value "$node" "systemctl is-active $service")
|
||||
|
||||
if [[ "$status" == "active" ]]; then
|
||||
echo -e " ${GREEN}✓${NC} $label: active [pass]"
|
||||
return 0
|
||||
else
|
||||
echo -e " ${RED}✗${NC} $label: $status [fail]"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if a oneshot service completed successfully
|
||||
# Usage: assert_service_completed "$node" "service-name" ["optional label"]
|
||||
assert_service_completed() {
|
||||
local node="$1"
|
||||
local service="$2"
|
||||
local label="${3:-$service}"
|
||||
|
||||
local status
|
||||
status=$(cmd_value "$node" "systemctl is-active $service 2>/dev/null || echo 'inactive'")
|
||||
|
||||
if [[ "$status" == "inactive" ]]; then
|
||||
local exit_status
|
||||
exit_status=$(cmd_value "$node" "systemctl show -p ExecMainStatus $service | cut -d= -f2")
|
||||
if [[ "$exit_status" == "0" ]]; then
|
||||
echo -e " ${GREEN}✓${NC} $label: completed successfully [pass]"
|
||||
return 0
|
||||
else
|
||||
echo -e " ${RED}✗${NC} $label: failed (exit status: $exit_status) [fail]"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
echo -e " ${GREEN}✓${NC} $label: $status [pass]"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if service SubState is running
|
||||
# Usage: assert_service_running "$node" "service-name" ["optional label"]
|
||||
assert_service_running() {
|
||||
local node="$1"
|
||||
local service="$2"
|
||||
local label="${3:-$service}"
|
||||
|
||||
local state
|
||||
state=$(cmd_value "$node" "systemctl show -p SubState $service --value")
|
||||
|
||||
if [[ "$state" == "running" ]]; then
|
||||
echo -e " ${GREEN}✓${NC} $label: running [pass]"
|
||||
return 0
|
||||
else
|
||||
echo -e " ${RED}✗${NC} $label: $state [fail]"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Process Assertions
|
||||
# ============================================================================
|
||||
|
||||
# Check if a process is running (using pgrep pattern)
|
||||
# Usage: assert_process_running "$node" "pattern" "label"
|
||||
assert_process_running() {
|
||||
local node="$1"
|
||||
local pattern="$2"
|
||||
local label="$3"
|
||||
|
||||
local result
|
||||
result=$(cmd_clean "$node" "pgrep -a $pattern || echo ''")
|
||||
|
||||
if [[ -n "$result" ]]; then
|
||||
echo -e " ${GREEN}✓${NC} $label process running [pass]"
|
||||
return 0
|
||||
else
|
||||
echo -e " ${RED}✗${NC} $label process not running [fail]"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Check process count meets minimum
|
||||
# Usage: assert_process_count "$node" "pattern" "min_count" "label"
|
||||
assert_process_count() {
|
||||
local node="$1"
|
||||
local pattern="$2"
|
||||
local min_count="$3"
|
||||
local label="$4"
|
||||
|
||||
local count
|
||||
count=$(cmd_value "$node" "pgrep -c $pattern || echo 0")
|
||||
|
||||
if [[ "$count" -ge "$min_count" ]]; then
|
||||
echo -e " ${GREEN}✓${NC} $count $label processes running [pass]"
|
||||
return 0
|
||||
else
|
||||
echo -e " ${RED}✗${NC} Expected $min_count $label processes, found $count [fail]"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Port Assertions
|
||||
# ============================================================================
|
||||
|
||||
# Check if a port is listening
|
||||
# Usage: assert_port_listening "$node" "port" ["label"]
|
||||
assert_port_listening() {
|
||||
local node="$1"
|
||||
local port="$2"
|
||||
local label="${3:-Port $port}"
|
||||
|
||||
local result
|
||||
result=$(cmd "$node" "ss -tlnp | grep :$port")
|
||||
|
||||
if [[ "$result" == *":$port"* ]]; then
|
||||
echo -e " ${GREEN}✓${NC} $label is listening [pass]"
|
||||
return 0
|
||||
else
|
||||
echo -e " ${RED}✗${NC} $label is not listening [fail]"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# HTTP Assertions
|
||||
# ============================================================================
|
||||
|
||||
# Check HTTP status code
|
||||
# Usage: assert_http_status "$node" "url" "expected_codes" ["label"]
|
||||
# expected_codes can be space-separated: "200 302 303"
|
||||
assert_http_status() {
|
||||
local node="$1"
|
||||
local url="$2"
|
||||
local expected="$3"
|
||||
local label="${4:-HTTP $url}"
|
||||
|
||||
local code
|
||||
code=$(cmd_value "$node" "curl -s -o /dev/null -w '%{http_code}' '$url' 2>/dev/null || echo '000'")
|
||||
|
||||
for exp in $expected; do
|
||||
if [[ "$code" == "$exp" ]]; then
|
||||
echo -e " ${GREEN}✓${NC} $label: HTTP $code [pass]"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
echo -e " ${RED}✗${NC} $label: HTTP $code (expected: $expected) [fail]"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Check HTTP response contains string
|
||||
# Usage: assert_http_contains "$node" "url" "expected_string" ["label"]
|
||||
assert_http_contains() {
|
||||
local node="$1"
|
||||
local url="$2"
|
||||
local expected="$3"
|
||||
local label="${4:-HTTP $url}"
|
||||
|
||||
local response
|
||||
response=$(cmd_clean "$node" "curl -s '$url' 2>/dev/null")
|
||||
|
||||
if [[ "$response" == *"$expected"* ]]; then
|
||||
echo -e " ${GREEN}✓${NC} $label contains '$expected' [pass]"
|
||||
return 0
|
||||
else
|
||||
echo -e " ${RED}✗${NC} $label missing '$expected' [fail]"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Check HTTP response contains multiple strings (all must match)
|
||||
# Usage: assert_http_contains_all "$node" "url" "string1" "string2" ... ["--label" "label"]
|
||||
assert_http_contains_all() {
|
||||
local node="$1"
|
||||
local url="$2"
|
||||
shift 2
|
||||
|
||||
local label="HTTP $url"
|
||||
local patterns=()
|
||||
|
||||
# Parse arguments - check for --label flag
|
||||
while [[ $# -gt 0 ]]; do
|
||||
if [[ "$1" == "--label" ]]; then
|
||||
label="$2"
|
||||
shift 2
|
||||
else
|
||||
patterns+=("$1")
|
||||
shift
|
||||
fi
|
||||
done
|
||||
|
||||
local response
|
||||
response=$(cmd_clean "$node" "curl -s '$url' 2>/dev/null")
|
||||
|
||||
for pattern in "${patterns[@]}"; do
|
||||
if [[ "$response" != *"$pattern"* ]]; then
|
||||
echo -e " ${RED}✗${NC} $label missing '$pattern' [fail]"
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
|
||||
echo -e " ${GREEN}✓${NC} $label [pass]"
|
||||
return 0
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# String Assertions
|
||||
# ============================================================================
|
||||
|
||||
# Check if value equals expected
|
||||
# Usage: assert_equals "actual" "expected" "label"
|
||||
assert_equals() {
|
||||
local actual="$1"
|
||||
local expected="$2"
|
||||
local label="$3"
|
||||
|
||||
if [[ "$actual" == "$expected" ]]; then
|
||||
echo -e " ${GREEN}✓${NC} $label [pass]"
|
||||
return 0
|
||||
else
|
||||
echo -e " ${RED}✗${NC} $label: got '$actual', expected '$expected' [fail]"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if value contains substring
|
||||
# Usage: assert_contains "haystack" "needle" "label"
|
||||
assert_contains() {
|
||||
local haystack="$1"
|
||||
local needle="$2"
|
||||
local label="$3"
|
||||
|
||||
if [[ "$haystack" == *"$needle"* ]]; then
|
||||
echo -e " ${GREEN}✓${NC} $label [pass]"
|
||||
return 0
|
||||
else
|
||||
echo -e " ${RED}✗${NC} $label: missing '$needle' [fail]"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if value contains all substrings
|
||||
# Usage: assert_contains_all "haystack" "label" "needle1" "needle2" ...
|
||||
assert_contains_all() {
|
||||
local haystack="$1"
|
||||
local label="$2"
|
||||
shift 2
|
||||
|
||||
for needle in "$@"; do
|
||||
if [[ "$haystack" != *"$needle"* ]]; then
|
||||
echo -e " ${RED}✗${NC} $label: missing '$needle' [fail]"
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
|
||||
echo -e " ${GREEN}✓${NC} $label [pass]"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Check if value is not empty
|
||||
# Usage: assert_not_empty "value" "label"
|
||||
assert_not_empty() {
|
||||
local value="$1"
|
||||
local label="$2"
|
||||
|
||||
if [[ -n "$value" ]]; then
|
||||
echo -e " ${GREEN}✓${NC} $label [pass]"
|
||||
return 0
|
||||
else
|
||||
echo -e " ${RED}✗${NC} $label: empty [fail]"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if value is empty or nil (for Redis-style responses)
|
||||
# Usage: assert_empty_or_nil "value" "label"
|
||||
assert_empty_or_nil() {
|
||||
local value="$1"
|
||||
local label="$2"
|
||||
|
||||
if [[ -z "$value" ]] || [[ "$value" == "nil" ]] || [[ "$value" == "(nil)" ]]; then
|
||||
echo -e " ${GREEN}✓${NC} $label [pass]"
|
||||
return 0
|
||||
else
|
||||
echo -e " ${RED}✗${NC} $label: got '$value', expected empty/nil [fail]"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if value does NOT contain error indicators
|
||||
# Usage: assert_no_error "value" "label"
|
||||
assert_no_error() {
|
||||
local value="$1"
|
||||
local label="$2"
|
||||
|
||||
if [[ "$value" != *"ERROR"* ]] && [[ "$value" != *"error"* ]] && [[ "$value" != *"Error"* ]]; then
|
||||
echo -e " ${GREEN}✓${NC} $label [pass]"
|
||||
return 0
|
||||
else
|
||||
echo -e " ${RED}✗${NC} $label: error found [fail]"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# File System Assertions
|
||||
# ============================================================================
|
||||
|
||||
# Check if file exists on remote node
|
||||
# Usage: assert_file_exists "$node" "/path/to/file" ["label"]
|
||||
assert_file_exists() {
|
||||
local node="$1"
|
||||
local path="$2"
|
||||
local label="${3:-File $path}"
|
||||
|
||||
local result
|
||||
result=$(cmd_value "$node" "test -f '$path' && echo 'exists' || echo 'missing'")
|
||||
|
||||
if [[ "$result" == "exists" ]]; then
|
||||
echo -e " ${GREEN}✓${NC} $label exists [pass]"
|
||||
return 0
|
||||
else
|
||||
echo -e " ${RED}✗${NC} $label not found [fail]"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if directory exists on remote node
|
||||
# Usage: assert_dir_exists "$node" "/path/to/dir" ["label"]
|
||||
assert_dir_exists() {
|
||||
local node="$1"
|
||||
local path="$2"
|
||||
local label="${3:-Directory $path}"
|
||||
|
||||
local result
|
||||
result=$(cmd_value "$node" "test -d '$path' && echo 'exists' || echo 'missing'")
|
||||
|
||||
if [[ "$result" == "exists" ]]; then
|
||||
echo -e " ${GREEN}✓${NC} $label exists [pass]"
|
||||
return 0
|
||||
else
|
||||
echo -e " ${RED}✗${NC} $label not found [fail]"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Container Assertions
|
||||
# ============================================================================
|
||||
|
||||
# Check if a podman container is running
|
||||
# Usage: assert_container_running "$node" "container-name" ["label"]
|
||||
assert_container_running() {
|
||||
local node="$1"
|
||||
local container="$2"
|
||||
local label="${3:-Container $container}"
|
||||
|
||||
local status
|
||||
status=$(cmd_clean "$node" "podman ps --filter name=$container --format '{{.Names}} {{.Status}}'")
|
||||
|
||||
if [[ "$status" == *"$container"* ]]; then
|
||||
echo -e " ${GREEN}✓${NC} $label running [pass]"
|
||||
return 0
|
||||
else
|
||||
echo -e " ${RED}✗${NC} $label not running [fail]"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Comparison Assertions
|
||||
# ============================================================================
|
||||
|
||||
# Check if numeric value is greater than or equal to expected
|
||||
# Usage: assert_gte "actual" "expected" "label"
|
||||
assert_gte() {
|
||||
local actual="$1"
|
||||
local expected="$2"
|
||||
local label="$3"
|
||||
|
||||
if [[ "$actual" -ge "$expected" ]]; then
|
||||
echo -e " ${GREEN}✓${NC} $label ($actual >= $expected) [pass]"
|
||||
return 0
|
||||
else
|
||||
echo -e " ${RED}✗${NC} $label: $actual < $expected [fail]"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if numeric value is less than expected (for ordering/timestamps)
|
||||
# Usage: assert_lt "actual" "expected" "label"
|
||||
assert_lt() {
|
||||
local actual="$1"
|
||||
local expected="$2"
|
||||
local label="$3"
|
||||
|
||||
if [[ -n "$actual" ]] && [[ -n "$expected" ]] && [[ "$actual" -lt "$expected" ]]; then
|
||||
echo -e " ${GREEN}✓${NC} $label [pass]"
|
||||
return 0
|
||||
else
|
||||
echo -e " ${YELLOW}!${NC} $label: could not verify [warn]"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Soft Assertions (warnings instead of failures)
|
||||
# ============================================================================
|
||||
|
||||
# Soft assertion that shows warning instead of failure
|
||||
# Usage: assert_warn "condition_result" "label" "warn_message"
|
||||
# condition_result should be "true" or "false"
|
||||
assert_warn() {
|
||||
local condition="$1"
|
||||
local label="$2"
|
||||
local warn_msg="${3:-}"
|
||||
|
||||
if [[ "$condition" == "true" ]]; then
|
||||
echo -e " ${GREEN}✓${NC} $label [pass]"
|
||||
return 0
|
||||
else
|
||||
if [[ -n "$warn_msg" ]]; then
|
||||
echo -e " ${YELLOW}!${NC} $label ($warn_msg) [warn]"
|
||||
else
|
||||
echo -e " ${YELLOW}!${NC} $label [warn]"
|
||||
fi
|
||||
return 0 # Return success for soft assertions
|
||||
fi
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Utility: Show logs on failure
|
||||
# ============================================================================
|
||||
|
||||
# Show service logs (call after a failed assertion)
|
||||
# Usage: show_service_logs "$node" "service-name" [lines]
|
||||
show_service_logs() {
|
||||
local node="$1"
|
||||
local service="$2"
|
||||
local lines="${3:-50}"
|
||||
|
||||
echo ""
|
||||
echo "Service logs for $service:"
|
||||
cmd "$node" "journalctl -n $lines -u $service"
|
||||
}
|
||||
|
||||
# Show container logs (call after a failed assertion)
|
||||
# Usage: show_container_logs "$node" "container-name" [lines]
|
||||
show_container_logs() {
|
||||
local node="$1"
|
||||
local container="$2"
|
||||
local lines="${3:-50}"
|
||||
|
||||
echo ""
|
||||
echo "Container logs for $container:"
|
||||
cmd "$node" "podman logs --tail $lines $container"
|
||||
}
|
||||
Reference in New Issue
Block a user