05ab5eeb
test: a cold attach is three ssh runs — endpoint, start, endpoint
a73x 2026-08-28 19:53
Commit message
test/e2e_04_handoff.sh
| Old | New | ||
|---|---|---|---|
| @@ -7,8 +7,9 @@ | |||
| 7 | # per daemon: the handoff dials the DEFAULT socket on the far side, and the | 7 | # per daemon: the handoff dials the DEFAULT socket on the far side, and the |
| 8 | # far side is this box, so each scenario's default socket has to be one of | 8 | # far side is this box, so each scenario's default socket has to be one of |
| 9 | # ours rather than the operator's. Two daemons, no more — the one a cold | 9 | # ours rather than the operator's. Two daemons, no more — the one a cold |
| 10 | # attach auto-starts, and the key-mismatch one that cannot be shared | 10 | # attach starts by running `muxd start` over the shim, and the key-mismatch |
| 11 | # because it holds a key nothing else on this box has. | 11 | # one that cannot be shared because it holds a key nothing else on this box |
| 12 | # has. | ||
| 12 | SSHIM_DIR="${TMPDIR:-/tmp}/muxd-e2e-sshim-$$" | 13 | SSHIM_DIR="${TMPDIR:-/tmp}/muxd-e2e-sshim-$$" |
| 13 | defer_rm "$SSHIM_DIR" | 14 | defer_rm "$SSHIM_DIR" |
| 14 | SSHIM_PIDLOG="$SSHIM_DIR/pids" | 15 | SSHIM_PIDLOG="$SSHIM_DIR/pids" |
| @@ -90,9 +91,10 @@ HPATH="$SSHIM_DIR:$(dirname "$MUXD"):$PATH" | |||
| 90 | # attempt below would fail at DNS without ever dialling. | 91 | # attempt below would fail at DNS without ever dialling. |
| 91 | HHOST="mux-e2e@127.0.0.1" | 92 | HHOST="mux-e2e@127.0.0.1" |
| 92 | HCACHE="$XDG_CACHE_HOME/mux/hosts/$HHOST" | 93 | HCACHE="$XDG_CACHE_HOME/mux/hosts/$HHOST" |
| 93 | # (a) COLD: no daemon, no cache. The attach has to produce the daemon (via | 94 | # (a) COLD: no daemon, no cache. The attach has to produce the daemon — |
| 94 | # `muxd endpoint`'s own auto-start), fetch coordinates over the shim, and | 95 | # `muxd endpoint` refuses a box that has none, and the CLIENT answers that |
| 95 | # END UP ON QUIC — and that last part is proven by observation rather than | 96 | # by running `muxd start` over the shim — fetch coordinates over the shim, |
| 97 | # and END UP ON QUIC — and that last part is proven by observation rather than | ||
| 96 | # inference: the ssh the announce arrived on is killed by the client on | 98 | # inference: the ssh the announce arrived on is killed by the client on |
| 97 | # QUIC success, so once its pid is OBSERVED gone, a second marker still | 99 | # QUIC success, so once its pid is OBSERVED gone, a second marker still |
| 98 | # making the round trip can only be riding QUIC. The pipe's owner is dead. | 100 | # making the round trip can only be riding QUIC. The pipe's owner is dead. |
| @@ -108,12 +110,20 @@ wait_for "$OUT.h1" "cold-one" 25 || { | |||
| 108 | echo " A client that blocks here read no announce line off the ssh pipe." | 110 | echo " A client that blocks here read no announce line off the ssh pipe." |
| 109 | cat "$OUT.h1" "$OUT.h1.err" 2>/dev/null; exit 1; } | 111 | cat "$OUT.h1" "$OUT.h1.err" 2>/dev/null; exit 1; } |
| 110 | 112 | ||
| 111 | # Exactly one ssh, and its pid, from the log rather than from ps. | 113 | # Exactly three ssh runs, and the LAST one's pid, from the log rather than |
| 114 | # from ps. Three is the cold shape and it is bounded: `muxd endpoint` on a | ||
| 115 | # box with no daemon, then `muxd start`, then `muxd endpoint` again. Never | ||
| 116 | # a fourth — the ask buys one start and one retry — and the count is what | ||
| 117 | # says so: a client that looped would show four here, not a hang. | ||
| 112 | HSHIMS=$(wc -l < "$SSHIM_PIDLOG") | 118 | HSHIMS=$(wc -l < "$SSHIM_PIDLOG") |
| 113 | [ "$HSHIMS" -eq 1 ] || { | 119 | [ "$HSHIMS" -eq 3 ] || { |
| 114 | echo "e2e FAIL: cold handoff ran $HSHIMS ssh invocations, want exactly 1" | 120 | echo "e2e FAIL: cold handoff ran $HSHIMS ssh invocations, want exactly 3" |
| 121 | echo " (muxd endpoint on an empty box, muxd start, muxd endpoint)" | ||
| 115 | cat "$SSHIM_PIDLOG"; exit 1; } | 122 | cat "$SSHIM_PIDLOG"; exit 1; } |
| 116 | HSHIMPID=$(head -1 "$SSHIM_PIDLOG") | 123 | # The LAST, not the first: the first two are the refusal and the start, and |
| 124 | # both are already dead by construction. The ssh whose death proves QUIC | ||
| 125 | # took over is the one that carried the announce. | ||
| 126 | HSHIMPID=$(tail -1 "$SSHIM_PIDLOG") | ||
| 117 | wait_pid_gone "$HSHIMPID" "cold handoff: QUIC took over, so ssh must be gone" | 127 | wait_pid_gone "$HSHIMPID" "cold handoff: QUIC took over, so ssh must be gone" |
| 118 | # The second marker is typed only now, after the death was OBSERVED, so its | 128 | # The second marker is typed only now, after the death was OBSERVED, so its |
| 119 | # round trip is traffic that moved after the pipe's owner died — by | 129 | # round trip is traffic that moved after the pipe's owner died — by |
| @@ -129,12 +139,15 @@ wait_for "$OUT.h1" "cold-two" 20 || { | |||
| 129 | cat "$OUT.h1" "$OUT.h1.err" 2>/dev/null; exit 1; } | 139 | cat "$OUT.h1" "$OUT.h1.err" 2>/dev/null; exit 1; } |
| 130 | pipe_detach "cold handoff client" | 140 | pipe_detach "cold handoff client" |
| 131 | 141 | ||
| 132 | # The daemon `muxd endpoint` started, by the pid its own up-line reported — | 142 | # The daemon the CLIENT started, by the pid `muxd start`'s own up-line |
| 133 | # the only handle this suite has on a process that is nobody's child. Same | 143 | # reported — the only handle this suite has on a process that is nobody's |
| 144 | # child. The line is `muxd start`'s now, not `muxd endpoint`'s, and it | ||
| 145 | # reaches this file the same way ssh's own stderr does: inherited. Same | ||
| 134 | # accepted gap as the M13 blocks: a failure above leaves it untracked, and | 146 | # accepted gap as the M13 blocks: a failure above leaves it untracked, and |
| 135 | # the trap's stop-by-socket is what covers that. | 147 | # the trap's stop-by-socket is what covers that. |
| 136 | grep -q '^muxd endpoint: starting' "$OUT.h1.err" || { | 148 | grep -q '^muxd: starting' "$OUT.h1.err" || { |
| 137 | echo "e2e FAIL: cold handoff printed no endpoint starting line" | 149 | echo "e2e FAIL: cold handoff printed no muxd start line — the client did not" |
| 150 | echo " start the daemon that muxd endpoint refused to" | ||
| 138 | cat "$OUT.h1.err"; exit 1; } | 151 | cat "$OUT.h1.err"; exit 1; } |
| 139 | HAPID=$(sed -n 's/.* pid=\([0-9]*\).*/\1/p' "$OUT.h1.err" | head -1) | 152 | HAPID=$(sed -n 's/.* pid=\([0-9]*\).*/\1/p' "$OUT.h1.err" | head -1) |
| 140 | defer_kill "$HAPID" | 153 | defer_kill "$HAPID" |