01255d37
test: the e2e suite pins the refusal's words for run, status and send
a73x 2026-08-26 06:24
Commit message
test/e2e.sh
| Old | New | ||
|---|---|---|---|
| @@ -396,6 +396,13 @@ HYKEY="${TMPDIR:-/tmp}/mux-e2e-hydkey-$$" | |||
| 396 | HYSTATE="${TMPDIR:-/tmp}/mux-e2e-hyd-state-$$" | 396 | HYSTATE="${TMPDIR:-/tmp}/mux-e2e-hyd-state-$$" |
| 397 | HYWALL="$HYSTATE/mux/wall" | 397 | HYWALL="$HYSTATE/mux/wall" |
| 398 | D65PID="" | 398 | D65PID="" |
| 399 | # The refused-attach leg: its own daemon, because its assertions are about | ||
| 400 | # what a daemon says to a name it does NOT have, and a socket shared with | ||
| 401 | # another leg would let that leg's sessions decide what "does not have" | ||
| 402 | # means. | ||
| 403 | SOCK66="${TMPDIR:-/tmp}/muxd-e2e-refuse-$$.sock" | ||
| 404 | REFSTATE="${TMPDIR:-/tmp}/mux-e2e-refuse-state-$$" | ||
| 405 | D66PID="" | ||
| 399 | D54PID="" | 406 | D54PID="" |
| 400 | D55PID="" | 407 | D55PID="" |
| 401 | D56PID="" | 408 | D56PID="" |
| @@ -1352,6 +1359,7 @@ cleanup() { | |||
| 1352 | [ -n "${D63PID:-}" ] && kill "$D63PID" 2>/dev/null || true | 1359 | [ -n "${D63PID:-}" ] && kill "$D63PID" 2>/dev/null || true |
| 1353 | [ -n "${D64PID:-}" ] && kill "$D64PID" 2>/dev/null || true | 1360 | [ -n "${D64PID:-}" ] && kill "$D64PID" 2>/dev/null || true |
| 1354 | [ -n "${D65PID:-}" ] && kill "$D65PID" 2>/dev/null || true | 1361 | [ -n "${D65PID:-}" ] && kill "$D65PID" 2>/dev/null || true |
| 1362 | [ -n "${D66PID:-}" ] && kill "$D66PID" 2>/dev/null || true | ||
| 1355 | # The ssh-agents the forwarding legs start. Not mux processes and so not | 1363 | # The ssh-agents the forwarding legs start. Not mux processes and so not |
| 1356 | # the leak sweep's business, but they are daemons this file forked: left | 1364 | # the leak sweep's business, but they are daemons this file forked: left |
| 1357 | # alive they outlive the suite holding a private key, which is the one | 1365 | # alive they outlive the suite holding a private key, which is the one |
| @@ -1405,6 +1413,7 @@ cleanup() { | |||
| 1405 | [ -S "$SOCK60" ] && "$MUXD" stop --sock "$SOCK60" 2>/dev/null || true | 1413 | [ -S "$SOCK60" ] && "$MUXD" stop --sock "$SOCK60" 2>/dev/null || true |
| 1406 | [ -S "$SOCK61" ] && "$MUXD" stop --sock "$SOCK61" 2>/dev/null || true | 1414 | [ -S "$SOCK61" ] && "$MUXD" stop --sock "$SOCK61" 2>/dev/null || true |
| 1407 | [ -S "$SOCK64" ] && "$MUXD" stop --sock "$SOCK64" 2>/dev/null || true | 1415 | [ -S "$SOCK64" ] && "$MUXD" stop --sock "$SOCK64" 2>/dev/null || true |
| 1416 | [ -S "$SOCK66" ] && "$MUXD" stop --sock "$SOCK66" 2>/dev/null || true | ||
| 1408 | 1417 | ||
| 1409 | # ---- the leak sweep (hygiene kit, 6a) ---- | 1418 | # ---- the leak sweep (hygiene kit, 6a) ---- |
| 1410 | # Here rather than at the bottom of the file, which `set -e` reaches only | 1419 | # Here rather than at the bottom of the file, which `set -e` reaches only |
| @@ -1421,7 +1430,8 @@ cleanup() { | |||
| 1421 | "$D32PID" "$D33PID" "$D34PID" "$D35PID" "$D36PID" "$D37PID" \ | 1430 | "$D32PID" "$D33PID" "$D34PID" "$D35PID" "$D36PID" "$D37PID" \ |
| 1422 | "$D38PID" "$D39PID" "$D40PID" "$D41PID" "$D42PID" "$D43PID" "$D54PID" \ | 1431 | "$D38PID" "$D39PID" "$D40PID" "$D41PID" "$D42PID" "$D43PID" "$D54PID" \ |
| 1423 | "$D55PID" "$D56PID" "$D57PID" "$D58PID" "$D59PID" \ | 1432 | "$D55PID" "$D56PID" "$D57PID" "$D58PID" "$D59PID" \ |
| 1424 | "$D60PID" "$D61PID" "$D62PID" "$D63PID" "$D64PID" "$D65PID" | 1433 | "$D60PID" "$D61PID" "$D62PID" "$D63PID" "$D64PID" "$D65PID" \ |
| 1434 | "$D66PID" | ||
| 1425 | _leak=0 | 1435 | _leak=0 |
| 1426 | leak_sweep "$_rc" || _leak=1 | 1436 | leak_sweep "$_rc" || _leak=1 |
| 1427 | 1437 | ||
| @@ -1521,7 +1531,9 @@ cleanup() { | |||
| 1521 | "$OUT.hyd.d" "$OUT.hydcap" "$OUT.hydcap.err" "$OUT.hydpc" "$OUT.hydgrid" \ | 1531 | "$OUT.hyd.d" "$OUT.hydcap" "$OUT.hydcap.err" "$OUT.hydpc" "$OUT.hydgrid" \ |
| 1522 | "$OUT.hydsta" "$OUT.hydstb" "$OUT.hydghost" "$OUT.hydpre" "$OUT.hydfa" \ | 1532 | "$OUT.hydsta" "$OUT.hydstb" "$OUT.hydghost" "$OUT.hydpre" "$OUT.hydfa" \ |
| 1523 | "$OUT.hydstop" "$OUT.hydfcap" "$OUT.hydfcap.err" "$OUT.hydfpc" \ | 1533 | "$OUT.hydstop" "$OUT.hydfcap" "$OUT.hydfcap.err" "$OUT.hydfpc" \ |
| 1524 | "$OUT.hydfold" "$OUT.hydfgrid" "$SOCK64" "$HYKEY" | 1534 | "$OUT.hydfold" "$OUT.hydfgrid" "$SOCK64" "$HYKEY" \ |
| 1535 | "$OUT.ref.d" "$OUT.refrun" "$OUT.refstatus" "$OUT.refsend" \ | ||
| 1536 | "$OUT.refalive" "$OUT.refstop" "$SOCK66" | ||
| 1525 | # ...and the non-tty capture that leg's session feeds. | 1537 | # ...and the non-tty capture that leg's session feeds. |
| 1526 | rm -f "$OUT.nogate" | 1538 | rm -f "$OUT.nogate" |
| 1527 | # ...and its other half: the paste capture and the file nvim wrote, which | 1539 | # ...and its other half: the paste capture and the file nvim wrote, which |
| @@ -8719,8 +8731,78 @@ D65PID="" | |||
| 8719 | rm -rf "$HYSTATE" | 8731 | rm -rf "$HYSTATE" |
| 8720 | ok "a saved local line comes back as a fresh session, by wall and by fold; a remote one joins only" | 8732 | ok "a saved local line comes back as a fresh session, by wall and by fold; a remote one joins only" |
| 8721 | 8733 | ||
| 8722 | [ "$OK_COUNT" = "74" ] || { | 8734 | # --------------------------------------------------------------------------- |
| 8723 | echo "e2e FAIL: $OK_COUNT scenario checkpoints ran, the pin says 74 —" | 8735 | # A refused attach is not a shell that exited. |
| 8736 | # | ||
| 8737 | # muxa attaches at 0x0, and a 0x0 attach is join-only: the daemon refuses a | ||
| 8738 | # name it does not hold by sending exit_status 1 and closing — the same frame | ||
| 8739 | # a real shell's exit sends. muxa used to report that as | ||
| 8740 | # `{"reason":"session_ended","exit_code":1}` and `{"error":"session ended"}`, | ||
| 8741 | # telling an agent a command had run and failed when no shell ever existed, | ||
| 8742 | # while `status` got no answer at all and blamed the daemon (`DaemonGone`). | ||
| 8743 | # The snapshot tells the two apart — a served attach always sends one first | ||
| 8744 | # — and what this leg pins is the words an agent actually parses. | ||
| 8745 | mkdir -p "$REFSTATE" | ||
| 8746 | XDG_STATE_HOME="$REFSTATE" "$MUXD" run --sock "$SOCK66" --shell /bin/sh > "$OUT.ref.d" 2>&1 & | ||
| 8747 | D66PID=$! | ||
| 8748 | wait_sock "$SOCK66" "$OUT.ref.d" "refused-attach daemon never bound" | ||
| 8749 | |||
| 8750 | # Each verb twice over: the words it must say, and the words it must not. | ||
| 8751 | # The negative half is the whole regression — a reply that added "attach | ||
| 8752 | # refused" while still claiming a session ended would pass a one-sided grep. | ||
| 8753 | refuse_leg() { | ||
| 8754 | _out="$OUT.ref$1" | ||
| 8755 | shift | ||
| 8756 | set +e | ||
| 8757 | XDG_STATE_HOME="$REFSTATE" timeout 20 "$MUXA" "$@" --sock "$SOCK66" \ | ||
| 8758 | --session nosuch --timeout 5000 > "$_out" 2>&1 | ||
| 8759 | _rc=$? | ||
| 8760 | set -e | ||
| 8761 | [ "$_rc" -eq 1 ] || { | ||
| 8762 | echo "e2e FAIL: refused-attach: muxa $1 on a missing session exited $_rc, want 1:" | ||
| 8763 | cat "$_out"; exit 1; } | ||
| 8764 | grep -qF '"error":"attach refused"' "$_out" || { | ||
| 8765 | echo "e2e FAIL: refused-attach: muxa $1 did not name the refusal:" | ||
| 8766 | cat "$_out"; exit 1; } | ||
| 8767 | grep -qF 'so nosuch must already exist' "$_out" || { | ||
| 8768 | echo "e2e FAIL: refused-attach: muxa $1 did not name the session asked for:" | ||
| 8769 | cat "$_out"; exit 1; } | ||
| 8770 | grep -qF 'room for one more client' "$_out" || { | ||
| 8771 | echo "e2e FAIL: refused-attach: muxa $1 blamed absence for a refusal that has two causes:" | ||
| 8772 | cat "$_out"; exit 1; } | ||
| 8773 | grep -qF 'session_ended' "$_out" && { | ||
| 8774 | echo "e2e FAIL: refused-attach: muxa $1 still reports a session that ended:" | ||
| 8775 | cat "$_out"; exit 1; } | ||
| 8776 | grep -qF 'session ended' "$_out" && { | ||
| 8777 | echo "e2e FAIL: refused-attach: muxa $1 still reports a session that ended:" | ||
| 8778 | cat "$_out"; exit 1; } | ||
| 8779 | grep -qF 'DaemonGone' "$_out" && { | ||
| 8780 | echo "e2e FAIL: refused-attach: muxa $1 blamed the daemon for a missing name:" | ||
| 8781 | cat "$_out"; exit 1; } | ||
| 8782 | return 0 | ||
| 8783 | } | ||
| 8784 | refuse_leg run run true | ||
| 8785 | refuse_leg status status | ||
| 8786 | refuse_leg send send x | ||
| 8787 | |||
| 8788 | # ...and the daemon that said no three times is still serving. Refusing is | ||
| 8789 | # an answer, not a fault: a daemon that died on a typed `--session` would | ||
| 8790 | # turn one bad name into everyone else's outage. | ||
| 8791 | XDG_STATE_HOME="$REFSTATE" timeout 20 "$MUXA" status --sock "$SOCK66" \ | ||
| 8792 | --session 0 > "$OUT.refalive" 2>&1 || { | ||
| 8793 | echo "e2e FAIL: refused-attach: the daemon stopped answering after refusing:" | ||
| 8794 | cat "$OUT.refalive"; exit 1; } | ||
| 8795 | grep -qF '"cols":' "$OUT.refalive" || { | ||
| 8796 | echo "e2e FAIL: refused-attach: status on the live session is not a status reply:" | ||
| 8797 | cat "$OUT.refalive"; exit 1; } | ||
| 8798 | |||
| 8799 | assert_stopped "$SOCK66" "$D66PID" "refused-attach" "$OUT.refstop" | ||
| 8800 | D66PID="" | ||
| 8801 | rm -rf "$REFSTATE" | ||
| 8802 | ok "muxa names a refused attach instead of a shell that never ran" | ||
| 8803 | |||
| 8804 | [ "$OK_COUNT" = "75" ] || { | ||
| 8805 | echo "e2e FAIL: $OK_COUNT scenario checkpoints ran, the pin says 75 —" | ||
| 8724 | echo " a scenario was added (update the pin) or silently lost" | 8806 | echo " a scenario was added (update the pin) or silently lost" |
| 8725 | exit 1 | 8807 | exit 1 |
| 8726 | } | 8808 | } |