diff options
Diffstat (limited to 'scripts')
| -rwxr-xr-x | scripts/smoke_live_handoff_sessions.sh | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/scripts/smoke_live_handoff_sessions.sh b/scripts/smoke_live_handoff_sessions.sh new file mode 100755 index 00000000..44dba425 --- /dev/null +++ b/scripts/smoke_live_handoff_sessions.sh @@ -0,0 +1,221 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +HERDR_BIN="${HERDR_BIN:-$ROOT/target/debug/herdr}" +BASE="${BASE:-$(mktemp -d /tmp/herdr-handoff-smoke.XXXXXX)}" +CONFIG_HOME="$BASE/config" +RUNTIME_DIR="$BASE/runtime" +STATE_DIR="$BASE/state" + +if [[ "$CONFIG_HOME" == "$HOME/.config" || "$CONFIG_HOME" == "$HOME/.config/"* ]]; then + echo "refusing to run smoke test against $CONFIG_HOME" >&2 + exit 1 +fi + +sessions=("default" "work" "api") +ports=() +server_pids=() + +cleanup() { + set +e + for session in "${sessions[@]}"; do + run_herdr "$session" server stop >/dev/null 2>&1 || true + done + for pid in "${server_pids[@]}"; do + kill "$pid" >/dev/null 2>&1 || true + done +} +trap cleanup EXIT + +run_herdr() { + local session="$1" + shift + local socket + socket="$(api_socket "$session")" + assert_smoke_socket "$socket" + mkdir -p "$(dirname "$socket")" "$RUNTIME_DIR" "$STATE_DIR" + env -u HERDR_SOCKET_PATH \ + -u HERDR_CLIENT_SOCKET_PATH \ + -u HERDR_SESSION \ + XDG_CONFIG_HOME="$CONFIG_HOME" \ + XDG_RUNTIME_DIR="$RUNTIME_DIR" \ + XDG_STATE_HOME="$STATE_DIR" \ + "$HERDR_BIN" --session "$session" "$@" +} + +session_dir() { + local session="$1" + if [[ "$session" == "default" ]]; then + printf '%s/herdr-dev' "$CONFIG_HOME" + else + printf '%s/herdr-dev/sessions/%s' "$CONFIG_HOME" "$session" + fi +} + +api_socket() { + printf '%s/herdr.sock' "$(session_dir "$1")" +} + +client_socket() { + printf '%s/herdr-client.sock' "$(session_dir "$1")" +} + +assert_smoke_socket() { + local socket="$1" + case "$socket" in + "$CONFIG_HOME"/herdr-dev/herdr.sock | "$CONFIG_HOME"/herdr-dev/sessions/*/herdr.sock) + ;; + *) + echo "refusing to use non-smoke socket: $socket" >&2 + exit 1 + ;; + esac +} + +wait_for_socket() { + local socket="$1" + for _ in {1..200}; do + [[ -S "$socket" ]] && return 0 + sleep 0.05 + done + echo "socket did not appear: $socket" >&2 + return 1 +} + +wait_for_http() { + local port="$1" + local expected="$2" + for _ in {1..200}; do + if curl -fsS "http://127.0.0.1:$port/" | grep -q "$expected"; then + return 0 + fi + sleep 0.05 + done + echo "http server on port $port did not return $expected" >&2 + return 1 +} + +json_request() { + local socket="$1" + local body="$2" + python3 - "$socket" "$body" <<'PY' +import socket +import sys + +path, body = sys.argv[1], sys.argv[2] +client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) +client.connect(path) +client.sendall(body.encode() + b"\n") +response = b"" +while not response.endswith(b"\n"): + chunk = client.recv(65536) + if not chunk: + break + response += chunk +print(response.decode().strip()) +PY +} + +pane_id_for_session() { + local session="$1" + local socket + socket="$(api_socket "$session")" + json_request "$socket" '{"id":"smoke:workspace:create","method":"workspace.create","params":{"cwd":"/tmp","focus":true}}' \ + | python3 -c 'import json,sys; print(json.load(sys.stdin)["result"]["root_pane"]["pane_id"])' +} + +send_text() { + local session="$1" + local pane="$2" + local text="$3" + local socket + socket="$(api_socket "$session")" + python3 - "$socket" "$pane" "$text" <<'PY' +import json +import socket +import sys + +path, pane, text = sys.argv[1], sys.argv[2], sys.argv[3] +request = { + "id": "smoke:pane:send", + "method": "pane.send_input", + "params": {"pane_id": pane, "text": text, "keys": ["Enter"]}, +} +client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) +client.connect(path) +client.sendall(json.dumps(request).encode() + b"\n") +response = b"" +while not response.endswith(b"\n"): + chunk = client.recv(65536) + if not chunk: + break + response += chunk +if b'"error"' in response: + raise SystemExit(response.decode()) +PY +} + +unused_port() { + python3 - <<'PY' +import socket +sock = socket.socket() +sock.bind(("127.0.0.1", 0)) +print(sock.getsockname()[1]) +sock.close() +PY +} + +smoke_http_count() { + local count=0 + local port matches + for port in "${ports[@]}"; do + matches="$(pgrep -fc "python3 -m http.server $port --bind 127.0.0.1" || true)" + if [[ -n "$matches" ]]; then + count=$((count + matches)) + fi + done + printf '%s\n' "$count" +} + +echo "using herdr: $HERDR_BIN" +echo "smoke base: $BASE" + +cargo build --locked --manifest-path "$ROOT/Cargo.toml" >/dev/null +mkdir -p "$CONFIG_HOME/herdr-dev" "$RUNTIME_DIR" "$STATE_DIR" +printf 'onboarding = false\n' > "$CONFIG_HOME/herdr-dev/config.toml" + +for session in "${sessions[@]}"; do + echo "starting smoke session $session at $(api_socket "$session")" + run_herdr "$session" server >/dev/null 2>&1 & + server_pids+=("$!") + wait_for_socket "$(api_socket "$session")" +done + +for session in "${sessions[@]}"; do + port="$(unused_port)" + ports+=("$port") + web="$BASE/web-$session" + mkdir -p "$web" + printf 'hello-from-%s\n' "$session" > "$web/index.html" + pane="$(pane_id_for_session "$session")" + send_text "$session" "$pane" "cd '$web' && python3 -m http.server $port --bind 127.0.0.1" + wait_for_http "$port" "hello-from-$session" +done + +before_count="$(smoke_http_count)" +echo "smoke python http.server process count before handoff: $before_count" + +for session in "${sessions[@]}"; do + socket="$(api_socket "$session")" + json_request "$socket" '{"id":"smoke:handoff","method":"server.live_handoff","params":{}}' >/dev/null + wait_for_socket "$socket" +done + +for i in "${!sessions[@]}"; do + wait_for_http "${ports[$i]}" "hello-from-${sessions[$i]}" +done + +after_count="$(smoke_http_count)" +echo "smoke python http.server process count after handoff: $after_count" +echo "multi-session live handoff smoke passed" |
