#!/usr/bin/env bats # Tests for agent-roster: report other live Claude agents in a project. # # pgrep and /proc are the system boundary, so the test injects both and runs # the real include/exclude logic against fixtures — no Claude processes are # spawned. Injection points: # ROSTER_PGREP command standing in for pgrep (a stub printing $FAKE_PIDS) # ROSTER_PROC proc dir (a fixture of /cwd symlinks + /status) # ROSTER_SELF_PID the scanner's own pid, so the ancestry walk is testable # # Fixture process tree: pid 1000 (the scanner) is a child of 999 (the current # session's claude), which is a child of init (1). So 999 must always be # excluded as scanner ancestry; other claude pids are judged by cwd. setup() { SCRIPT_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)" ROSTER="$SCRIPT_DIR/agent-roster" PROC="$BATS_TEST_TMPDIR/proc" ROOT="$BATS_TEST_TMPDIR/project" mkdir -p "$PROC" "$ROOT/sub" "$BATS_TEST_TMPDIR/elsewhere" PGREP_STUB="$BATS_TEST_TMPDIR/pgrep" cat >"$PGREP_STUB" <<'EOF' #!/usr/bin/env bash printf '%s\n' $FAKE_PIDS EOF chmod +x "$PGREP_STUB" SELF=1000 # scanner (1000) <- session claude (999) <- init (1) mkproc 1000 "$ROOT" 999 mkproc 999 "$ROOT" 1 } # mkproc PID CWD PPID — register a fake process in the fixture proc dir. mkproc() { mkdir -p "$PROC/$1" ln -sf "$2" "$PROC/$1/cwd" printf 'PPid:\t%s\n' "$3" >"$PROC/$1/status" } run_roster() { ROSTER_PGREP="$PGREP_STUB" ROSTER_PROC="$PROC" ROSTER_SELF_PID="$SELF" \ FAKE_PIDS="$FAKE_PIDS" run "$ROSTER" "$ROOT" } @test "agent-roster: alone (only the session's own claude) exits 0, no output" { FAKE_PIDS="999" run_roster [ "$status" -eq 0 ] [ -z "$output" ] } @test "agent-roster: one other agent in-project is printed, exit 1" { mkproc 2000 "$ROOT" 1 FAKE_PIDS="999 2000" run_roster [ "$status" -eq 1 ] [[ "$output" == *"2000"* ]] [[ "$output" == *"$ROOT"* ]] } @test "agent-roster: two other agents both printed, exit 1" { mkproc 2000 "$ROOT" 1 mkproc 2001 "$ROOT/sub" 1 FAKE_PIDS="999 2000 2001" run_roster [ "$status" -eq 1 ] [[ "$output" == *"2000"* ]] [[ "$output" == *"2001"* ]] [ "${#lines[@]}" -eq 2 ] } @test "agent-roster: the scanner's session-claude ancestor is excluded even with matching cwd" { # 999 has cwd == ROOT but is scanner ancestry; must not appear. FAKE_PIDS="999" run_roster [ "$status" -eq 0 ] [[ "$output" != *"999"* ]] } @test "agent-roster: cwd outside the project root is excluded" { mkproc 3000 "$BATS_TEST_TMPDIR/elsewhere" 1 FAKE_PIDS="999 3000" run_roster [ "$status" -eq 0 ] [ -z "$output" ] } @test "agent-roster: cwd in a subdirectory of root is included" { mkproc 2002 "$ROOT/sub" 1 FAKE_PIDS="999 2002" run_roster [ "$status" -eq 1 ] [[ "$output" == *"2002"* ]] } @test "agent-roster: a sibling path sharing a prefix is not a false match" { # ROOT is .../project; .../project-other must not count as inside it. mkdir -p "$BATS_TEST_TMPDIR/project-other" mkproc 3100 "$BATS_TEST_TMPDIR/project-other" 1 FAKE_PIDS="999 3100" run_roster [ "$status" -eq 0 ] [ -z "$output" ] } @test "agent-roster: a pid that vanished between pgrep and the proc read is skipped" { # 4000 has no fixture dir, simulating a process gone by readlink time. FAKE_PIDS="999 4000" run_roster [ "$status" -eq 0 ] [ -z "$output" ] } @test "agent-roster: missing proc reports unavailable on stderr, exit 2, never silent-alone" { ROSTER_PGREP="$PGREP_STUB" ROSTER_PROC="$BATS_TEST_TMPDIR/nonexistent" \ ROSTER_SELF_PID="$SELF" FAKE_PIDS="999 2000" run "$ROSTER" "$ROOT" [ "$status" -eq 2 ] [[ "$output" == *"roster unavailable"* ]] } @test "agent-roster: a missing pgrep reports unavailable, exit 2, never silent-alone" { # If pgrep itself is absent, the scan can't run; reporting "alone" would be a # false negative the "never silent-alone" invariant forbids. mkproc 2000 "$ROOT" 1 ROSTER_PGREP="$BATS_TEST_TMPDIR/no-such-pgrep" ROSTER_PROC="$PROC" \ ROSTER_SELF_PID="$SELF" FAKE_PIDS="999 2000" run "$ROSTER" "$ROOT" [ "$status" -eq 2 ] [[ "$output" == *"roster unavailable"* ]] } @test "agent-roster: defaults project root to PWD when no argument is given" { mkproc 2000 "$ROOT" 1 FAKE_PIDS="999 2000" ROSTER_PGREP="$PGREP_STUB" ROSTER_PROC="$PROC" ROSTER_SELF_PID="$SELF" \ FAKE_PIDS="$FAKE_PIDS" run env -C "$ROOT" "$ROSTER" [ "$status" -eq 1 ] [[ "$output" == *"2000"* ]] }