From 3128ab43b369df03d19c96c597863ea15d855ef9 Mon Sep 17 00:00:00 2001 From: ZGaetano Date: Wed, 20 May 2026 13:49:35 -0400 Subject: [PATCH] =?UTF-8?q?feat(deploy):=20test-api.sh=20=E2=80=94=20API?= =?UTF-8?q?=20smoke=20test=20covering=20all=20major=20endpoints?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deploy/test-api.sh | 170 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 deploy/test-api.sh diff --git a/deploy/test-api.sh b/deploy/test-api.sh new file mode 100644 index 0000000..56c0e68 --- /dev/null +++ b/deploy/test-api.sh @@ -0,0 +1,170 @@ +#!/usr/bin/env bash +# ============================================================================= +# Wild Dragon MAM — API Smoke Test +# ============================================================================= +# Hits every major endpoint and reports pass/fail. +# +# Usage: +# MAM_API_URL=http://10.0.0.25:47432 ./deploy/test-api.sh +# MAM_API_URL=http://10.0.0.25:47432 NODE_TOKEN=wd_xxxx ./deploy/test-api.sh +# ============================================================================= + +set -euo pipefail + +BASE="${MAM_API_URL:-http://localhost:47432}" +TOKEN="${NODE_TOKEN:-}" + +PASS=0; FAIL=0; SKIP=0 + +GRN='\033[0;32m'; RED='\033[0;31m'; YEL='\033[1;33m'; CYN='\033[0;36m'; BLD='\033[1m'; NC='\033[0m' + +pass() { PASS=$((PASS+1)); echo -e " ${GRN}PASS${NC} $1"; } +fail() { FAIL=$((FAIL+1)); echo -e " ${RED}FAIL${NC} $1 ${RED}← $2${NC}"; } +skip() { SKIP=$((SKIP+1)); echo -e " ${YEL}SKIP${NC} $1 ${YEL}($2)${NC}"; } +header() { echo -e "\n${BLD}$1${NC}"; } + +# Auth headers array (works for both GNU and BSD curl) +AUTH_ARGS=() +[[ -n "$TOKEN" ]] && AUTH_ARGS+=(-H "Authorization: Bearer $TOKEN") + +# GET request — check HTTP status code +check_status() { + local label="$1" path="$2" want="$3" + local got + got=$(curl -sf -o /dev/null -w "%{http_code}" "${AUTH_ARGS[@]}" "$BASE$path" 2>/dev/null) || got="000" + if [[ "$got" == "$want" ]]; then + pass "$label [HTTP $got]" + else + fail "$label [HTTP $got]" "expected $want" + fi +} + +# GET request — check response body contains a string +check_body() { + local label="$1" path="$2" needle="$3" + local body + body=$(curl -sf "${AUTH_ARGS[@]}" "$BASE$path" 2>/dev/null) || { fail "$label" "request failed"; return; } + if echo "$body" | grep -q "$needle"; then + pass "$label" + else + fail "$label" "'$needle' not in response" + fi +} + +# POST request — check HTTP status +check_post() { + local label="$1" path="$2" data="$3" want="$4" + local got + got=$(curl -sf -o /dev/null -w "%{http_code}" \ + "${AUTH_ARGS[@]}" \ + -H "Content-Type: application/json" \ + -X POST -d "$data" \ + "$BASE$path" 2>/dev/null) || got="000" + if [[ "$got" == "$want" ]]; then + pass "$label [HTTP $got]" + else + fail "$label [HTTP $got]" "expected $want" + fi +} + +# ───────────────────────────────────────────────────────────────────────────── +echo "" +echo -e "${BLD}${CYN}Wild Dragon MAM — API Smoke Test${NC}" +echo -e " Base URL : ${BLD}$BASE${NC}" +[[ -n "$TOKEN" ]] && echo -e " Auth : Bearer token" || echo -e " Auth : none" +echo "" + +# ── Connectivity ───────────────────────────────────────────────────────────── +header "Connectivity" +if curl -sf -o /dev/null "$BASE/api/v1/auth/whoami" 2>/dev/null || \ + curl -sf -o /dev/null "$BASE/api/v1/cluster" 2>/dev/null; then + pass "API server reachable at $BASE" +else + fail "API server reachable" "cannot connect to $BASE" + echo -e "\n ${RED}Cannot reach the server — aborting.${NC}" + exit 1 +fi + +# ── Auth ───────────────────────────────────────────────────────────────────── +header "Auth" +check_status "GET /auth/whoami" "/api/v1/auth/whoami" 200 + +# ── Assets ─────────────────────────────────────────────────────────────────── +header "Assets" +check_status "GET /assets" "/api/v1/assets" 200 +check_status "GET /assets 404 on bogus" "/api/v1/assets/00000000-0000-0000-0000-000000000000" 404 + +# ── Projects ───────────────────────────────────────────────────────────────── +header "Projects" +check_status "GET /projects" "/api/v1/projects" 200 +check_body "GET /projects returns []" "/api/v1/projects" "[" + +# ── Bins ───────────────────────────────────────────────────────────────────── +header "Bins" +check_status "GET /bins" "/api/v1/bins" 200 + +# ── Jobs ───────────────────────────────────────────────────────────────────── +header "Jobs" +check_status "GET /jobs" "/api/v1/jobs" 200 +check_body "GET /jobs returns array" "/api/v1/jobs" "[" + +# ── Recorders ──────────────────────────────────────────────────────────────── +header "Recorders" +check_status "GET /recorders" "/api/v1/recorders" 200 + +# ── Sequences (Editor) ─────────────────────────────────────────────────────── +header "Sequences" +check_status "GET /sequences" "/api/v1/sequences" 200 + +# ── Cluster ────────────────────────────────────────────────────────────────── +header "Cluster" +check_status "GET /cluster" "/api/v1/cluster" 200 +check_body "GET /cluster returns []" "/api/v1/cluster" "[" + +# Heartbeat test — registers a temporary smoke-test node +TEST_HOST="smoke-test-$(date +%s)" +check_post "POST /cluster/heartbeat" "/api/v1/cluster/heartbeat" \ + "{\"hostname\":\"$TEST_HOST\",\"role\":\"smoketest\",\"cpu_usage\":0,\"mem_used_mb\":512,\"mem_total_mb\":4096}" \ + 200 + +# Verify the node appeared +NODE_ID=$(curl -sf "${AUTH_ARGS[@]}" "$BASE/api/v1/cluster" 2>/dev/null \ + | grep -o '"id":"[^"]*"' | head -1 | grep -o '[0-9a-f-]\{36\}' || true) + +if [[ -n "$NODE_ID" ]]; then + pass "Cluster node visible in registry" + # Clean up — deregister the smoke node + DEL_STATUS=$(curl -sf -o /dev/null -w "%{http_code}" \ + "${AUTH_ARGS[@]}" -X DELETE "$BASE/api/v1/cluster/$NODE_ID" 2>/dev/null) || DEL_STATUS="000" + [[ "$DEL_STATUS" == "200" ]] && pass "DELETE /cluster/:id (cleanup)" \ + || fail "DELETE /cluster/:id (cleanup)" "HTTP $DEL_STATUS" +else + skip "Cluster node visible in registry" "could not parse node id" +fi + +# ── System / Containers ─────────────────────────────────────────────────────── +header "System" +check_status "GET /system/containers" "/api/v1/system/containers" 200 +check_body "Containers returns array" "/api/v1/system/containers" "[" + +# ── Capture ────────────────────────────────────────────────────────────────── +header "Capture" +check_status "GET /capture/status" "/api/v1/capture/status" 200 + +# ── Users / Tokens (admin) ─────────────────────────────────────────────────── +header "Users / Tokens" +check_status "GET /users" "/api/v1/users" 200 +check_status "GET /tokens" "/api/v1/tokens" 200 + +# ── Summary ─────────────────────────────────────────────────────────────────── +TOTAL=$((PASS + FAIL + SKIP)) +echo "" +echo -e "${BLD}Results:${NC} ${GRN}${PASS} passed${NC} / ${RED}${FAIL} failed${NC} / ${YEL}${SKIP} skipped${NC} / $TOTAL total" +echo "" + +if [[ $FAIL -gt 0 ]]; then + echo -e "${RED}Some tests failed. Check the output above.${NC}" + exit 1 +else + echo -e "${GRN}All tests passed.${NC}" +fi