aboutsummaryrefslogtreecommitdiffstats
path: root/tests/serverctl.sh
diff options
context:
space:
mode:
authorblasty <blasty@local>2026-07-09 11:22:18 +0200
committerblasty <blasty@local>2026-07-09 11:22:18 +0200
commit90636755b26c5dbee8acdda5e37c7aff9e896854 (patch)
tree7aa0176977291608e06ce19bd35058f40da6d3e5 /tests/serverctl.sh
parentpersistent MCP client: warm handshake, keep-alive pool, error taxonomy, threa... (diff)
downloadida-tui-90636755b26c5dbee8acdda5e37c7aff9e896854.tar.gz
ida-tui-90636755b26c5dbee8acdda5e37c7aff9e896854.tar.xz
ida-tui-90636755b26c5dbee8acdda5e37c7aff9e896854.zip
harden client: transparent session auto-recovery + stress suite
- auto-recover stale db ("Session not found" after server restart): drop pin, re-resolve sole session, retry once. Only when db was auto-injected; never silently switches an explicitly-pinned db (auto_recover_session gate). - tests/serverctl.sh: start/stop/kill9/ready control over spawn.sh - tests/stress_client.py: 6 adversarial scenarios, 24 assertions: dead-port fail-fast, tight-timeout recovery, worker crash, full restart (naive auto-recovery + no-autoswitch), 300/16 concurrency, kill-under-churn. All clean: no hangs, no deadlocks, no non-IDAError leaks.
Diffstat (limited to 'tests/serverctl.sh')
-rwxr-xr-xtests/serverctl.sh65
1 files changed, 65 insertions, 0 deletions
diff --git a/tests/serverctl.sh b/tests/serverctl.sh
new file mode 100755
index 0000000..a5bc098
--- /dev/null
+++ b/tests/serverctl.sh
@@ -0,0 +1,65 @@
+#!/usr/bin/env bash
+# Control the ida-pro-mcp server for stress testing. Assumes ~/ida-venv + spawn.sh.
+set -u
+REPO="$(cd "$(dirname "$0")/.." && pwd)"
+PORT=8745
+LOG=/tmp/ida-stress-spawn.log
+
+wait_port() { # wait_port <up|down> <secs>
+ local want="$1" secs="${2:-40}" i
+ for ((i=0; i<secs*2; i++)); do
+ if ss -ltn 2>/dev/null | grep -q ":$PORT "; then
+ [ "$want" = up ] && return 0
+ else
+ [ "$want" = down ] && return 0
+ fi
+ sleep 0.5
+ done
+ return 1
+}
+
+wait_ready() { # wait until hexrays_ready via the client
+ local secs="${1:-60}" i
+ for ((i=0; i<secs; i++)); do
+ if python3 -c "
+import sys; sys.path.insert(0,'$REPO')
+from idatui.client import IDAClient
+try:
+ c=IDAClient(); c.connect()
+ ss=[s for s in c.list_sessions() if s.session_id]
+ if ss:
+ c.set_db(ss[0].session_id)
+ if c.health().get('hexrays_ready'): print(ss[0].session_id); sys.exit(0)
+except Exception: pass
+sys.exit(1)
+" 2>/dev/null; then return 0; fi
+ sleep 1
+ done
+ return 1
+}
+
+case "${1:-}" in
+ start)
+ cd "$REPO"
+ source ~/ida-venv/bin/activate 2>/dev/null
+ nohup ./spawn.sh >"$LOG" 2>&1 &
+ wait_port up 40 || { echo "PORT_TIMEOUT"; tail -5 "$LOG"; exit 1; }
+ wait_ready 90 || { echo "READY_TIMEOUT"; tail -5 "$LOG"; exit 1; }
+ ;;
+ stop)
+ # Kill the whole tree: uv wrapper, supervisor, worker.
+ pkill -9 -f 'idalib_server' 2>/dev/null
+ pkill -9 -f 'idalib-mcp' 2>/dev/null
+ pkill -9 -f 'uv run idalib' 2>/dev/null
+ wait_port down 20 || { echo "STOP_TIMEOUT"; exit 1; }
+ ;;
+ kill9)
+ # Hard kill only the worker (simulate a crash of the analysis process).
+ pkill -9 -f 'idalib_server' 2>/dev/null
+ ;;
+ ready)
+ wait_ready "${2:-60}"
+ ;;
+ *)
+ echo "usage: $0 {start|stop|kill9|ready [secs]}"; exit 2;;
+esac