hyperhive/tests/dashboard.sh

156 lines
4.7 KiB
Bash
Executable file

#!/usr/bin/env bash
# Phase 6 + 7 smoke test: dashboard HTTP, per-container web UIs,
# approve-by-POST, SSE endpoint, and orphan-approval GC.
#
# Runs as root on a host with services.hive-c0re enabled and the hm1nd
# container declared. Idempotent — wipes any prior alice state.
set -euo pipefail
AGENT=alice
PKG=htop
HOST=${HOST:-localhost}
DASH_PORT=${DASH_PORT:-7000}
MGR_PORT=${MGR_PORT:-8000}
cleanup() {
sudo hive-c0re kill "$AGENT" 2>/dev/null || true
sudo nixos-container destroy "h-${AGENT}" 2>/dev/null || true
sudo rm -rf \
"/var/lib/hyperhive/agents/${AGENT}" \
"/var/lib/hyperhive/applied/${AGENT}"
}
echo "=== precheck: hm1nd container is up ==="
if ! sudo machinectl status hm1nd >/dev/null 2>&1; then
echo " starting via systemd..."
sudo systemctl start container@hm1nd.service
for i in 1 2 3 4 5 6 7 8 9 10; do
sudo machinectl status hm1nd >/dev/null 2>&1 && break
sleep 0.5
done
fi
echo " ✓ hm1nd is up"
cleanup
echo "=== dashboard reachable ==="
curl -sf "http://${HOST}:${DASH_PORT}/" | grep -q "HYPERHIVE" || {
echo "FAIL: dashboard not serving expected content"
exit 1
}
echo " ✓ http://${HOST}:${DASH_PORT}/ → HTML with HYPERHIVE banner"
echo "=== /messages/stream SSE endpoint ==="
curl -sI "http://${HOST}:${DASH_PORT}/messages/stream" \
| grep -qi "content-type: text/event-stream" || {
echo "FAIL: /messages/stream is not SSE"
exit 1
}
echo " ✓ Content-Type: text/event-stream"
echo "=== manager UI reachable ==="
curl -sf "http://${HOST}:${MGR_PORT}/" | grep -q "hm1nd" || {
echo "FAIL: manager UI not reachable at :${MGR_PORT}"
exit 1
}
echo " ✓ http://${HOST}:${MGR_PORT}/ → hm1nd label"
echo "=== spawn ${AGENT} ==="
sudo hive-c0re spawn "$AGENT"
echo "=== pick up ${AGENT}'s port from dashboard ==="
sleep 2
ALICE_PORT=$(curl -sf "http://${HOST}:${DASH_PORT}/" \
| sed -nE "s|.*href=\"http://[^:]+:([0-9]+)/\">${AGENT}<.*|\\1|p" \
| head -1)
if [ -z "$ALICE_PORT" ]; then
echo "FAIL: ${AGENT} port not found in dashboard"
exit 1
fi
echo "${AGENT} port: ${ALICE_PORT}"
echo "=== ${AGENT} UI reachable ==="
for i in 1 2 3 4 5 6 7 8 9 10; do
curl -sf "http://${HOST}:${ALICE_PORT}/" | grep -q "${AGENT}" && break
sleep 1
done
curl -sf "http://${HOST}:${ALICE_PORT}/" | grep -q "${AGENT}" || {
echo "FAIL: ${AGENT} UI not reachable at :${ALICE_PORT}"
exit 1
}
echo " ✓ http://${HOST}:${ALICE_PORT}/ → ${AGENT} label"
echo "=== ${PKG} not in path pre-approve ==="
if sudo nixos-container run "h-${AGENT}" -- which "$PKG" 2>/dev/null; then
echo "FAIL: ${PKG} already in path"
exit 1
fi
echo " ✓"
echo "=== manager submits approval (via hm1nd) ==="
sudo nixos-container run hm1nd -- bash -c "
set -euo pipefail
cd /agents/${AGENT}/config
cat > agent.nix <<'EOF'
{ pkgs, ... }:
{
environment.systemPackages = [ pkgs.${PKG} ];
}
EOF
git commit -am 'add ${PKG}'
SHA=\$(git rev-parse HEAD)
echo \" manager commit SHA=\$SHA\"
hive-m1nd request-apply-commit ${AGENT} \$SHA
"
echo "=== pick approval id from dashboard ==="
ID=$(curl -sf "http://${HOST}:${DASH_PORT}/" \
| sed -nE 's|.*hive-c0re approve ([0-9]+).*|\1|p' \
| head -1)
if [ -z "$ID" ]; then
echo "FAIL: approval id not found in dashboard"
exit 1
fi
echo " ✓ approval id: ${ID}"
echo "=== POST /approve/${ID} (browser button equivalent) ==="
HTTP_CODE=$(curl -s -o /dev/null -w '%{http_code}' \
-X POST "http://${HOST}:${DASH_PORT}/approve/${ID}")
if [ "$HTTP_CODE" != "303" ] && [ "$HTTP_CODE" != "302" ]; then
echo "FAIL: expected 303 redirect, got HTTP ${HTTP_CODE}"
exit 1
fi
echo " ✓ HTTP ${HTTP_CODE} (redirect)"
echo "=== verify ${PKG} now in h-${AGENT} ==="
sudo nixos-container run "h-${AGENT}" -- which "$PKG"
echo "=== orphan-GC: cleanup ${AGENT}, refresh dashboard, orphan disappears ==="
sudo nixos-container run hm1nd -- bash -c "
set -euo pipefail
cd /agents/${AGENT}/config
echo '{ ... }: { }' > agent.nix
git commit -am 'noop'
SHA=\$(git rev-parse HEAD)
hive-m1nd request-apply-commit ${AGENT} \$SHA
"
ORPHAN_ID=$(sudo hive-c0re pending \
| sed -nE 's/^[[:space:]]*"id":[[:space:]]*([0-9]+).*/\1/p' \
| tail -1)
echo " queued orphan id: ${ORPHAN_ID}"
cleanup
# First dashboard render triggers GC.
curl -sf "http://${HOST}:${DASH_PORT}/" >/dev/null
sleep 0.5
if sudo hive-c0re pending | grep -q "\"id\": ${ORPHAN_ID}"; then
echo "FAIL: orphan ${ORPHAN_ID} still pending after dashboard render"
exit 1
fi
echo " ✓ orphan ${ORPHAN_ID} cleaned up"
echo
echo "=== summary ==="
echo " dashboard http://${HOST}:${DASH_PORT}/"
echo " manager UI http://${HOST}:${MGR_PORT}/"
echo " (alice torn down)"