Files
ukmesh/scripts/test-alert-receiver.sh
T
hermes-gadgetandgadgethd 029cc6ac33 fix(ops): ukmesh deploy/alert/stats hardening (#47 #54 #55 #57) (#104)
* test(viewshed): inject post-commit side-effect failures

* fix(deploy): rollback on unhealthy or mismatched sites

* fix(alerts): persist forwarding queue across restarts

* perf(stats): add per-network aggregate cutover controls

* docs: add Mission C5d handoff

* test(viewshed): correct side-effect marker cursor row sets

* fix(alerts): keep archive-only receiver live

---------

Co-authored-by: gadgethd <111318106+gadgethd@users.noreply.github.com>
2026-10-01 00:24:31 +01:00

71 lines
2.6 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
tmp_dir="$(mktemp -d "${repo_dir}/.test-alert-receiver.XXXXXX")"
port="$((18080 + ($$ % 1000)))"
receiver_pid=""
cleanup() {
if [ -n "$receiver_pid" ]; then
kill "$receiver_pid" >/dev/null 2>&1 || true
wait "$receiver_pid" >/dev/null 2>&1 || true
fi
rm -rf "$tmp_dir"
}
trap cleanup EXIT
(
cd "$repo_dir/backend"
ALERT_RECEIVER_PORT="$port" \
ALERT_RECEIVER_PATH="$tmp_dir/alerts.jsonl" \
node --import tsx src/workers/alert-receiver.ts
) >"$tmp_dir/receiver.log" 2>&1 &
receiver_pid="$!"
for _ in $(seq 1 40); do
if curl --silent "http://127.0.0.1:${port}/healthz" >/dev/null; then
break
fi
sleep 0.25
done
health_code="$(curl --silent --output "$tmp_dir/health.json" --write-out '%{http_code}' "http://127.0.0.1:${port}/healthz")"
test "$health_code" = 200
node -e '
const health = JSON.parse(require("fs").readFileSync(process.argv[1], "utf8"));
if (health.status !== "degraded" || !health.detail.includes("archive-only")) {
throw new Error(`unexpected archive-only liveness response: ${JSON.stringify(health)}`);
}
' "$tmp_dir/health.json"
ready_code="$(curl --silent --output "$tmp_dir/ready.json" --write-out '%{http_code}' "http://127.0.0.1:${port}/readyz")"
test "$ready_code" = 503
node -e '
const ready = JSON.parse(require("fs").readFileSync(process.argv[1], "utf8"));
if (ready.status !== "degraded" || !ready.detail.includes("archive-only")) {
throw new Error(`unexpected archive-only readiness response: ${JSON.stringify(ready)}`);
}
' "$tmp_dir/ready.json"
curl --fail --silent \
-H 'content-type: application/json' \
--data '{"kind":"alert","service":"meshcore-analytics","check":"dependency_readiness","detail":"test"}' \
"http://127.0.0.1:${port}/alerts" >/dev/null
curl --fail --silent \
-H 'content-type: application/json' \
--data '{"kind":"recovery","service":"meshcore-analytics","check":"dependency_readiness","detail":"test"}' \
"http://127.0.0.1:${port}/alerts" >/dev/null
node -e '
const fs = require("fs");
const records = fs.readFileSync(process.argv[1], "utf8").trim().split("\n").map(JSON.parse);
if (records.length !== 2) throw new Error(`expected two receipts, got ${records.length}`);
if (records[0].status !== "firing" || records[1].status !== "recovery") {
throw new Error(`unexpected receipt states: ${records.map((r) => r.status).join(",")}`);
}
if (JSON.stringify(records).includes("\"detail\"")) {
throw new Error("receipt persisted unbounded alert detail");
}
' "$tmp_dir/alerts.jsonl"
echo "Synthetic firing and recovery reached the bounded test receiver."