Initial pre-release
tmux-party: share a tmux session with people on the same UNIX host. Single-file POSIX shell (party) with a filesystem + tmux server-access trust model. See README.md.
This commit is contained in:
commit
6be0ac1877
20 changed files with 3869 additions and 0 deletions
122
tests/30-roster.bats
Normal file
122
tests/30-roster.bats
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
#!/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" <<EOF
|
||||
#!/bin/sh
|
||||
exit $1
|
||||
EOF
|
||||
chmod +x "$PARTY_TMP/tmux-stub"
|
||||
PARTY_TMUX="$PARTY_TMP/tmux-stub"
|
||||
}
|
||||
|
||||
@test "is_party_alive: tmux probe ok → true (regardless of PID liveness)" {
|
||||
# Liveness is decided by the tmux probe alone; the PID arg is kept for
|
||||
# caller-API compatibility and numeric-validation, but is not signal-
|
||||
# probed (POSIX kill(2) returns EPERM cross-user on illumos/BSD/macOS,
|
||||
# which broke cross-user discovery in earlier revisions). With a stub
|
||||
# tmux returning 0, both a live and a never-existed PID must pass.
|
||||
_stub_tmux 0
|
||||
( sleep 30 ) &
|
||||
pid=$!
|
||||
is_party_alive "$pid" /dev/null
|
||||
kill "$pid" 2>/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" ]
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue