Files
kyle e436c62a52 Add the smoke run, README and systemd unit
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-25 02:40:33 -07:00

46 lines
2.8 KiB
Bash
Executable File

#!/bin/sh
# Smoke run: two fake upstreams, one crossbar, real HTTP. Prints "smoke: ok" or fails.
# Needs: bin/crossbar and bin/fakeupstream (make build), curl.
set -eu
cd "$(dirname "$0")/.."
tmp=$(mktemp -d); trap 'kill $pids 2>/dev/null; rm -rf "$tmp"' EXIT INT TERM
pids=""
bin/fakeupstream -listen 127.0.0.1:18081 -name alpha -models ornith-1.5-35b-a3b,small-9b -down-file "$tmp/alpha.down" >"$tmp/alpha.log" 2>&1 & pids="$pids $!"
bin/fakeupstream -listen 127.0.0.1:18082 -name beta -models ornith-1.5-35b-a3b -down-file "$tmp/beta.down" >"$tmp/beta.log" 2>&1 & pids="$pids $!"
bin/crossbar -config example.toml >"$tmp/crossbar.log" 2>&1 & pids="$pids $!"
sleep 1.5
fail() { echo "smoke: FAIL: $*" >&2; echo "--- crossbar.log"; cat "$tmp/crossbar.log"; exit 1; }
base=http://127.0.0.1:17777
h=$(curl -s -o /dev/null -w '%{http_code} %header{X-Crossbar-Host}' "$base/opencode-a/v1/models")
[ "$h" = "200 alpha" ] || fail "opencode-a should go to alpha, got '$h'"
h=$(curl -s -o /dev/null -w '%{http_code} %header{X-Crossbar-Host}' "$base/hermes-x/v1/models")
[ "$h" = "200 beta" ] || fail "hermes-x should go to beta, got '$h'"
h=$(curl -s -o /dev/null -w '%{http_code}' "$base/nope/v1/models")
[ "$h" = "404" ] || fail "unknown route should be 404, got '$h'"
touch "$tmp/alpha.down"; sleep 2.5 # poll_interval is 1s in example.toml
h=$(curl -s -o /dev/null -w '%{http_code} %header{X-Crossbar-Host}' "$base/opencode-a/v1/models")
[ "$h" = "200 beta" ] || fail "with alpha down, opencode-a should fail over to beta, got '$h'"
curl -s "$base/_crossbar/hosts" | grep -q '"alpha":{"healthy":false' || fail "/_crossbar/hosts does not show alpha unhealthy: $(curl -s $base/_crossbar/hosts)"
rm "$tmp/alpha.down"; sleep 3.5 # recovery needs two good polls
h=$(curl -s -o /dev/null -w '%header{X-Crossbar-Host}' "$base/opencode-a/v1/models")
[ "$h" = "alpha" ] || fail "alpha should be back after two good polls, got '$h'"
# Streaming: five chunks 200 ms apart must arrive over >= 0.6 s, not all at once at the end.
start=$(date +%s%N)
first=""
curl -sN -X POST -H 'Content-Type: application/json' -d '{"model":"ornith-1.5-35b-a3b","stream":true,"messages":[]}' \
"$base/opencode-a/v1/chat/completions" | while IFS= read -r line; do
[ -n "$line" ] || continue
now=$(date +%s%N); echo "$(( (now - start) / 1000000 )) $line"
done > "$tmp/stream.txt"
firstms=$(head -1 "$tmp/stream.txt" | cut -d' ' -f1); lastms=$(tail -1 "$tmp/stream.txt" | cut -d' ' -f1)
[ -n "$firstms" ] && [ "$((lastms - firstms))" -ge 600 ] || fail "stream arrived in one burst (first ${firstms:-?} ms, last ${lastms:-?} ms):
$(cat "$tmp/stream.txt")"
grep -q 'DONE' "$tmp/stream.txt" || fail "stream did not end with [DONE]"
grep -q 'route=opencode-a host=alpha' "$tmp/crossbar.log" || fail "no request log line"
echo "smoke: ok (stream spread $((lastms - firstms)) ms)"