#!/usr/bin/env bats load 'helpers' setup() { setup_party_sandbox load_party_lib } @test "roster_record_path composes deterministically" { out=$(roster_record_path "veg" "debug-the-deploy") [ "$out" = "$PARTY_SOCKET_DIR/party-veg:debug-the-deploy.d/roster" ] } @test "party_dir_path composes deterministically" { out=$(party_dir_path "veg" "debug-the-deploy") [ "$out" = "$PARTY_SOCKET_DIR/party-veg:debug-the-deploy.d" ] } @test "socket_path lives inside the per-party private dir" { out=$(socket_path "veg" "debug-the-deploy") [ "$out" = "$PARTY_SOCKET_DIR/party-veg:debug-the-deploy.d/sock" ] } @test "roster_write then roster_read round-trips all fields" { ensure_party_dir "$USER" "rt-test" rec=$(roster_record_path "$USER" "rt-test") # roster_read derives RR_HOST_USER, RR_PARTY_NAME, and RR_SOCKET from # the dir basename and filesystem; SERVER_PID, GROUP, and CREATED come # from the file. The values written here for HOST_USER/PARTY_NAME/ # SOCKET are advisory and overlap with what roster_read derives. derived_sock="$PARTY_SOCKET_DIR/party-$USER:rt-test.d/sock" roster_write "$rec" \ HOST_USER "$USER" \ PARTY_NAME "rt-test" \ SOCKET "$derived_sock" \ SERVER_PID 12345 \ CREATED "2026-04-26T18:42:00Z" [ -f "$rec" ] roster_read "$rec" [ "$RR_HOST_USER" = "$USER" ] [ "$RR_PARTY_NAME" = "rt-test" ] [ "$RR_SOCKET" = "$derived_sock" ] [ "$RR_SERVER_PID" = "12345" ] [ "$RR_CREATED" = "2026-04-26T18:42:00Z" ] } @test "roster_write is atomic: no partial files on failure" { ensure_party_dir "$USER" "atomic" rec=$(roster_record_path "$USER" "atomic") roster_write "$rec" HOST_USER "$USER" PARTY_NAME "atomic" \ SOCKET "/tmp/sock" SERVER_PID 1 CREATED 0 # The write goes via a temp file; no .tmp leftover should remain in # the per-party dir. ! ls "${rec%/*}"/*.tmp 2>/dev/null } @test "roster_read fails on missing file" { run roster_read "$PARTY_SOCKET_DIR/party-nobody:nope.d/roster" [ "$status" -ne 0 ] } # Helper: write a $PARTY_TMUX stub that exits with the given code on # every invocation. Used to test is_party_alive's tmux probe in isolation. _stub_tmux() { cat > "$PARTY_TMP/tmux-stub" </dev/null wait "$pid" 2>/dev/null || true # Same PID, now reaped — tmux stub still says yes, so still alive. is_party_alive "$pid" /dev/null # And a PID we never owned (init/launchd, root) — likewise alive. is_party_alive 1 /dev/null } @test "is_party_alive: empty/non-numeric PID → false" { _stub_tmux 0 ! is_party_alive "" /dev/null ! is_party_alive "abc" /dev/null } @test "is_party_alive: tmux probe fails → false" { # PID-reuse / planted nc -lU socket scenario: the socket isn't a real # tmux server, so the tmux handshake fails. is_party_alive rejects # regardless of PID state (regression seen cross-user on illumos # native). _stub_tmux 1 ( sleep 30 ) & pid=$! ! is_party_alive "$pid" /dev/null kill "$pid" 2>/dev/null wait "$pid" 2>/dev/null || true ! is_party_alive 1 /dev/null } @test "roster_list returns full record paths under PARTY_SOCKET_DIR" { for n in alpha beta gamma; do ensure_party_dir "$USER" "$n" rec=$(roster_record_path "$USER" "$n") roster_write "$rec" HOST_USER "$USER" PARTY_NAME "$n" \ SOCKET "/tmp/s" SERVER_PID 1 CREATED 0 done out=$(roster_list | sort | tr '\n' ' ') expected="$PARTY_SOCKET_DIR/party-$USER:alpha.d/roster $PARTY_SOCKET_DIR/party-$USER:beta.d/roster $PARTY_SOCKET_DIR/party-$USER:gamma.d/roster " [ "$out" = "$expected" ] }