81 lines
3.5 KiB
Bash
Executable file
81 lines
3.5 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# apricot-async-smoke.sh — End-to-end smoke for the p2-64 launch/status/fetch protocol.
|
|
#
|
|
# Exercises a tiny batch (smoke 1 50) through the full async loop:
|
|
# 1. launch → bare stamp on stdout
|
|
# 2. status → valid JSON immediately, state in {running, unreachable}
|
|
# 3. wait loop → poll until state==complete (or fail)
|
|
# 4. fetch → rsync results to .local/iter/<stamp>/
|
|
# 5. verify → at least one game_*/turn_stats.jsonl present locally
|
|
#
|
|
# Skips gracefully (exit 0) if apricot is unreachable, so this can run on plum
|
|
# without blocking when the RUN host is offline.
|
|
#
|
|
# Usage:
|
|
# bash scripts/apricot-async-smoke.sh # default smoke 1 50
|
|
# POLL_TIMEOUT_S=600 bash scripts/apricot-async-smoke.sh # extend the wait
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
|
APRICOT="${APRICOT_SSH_ALIAS:-apricot}"
|
|
POLL_TIMEOUT_S="${POLL_TIMEOUT_S:-900}"
|
|
POLL_INTERVAL_S="${POLL_INTERVAL_S:-15}"
|
|
|
|
log() { printf '[%s] %s\n' "$(date +%H:%M:%S)" "$*" >&2; }
|
|
|
|
# ── Reachability gate: skip if apricot can't be reached at all. ──────────────
|
|
if ! ssh -o ConnectTimeout=5 -o BatchMode=yes "$APRICOT" 'echo ok' >/dev/null 2>&1; then
|
|
log "apricot unreachable; skipping smoke (exit 0)"
|
|
exit 0
|
|
fi
|
|
|
|
# ── Step 1: launch ───────────────────────────────────────────────────────────
|
|
log "launching smoke 1 50 …"
|
|
STAMP="$(bash "$SCRIPT_DIR/apricot-run.sh" launch smoke 1 50)"
|
|
if [[ -z "$STAMP" ]]; then
|
|
log "FAIL: launch returned empty stamp"
|
|
exit 1
|
|
fi
|
|
log "launched stamp=$STAMP"
|
|
|
|
# ── Step 2: status (must be valid JSON, must mention the stamp) ──────────────
|
|
STATUS_JSON="$(bash "$SCRIPT_DIR/apricot-run.sh" status "$STAMP")"
|
|
log "initial status: $STATUS_JSON"
|
|
case "$STATUS_JSON" in
|
|
*"\"stamp\":\"$STAMP\""*) ;;
|
|
*) log "FAIL: status JSON missing stamp field"; exit 1 ;;
|
|
esac
|
|
|
|
# ── Step 3: poll until complete | failed (with timeout) ──────────────────────
|
|
log "polling every ${POLL_INTERVAL_S}s up to ${POLL_TIMEOUT_S}s …"
|
|
DEADLINE=$(( $(date +%s) + POLL_TIMEOUT_S ))
|
|
STATE="running"
|
|
while (( $(date +%s) < DEADLINE )); do
|
|
STATUS_JSON="$(bash "$SCRIPT_DIR/apricot-run.sh" status "$STAMP" || true)"
|
|
STATE="$(echo "$STATUS_JSON" | sed -n 's/.*"state":"\([^"]*\)".*/\1/p')"
|
|
log "state=$STATE ($STATUS_JSON)"
|
|
case "$STATE" in
|
|
complete) break ;;
|
|
failed) log "FAIL: batch failed; journalctl --user -u mc-batch-$STAMP on $APRICOT"; exit 1 ;;
|
|
esac
|
|
sleep "$POLL_INTERVAL_S"
|
|
done
|
|
|
|
if [[ "$STATE" != "complete" ]]; then
|
|
log "FAIL: did not reach complete within ${POLL_TIMEOUT_S}s (last state=$STATE)"
|
|
exit 1
|
|
fi
|
|
|
|
# ── Step 4: fetch ────────────────────────────────────────────────────────────
|
|
LOCAL_DEST="$(bash "$SCRIPT_DIR/apricot-run.sh" fetch "$STAMP")"
|
|
log "fetched to: $LOCAL_DEST"
|
|
|
|
# ── Step 5: verify result presence ───────────────────────────────────────────
|
|
if ! find "$LOCAL_DEST" -path '*/game_*/turn_stats.jsonl' -type f | grep -q .; then
|
|
log "FAIL: no turn_stats.jsonl found under $LOCAL_DEST"
|
|
exit 1
|
|
fi
|
|
|
|
log "OK — async protocol smoke passed for stamp=$STAMP"
|