feat: party clean removes the caller's own crash leftovers
Turns the manual rm -rf recovery from host's EEXIST message into a verb, behind the same gates cmd_close uses: own-basename glob, no symlinks, ownership check, and a dead socket. Live parties are skipped with a pointer to party close.
This commit is contained in:
parent
6799a57405
commit
a011e4b03c
6 changed files with 133 additions and 9 deletions
81
tests/85-clean.bats
Normal file
81
tests/85-clean.bats
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
#!/usr/bin/env bats
|
||||
#
|
||||
# party clean: remove the caller's own dead party dirs. Mistake-proofing
|
||||
# gates mirror cmd_close: own-basename glob, no symlinks, [ -O ], and a
|
||||
# dead socket. Liveness is faked through PARTY_TMUX stubs so no real
|
||||
# server or group membership is needed.
|
||||
|
||||
load 'helpers'
|
||||
|
||||
setup() {
|
||||
setup_party_sandbox
|
||||
load_party_lib
|
||||
}
|
||||
|
||||
teardown() { teardown_party_sandbox; }
|
||||
|
||||
@test "clean removes a dead leftover dir" {
|
||||
ensure_party_dir "$USER" ghost
|
||||
run "$PARTY_BIN" clean
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"removed"*"ghost"* ]]
|
||||
[ ! -d "$PARTY_SOCKET_DIR/party-$USER:ghost.d" ]
|
||||
}
|
||||
|
||||
@test "clean removes a crash-before-bind dir (no sock at all)" {
|
||||
mkdir "$PARTY_SOCKET_DIR/party-$USER:stillborn.d"
|
||||
run "$PARTY_BIN" clean
|
||||
[ "$status" -eq 0 ]
|
||||
[ ! -d "$PARTY_SOCKET_DIR/party-$USER:stillborn.d" ]
|
||||
}
|
||||
|
||||
@test "clean skips a live party and says to use close" {
|
||||
cat > "$PARTY_TMP/tmux-ok" <<'EOF'
|
||||
#!/bin/sh
|
||||
exit 0
|
||||
EOF
|
||||
chmod +x "$PARTY_TMP/tmux-ok"
|
||||
export PARTY_TMUX="$PARTY_TMP/tmux-ok"
|
||||
ensure_party_dir "$USER" running
|
||||
run "$PARTY_BIN" clean
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"skipping"*"running"* ]]
|
||||
[[ "$output" == *"party close"* ]]
|
||||
[ -d "$PARTY_SOCKET_DIR/party-$USER:running.d" ]
|
||||
}
|
||||
|
||||
@test "clean never follows a planted symlink" {
|
||||
mkdir "$PARTY_TMP/target"
|
||||
: > "$PARTY_TMP/target/precious"
|
||||
ln -s "$PARTY_TMP/target" "$PARTY_SOCKET_DIR/party-$USER:lnk.d"
|
||||
run "$PARTY_BIN" clean
|
||||
[ "$status" -eq 0 ]
|
||||
[ -e "$PARTY_TMP/target/precious" ]
|
||||
[ -L "$PARTY_SOCKET_DIR/party-$USER:lnk.d" ]
|
||||
}
|
||||
|
||||
@test "clean ignores other users' dirs" {
|
||||
ensure_party_dir nobody theirparty
|
||||
run "$PARTY_BIN" clean
|
||||
[ "$status" -eq 0 ]
|
||||
[ -d "$PARTY_SOCKET_DIR/party-nobody:theirparty.d" ]
|
||||
}
|
||||
|
||||
@test "clean with nothing to do says so" {
|
||||
run "$PARTY_BIN" clean
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"nothing to clean"* ]]
|
||||
}
|
||||
|
||||
@test "clean rejects arguments" {
|
||||
run "$PARTY_BIN" clean extra
|
||||
[ "$status" -eq 2 ]
|
||||
}
|
||||
|
||||
@test "host's EEXIST message recommends party clean" {
|
||||
ensure_party_dir "$USER" blocked
|
||||
export TMUX_PARTY_GROUP="$(id -gn)"
|
||||
run "$PARTY_BIN" host blocked
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"party clean"* ]]
|
||||
}
|
||||
|
|
@ -564,7 +564,7 @@ STUB
|
|||
# deliberately do NOT auto-clean: the same code path triggers on a
|
||||
# concurrent in-flight host attempt for the same name, and racing
|
||||
# rm -rf calls would wipe each other's fresh dirs.
|
||||
# Recovery is a manual `rm -rf` per the error message.
|
||||
# Recovery is `party clean` per the error message.
|
||||
party_dir="$PARTY_SOCKET_DIR/party-$USER:resurrect.d"
|
||||
mkdir -p "$party_dir"
|
||||
: > "$party_dir/sock"
|
||||
|
|
@ -572,7 +572,7 @@ STUB
|
|||
run "$PARTY_BIN" host resurrect
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" == *"already exists"* ]]
|
||||
[[ "$output" == *"rm -rf $party_dir"* ]]
|
||||
[[ "$output" == *"party clean"* ]]
|
||||
|
||||
# The leftover dir is untouched — proves we did not race-clean.
|
||||
[ -d "$party_dir" ]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue