#!/usr/bin/env bash # Tests para kill_fleet_agent. Usa fixtures en dirs temporales (FN_FLEET_*) y # --dry-run para no matar procesos ni cerrar windows reales. set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/kill_fleet_agent.sh" PASS=0 FAIL=0 assert_contains() { local test_name="$1" needle="$2" haystack="$3" if echo "$haystack" | grep -qF "$needle"; then echo "PASS: $test_name" PASS=$((PASS+1)) else echo "FAIL: $test_name — expected to contain '$needle'" echo " got: $haystack" FAIL=$((FAIL+1)) fi } assert_rc() { local test_name="$1" expected="$2" actual="$3" if [[ "$actual" == "$expected" ]]; then echo "PASS: $test_name (rc=$actual)" PASS=$((PASS+1)) else echo "FAIL: $test_name — expected rc=$expected, got rc=$actual" FAIL=$((FAIL+1)) fi } # --- Fixtures: sessions/.json + goals/.json en dirs temporales --- TMP="$(mktemp -d)" SESS="$TMP/sessions" GOALS="$TMP/goals" mkdir -p "$SESS" "$GOALS" # Ejecutor: PID 4242, sessionId executor-aaa-111, role=executor. echo '{"sessionId":"executor-aaa-111","cwd":"/tmp/x"}' > "$SESS/4242.json" echo '{"goal":"hacer X","role":"executor","dod_contract":"golden..."}' > "$GOALS/executor-aaa-111.json" # Orquestador: PID 5555, sessionId orchestrator-bbb-222, role=orchestrator. echo '{"sessionId":"orchestrator-bbb-222","cwd":"/tmp/y"}' > "$SESS/5555.json" echo '{"goal":"orquestar","role":"orchestrator"}' > "$GOALS/orchestrator-bbb-222.json" trap 'rm -rf "$TMP"' EXIT export FN_FLEET_SESSIONS_DIR="$SESS" export FN_FLEET_GOALS_DIR="$GOALS" # Forzar self_pid a un valor que NO colisione con los fixtures (salvo el test self). export FN_FLEET_SELF_PID=999999 # --- Test 1 (golden): resolver ejecutor por sessionId, dry-run imprime plan --- set +e out=$(kill_fleet_agent executor-aaa-111 --socket nope --dry-run 2>&1); rc=$? set -e assert_rc "golden: ejecutor por sessionId sale 0" 0 "$rc" assert_contains "golden: plan muestra el PID resuelto" "PID: 4242" "$out" assert_contains "golden: plan muestra el sessionId" "executor-aaa-111" "$out" assert_contains "golden: plan muestra role executor" "role: executor" "$out" assert_contains "golden: dry-run no mata" "DRY-RUN" "$out" # --- Test 2 (golden por PID + prefijo de sessionId) --- set +e out=$(kill_fleet_agent 4242 --dry-run 2>&1); rc=$? set -e assert_rc "golden: target por PID sale 0" 0 "$rc" assert_contains "golden: PID resuelve su sessionId" "executor-aaa-111" "$out" set +e out=$(kill_fleet_agent executor-aaa --dry-run 2>&1); rc=$? set -e assert_rc "edge: prefijo de sessionId resuelve" 0 "$rc" assert_contains "edge: prefijo resuelve al PID 4242" "PID: 4242" "$out" # --- Test 3 (EDGE guard role): negar matar a un orchestrator --- set +e out=$(kill_fleet_agent orchestrator-bbb-222 --dry-run 2>&1); rc=$? set -e assert_rc "guard: matar orchestrator devuelve rc=3" 3 "$rc" assert_contains "guard: mensaje menciona role=orchestrator" "role=orchestrator" "$out" # --- Test 4 (EDGE guard self): negar matar a la sesion actual --- set +e out=$(FN_FLEET_SELF_PID=4242 kill_fleet_agent executor-aaa-111 --dry-run 2>&1); rc=$? set -e assert_rc "guard: matar self devuelve rc=3" 3 "$rc" assert_contains "guard: mensaje self menciona no suicidarse" "No me suicido" "$out" # --- Test 5 (ERROR): target no resuelto a un PID --- set +e out=$(kill_fleet_agent sesion-inexistente-zzz --dry-run 2>&1); rc=$? set -e assert_rc "error: target inexistente devuelve rc=2" 2 "$rc" assert_contains "error: mensaje de no resuelto" "no se pudo resolver" "$out" # --- Test 6 (ERROR): falta el target --- set +e out=$(kill_fleet_agent --dry-run 2>&1); rc=$? set -e assert_rc "error: sin target devuelve rc=2" 2 "$rc" assert_contains "error: mensaje falta target" "falta el target" "$out" # --- Test 7 (Guard 3 predicado): _fleet_window_hosts_tui --- # La window 'console' SIEMPRE se considera que aloja la TUI (no se cierra entera). assert_predicate() { local test_name="$1" expected="$2"; shift 2 set +e _fleet_window_hosts_tui "$@"; local rc=$? set -e assert_rc "$test_name" "$expected" "$rc" } # Nombre de window 'console' -> aloja TUI (rc 0), aunque ningun pane sea fleetview. assert_predicate "guard3: window 'console' aloja la TUI" 0 "console" $'1234 claude\n5678 bash' # Algun pane corre 'fleetview' -> aloja TUI (rc 0), aunque la window no sea console. assert_predicate "guard3: pane fleetview aloja la TUI" 0 "claude" $'1111 bash\n2222 fleetview' # Ni console ni fleetview -> NO aloja la TUI (rc 1): kill-window normal. assert_predicate "guard3: window normal no aloja la TUI" 1 "claude" $'3333 claude\n4444 bash' # Substring que contiene 'fleetview' pero no es el comando exacto -> NO matchea (grep -qx). assert_predicate "guard3: comando 'fleetviewer' no falsea positivo" 1 "work" $'7777 fleetviewer' echo "---" echo "Results: $PASS passed, $FAIL failed" [[ $FAIL -eq 0 ]] || exit 1