Files
agent-helm/helmd/scripts/integration-test.sh
claude 12ffcaa2bd
All checks were successful
helmd-image / build (push) Successful in 36s
helmd-release / build-release (push) Successful in 1m6s
helmd: inbäddad webbklient (vanilla SPA) + Docker-image för Pi5 (LAN-only)
- web/: token-login, sessionslista, ANSI-skärmvy (SSE+poll), promptfält,
  frågekort, tangentrad, delningsflik (bild/HTML-sandbox/markdown), inställningar
- go:embed via webfs.go — servern förblir en enda binär, strikt CSP
- browser-verifierad mot riktig agy (fråga -> kort -> svar -> kört)
- Dockerfile (alpine + tmux/bash) + helmd-image.yaml -> localhost:5000/helmd
- integrationstest utökat till 29 gröna

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-05 22:17:12 +02:00

133 lines
6.2 KiB
Bash
Executable File

#!/bin/bash
# Integrationstest för helmd. Körs i en isolerad container (se
# scripts/run-integration.sh) men fungerar var som helst där tmux,
# curl och binären finns och där HOME får smutsas ner.
set -eu
BIN="${HELMD_BIN:-./build/helmd}"
export HOME="${TEST_HOME:-$(mktemp -d)}"
export HELMD_CONFIG="$HOME/helmd-config.json"
API=http://127.0.0.1:8788
PASS=0; FAIL=0
say() { printf '\n== %s\n' "$*"; }
ok() { PASS=$((PASS+1)); echo " OK: $*"; }
fail() { FAIL=$((FAIL+1)); echo " FAIL: $*" >&2; }
expect_contains() { # haystackfil, nål, beskrivning
if grep -qF "$2" "$1"; then ok "$3"; else fail "$3 — hittade inte: $2"; cat "$1" | tail -20; fi
}
curl_api() { curl -sS -H "Authorization: Bearer $TOKEN" "$@"; }
wait_for() { # beskrivning, timeout-sek, kommando...
local desc="$1" t="$2"; shift 2
for _ in $(seq 1 $((t*2))); do
if "$@" >/dev/null 2>&1; then ok "$desc"; return 0; fi
sleep 0.5
done
fail "$desc (timeout ${t}s)"; return 1
}
say "startar helmd"
TOKEN=$("$BIN" token)
"$BIN" serve --listen 127.0.0.1:8788 &
HELMD_PID=$!
trap 'kill $HELMD_PID 2>/dev/null || true; tmux kill-server 2>/dev/null || true' EXIT
wait_for "servern svarar på /api/health" 10 \
curl -fsS -H "Authorization: Bearer $TOKEN" $API/api/health
say "auth"
CODE=$(curl -s -o /dev/null -w '%{http_code}' $API/api/sessions)
[ "$CODE" = 401 ] && ok "utan token => 401" || fail "utan token gav $CODE"
CODE=$(curl -s -o /dev/null -w '%{http_code}' "$API/api/sessions?token=$TOKEN")
[ "$CODE" = 200 ] && ok "query-token => 200" || fail "query-token gav $CODE"
say "webbklient (inbäddad)"
curl -s $API/ > /tmp/ui.html
expect_contains /tmp/ui.html '<title>agent-helm</title>' "index.html serveras utan auth"
curl -s $API/app.js | grep -q 'ansiToHtml' && ok "app.js serveras" || fail "app.js"
CODE=$(curl -s -o /dev/null -w '%{http_code}' $API/style.css)
[ "$CODE" = 200 ] && ok "style.css => 200" || fail "style.css gav $CODE"
say "stäng av ntfy för testet (PUT /api/config)"
curl_api -X PUT -d '{"ntfy":{"server":"https://ntfy.brasse-pc.eu","topic":"agent-helm","allowed_topics":["agent-helm","claude"],"enabled":false,"notify_on_question":false}}' \
$API/api/config > /tmp/cfg.json
expect_contains /tmp/cfg.json '"saved":true' "config sparad"
curl_api $API/api/config | grep -q '"enabled":false' && ok "ntfy avstängd" || fail "ntfy fortfarande på"
say "session: skapa med mock-agent"
MOCK="$(cd "$(dirname "$0")/.." && pwd)/testdata/mock-agent.sh"
curl_api -X POST -d "{\"name\":\"prov\",\"cmd\":\"bash $MOCK\",\"cwd\":\"/tmp\"}" \
$API/api/sessions > /tmp/sess.json
expect_contains /tmp/sess.json '"name":"prov"' "session skapad"
say "fråga 1: onumrerad trust-fråga (pilnavigering)"
q_has_two_options() { curl_api $API/api/sessions/prov/question | grep -q '"No, exit"'; }
wait_for "trust-frågan detekterad" 10 q_has_two_options
curl_api $API/api/sessions/prov/question > /tmp/q1.json
expect_contains /tmp/q1.json '"selected":0' "markören står på första valet"
curl_api -X POST -d '{"option":2}' $API/api/sessions/prov/answer > /tmp/a1.json
expect_contains /tmp/a1.json '"answered":true' "svar skickat"
screen_has() { curl_api "$API/api/sessions/prov/screen" | grep -qF "$1"; }
wait_for "mocken fick svaret (ned+enter => val 1)" 10 screen_has "TRUST_ANSWER=1"
say "prompt"
curl_api -X POST -d '{"text":"hej från testet"}' $API/api/sessions/prov/prompt > /dev/null
wait_for "prompten nådde agenten" 10 screen_has "ECHO: hej från testet"
say "fråga 2: numrerad godkännandefråga (sifferval)"
curl_api -X POST -d '{"text":"ask-numbered"}' $API/api/sessions/prov/prompt > /dev/null
q2_detected() { curl_api $API/api/sessions/prov/question | grep -q '"numbered":true'; }
wait_for "numrerad fråga detekterad" 10 q2_detected
curl_api -X POST -d '{"option":3}' $API/api/sessions/prov/answer > /dev/null
wait_for "mocken fick siffran 3" 10 screen_has "PICKED=3"
say "raw keys + mode"
curl_api -X POST -d '{"keys":["Enter"]}' $API/api/sessions/prov/keys | grep -q '"sent":true' \
&& ok "keys-endpoint" || fail "keys-endpoint"
curl_api -X POST -d '{"action":"cycle"}' $API/api/sessions/prov/mode | grep -q '"sent":true' \
&& ok "mode cycle (BTab)" || fail "mode cycle"
say "SSE-events"
(curl_api -N --max-time 4 "$API/api/events" > /tmp/events.txt 2>/dev/null || true) &
SSE_PID=$!
sleep 0.5
curl_api -X POST -d '{"text":"sse-test"}' $API/api/sessions/prov/prompt > /dev/null
wait $SSE_PID || true
expect_contains /tmp/events.txt 'event: hello' "SSE hello"
expect_contains /tmp/events.txt 'event: screen' "SSE screen-event vid ändring"
say "fildelning"
printf '<h1>rapport</h1>' > /tmp/rapport.html
"$BIN" share --note "testrapport" --session prov /tmp/rapport.html > /tmp/share.out
expect_contains /tmp/share.out "delad: rapport.html" "helmd share-CLI"
curl_api $API/api/shares > /tmp/shares.json
expect_contains /tmp/shares.json '"note":"testrapport"' "delningen listas"
SHARE_ID=$(grep -o '"id":"[a-f0-9]*"' /tmp/shares.json | head -1 | cut -d'"' -f4)
curl_api "$API/api/shares/$SHARE_ID/raw" > /tmp/share.raw
expect_contains /tmp/share.raw '<h1>rapport</h1>' "raw-innehåll serveras"
printf 'x' > /tmp/otillaten.sh
CODE=$(curl_api -s -o /dev/null -w '%{http_code}' -F file=@/tmp/otillaten.sh $API/api/shares)
[ "$CODE" = 400 ] && ok "otillåten filtyp => 400" || fail "otillåten filtyp gav $CODE"
curl_api -X DELETE "$API/api/shares/$SHARE_ID" | grep -q '"deleted":true' \
&& ok "delning raderad" || fail "radering"
say "notify-regler"
CODE=$(curl_api -s -o /dev/null -w '%{http_code}' -X POST -d '{"topic":"hemligt","message":"x"}' $API/api/notify)
[ "$CODE" = 403 ] && ok "otillåten topic => 403" || fail "otillåten topic gav $CODE"
curl_api -X POST -d '{"topic":"claude","message":"tyst (ntfy disabled)"}' $API/api/notify \
| grep -q '"published":true' && ok "tillåten topic => ok (ntfy av => no-op)" || fail "tillåten topic"
say "session: avsluta + döda"
curl_api -X POST -d '{"text":"exit"}' $API/api/sessions/prov/prompt > /dev/null
sess_dead() { curl_api $API/api/sessions/prov | grep -q '"alive":false'; }
wait_for "exit upptäcks (alive=false)" 10 sess_dead
curl_api -X DELETE $API/api/sessions/prov | grep -q '"killed":true' \
&& ok "session dödad" || fail "kill"
echo
echo "================================"
echo "PASS: $PASS FAIL: $FAIL"
[ "$FAIL" = 0 ] && echo "ALLA TESTER GRÖNA" || exit 1