37d38ee4
refactor: the trap reads a register, not four hand-kept lists
a73x 2026-08-26 18:34
Commit message
test/e2e.sh
| Old | New | ||
|---|---|---|---|
| @@ -94,16 +94,121 @@ done | |||
| 94 | echo " daemon can still report a command's real exit code" | 94 | echo " daemon can still report a command's real exit code" |
| 95 | exit 1; } | 95 | exit 1; } |
| 96 | 96 | ||
| 97 | # ---- the cleanup registry --------------------------------------------- | ||
| 98 | # Every process and every artifact a leg creates is REGISTERED where it is | ||
| 99 | # created, and the EXIT trap walks the registers. Before this, cleanup() | ||
| 100 | # carried four hand-maintained lists naming ~137 $SOCKnn/$DnnPID variables, | ||
| 101 | # and a leg added without all four edits leaked: 102 captures were missing | ||
| 102 | # from them by 2026-08-19, enough that `make soak` refused to start. A list | ||
| 103 | # kept somewhere other than the code it describes is a list that goes | ||
| 104 | # stale, so there is no list — registering IS the statement that creates | ||
| 105 | # the thing. | ||
| 106 | # | ||
| 107 | # Captures are the exception, and deliberately so: every one of them is | ||
| 108 | # spelled from $OUT, and the trap removes that whole set by the same | ||
| 109 | # pattern leak_sweep already reads it by. A pattern cannot forget a leg, | ||
| 110 | # and forgetting was the failure. What has to be registered is what no | ||
| 111 | # pattern can find — pids, and the artifacts spelled somewhere other than | ||
| 112 | # $OUT. | ||
| 113 | # | ||
| 114 | # Newline-joined strings rather than arrays: the shebang is /bin/sh and the | ||
| 115 | # build's shell gate lints this file as POSIX sh. No path here can hold a | ||
| 116 | # newline (every one is spelled from $TMPDIR, $OUT and $$ in this file), | ||
| 117 | # and cleanup sets IFS to a newline before walking them, so a $TMPDIR with | ||
| 118 | # a space in it still reads as one path. | ||
| 119 | E2E_KILL="" | ||
| 120 | E2E_SOCK="" | ||
| 121 | E2E_RM="" | ||
| 122 | |||
| 123 | # defer_kill PID... — a process the trap must end. Newest first, so | ||
| 124 | # teardown runs in the reverse of creation order and a client is signalled | ||
| 125 | # before the daemon it is attached to. | ||
| 126 | # | ||
| 127 | # An `if` rather than `[ -n "$_dk" ] && ...`, for wait_sock's reason: a | ||
| 128 | # false guard as the last command in a function becomes that function's | ||
| 129 | # exit status, and under `set -e` registering an empty pid would abort the | ||
| 130 | # caller. | ||
| 131 | defer_kill() { | ||
| 132 | for _dk in "$@"; do | ||
| 133 | if [ -n "$_dk" ]; then | ||
| 134 | # Already registered is not an error: pipe_mux names the same | ||
| 135 | # FIFO on every call, and a leg that starts two daemons on one | ||
| 136 | # path registers it twice. Registering twice must cost nothing, | ||
| 137 | # or callers start reasoning about who registered first. | ||
| 138 | case " | ||
| 139 | $E2E_KILL" in | ||
| 140 | *" | ||
| 141 | $_dk | ||
| 142 | "*) continue ;; | ||
| 143 | esac | ||
| 144 | E2E_KILL="$_dk | ||
| 145 | $E2E_KILL" | ||
| 146 | fi | ||
| 147 | done | ||
| 148 | } | ||
| 149 | |||
| 150 | # defer_sock PATH... — a path a daemon may be listening on. The trap asks | ||
| 151 | # `muxd stop` there before it kills anything and long before it unlinks the | ||
| 152 | # path: a daemon this shell never forked — one a proxy, `muxd start` or the | ||
| 153 | # handoff spawned — has no pid here, and the socket is the only handle | ||
| 154 | # there is. | ||
| 155 | defer_sock() { | ||
| 156 | for _ds in "$@"; do | ||
| 157 | if [ -n "$_ds" ]; then | ||
| 158 | # Already registered is not an error: pipe_mux names the same | ||
| 159 | # FIFO on every call, and a leg that starts two daemons on one | ||
| 160 | # path registers it twice. Registering twice must cost nothing, | ||
| 161 | # or callers start reasoning about who registered first. | ||
| 162 | case " | ||
| 163 | $E2E_SOCK" in | ||
| 164 | *" | ||
| 165 | $_ds | ||
| 166 | "*) continue ;; | ||
| 167 | esac | ||
| 168 | E2E_SOCK="$_ds | ||
| 169 | $E2E_SOCK" | ||
| 170 | fi | ||
| 171 | done | ||
| 172 | } | ||
| 173 | |||
| 174 | # defer_rm PATH... — an artifact the trap must remove: a key, a generated | ||
| 175 | # script, a private HOME, a state home. Registered at the line that spells | ||
| 176 | # the path, so the two can never drift apart. Files go out through the leak | ||
| 177 | # sweep's banking; directories are removed whole. | ||
| 178 | defer_rm() { | ||
| 179 | for _dr in "$@"; do | ||
| 180 | if [ -n "$_dr" ]; then | ||
| 181 | # Already registered is not an error: pipe_mux names the same | ||
| 182 | # FIFO on every call, and a leg that starts two daemons on one | ||
| 183 | # path registers it twice. Registering twice must cost nothing, | ||
| 184 | # or callers start reasoning about who registered first. | ||
| 185 | case " | ||
| 186 | $E2E_RM" in | ||
| 187 | *" | ||
| 188 | $_dr | ||
| 189 | "*) continue ;; | ||
| 190 | esac | ||
| 191 | E2E_RM="$_dr | ||
| 192 | $E2E_RM" | ||
| 193 | fi | ||
| 194 | done | ||
| 195 | } | ||
| 196 | |||
| 197 | |||
| 97 | SOCK="${TMPDIR:-/tmp}/muxd-e2e-$$.sock" | 198 | SOCK="${TMPDIR:-/tmp}/muxd-e2e-$$.sock" |
| 199 | defer_sock "$SOCK" | ||
| 98 | OUT="${TMPDIR:-/tmp}/mux-e2e-out-$$" | 200 | OUT="${TMPDIR:-/tmp}/mux-e2e-out-$$" |
| 99 | # M10: hermetic XDG homes. Key-default scenarios must see OUR key or none, | 201 | # M10: hermetic XDG homes. Key-default scenarios must see OUR key or none, |
| 100 | # never the developer's real ~/.config/mux/key. | 202 | # never the developer's real ~/.config/mux/key. |
| 101 | XDG_CONFIG_HOME="${TMPDIR:-/tmp}/mux-e2e-cfg-$$" | 203 | XDG_CONFIG_HOME="${TMPDIR:-/tmp}/mux-e2e-cfg-$$" |
| 204 | defer_rm "$XDG_CONFIG_HOME" | ||
| 102 | XDG_STATE_HOME="${TMPDIR:-/tmp}/mux-e2e-state-$$" | 205 | XDG_STATE_HOME="${TMPDIR:-/tmp}/mux-e2e-state-$$" |
| 206 | defer_rm "$XDG_STATE_HOME" | ||
| 103 | # M14: and the same for the handoff's per-host cache. It holds a KEY, and | 207 | # M14: and the same for the handoff's per-host cache. It holds a KEY, and |
| 104 | # the M14 scenarios both read and poison it — neither of which may ever | 208 | # the M14 scenarios both read and poison it — neither of which may ever |
| 105 | # touch the developer's real ~/.cache/mux. | 209 | # touch the developer's real ~/.cache/mux. |
| 106 | XDG_CACHE_HOME="${TMPDIR:-/tmp}/mux-e2e-cache-$$" | 210 | XDG_CACHE_HOME="${TMPDIR:-/tmp}/mux-e2e-cache-$$" |
| 211 | defer_rm "$XDG_CACHE_HOME" | ||
| 107 | export XDG_CONFIG_HOME XDG_STATE_HOME XDG_CACHE_HOME | 212 | export XDG_CONFIG_HOME XDG_STATE_HOME XDG_CACHE_HOME |
| 108 | # ...and the same argument for $SHELL, which is not an XDG home but is read | 213 | # ...and the same argument for $SHELL, which is not an XDG home but is read |
| 109 | # the same way: every daemon this suite AUTO-STARTS gets no --shell flag and | 214 | # the same way: every daemon this suite AUTO-STARTS gets no --shell flag and |
| @@ -132,62 +237,63 @@ unset MUX_KEY_FILE | |||
| 132 | # asserting against the developer's keyring. The legs that want an agent | 237 | # asserting against the developer's keyring. The legs that want an agent |
| 133 | # export one per command, at a path this file made. | 238 | # export one per command, at a path this file made. |
| 134 | unset SSH_AUTH_SOCK | 239 | unset SSH_AUTH_SOCK |
| 135 | # Second daemon, used only by the M7 abort scenario; declared here so the | 240 | # Second daemon, used only by the M7 abort scenario. |
| 136 | # trap below can reference them under `set -u` before they are ever started. | ||
| 137 | SOCK2="${TMPDIR:-/tmp}/muxd-e2e-abort-$$.sock" | 241 | SOCK2="${TMPDIR:-/tmp}/muxd-e2e-abort-$$.sock" |
| 138 | D2PID="" | 242 | defer_sock "$SOCK2" |
| 139 | # Third daemon, for the restart scenario: it gets killed and started again on | 243 | # Third daemon, for the restart scenario: it gets killed and started again on |
| 140 | # the same path, so it cannot share the long-lived one. | 244 | # the same path, so it cannot share the long-lived one. |
| 141 | SOCK3="${TMPDIR:-/tmp}/muxd-e2e-restart-$$.sock" | 245 | SOCK3="${TMPDIR:-/tmp}/muxd-e2e-restart-$$.sock" |
| 142 | D3PID="" | 246 | defer_sock "$SOCK3" |
| 143 | # Fourth daemon, for the M8 --quic scenario: it is the only one holding a UDP | 247 | # Fourth daemon, for the M8 --quic scenario: it is the only one holding a UDP |
| 144 | # port, so it gets its own path rather than sharing the long-lived one. | 248 | # port, so it gets its own path rather than sharing the long-lived one. |
| 145 | SOCK4="${TMPDIR:-/tmp}/muxd-e2e-quic-$$.sock" | 249 | SOCK4="${TMPDIR:-/tmp}/muxd-e2e-quic-$$.sock" |
| 250 | defer_sock "$SOCK4" "$SOCK4.nokey" "$SOCK4.second" | ||
| 146 | QKEY="${TMPDIR:-/tmp}/mux-e2e-key-$$" | 251 | QKEY="${TMPDIR:-/tmp}/mux-e2e-key-$$" |
| 147 | D4PID="" | 252 | defer_rm "$QKEY" "$QKEY.wrong" "$QKEY.bad" |
| 148 | # A port out of the way of the ephemeral range, made per-run so two suites can | 253 | # A port out of the way of the ephemeral range, made per-run so two suites can |
| 149 | # overlap. Collisions surface as a loud bind failure, never as a silent pass. | 254 | # overlap. Collisions surface as a loud bind failure, never as a silent pass. |
| 150 | QPORT=$(( 21000 + ($$ % 4000) )) | 255 | QPORT=$(( 21000 + ($$ % 4000) )) |
| 151 | # M9 prediction: each scenario needs a session whose LINE DISCIPLINE it | 256 | # M9 prediction: each scenario needs a session whose LINE DISCIPLINE it |
| 152 | # controls, so they cannot share the long-lived /bin/sh daemon. | 257 | # controls, so they cannot share the long-lived /bin/sh daemon. |
| 153 | SOCK5="${TMPDIR:-/tmp}/muxd-e2e-pred-$$.sock" | 258 | SOCK5="${TMPDIR:-/tmp}/muxd-e2e-pred-$$.sock" |
| 154 | D5PID="" | 259 | defer_sock "$SOCK5" |
| 155 | SOCK6="${TMPDIR:-/tmp}/muxd-e2e-pw-$$.sock" | 260 | SOCK6="${TMPDIR:-/tmp}/muxd-e2e-pw-$$.sock" |
| 156 | D6PID="" | 261 | defer_sock "$SOCK6" |
| 157 | SOCK7="${TMPDIR:-/tmp}/muxd-e2e-raw-$$.sock" | 262 | SOCK7="${TMPDIR:-/tmp}/muxd-e2e-raw-$$.sock" |
| 158 | D7PID="" | 263 | defer_sock "$SOCK7" |
| 159 | PWSH="${TMPDIR:-/tmp}/mux-e2e-pw-$$.sh" | 264 | PWSH="${TMPDIR:-/tmp}/mux-e2e-pw-$$.sh" |
| 265 | defer_rm "$PWSH" | ||
| 160 | # M10 key-resolution daemons. Two, not one: the first scenario's client | 266 | # M10 key-resolution daemons. Two, not one: the first scenario's client |
| 161 | # detaches and its daemon is killed, and the second must not be sharing | 267 | # detaches and its daemon is killed, and the second must not be sharing |
| 162 | # either. Ports in bands of their own so a concurrent suite cannot collide. | 268 | # either. Ports in bands of their own so a concurrent suite cannot collide. |
| 163 | SOCK9="${TMPDIR:-/tmp}/muxd-e2e-envkey-$$.sock" | 269 | SOCK9="${TMPDIR:-/tmp}/muxd-e2e-envkey-$$.sock" |
| 164 | D9PID="" | 270 | defer_sock "$SOCK9" |
| 165 | SOCK10="${TMPDIR:-/tmp}/muxd-e2e-flagwins-$$.sock" | 271 | SOCK10="${TMPDIR:-/tmp}/muxd-e2e-flagwins-$$.sock" |
| 166 | D10PID="" | 272 | defer_sock "$SOCK10" |
| 167 | QPORT2=$(( 26000 + ($$ % 4000) )) | 273 | QPORT2=$(( 26000 + ($$ % 4000) )) |
| 168 | QPORT3=$(( 31000 + ($$ % 4000) )) | 274 | QPORT3=$(( 31000 + ($$ % 4000) )) |
| 169 | # M10 `muxd start`. These daemons are spawned DETACHED, so the suite never | 275 | # M10 `muxd start`. These daemons are spawned DETACHED, so the suite never |
| 170 | # holds their pids as shell jobs — it reads them off the up-line and kills | 276 | # holds their pids as shell jobs — it reads them off the up-line and kills |
| 171 | # by that tracked pid, never by name. | 277 | # by that tracked pid, never by name. |
| 172 | SOCK8="${TMPDIR:-/tmp}/muxd-e2e-start-$$.sock" | 278 | SOCK8="${TMPDIR:-/tmp}/muxd-e2e-start-$$.sock" |
| 279 | defer_sock "$SOCK8" | ||
| 173 | SOCK8T="${TMPDIR:-/tmp}/muxd-e2e-trunc-$$.sock" | 280 | SOCK8T="${TMPDIR:-/tmp}/muxd-e2e-trunc-$$.sock" |
| 281 | defer_sock "$SOCK8T" | ||
| 174 | SOCK11="${TMPDIR:-/tmp}/muxd-e2e-goal-$$.sock" | 282 | SOCK11="${TMPDIR:-/tmp}/muxd-e2e-goal-$$.sock" |
| 283 | defer_sock "$SOCK11" | ||
| 175 | QPORT4=$(( 36000 + ($$ % 4000) )) | 284 | QPORT4=$(( 36000 + ($$ % 4000) )) |
| 176 | SPID="" | ||
| 177 | TPID="" | ||
| 178 | GPID="" | ||
| 179 | # M12 pty scenarios. Each needs a daemon whose grid size it owns: tp2 | 285 | # M12 pty scenarios. Each needs a daemon whose grid size it owns: tp2 |
| 180 | # resizes the grid twice and tp1's session is a scrollback-generating | 286 | # resizes the grid twice and tp1's session is a scrollback-generating |
| 181 | # wrapper, so neither can share the long-lived /bin/sh daemon. | 287 | # wrapper, so neither can share the long-lived /bin/sh daemon. |
| 182 | SOCK12="${TMPDIR:-/tmp}/muxd-e2e-tp2-$$.sock" | 288 | SOCK12="${TMPDIR:-/tmp}/muxd-e2e-tp2-$$.sock" |
| 183 | D12PID="" | 289 | defer_sock "$SOCK12" |
| 184 | SOCK13="${TMPDIR:-/tmp}/muxd-e2e-tp1-$$.sock" | 290 | SOCK13="${TMPDIR:-/tmp}/muxd-e2e-tp1-$$.sock" |
| 185 | D13PID="" | 291 | defer_sock "$SOCK13" |
| 186 | # tp1's session: a wrapper that fills the scrollback and then becomes cat. | 292 | # tp1's session: a wrapper that fills the scrollback and then becomes cat. |
| 187 | TP1SH="${TMPDIR:-/tmp}/mux-e2e-tp1-$$.sh" | 293 | TP1SH="${TMPDIR:-/tmp}/mux-e2e-tp1-$$.sh" |
| 294 | defer_rm "$TP1SH" | ||
| 188 | # tp1 runs its fixture in the BACKGROUND — the tear has to happen while the | 295 | # tp1 runs its fixture in the BACKGROUND — the tear has to happen while the |
| 189 | # script is mid-flight — so its pid is tracked and killed like a daemon's. | 296 | # script is mid-flight — so its pid is tracked and killed like a daemon's. |
| 190 | TP1PID="" | ||
| 191 | # M13 auto-start + stop. Two paths: the proxy arc's daemon is spawned BY | 297 | # M13 auto-start + stop. Two paths: the proxy arc's daemon is spawned BY |
| 192 | # the proxy, the pty leg's by local mux under the M12 fixture. Both are | 298 | # the proxy, the pty leg's by local mux under the M12 fixture. Both are |
| 193 | # torn down by `muxd stop` — the verb under test is also the cleanup, and | 299 | # torn down by `muxd stop` — the verb under test is also the cleanup, and |
| @@ -195,27 +301,33 @@ TP1PID="" | |||
| 195 | # each pid is read off the up-line its own spawner printed, which is the | 301 | # each pid is read off the up-line its own spawner printed, which is the |
| 196 | # only handle that can never name a bystander. | 302 | # only handle that can never name a bystander. |
| 197 | SOCK14="${TMPDIR:-/tmp}/muxd-e2e-astart-$$.sock" | 303 | SOCK14="${TMPDIR:-/tmp}/muxd-e2e-astart-$$.sock" |
| 304 | defer_sock "$SOCK14" | ||
| 198 | SOCK15="${TMPDIR:-/tmp}/muxd-e2e-aspty-$$.sock" | 305 | SOCK15="${TMPDIR:-/tmp}/muxd-e2e-aspty-$$.sock" |
| 199 | APID="" | 306 | defer_sock "$SOCK15" |
| 200 | PAPID="" | ||
| 201 | # M14 ssh→QUIC handoff. The shim that stands in for ssh (built where the | 307 | # M14 ssh→QUIC handoff. The shim that stands in for ssh (built where the |
| 202 | # scenarios run, declared here so the trap can reach it), and a RUNTIME DIR | 308 | # scenarios run), and a RUNTIME DIR |
| 203 | # per daemon: the handoff dials the DEFAULT socket on the far side, and the | 309 | # per daemon: the handoff dials the DEFAULT socket on the far side, and the |
| 204 | # far side is this box, so each scenario's default socket has to be one of | 310 | # far side is this box, so each scenario's default socket has to be one of |
| 205 | # ours rather than the operator's. Two daemons, no more — the one a cold | 311 | # ours rather than the operator's. Two daemons, no more — the one a cold |
| 206 | # attach auto-starts, and the key-mismatch one that cannot be shared | 312 | # attach auto-starts, and the key-mismatch one that cannot be shared |
| 207 | # because it holds a key nothing else on this box has. | 313 | # because it holds a key nothing else on this box has. |
| 208 | SSHIM_DIR="${TMPDIR:-/tmp}/muxd-e2e-sshim-$$" | 314 | SSHIM_DIR="${TMPDIR:-/tmp}/muxd-e2e-sshim-$$" |
| 315 | defer_rm "$SSHIM_DIR" | ||
| 209 | SSHIM_PIDLOG="$SSHIM_DIR/pids" | 316 | SSHIM_PIDLOG="$SSHIM_DIR/pids" |
| 210 | export SSHIM_PIDLOG | 317 | export SSHIM_PIDLOG |
| 211 | HRUN="${TMPDIR:-/tmp}/mux-e2e-hrun-$$" | 318 | HRUN="${TMPDIR:-/tmp}/mux-e2e-hrun-$$" |
| 319 | defer_rm "$HRUN" | ||
| 212 | HRUN2="${TMPDIR:-/tmp}/mux-e2e-hrun2-$$" | 320 | HRUN2="${TMPDIR:-/tmp}/mux-e2e-hrun2-$$" |
| 321 | defer_rm "$HRUN2" | ||
| 213 | SOCK16="$HRUN/muxd.sock" | 322 | SOCK16="$HRUN/muxd.sock" |
| 214 | SOCK17="$HRUN2/muxd.sock" | 323 | SOCK17="$HRUN2/muxd.sock" |
| 324 | defer_sock "$SOCK16" "$SOCK17" | ||
| 215 | HKEY="${TMPDIR:-/tmp}/mux-e2e-hkey-$$" | 325 | HKEY="${TMPDIR:-/tmp}/mux-e2e-hkey-$$" |
| 326 | defer_rm "$HKEY" | ||
| 216 | # A config home that is a FILE: `muxd endpoint` cannot create a key under | 327 | # A config home that is a FILE: `muxd endpoint` cannot create a key under |
| 217 | # it and cannot find one, which is the announce-none scenario's lever. | 328 | # it and cannot find one, which is the announce-none scenario's lever. |
| 218 | HCFGBAD="${TMPDIR:-/tmp}/mux-e2e-hnokey-$$" | 329 | HCFGBAD="${TMPDIR:-/tmp}/mux-e2e-hnokey-$$" |
| 330 | defer_rm "$HCFGBAD" | ||
| 219 | # Bands of their own, like every other port here, so a concurrent suite | 331 | # Bands of their own, like every other port here, so a concurrent suite |
| 220 | # cannot collide — and BELOW the ephemeral range (32768–60999 here), which | 332 | # cannot collide — and BELOW the ephemeral range (32768–60999 here), which |
| 221 | # for HDEADPORT is not housekeeping but the scenario's correctness. It is | 333 | # for HDEADPORT is not housekeeping but the scenario's correctness. It is |
| @@ -225,47 +337,38 @@ HCFGBAD="${TMPDIR:-/tmp}/mux-e2e-hnokey-$$" | |||
| 225 | # quietly asserts a heal that never had to happen. | 337 | # quietly asserts a heal that never had to happen. |
| 226 | HQPORT=$(( 11000 + ($$ % 4000) )) | 338 | HQPORT=$(( 11000 + ($$ % 4000) )) |
| 227 | HDEADPORT=$(( 16000 + ($$ % 4000) )) | 339 | HDEADPORT=$(( 16000 + ($$ % 4000) )) |
| 228 | HAPID="" | 340 | # The pipe_mux client in flight, and its FIFO. Both are registered by |
| 229 | HDPID="" | 341 | # pipe_mux itself; its `timeout` stays the primary guarantee and the trap |
| 230 | # The pipe_mux client in flight, and its FIFO. Bounded by its own | 342 | # is the backstop for a scenario that exits between pipe_mux and |
| 231 | # `timeout`, which stays the primary guarantee; this is the trap's backstop | 343 | # pipe_detach, leaving a client the shell would otherwise orphan. |
| 232 | # for a scenario that exits between pipe_mux and pipe_detach, leaving a | ||
| 233 | # client the shell would otherwise orphan. Declared here so the trap can | ||
| 234 | # read them under `set -u`. | ||
| 235 | PIPE_PID="" | ||
| 236 | PIPE_IN="" | ||
| 237 | # M-web. Three daemons (the passivity pin's, the hub-basic one, and the | 344 | # M-web. Three daemons (the passivity pin's, the hub-basic one, and the |
| 238 | # tear scenario's two incarnations share SOCK20), two hub processes, and | 345 | # tear scenario's two incarnations share SOCK20), two hub processes, and |
| 239 | # a port band of its own following the 5000-spacing convention — INSIDE | 346 | # a port band of its own following the 5000-spacing convention — INSIDE |
| 240 | # the ephemeral range, which is fine for ports we bind (only provably-DEAD | 347 | # the ephemeral range, which is fine for ports we bind (only provably-DEAD |
| 241 | # ports must stay below 32768; see HDEADPORT above). | 348 | # ports must stay below 32768; see HDEADPORT above). |
| 242 | SOCK18="${TMPDIR:-/tmp}/muxd-e2e-web-a-$$.sock" | 349 | SOCK18="${TMPDIR:-/tmp}/muxd-e2e-web-a-$$.sock" |
| 350 | defer_sock "$SOCK18" | ||
| 243 | SOCK19="${TMPDIR:-/tmp}/muxd-e2e-web-b-$$.sock" | 351 | SOCK19="${TMPDIR:-/tmp}/muxd-e2e-web-b-$$.sock" |
| 352 | defer_sock "$SOCK19" | ||
| 244 | SOCK20="${TMPDIR:-/tmp}/muxd-e2e-web-c-$$.sock" | 353 | SOCK20="${TMPDIR:-/tmp}/muxd-e2e-web-c-$$.sock" |
| 354 | defer_sock "$SOCK20" | ||
| 245 | WPORT=$(( 41000 + ($$ % 4000) )) | 355 | WPORT=$(( 41000 + ($$ % 4000) )) |
| 246 | WPORT2=$(( 46000 + ($$ % 4000) )) | 356 | WPORT2=$(( 46000 + ($$ % 4000) )) |
| 247 | D14PID="" | ||
| 248 | D15PID="" | ||
| 249 | D16PID="" | ||
| 250 | D17PID="" | ||
| 251 | W1PID="" | ||
| 252 | W2PID="" | ||
| 253 | WCLIPID="" | ||
| 254 | # M18. Two daemons — the CLI multi-session block's and the wall's — and one | 357 | # M18. Two daemons — the CLI multi-session block's and the wall's — and one |
| 255 | # more hub on the next 5000-spaced port. Only two sockets for four-and-some | 358 | # more hub on the next 5000-spaced port. Only two sockets for four-and-some |
| 256 | # sessions, which is the whole point of the milestone: sessions are named on | 359 | # sessions, which is the whole point of the milestone: sessions are named on |
| 257 | # one socket, not spread across one socket each. | 360 | # one socket, not spread across one socket each. |
| 258 | SOCK21="${TMPDIR:-/tmp}/muxd-e2e-m18-$$.sock" | 361 | SOCK21="${TMPDIR:-/tmp}/muxd-e2e-m18-$$.sock" |
| 362 | defer_sock "$SOCK21" | ||
| 259 | SOCK22="${TMPDIR:-/tmp}/muxd-e2e-m18web-$$.sock" | 363 | SOCK22="${TMPDIR:-/tmp}/muxd-e2e-m18web-$$.sock" |
| 364 | defer_sock "$SOCK22" | ||
| 260 | WPORT3=$(( 51000 + ($$ % 4000) )) | 365 | WPORT3=$(( 51000 + ($$ % 4000) )) |
| 261 | D18PID="" | ||
| 262 | D19PID="" | ||
| 263 | W3PID="" | ||
| 264 | # ...and a third, the only M18 daemon holding a UDP port: it serves the | 366 | # ...and a third, the only M18 daemon holding a UDP port: it serves the |
| 265 | # session socket AND a QUIC listener at once, which is what lets one block | 367 | # session socket AND a QUIC listener at once, which is what lets one block |
| 266 | # ask whether a session name means the same session on either transport. | 368 | # ask whether a session name means the same session on either transport. |
| 267 | # Next 5000-spaced band after WPORT3. | 369 | # Next 5000-spaced band after WPORT3. |
| 268 | SOCK23="${TMPDIR:-/tmp}/muxd-e2e-m18quic-$$.sock" | 370 | SOCK23="${TMPDIR:-/tmp}/muxd-e2e-m18quic-$$.sock" |
| 371 | defer_sock "$SOCK23" | ||
| 269 | QPORT5=$(( 56000 + ($$ % 4000) )) | 372 | QPORT5=$(( 56000 + ($$ % 4000) )) |
| 270 | # A key of its own rather than the M8 block's $QKEY: that one is rm_swept | 373 | # A key of its own rather than the M8 block's $QKEY: that one is rm_swept |
| 271 | # the moment the M8 scenarios finish (see the sweep after the key-source | 374 | # the moment the M8 scenarios finish (see the sweep after the key-source |
| @@ -273,7 +376,7 @@ QPORT5=$(( 56000 + ($$ % 4000) )) | |||
| 273 | # deleted file would make this block's daemon fail to bind for a reason | 376 | # deleted file would make this block's daemon fail to bind for a reason |
| 274 | # that has nothing to do with sessions. | 377 | # that has nothing to do with sessions. |
| 275 | M18KEY="${TMPDIR:-/tmp}/mux-e2e-m18key-$$" | 378 | M18KEY="${TMPDIR:-/tmp}/mux-e2e-m18key-$$" |
| 276 | D20PID="" | 379 | defer_rm "$M18KEY" |
| 277 | 380 | ||
| 278 | # The bell leg's own daemon. A socket of its own is load-bearing rather than | 381 | # The bell leg's own daemon. A socket of its own is load-bearing rather than |
| 279 | # tidiness, and the argument is at the leg itself: that scenario counts BEL | 382 | # tidiness, and the argument is at the leg itself: that scenario counts BEL |
| @@ -282,7 +385,7 @@ D20PID="" | |||
| 282 | # attaching there is told so as `ESC]0;...BEL` — which would land in the | 385 | # attaching there is told so as `ESC]0;...BEL` — which would land in the |
| 283 | # capture and make the count assert something other than what it says. | 386 | # capture and make the count assert something other than what it says. |
| 284 | SOCK24="${TMPDIR:-/tmp}/muxd-e2e-bell-$$.sock" | 387 | SOCK24="${TMPDIR:-/tmp}/muxd-e2e-bell-$$.sock" |
| 285 | D21PID="" | 388 | defer_sock "$SOCK24" |
| 286 | 389 | ||
| 287 | # The dynamic-wall leg: one daemon, one hub restarted three times, and a | 390 | # The dynamic-wall leg: one daemon, one hub restarted three times, and a |
| 288 | # STATE HOME of its own on the 61000 band — the last 5000-spaced one that | 391 | # STATE HOME of its own on the 61000 band — the last 5000-spaced one that |
| @@ -293,82 +396,78 @@ D21PID="" | |||
| 293 | # it would be some other block's. Never the developer's ~/.local/state either; that is | 396 | # it would be some other block's. Never the developer's ~/.local/state either; that is |
| 294 | # why every muxweb here is spawned with the override in front of it. | 397 | # why every muxweb here is spawned with the override in front of it. |
| 295 | SOCK25="${TMPDIR:-/tmp}/muxd-e2e-dynwall-$$.sock" | 398 | SOCK25="${TMPDIR:-/tmp}/muxd-e2e-dynwall-$$.sock" |
| 399 | defer_sock "$SOCK25" | ||
| 296 | WPORT4=$(( 61000 + ($$ % 4000) )) | 400 | WPORT4=$(( 61000 + ($$ % 4000) )) |
| 297 | DWSTATE="${TMPDIR:-/tmp}/mux-e2e-dynwall-state-$$" | 401 | DWSTATE="${TMPDIR:-/tmp}/mux-e2e-dynwall-state-$$" |
| 298 | D22PID="" | 402 | defer_rm "$DWSTATE" |
| 299 | W4PID="" | ||
| 300 | 403 | ||
| 301 | # The CLI wall (`mux wall`): its own daemon, so its two sessions can't be | 404 | # The CLI wall (`mux wall`): its own daemon, so its two sessions can't be |
| 302 | # confused with any other block's. | 405 | # confused with any other block's. |
| 303 | SOCK26="${TMPDIR:-/tmp}/muxd-e2e-cliwall-$$.sock" | 406 | SOCK26="${TMPDIR:-/tmp}/muxd-e2e-cliwall-$$.sock" |
| 304 | D23PID="" | 407 | defer_sock "$SOCK26" |
| 305 | 408 | ||
| 306 | # The prefix chord (Ctrl-\ as a command key): its own daemon, so a chord | 409 | # The prefix chord (Ctrl-\ as a command key): its own daemon, so a chord |
| 307 | # that fails to detach cannot strand another block's session. | 410 | # that fails to detach cannot strand another block's session. |
| 308 | SOCK27="${TMPDIR:-/tmp}/muxd-e2e-prefix-$$.sock" | 411 | SOCK27="${TMPDIR:-/tmp}/muxd-e2e-prefix-$$.sock" |
| 309 | D24PID="" | 412 | defer_sock "$SOCK27" |
| 310 | 413 | ||
| 311 | # Ctrl-\ c (create a session and switch to it): its own daemon, because the | 414 | # Ctrl-\ c (create a session and switch to it): its own daemon, because the |
| 312 | # assertion is about which sessions EXIST — another block's session on the | 415 | # assertion is about which sessions EXIST — another block's session on the |
| 313 | # same daemon would change the name the chord picks. | 416 | # same daemon would change the name the chord picks. |
| 314 | SOCK28="${TMPDIR:-/tmp}/muxd-e2e-newsess-$$.sock" | 417 | SOCK28="${TMPDIR:-/tmp}/muxd-e2e-newsess-$$.sock" |
| 315 | D25PID="" | 418 | defer_sock "$SOCK28" |
| 316 | 419 | ||
| 317 | # Ctrl-\ n / Ctrl-\ p (step around the ring): its own daemon for the same | 420 | # Ctrl-\ n / Ctrl-\ p (step around the ring): its own daemon for the same |
| 318 | # reason as SOCK28, and more sharply — the ring IS the list of sessions on | 421 | # reason as SOCK28, and more sharply — the ring IS the list of sessions on |
| 319 | # one daemon, so a stray session from another block would change where a | 422 | # one daemon, so a stray session from another block would change where a |
| 320 | # step lands. | 423 | # step lands. |
| 321 | SOCK29="${TMPDIR:-/tmp}/muxd-e2e-ring-$$.sock" | 424 | SOCK29="${TMPDIR:-/tmp}/muxd-e2e-ring-$$.sock" |
| 322 | D26PID="" | 425 | defer_sock "$SOCK29" |
| 323 | |||
| 324 | # The zoom-era wall legs these belonged to are gone, but the cleanup trap | ||
| 325 | # cleanup trap still names every DxxPID and SOCKxx in bare form and the | ||
| 326 | # script runs under `set -u`. Bound empty so an unbound-variable abort never | ||
| 327 | # replaces a real failure's exit code; the legs that filled them are deleted. | ||
| 328 | SOCK30="" SOCK32="" SOCK38="" SOCK43="" SOCK44="" | ||
| 329 | M4STATE="" ZHASH="" ZHBSH="" ZHFLAG="" ZHSCRIPT="" | ||
| 330 | D27PID="" D29PID="" D35PID="" D40PID="" D41PID="" | ||
| 331 | 426 | ||
| 332 | # M5 (the self-attach refusal): its own daemon because the assertion reads | 427 | # M5 (the self-attach refusal): its own daemon because the assertion reads |
| 333 | # the SOCKET PATH out of a session shell's environment and compares it to | 428 | # the SOCKET PATH out of a session shell's environment and compares it to |
| 334 | # the one this block started — a shared daemon would make the comparison a | 429 | # the one this block started — a shared daemon would make the comparison a |
| 335 | # tautology about whichever block bound first. | 430 | # tautology about whichever block bound first. |
| 336 | SOCK31="${TMPDIR:-/tmp}/muxd-e2e-selfattach-$$.sock" | 431 | SOCK31="${TMPDIR:-/tmp}/muxd-e2e-selfattach-$$.sock" |
| 337 | D28PID="" | 432 | defer_sock "$SOCK31" |
| 338 | 433 | ||
| 339 | # The wheel pair. Each needs a scrollback of its own to scroll (or to prove | 434 | # The wheel pair. Each needs a scrollback of its own to scroll (or to prove |
| 340 | # it did not), which the long-lived /bin/sh daemon has no way to hold still, | 435 | # it did not), which the long-lived /bin/sh daemon has no way to hold still, |
| 341 | # and the second one needs a session that ASKS for the mouse — a mode that | 436 | # and the second one needs a session that ASKS for the mouse — a mode that |
| 342 | # would follow every other scenario sharing the daemon around. | 437 | # would follow every other scenario sharing the daemon around. |
| 343 | SOCK33="${TMPDIR:-/tmp}/muxd-e2e-wheel-$$.sock" | 438 | SOCK33="${TMPDIR:-/tmp}/muxd-e2e-wheel-$$.sock" |
| 344 | D30PID="" | 439 | defer_sock "$SOCK33" |
| 345 | WHEELSH="${TMPDIR:-/tmp}/mux-e2e-wheel-$$.sh" | 440 | WHEELSH="${TMPDIR:-/tmp}/mux-e2e-wheel-$$.sh" |
| 441 | defer_rm "$WHEELSH" | ||
| 346 | SOCK34="${TMPDIR:-/tmp}/muxd-e2e-appmouse-$$.sock" | 442 | SOCK34="${TMPDIR:-/tmp}/muxd-e2e-appmouse-$$.sock" |
| 347 | D31PID="" | 443 | defer_sock "$SOCK34" |
| 348 | MOUSESH="${TMPDIR:-/tmp}/mux-e2e-appmouse-$$.sh" | 444 | MOUSESH="${TMPDIR:-/tmp}/mux-e2e-appmouse-$$.sh" |
| 445 | defer_rm "$MOUSESH" | ||
| 349 | # The alternate-screen half of the wheel: its own daemon because the | 446 | # The alternate-screen half of the wheel: its own daemon because the |
| 350 | # session under test is a PAGER holding the alt screen for its whole life, | 447 | # session under test is a PAGER holding the alt screen for its whole life, |
| 351 | # which no other scenario could share a grid with. And the no-terminal | 448 | # which no other scenario could share a grid with. And the no-terminal |
| 352 | # half, whose session is a bare `cat` so that what reaches the pty is | 449 | # half, whose session is a bare `cat` so that what reaches the pty is |
| 353 | # echoed back into the grid the assertion reads. | 450 | # echoed back into the grid the assertion reads. |
| 354 | SOCK35="${TMPDIR:-/tmp}/muxd-e2e-pager-$$.sock" | 451 | SOCK35="${TMPDIR:-/tmp}/muxd-e2e-pager-$$.sock" |
| 355 | D32PID="" | 452 | defer_sock "$SOCK35" |
| 356 | LESSSH="${TMPDIR:-/tmp}/mux-e2e-pager-$$.sh" | 453 | LESSSH="${TMPDIR:-/tmp}/mux-e2e-pager-$$.sh" |
| 454 | defer_rm "$LESSSH" | ||
| 357 | LESSDATA="${TMPDIR:-/tmp}/mux-e2e-pager-$$.txt" | 455 | LESSDATA="${TMPDIR:-/tmp}/mux-e2e-pager-$$.txt" |
| 456 | defer_rm "$LESSDATA" | ||
| 358 | SOCK36="${TMPDIR:-/tmp}/muxd-e2e-pipestdin-$$.sock" | 457 | SOCK36="${TMPDIR:-/tmp}/muxd-e2e-pipestdin-$$.sock" |
| 359 | D33PID="" | 458 | defer_sock "$SOCK36" |
| 360 | 459 | ||
| 361 | # The focus-skip leg, on a daemon of its own for the grid-size reason: it | 460 | # The focus-skip leg, on a daemon of its own for the grid-size reason: it |
| 362 | # asserts on grid sizes and on how many clients a session ever had at once, | 461 | # asserts on grid sizes and on how many clients a session ever had at once, |
| 363 | # and a session another block created — or another block's client sitting | 462 | # and a session another block created — or another block's client sitting |
| 364 | # on this daemon — would make both numbers say nothing. | 463 | # on this daemon — would make both numbers say nothing. |
| 365 | SOCK37="${TMPDIR:-/tmp}/muxd-e2e-focusskip-$$.sock" | 464 | SOCK37="${TMPDIR:-/tmp}/muxd-e2e-focusskip-$$.sock" |
| 366 | D34PID="" | 465 | defer_sock "$SOCK37" |
| 367 | # The dead tile. Its own daemon because the leg needs a session name that | 466 | # The dead tile. Its own daemon because the leg needs a session name that |
| 368 | # does NOT exist — the daemon refuses the attach — and any other block's | 467 | # does NOT exist — the daemon refuses the attach — and any other block's |
| 369 | # daemon might have one by that name. | 468 | # daemon might have one by that name. |
| 370 | SOCK39="${TMPDIR:-/tmp}/muxd-e2e-deadtile-$$.sock" | 469 | SOCK39="${TMPDIR:-/tmp}/muxd-e2e-deadtile-$$.sock" |
| 371 | D36PID="" | 470 | defer_sock "$SOCK39" |
| 372 | 471 | ||
| 373 | # The wheel inside the focused tile. Two daemons for the wheel pair's own | 472 | # The wheel inside the focused tile. Two daemons for the wheel pair's own |
| 374 | # reason, turned up one notch: each needs a session whose SHELL is fixed for | 473 | # reason, turned up one notch: each needs a session whose SHELL is fixed for |
| @@ -377,32 +476,46 @@ D36PID="" | |||
| 377 | # terminal around. Both use the daemon's DEFAULT session, so the wall | 476 | # terminal around. Both use the daemon's DEFAULT session, so the wall |
| 378 | # spelling is a bare `--sock PATH` and nothing has to create anything. | 477 | # spelling is a bare `--sock PATH` and nothing has to create anything. |
| 379 | SOCK41="${TMPDIR:-/tmp}/muxd-e2e-wallwheel-$$.sock" | 478 | SOCK41="${TMPDIR:-/tmp}/muxd-e2e-wallwheel-$$.sock" |
| 380 | D38PID="" | 479 | defer_sock "$SOCK41" |
| 381 | ZWHEELSH="${TMPDIR:-/tmp}/mux-e2e-wallwheel-$$.sh" | 480 | ZWHEELSH="${TMPDIR:-/tmp}/mux-e2e-wallwheel-$$.sh" |
| 481 | defer_rm "$ZWHEELSH" | ||
| 382 | SOCK42="${TMPDIR:-/tmp}/muxd-e2e-wallappmouse-$$.sock" | 482 | SOCK42="${TMPDIR:-/tmp}/muxd-e2e-wallappmouse-$$.sock" |
| 383 | D39PID="" | 483 | defer_sock "$SOCK42" |
| 384 | ZMOUSESH="${TMPDIR:-/tmp}/mux-e2e-wallappmouse-$$.sh" | 484 | ZMOUSESH="${TMPDIR:-/tmp}/mux-e2e-wallappmouse-$$.sh" |
| 485 | defer_rm "$ZMOUSESH" | ||
| 385 | 486 | ||
| 386 | # The scrollback-rect leg: a focused tile's history page must own only its | 487 | # The scrollback-rect leg: a focused tile's history page must own only its |
| 387 | # sub-rect, so its daemon gets a socket of its own for the grid-size | 488 | # sub-rect, so its daemon gets a socket of its own for the grid-size |
| 388 | # reason every wall leg has. | 489 | # reason every wall leg has. |
| 389 | SOCK53="${TMPDIR:-/tmp}/muxd-e2e-sbrect-$$.sock" | 490 | SOCK53="${TMPDIR:-/tmp}/muxd-e2e-sbrect-$$.sock" |
| 491 | defer_sock "$SOCK53" | ||
| 390 | SOCK54="${TMPDIR:-/tmp}/muxd-e2e-fullscreen-$$.sock" | 492 | SOCK54="${TMPDIR:-/tmp}/muxd-e2e-fullscreen-$$.sock" |
| 493 | defer_sock "$SOCK54" | ||
| 391 | SOCK55="${TMPDIR:-/tmp}/muxd-e2e-resize-$$.sock" | 494 | SOCK55="${TMPDIR:-/tmp}/muxd-e2e-resize-$$.sock" |
| 495 | defer_sock "$SOCK55" | ||
| 392 | SOCK56="${TMPDIR:-/tmp}/muxd-e2e-spanclear-$$.sock" | 496 | SOCK56="${TMPDIR:-/tmp}/muxd-e2e-spanclear-$$.sock" |
| 497 | defer_sock "$SOCK56" | ||
| 393 | SOCK57="${TMPDIR:-/tmp}/muxd-e2e-hjkl-$$.sock" | 498 | SOCK57="${TMPDIR:-/tmp}/muxd-e2e-hjkl-$$.sock" |
| 499 | defer_sock "$SOCK57" | ||
| 394 | SOCK58="${TMPDIR:-/tmp}/muxd-e2e-splitbirth-$$.sock" | 500 | SOCK58="${TMPDIR:-/tmp}/muxd-e2e-splitbirth-$$.sock" |
| 501 | defer_sock "$SOCK58" | ||
| 395 | SOCK59="${TMPDIR:-/tmp}/muxd-e2e-lprrestore-$$.sock" | 502 | SOCK59="${TMPDIR:-/tmp}/muxd-e2e-lprrestore-$$.sock" |
| 503 | defer_sock "$SOCK59" | ||
| 396 | SOCK60="${TMPDIR:-/tmp}/muxd-e2e-lpheal-$$.sock" | 504 | SOCK60="${TMPDIR:-/tmp}/muxd-e2e-lpheal-$$.sock" |
| 505 | defer_sock "$SOCK60" | ||
| 397 | SOCK61="${TMPDIR:-/tmp}/muxd-e2e-lpdegrade-$$.sock" | 506 | SOCK61="${TMPDIR:-/tmp}/muxd-e2e-lpdegrade-$$.sock" |
| 507 | defer_sock "$SOCK61" | ||
| 398 | SOCK62="${TMPDIR:-/tmp}/muxd-e2e-promptA-$$.sock" | 508 | SOCK62="${TMPDIR:-/tmp}/muxd-e2e-promptA-$$.sock" |
| 509 | defer_sock "$SOCK62" | ||
| 399 | SOCK63="${TMPDIR:-/tmp}/muxd-e2e-promptB-$$.sock" | 510 | SOCK63="${TMPDIR:-/tmp}/muxd-e2e-promptB-$$.sock" |
| 511 | defer_sock "$SOCK63" | ||
| 400 | # The hydrated-create leg. One daemon, and it serves QUIC as well as its | 512 | # The hydrated-create leg. One daemon, and it serves QUIC as well as its |
| 401 | # socket: the leg's whole point is the LOCAL/remote split, so both halves | 513 | # socket: the leg's whole point is the LOCAL/remote split, so both halves |
| 402 | # have to be the same run of the same daemon or the comparison is between | 514 | # have to be the same run of the same daemon or the comparison is between |
| 403 | # two rigs rather than between two kinds of line. Short socket name on | 515 | # two rigs rather than between two kinds of line. Short socket name on |
| 404 | # purpose — the assertion reads a label bar back off a 70-column render. | 516 | # purpose — the assertion reads a label bar back off a 70-column render. |
| 405 | SOCK64="${TMPDIR:-/tmp}/muxd-e2e-hyd-$$.sock" | 517 | SOCK64="${TMPDIR:-/tmp}/muxd-e2e-hyd-$$.sock" |
| 518 | defer_sock "$SOCK64" | ||
| 406 | # Base 6000, below the 5000-spaced band the other QUIC ports share: every | 519 | # Base 6000, below the 5000-spaced band the other QUIC ports share: every |
| 407 | # base from 11000 up is already taken, and a DUPLICATED base passes only | 520 | # base from 11000 up is already taken, and a DUPLICATED base passes only |
| 408 | # for as long as the other leg's daemon happens to be dead by the time | 521 | # for as long as the other leg's daemon happens to be dead by the time |
| @@ -410,16 +523,18 @@ SOCK64="${TMPDIR:-/tmp}/muxd-e2e-hyd-$$.sock" | |||
| 410 | # suite's, which is why the base has to be the leg's own. | 523 | # suite's, which is why the base has to be the leg's own. |
| 411 | HYPORT=$(( 6000 + ($$ % 4000) )) | 524 | HYPORT=$(( 6000 + ($$ % 4000) )) |
| 412 | HYKEY="${TMPDIR:-/tmp}/mux-e2e-hydkey-$$" | 525 | HYKEY="${TMPDIR:-/tmp}/mux-e2e-hydkey-$$" |
| 526 | defer_rm "$HYKEY" | ||
| 413 | HYSTATE="${TMPDIR:-/tmp}/mux-e2e-hyd-state-$$" | 527 | HYSTATE="${TMPDIR:-/tmp}/mux-e2e-hyd-state-$$" |
| 528 | defer_rm "$HYSTATE" | ||
| 414 | HYWALL="$HYSTATE/mux/wall" | 529 | HYWALL="$HYSTATE/mux/wall" |
| 415 | D65PID="" | ||
| 416 | # The refused-attach leg: its own daemon, because its assertions are about | 530 | # The refused-attach leg: its own daemon, because its assertions are about |
| 417 | # what a daemon says to a name it does NOT have, and a socket shared with | 531 | # what a daemon says to a name it does NOT have, and a socket shared with |
| 418 | # another leg would let that leg's sessions decide what "does not have" | 532 | # another leg would let that leg's sessions decide what "does not have" |
| 419 | # means. | 533 | # means. |
| 420 | SOCK66="${TMPDIR:-/tmp}/muxd-e2e-refuse-$$.sock" | 534 | SOCK66="${TMPDIR:-/tmp}/muxd-e2e-refuse-$$.sock" |
| 535 | defer_sock "$SOCK66" | ||
| 421 | REFSTATE="${TMPDIR:-/tmp}/mux-e2e-refuse-state-$$" | 536 | REFSTATE="${TMPDIR:-/tmp}/mux-e2e-refuse-state-$$" |
| 422 | D66PID="" | 537 | defer_rm "$REFSTATE" |
| 423 | # The browser half of the same ruling: one daemon serving a socket AND a | 538 | # The browser half of the same ruling: one daemon serving a socket AND a |
| 424 | # QUIC listener, one hub, a state home of its own. Two ports, and the | 539 | # QUIC listener, one hub, a state home of its own. Two ports, and the |
| 425 | # 5000-spaced bands are exhausted — 61000 is the last one that fits under | 540 | # 5000-spaced bands are exhausted — 61000 is the last one that fits under |
| @@ -430,22 +545,24 @@ D66PID="" | |||
| 430 | # daemon failing to bind, which is also why the two halves cannot share a | 545 | # daemon failing to bind, which is also why the two halves cannot share a |
| 431 | # base. | 546 | # base. |
| 432 | SOCK67="${TMPDIR:-/tmp}/muxd-e2e-wg-$$.sock" | 547 | SOCK67="${TMPDIR:-/tmp}/muxd-e2e-wg-$$.sock" |
| 548 | defer_sock "$SOCK67" | ||
| 433 | WGPORT=$(( 65000 + ($$ % 250) )) | 549 | WGPORT=$(( 65000 + ($$ % 250) )) |
| 434 | WGQPORT=$(( 65250 + ($$ % 250) )) | 550 | WGQPORT=$(( 65250 + ($$ % 250) )) |
| 435 | WGKEY="${TMPDIR:-/tmp}/mux-e2e-wgkey-$$" | 551 | WGKEY="${TMPDIR:-/tmp}/mux-e2e-wgkey-$$" |
| 552 | defer_rm "$WGKEY" | ||
| 436 | WGSTATE="${TMPDIR:-/tmp}/mux-e2e-wg-state-$$" | 553 | WGSTATE="${TMPDIR:-/tmp}/mux-e2e-wg-state-$$" |
| 554 | defer_rm "$WGSTATE" | ||
| 437 | WGWALL="$WGSTATE/mux/wall" | 555 | WGWALL="$WGSTATE/mux/wall" |
| 438 | # The refusal-spin leg. Its own everything: a shim dir on PATH, a state | 556 | # The refusal-spin leg. Its own everything: a shim dir on PATH, a state |
| 439 | # home holding the wall it restores, and a dial log the shim appends to. | 557 | # home holding the wall it restores, and a dial log the shim appends to. |
| 440 | SOCK68="${TMPDIR:-/tmp}/muxd-e2e-sp-$$.sock" | 558 | SOCK68="${TMPDIR:-/tmp}/muxd-e2e-sp-$$.sock" |
| 559 | defer_sock "$SOCK68" | ||
| 441 | SPPORT=$(( 26000 + ($$ % 4000) )) | 560 | SPPORT=$(( 26000 + ($$ % 4000) )) |
| 442 | SPSTATE="${TMPDIR:-/tmp}/mux-e2e-sp-state-$$" | 561 | SPSTATE="${TMPDIR:-/tmp}/mux-e2e-sp-state-$$" |
| 562 | defer_rm "$SPSTATE" | ||
| 443 | SPDIR="${TMPDIR:-/tmp}/mux-e2e-sp-shim-$$" | 563 | SPDIR="${TMPDIR:-/tmp}/mux-e2e-sp-shim-$$" |
| 564 | defer_rm "$SPDIR" | ||
| 444 | SPINLOG="$SPDIR/dials" | 565 | SPINLOG="$SPDIR/dials" |
| 445 | D67PID="" | ||
| 446 | W5PID="" | ||
| 447 | D68PID="" | ||
| 448 | W6PID="" | ||
| 449 | # `muxd upgrade` — four daemons, because each one is a different daemon | 566 | # `muxd upgrade` — four daemons, because each one is a different daemon |
| 450 | # LIFECYCLE and no two can share a process: the same-binary leg's daemon | 567 | # LIFECYCLE and no two can share a process: the same-binary leg's daemon |
| 451 | # ends up running a second image, the rollback leg's is born with the abort | 568 | # ends up running a second image, the rollback leg's is born with the abort |
| @@ -453,46 +570,37 @@ W6PID="" | |||
| 453 | # QUIC leg's owns a UDP socket. They run one after another, so the last of | 570 | # QUIC leg's owns a UDP socket. They run one after another, so the last of |
| 454 | # them is the only leg here that needs a port. | 571 | # them is the only leg here that needs a port. |
| 455 | SOCK69="${TMPDIR:-/tmp}/muxd-e2e-upgrade-$$.sock" | 572 | SOCK69="${TMPDIR:-/tmp}/muxd-e2e-upgrade-$$.sock" |
| 573 | defer_sock "$SOCK69" | ||
| 456 | SOCK70="${TMPDIR:-/tmp}/muxd-e2e-uproll-$$.sock" | 574 | SOCK70="${TMPDIR:-/tmp}/muxd-e2e-uproll-$$.sock" |
| 575 | defer_sock "$SOCK70" | ||
| 457 | SOCK71="${TMPDIR:-/tmp}/muxd-e2e-upagent-$$.sock" | 576 | SOCK71="${TMPDIR:-/tmp}/muxd-e2e-upagent-$$.sock" |
| 577 | defer_sock "$SOCK71" | ||
| 458 | SOCK72="${TMPDIR:-/tmp}/muxd-e2e-upquic-$$.sock" | 578 | SOCK72="${TMPDIR:-/tmp}/muxd-e2e-upquic-$$.sock" |
| 579 | defer_sock "$SOCK72" | ||
| 459 | SOCK73="${TMPDIR:-/tmp}/muxd-e2e-stopgone-$$.sock" | 580 | SOCK73="${TMPDIR:-/tmp}/muxd-e2e-stopgone-$$.sock" |
| 581 | defer_sock "$SOCK73" | ||
| 460 | # The next 4000-wide band DOWN from the hydrate leg's 6000: every base from | 582 | # The next 4000-wide band DOWN from the hydrate leg's 6000: every base from |
| 461 | # 11000 up is taken, and the 61000+ tail above the ephemeral range is spoken | 583 | # 11000 up is taken, and the 61000+ tail above the ephemeral range is spoken |
| 462 | # for by the two browser ports. A collision here reads as this leg's daemon | 584 | # for by the two browser ports. A collision here reads as this leg's daemon |
| 463 | # failing to bind, the same verdict every other band gives. | 585 | # failing to bind, the same verdict every other band gives. |
| 464 | UPQPORT=$(( 2000 + ($$ % 4000) )) | 586 | UPQPORT=$(( 2000 + ($$ % 4000) )) |
| 465 | UPKEY="${TMPDIR:-/tmp}/mux-e2e-upkey-$$" | 587 | UPKEY="${TMPDIR:-/tmp}/mux-e2e-upkey-$$" |
| 588 | defer_rm "$UPKEY" | ||
| 466 | # A HOME of its own for the session shell. The title assertion below is | 589 | # A HOME of its own for the session shell. The title assertion below is |
| 467 | # about a title the SESSION set, and a distribution's rc file repaints the | 590 | # about a title the SESSION set, and a distribution's rc file repaints the |
| 468 | # window title from PROMPT_COMMAND on every prompt (shellint.bash_init says | 591 | # window title from PROMPT_COMMAND on every prompt (shellint.bash_init says |
| 469 | # so of Arch's) — read out of the developer's own dotfiles, this leg would | 592 | # so of Arch's) — read out of the developer's own dotfiles, this leg would |
| 470 | # assert on whatever their prompt happens to spell. | 593 | # assert on whatever their prompt happens to spell. |
| 471 | UPHOME="${TMPDIR:-/tmp}/mux-e2e-uphome-$$" | 594 | UPHOME="${TMPDIR:-/tmp}/mux-e2e-uphome-$$" |
| 595 | defer_rm "$UPHOME" | ||
| 472 | # The candidate binary the refusal leg offers: a copy, so its exec bit can | 596 | # The candidate binary the refusal leg offers: a copy, so its exec bit can |
| 473 | # be taken away without touching the one every other scenario runs. | 597 | # be taken away without touching the one every other scenario runs. |
| 474 | UPBIN="${TMPDIR:-/tmp}/mux-e2e-upcand-$$" | 598 | UPBIN="${TMPDIR:-/tmp}/mux-e2e-upcand-$$" |
| 599 | defer_rm "$UPBIN" | ||
| 475 | UPAGENT="${TMPDIR:-/tmp}/mux-e2e-upagent-$$.sock" | 600 | UPAGENT="${TMPDIR:-/tmp}/mux-e2e-upagent-$$.sock" |
| 601 | defer_rm "$UPAGENT" | ||
| 476 | UPAGKEY="${TMPDIR:-/tmp}/mux-e2e-upagkey-$$" | 602 | UPAGKEY="${TMPDIR:-/tmp}/mux-e2e-upagkey-$$" |
| 477 | D69PID="" | 603 | defer_rm "$UPAGKEY" "$UPAGKEY.pub" |
| 478 | D70PID="" | ||
| 479 | D71PID="" | ||
| 480 | D72PID="" | ||
| 481 | D73PID="" | ||
| 482 | UPAGPID="" | ||
| 483 | UPPCPID="" | ||
| 484 | UPCPID="" | ||
| 485 | D54PID="" | ||
| 486 | D55PID="" | ||
| 487 | D56PID="" | ||
| 488 | D57PID="" | ||
| 489 | D58PID="" | ||
| 490 | D59PID="" | ||
| 491 | D60PID="" | ||
| 492 | D61PID="" | ||
| 493 | D62PID="" | ||
| 494 | D63PID="" | ||
| 495 | D64PID="" | ||
| 496 | 604 | ||
| 497 | # The wall as attach HISTORY (phase 2). A daemon AND a state home of its | 605 | # The wall as attach HISTORY (phase 2). A daemon AND a state home of its |
| 498 | # own, for the dynamic-wall leg's reason turned up one notch: what these | 606 | # own, for the dynamic-wall leg's reason turned up one notch: what these |
| @@ -502,15 +610,18 @@ D64PID="" | |||
| 502 | # The daemon is separate because the tile spelling contains the socket | 610 | # The daemon is separate because the tile spelling contains the socket |
| 503 | # path, which is what the assertions grep for. | 611 | # path, which is what the assertions grep for. |
| 504 | SOCK40="${TMPDIR:-/tmp}/muxd-e2e-wallhist-$$.sock" | 612 | SOCK40="${TMPDIR:-/tmp}/muxd-e2e-wallhist-$$.sock" |
| 613 | defer_sock "$SOCK40" | ||
| 505 | WHSTATE="${TMPDIR:-/tmp}/mux-e2e-wallhist-state-$$" | 614 | WHSTATE="${TMPDIR:-/tmp}/mux-e2e-wallhist-state-$$" |
| 615 | defer_rm "$WHSTATE" | ||
| 506 | WHWALL="$WHSTATE/mux/wall" | 616 | WHWALL="$WHSTATE/mux/wall" |
| 507 | # A state home whose wall FILE is a directory: the unwritable case, which | 617 | # A state home whose wall FILE is a directory: the unwritable case, which |
| 508 | # has to warn and let the attach happen anyway. | 618 | # has to warn and let the attach happen anyway. |
| 509 | WHBAD="${TMPDIR:-/tmp}/mux-e2e-wallbad-$$" | 619 | WHBAD="${TMPDIR:-/tmp}/mux-e2e-wallbad-$$" |
| 620 | defer_rm "$WHBAD" | ||
| 510 | # And a third, for the `x` block: its wall is built by two attaches and | 621 | # And a third, for the `x` block: its wall is built by two attaches and |
| 511 | # then eaten by `x`, so it must start empty and stay its own. | 622 | # then eaten by `x`, so it must start empty and stay its own. |
| 512 | WHXSTATE="${TMPDIR:-/tmp}/mux-e2e-wallx-state-$$" | 623 | WHXSTATE="${TMPDIR:-/tmp}/mux-e2e-wallx-state-$$" |
| 513 | D37PID="" | 624 | defer_rm "$WHXSTATE" |
| 514 | 625 | ||
| 515 | # The convergence block: `mux TARGET` is a wall of one tile whose rect is | 626 | # The convergence block: `mux TARGET` is a wall of one tile whose rect is |
| 516 | # the whole terminal. Three daemons and three state homes, each of them its own | 627 | # the whole terminal. Three daemons and three state homes, each of them its own |
| @@ -518,21 +629,25 @@ D37PID="" | |||
| 518 | # back is the wall FILE, and the shared $XDG_STATE_HOME is every socket the | 629 | # back is the wall FILE, and the shared $XDG_STATE_HOME is every socket the |
| 519 | # suite has ever attached to. | 630 | # suite has ever attached to. |
| 520 | SOCK45="${TMPDIR:-/tmp}/muxd-e2e-converge-$$.sock" | 631 | SOCK45="${TMPDIR:-/tmp}/muxd-e2e-converge-$$.sock" |
| 632 | defer_sock "$SOCK45" | ||
| 521 | CVSTATE="${TMPDIR:-/tmp}/mux-e2e-converge-state-$$" | 633 | CVSTATE="${TMPDIR:-/tmp}/mux-e2e-converge-state-$$" |
| 634 | defer_rm "$CVSTATE" | ||
| 522 | CVWALL="$CVSTATE/mux/wall" | 635 | CVWALL="$CVSTATE/mux/wall" |
| 523 | D45PID="" | ||
| 524 | # The ring-grows-the-wall leg needs TWO state homes: one for the client | 636 | # The ring-grows-the-wall leg needs TWO state homes: one for the client |
| 525 | # under test, and one for the setup client whose attach must NOT leave a | 637 | # under test, and one for the setup client whose attach must NOT leave a |
| 526 | # tile the leg would then find already there. That absence is the case | 638 | # tile the leg would then find already there. That absence is the case |
| 527 | # under test — a sibling the daemon knows and the wall does not. | 639 | # under test — a sibling the daemon knows and the wall does not. |
| 528 | SOCK46="${TMPDIR:-/tmp}/muxd-e2e-ringgrow-$$.sock" | 640 | SOCK46="${TMPDIR:-/tmp}/muxd-e2e-ringgrow-$$.sock" |
| 641 | defer_sock "$SOCK46" | ||
| 529 | RGSTATE="${TMPDIR:-/tmp}/mux-e2e-ringgrow-state-$$" | 642 | RGSTATE="${TMPDIR:-/tmp}/mux-e2e-ringgrow-state-$$" |
| 643 | defer_rm "$RGSTATE" | ||
| 530 | RGOTHER="${TMPDIR:-/tmp}/mux-e2e-ringgrow-other-$$" | 644 | RGOTHER="${TMPDIR:-/tmp}/mux-e2e-ringgrow-other-$$" |
| 531 | D46PID="" | 645 | defer_rm "$RGOTHER" |
| 532 | # The exit-semantics leg: a session ending in the focused tile. | 646 | # The exit-semantics leg: a session ending in the focused tile. |
| 533 | SOCK47="${TMPDIR:-/tmp}/muxd-e2e-exitsem-$$.sock" | 647 | SOCK47="${TMPDIR:-/tmp}/muxd-e2e-exitsem-$$.sock" |
| 648 | defer_sock "$SOCK47" | ||
| 534 | XESTATE="${TMPDIR:-/tmp}/mux-e2e-exitsem-state-$$" | 649 | XESTATE="${TMPDIR:-/tmp}/mux-e2e-exitsem-state-$$" |
| 535 | D47PID="" | 650 | defer_rm "$XESTATE" |
| 536 | 651 | ||
| 537 | # Agent forwarding: one socket path, two daemons in turn. The positive leg | 652 | # Agent forwarding: one socket path, two daemons in turn. The positive leg |
| 538 | # ends by typing `exit`, which ends that daemon's only session and takes the | 653 | # ends by typing `exit`, which ends that daemon's only session and takes the |
| @@ -545,13 +660,15 @@ D47PID="" | |||
| 545 | # session shell, so the room it has is the room every other socket in this | 660 | # session shell, so the room it has is the room every other socket in this |
| 546 | # file was given. | 661 | # file was given. |
| 547 | SOCK48="${TMPDIR:-/tmp}/muxd-e2e-agentfwd-$$.sock" | 662 | SOCK48="${TMPDIR:-/tmp}/muxd-e2e-agentfwd-$$.sock" |
| 663 | defer_sock "$SOCK48" | ||
| 548 | SOCK51="${TMPDIR:-/tmp}/muxd-e2e-inband-$$.sock" | 664 | SOCK51="${TMPDIR:-/tmp}/muxd-e2e-inband-$$.sock" |
| 549 | D51PID="" | 665 | defer_sock "$SOCK51" |
| 550 | SOCK52="${TMPDIR:-/tmp}/muxd-e2e-cursor-$$.sock" | 666 | SOCK52="${TMPDIR:-/tmp}/muxd-e2e-cursor-$$.sock" |
| 551 | D52PID="" | 667 | defer_sock "$SOCK52" |
| 552 | AGENT48="${TMPDIR:-/tmp}/mux-e2e-agent-$$.sock" | 668 | AGENT48="${TMPDIR:-/tmp}/mux-e2e-agent-$$.sock" |
| 553 | AGENT48PID="" | 669 | defer_rm "$AGENT48" |
| 554 | AGENT48KEY="${TMPDIR:-/tmp}/mux-e2e-agentkey-$$" | 670 | AGENT48KEY="${TMPDIR:-/tmp}/mux-e2e-agentkey-$$" |
| 671 | defer_rm "$AGENT48KEY" "$AGENT48KEY.pub" | ||
| 555 | D42PID="" | 672 | D42PID="" |
| 556 | 673 | ||
| 557 | # The flip leg gets a daemon of its own, and not for isolation's sake: the | 674 | # The flip leg gets a daemon of its own, and not for isolation's sake: the |
| @@ -561,12 +678,17 @@ D42PID="" | |||
| 561 | # the leg would pass having proved nothing. Beside the sockets for the | 678 | # the leg would pass having proved nothing. Beside the sockets for the |
| 562 | # sun_path reason above; these are dialled from inside a session too. | 679 | # sun_path reason above; these are dialled from inside a session too. |
| 563 | SOCK49="${TMPDIR:-/tmp}/muxd-e2e-agentflip-$$.sock" | 680 | SOCK49="${TMPDIR:-/tmp}/muxd-e2e-agentflip-$$.sock" |
| 681 | defer_sock "$SOCK49" | ||
| 564 | AGENT49A="${TMPDIR:-/tmp}/mux-e2e-agent2a-$$.sock" | 682 | AGENT49A="${TMPDIR:-/tmp}/mux-e2e-agent2a-$$.sock" |
| 683 | defer_rm "$AGENT49A" | ||
| 565 | AGENT49B="${TMPDIR:-/tmp}/mux-e2e-agent2b-$$.sock" | 684 | AGENT49B="${TMPDIR:-/tmp}/mux-e2e-agent2b-$$.sock" |
| 685 | defer_rm "$AGENT49B" | ||
| 566 | AGENT49APID="" | 686 | AGENT49APID="" |
| 567 | AGENT49BPID="" | 687 | AGENT49BPID="" |
| 568 | AGENT49AKEY="${TMPDIR:-/tmp}/mux-e2e-agent2akey-$$" | 688 | AGENT49AKEY="${TMPDIR:-/tmp}/mux-e2e-agent2akey-$$" |
| 689 | defer_rm "$AGENT49AKEY" "$AGENT49AKEY.pub" | ||
| 569 | AGENT49BKEY="${TMPDIR:-/tmp}/mux-e2e-agent2bkey-$$" | 690 | AGENT49BKEY="${TMPDIR:-/tmp}/mux-e2e-agent2bkey-$$" |
| 691 | defer_rm "$AGENT49BKEY" "$AGENT49BKEY.pub" | ||
| 570 | D43PID="" | 692 | D43PID="" |
| 571 | FLIPAPID="" | 693 | FLIPAPID="" |
| 572 | 694 | ||
| @@ -574,6 +696,7 @@ FLIPAPID="" | |||
| 574 | # every other leg does: the wall scenario above stops its daemon on the way | 696 | # every other leg does: the wall scenario above stops its daemon on the way |
| 575 | # out, so there is nothing left to reuse. | 697 | # out, so there is nothing left to reuse. |
| 576 | SOCK50="${TMPDIR:-/tmp}/muxd-e2e-wallmouse-$$.sock" | 698 | SOCK50="${TMPDIR:-/tmp}/muxd-e2e-wallmouse-$$.sock" |
| 699 | defer_sock "$SOCK50" | ||
| 577 | D48PID="" | 700 | D48PID="" |
| 578 | 701 | ||
| 579 | # One counter out of a MUX_PREDICT_STATS line. The client prints exactly one | 702 | # One counter out of a MUX_PREDICT_STATS line. The client prints exactly one |
| @@ -742,6 +865,34 @@ wait_sock() { | |||
| 742 | } | 865 | } |
| 743 | } | 866 | } |
| 744 | 867 | ||
| 868 | # start_daemon SOCK LOG LABEL [muxd args...] — a daemon in the background, | ||
| 869 | # registered before it is waited for. Sets $DPID, the pid to end it by. | ||
| 870 | # $DPID is scratch: the NEXT start_daemon overwrites it, so a leg that | ||
| 871 | # still needs its daemon further down keeps the pid under a name of its | ||
| 872 | # own. The long-lived daemon is $D1PID for exactly that reason — it is | ||
| 873 | # read some 5,000 lines after it is started. | ||
| 874 | # | ||
| 875 | # The registration is the whole reason this exists. A `muxd run &` written | ||
| 876 | # out by hand is three statements — the spawn, the pid, the wait — plus a | ||
| 877 | # fourth in cleanup() saying how to end it, and the fourth is the one that | ||
| 878 | # got forgotten. Here the spawn IS the registration and there is no fourth | ||
| 879 | # place to edit. | ||
| 880 | # | ||
| 881 | # Only for the plain shape. A daemon that needs an environment in front of | ||
| 882 | # it writes its own spawn and calls defer_kill/defer_sock itself: `env` or | ||
| 883 | # a VAR=VAL prefix on a FUNCTION call does not scope to the function — in | ||
| 884 | # POSIX sh it assigns in THIS shell and the value stays there for every | ||
| 885 | # scenario after it. | ||
| 886 | start_daemon() { | ||
| 887 | _sds="$1"; _sdl="$2"; _sdlab="$3"; shift 3 | ||
| 888 | "$MUXD" run --sock "$_sds" "$@" > "$_sdl" 2>&1 & | ||
| 889 | DPID=$! | ||
| 890 | defer_kill "$DPID" | ||
| 891 | defer_sock "$_sds" | ||
| 892 | wait_sock "$_sds" "$_sdl" "$_sdlab" | ||
| 893 | } | ||
| 894 | |||
| 895 | |||
| 745 | # pipe_mux OUT ERR CMD... — a client on a plain pipe, and the pipe kept | 896 | # pipe_mux OUT ERR CMD... — a client on a plain pipe, and the pipe kept |
| 746 | # open. ERR is the stderr capture, "" to leave it on the suite's own. | 897 | # open. ERR is the stderr capture, "" to leave it on the suite's own. |
| 747 | # The suite's non-tty scenarios used to be `{ printf cmd; sleep 2; printf | 898 | # The suite's non-tty scenarios used to be `{ printf cmd; sleep 2; printf |
| @@ -759,6 +910,7 @@ wait_sock() { | |||
| 759 | pipe_mux() { | 910 | pipe_mux() { |
| 760 | PIPE_OUT="$1"; PIPE_ERR="$2"; shift 2 | 911 | PIPE_OUT="$1"; PIPE_ERR="$2"; shift 2 |
| 761 | PIPE_IN="$PIPE_OUT.in" | 912 | PIPE_IN="$PIPE_OUT.in" |
| 913 | defer_rm "$PIPE_IN" | ||
| 762 | rm -f "$PIPE_IN" | 914 | rm -f "$PIPE_IN" |
| 763 | mkfifo "$PIPE_IN" | 915 | mkfifo "$PIPE_IN" |
| 764 | exec 9<>"$PIPE_IN" | 916 | exec 9<>"$PIPE_IN" |
| @@ -768,6 +920,7 @@ pipe_mux() { | |||
| 768 | "$@" < "$PIPE_IN" > "$PIPE_OUT" & | 920 | "$@" < "$PIPE_IN" > "$PIPE_OUT" & |
| 769 | fi | 921 | fi |
| 770 | PIPE_PID=$! | 922 | PIPE_PID=$! |
| 923 | defer_kill "$PIPE_PID" | ||
| 771 | } | 924 | } |
| 772 | 925 | ||
| 773 | # pipe_send FMT [ARGS] — printf into the open client, same spelling the | 926 | # pipe_send FMT [ARGS] — printf into the open client, same spelling the |
| @@ -988,6 +1141,7 @@ watch_clients() { | |||
| 988 | sleep 0.2 | 1141 | sleep 0.2 |
| 989 | done ) > "$2" & | 1142 | done ) > "$2" & |
| 990 | WATCH_PID=$! | 1143 | WATCH_PID=$! |
| 1144 | defer_kill "$WATCH_PID" | ||
| 991 | } | 1145 | } |
| 992 | 1146 | ||
| 993 | # unwatch_clients FILE — stop sampling. | 1147 | # unwatch_clients FILE — stop sampling. |
| @@ -1348,519 +1502,93 @@ cleanup() { | |||
| 1348 | # it. Every verdict below is composed onto THIS number, never in place of | 1502 | # it. Every verdict below is composed onto THIS number, never in place of |
| 1349 | # it: a run that failed at scenario 6 exits with scenario 6's failure. | 1503 | # it: a run that failed at scenario 6 exits with scenario 6's failure. |
| 1350 | _rc=$? | 1504 | _rc=$? |
| 1351 | # `${DPID:-}` rather than `$DPID`: DPID is the one variable this trap | 1505 | # The registers are newline-joined and the paths in them may hold spaces |
| 1352 | # reads that is assigned AFTER the trap is installed, and the scenarios | 1506 | # (a $TMPDIR nobody here chose); a newline IFS is what keeps each entry |
| 1353 | # above the first daemon (--version) can fail before it ever is. Under | 1507 | # one entry. |
| 1354 | # `set -u` the bare form would abort the trap on an unbound variable, | 1508 | _oifs=$IFS |
| 1355 | # skipping the rm below — a failing suite would also leave its files. | 1509 | IFS=' |
| 1356 | [ -n "${DPID:-}" ] && kill "$DPID" 2>/dev/null || true | 1510 | ' |
| 1357 | # `|| true` on every one of these: under `set -e` a kill of an | 1511 | # Sockets first, and by the daemon's own verb. `muxd stop` on a path |
| 1358 | # already-dead pid would abort the trap itself, skipping the rm below and | 1512 | # nobody serves is a no-op that exits 0, and on a daemon this shell never |
| 1359 | # failing a suite that had actually passed. | 1513 | # forked — one a proxy, `muxd start` or the handoff spawned — it is the |
| 1360 | [ -n "$D2PID" ] && kill "$D2PID" 2>/dev/null || true | 1514 | # only handle there is. Before the kills, and long before the unlink |
| 1361 | [ -n "$D3PID" ] && kill "$D3PID" 2>/dev/null || true | 1515 | # below: unlinking first would leave a live daemon nothing could reach |
| 1362 | [ -n "$D4PID" ] && kill "$D4PID" 2>/dev/null || true | ||
| 1363 | [ -n "$D5PID" ] && kill "$D5PID" 2>/dev/null || true | ||
| 1364 | [ -n "$D6PID" ] && kill "$D6PID" 2>/dev/null || true | ||
| 1365 | [ -n "$D7PID" ] && kill "$D7PID" 2>/dev/null || true | ||
| 1366 | [ -n "$D9PID" ] && kill "$D9PID" 2>/dev/null || true | ||
| 1367 | [ -n "$D10PID" ] && kill "$D10PID" 2>/dev/null || true | ||
| 1368 | [ -n "$D12PID" ] && kill "$D12PID" 2>/dev/null || true | ||
| 1369 | [ -n "$D13PID" ] && kill "$D13PID" 2>/dev/null || true | ||
| 1370 | # The fixture, by the pid the suite holds. Killing it closes the pty | ||
| 1371 | # master, and that SIGHUPs the client on the slave — the same guarantee | ||
| 1372 | # a real terminal gives, which is why the fixture never reaps its own | ||
| 1373 | # child and this trap does not chase one. | ||
| 1374 | [ -n "$TP1PID" ] && kill "$TP1PID" 2>/dev/null || true | ||
| 1375 | # The agent-flip leg's backgrounded client, on the same guarantee: its | ||
| 1376 | # own client dies with the pty master this kill closes. | ||
| 1377 | [ -n "$FLIPAPID" ] && kill "$FLIPAPID" 2>/dev/null || true | ||
| 1378 | # Detached daemons: killed by the pid their own up-line reported. | ||
| 1379 | [ -n "$SPID" ] && kill "$SPID" 2>/dev/null || true | ||
| 1380 | [ -n "$TPID" ] && kill "$TPID" 2>/dev/null || true | ||
| 1381 | [ -n "$GPID" ] && kill "$GPID" 2>/dev/null || true | ||
| 1382 | # The M13 auto-started daemons, by the pid their spawner's up-line | ||
| 1383 | # reported. Cleared by the scenarios themselves once `muxd stop` has | ||
| 1384 | # been OBSERVED to end them, so a pid here means a failing run. | ||
| 1385 | [ -n "$APID" ] && kill "$APID" 2>/dev/null || true | ||
| 1386 | [ -n "$PAPID" ] && kill "$PAPID" 2>/dev/null || true | ||
| 1387 | # ...and the same two by socket, because a spawn that failed between | ||
| 1388 | # the fork and the up-line leaves a daemon this trap holds no pid for. | ||
| 1389 | # `muxd stop` on a path nobody serves is a no-op that exits 0. | ||
| 1390 | [ -n "${MUXD:-}" ] && "$MUXD" stop --sock "$SOCK14" >/dev/null 2>&1 || true | ||
| 1391 | [ -n "${MUXD:-}" ] && "$MUXD" stop --sock "$SOCK15" >/dev/null 2>&1 || true | ||
| 1392 | # M14's two, the same way and for the same reason: the cold-handoff | ||
| 1393 | # daemon is spawned by `muxd endpoint` and is nobody's child here, so | ||
| 1394 | # its pid is read off the up-line and the socket stop backstops the | ||
| 1395 | # window before that read. The stops come BEFORE the rm -rf below — | ||
| 1396 | # unlinking a runtime dir first would leave a live daemon this trap | ||
| 1397 | # could no longer reach by path. | ||
| 1398 | [ -n "$HDPID" ] && kill "$HDPID" 2>/dev/null || true | ||
| 1399 | [ -n "$HAPID" ] && kill "$HAPID" 2>/dev/null || true | ||
| 1400 | # The backgrounded clients, by tracked pid. Their `timeout` bounds them | ||
| 1401 | # anyway; this only shortens the wait on a run that failed between a | ||
| 1402 | # launch and its wait. | ||
| 1403 | # Whatever pipe_mux client a failing scenario left mid-flight, and the | ||
| 1404 | # FIFO that was its stdin. | ||
| 1405 | [ -n "$PIPE_PID" ] && kill "$PIPE_PID" 2>/dev/null || true | ||
| 1406 | [ -n "$PIPE_IN" ] && rm -f "$PIPE_IN" || true | ||
| 1407 | [ -n "${MUXD:-}" ] && "$MUXD" stop --sock "$SOCK16" >/dev/null 2>&1 || true | ||
| 1408 | [ -n "${MUXD:-}" ] && "$MUXD" stop --sock "$SOCK17" >/dev/null 2>&1 || true | ||
| 1409 | # M-web: hubs and daemons by tracked pid, then stop-by-socket for any | ||
| 1410 | # daemon that died between fork and up-line. Hoisted up here with the | ||
| 1411 | # other kills so that every kill precedes the sweep below — a daemon | ||
| 1412 | # killed AFTER it would be swept before it had written its verdict, and | ||
| 1413 | # the sweep's answer would be about a lifecycle that had not ended. | ||
| 1414 | [ -n "$W1PID" ] && kill "$W1PID" 2>/dev/null || true | ||
| 1415 | [ -n "$W2PID" ] && kill "$W2PID" 2>/dev/null || true | ||
| 1416 | [ -n "$WCLIPID" ] && kill "$WCLIPID" 2>/dev/null || true | ||
| 1417 | [ -n "$D14PID" ] && kill "$D14PID" 2>/dev/null || true | ||
| 1418 | [ -n "$D15PID" ] && kill "$D15PID" 2>/dev/null || true | ||
| 1419 | [ -n "$D16PID" ] && kill "$D16PID" 2>/dev/null || true | ||
| 1420 | [ -n "$D17PID" ] && kill "$D17PID" 2>/dev/null || true | ||
| 1421 | # M18's two daemons and its hub. A multi-session daemon holds N shells, | ||
| 1422 | # so one leaked pid here is N leaked processes — the kill is by the | ||
| 1423 | # tracked pid all the same, and killing the daemon closes every pty | ||
| 1424 | # master it owns, which is what ends the shells on the other side. | ||
| 1425 | [ -n "$W3PID" ] && kill "$W3PID" 2>/dev/null || true | ||
| 1426 | [ -n "$D18PID" ] && kill "$D18PID" 2>/dev/null || true | ||
| 1427 | [ -n "$D19PID" ] && kill "$D19PID" 2>/dev/null || true | ||
| 1428 | [ -n "$D20PID" ] && kill "$D20PID" 2>/dev/null || true | ||
| 1429 | [ -n "$D21PID" ] && kill "$D21PID" 2>/dev/null || true | ||
| 1430 | # The dynamic-wall leg's hub and daemon. The hub variable is re-assigned | ||
| 1431 | # across three incarnations on the same port, so a pid here is whichever | ||
| 1432 | # one the run died under. | ||
| 1433 | [ -n "$W4PID" ] && kill "$W4PID" 2>/dev/null || true | ||
| 1434 | [ -n "${W5PID:-}" ] && kill "$W5PID" 2>/dev/null || true | ||
| 1435 | [ -n "${W6PID:-}" ] && kill "$W6PID" 2>/dev/null || true | ||
| 1436 | [ -n "$D22PID" ] && kill "$D22PID" 2>/dev/null || true | ||
| 1437 | [ -n "$D23PID" ] && kill "$D23PID" 2>/dev/null || true | ||
| 1438 | [ -n "$D24PID" ] && kill "$D24PID" 2>/dev/null || true | ||
| 1439 | [ -n "$D25PID" ] && kill "$D25PID" 2>/dev/null || true | ||
| 1440 | [ -n "$D26PID" ] && kill "$D26PID" 2>/dev/null || true | ||
| 1441 | [ -n "$D27PID" ] && kill "$D27PID" 2>/dev/null || true | ||
| 1442 | [ -n "$D28PID" ] && kill "$D28PID" 2>/dev/null || true | ||
| 1443 | [ -n "$D29PID" ] && kill "$D29PID" 2>/dev/null || true | ||
| 1444 | [ -n "$D30PID" ] && kill "$D30PID" 2>/dev/null || true | ||
| 1445 | [ -n "$D31PID" ] && kill "$D31PID" 2>/dev/null || true | ||
| 1446 | [ -n "$D32PID" ] && kill "$D32PID" 2>/dev/null || true | ||
| 1447 | [ -n "$D33PID" ] && kill "$D33PID" 2>/dev/null || true | ||
| 1448 | [ -n "$D34PID" ] && kill "$D34PID" 2>/dev/null || true | ||
| 1449 | [ -n "$D35PID" ] && kill "$D35PID" 2>/dev/null || true | ||
| 1450 | [ -n "$D36PID" ] && kill "$D36PID" 2>/dev/null || true | ||
| 1451 | [ -n "$D37PID" ] && kill "$D37PID" 2>/dev/null || true | ||
| 1452 | [ -n "$D38PID" ] && kill "$D38PID" 2>/dev/null || true | ||
| 1453 | [ -n "$D39PID" ] && kill "$D39PID" 2>/dev/null || true | ||
| 1454 | [ -n "$D40PID" ] && kill "$D40PID" 2>/dev/null || true | ||
| 1455 | [ -n "$D41PID" ] && kill "$D41PID" 2>/dev/null || true | ||
| 1456 | [ -n "$D42PID" ] && kill "$D42PID" 2>/dev/null || true | ||
| 1457 | [ -n "$D43PID" ] && kill "$D43PID" 2>/dev/null || true | ||
| 1458 | [ -n "${D51PID:-}" ] && kill "$D51PID" 2>/dev/null || true | ||
| 1459 | [ -n "${D52PID:-}" ] && kill "$D52PID" 2>/dev/null || true | ||
| 1460 | [ -n "${D55PID:-}" ] && kill "$D55PID" 2>/dev/null || true | ||
| 1461 | [ -n "${D57PID:-}" ] && kill "$D57PID" 2>/dev/null || true | ||
| 1462 | [ -n "${D58PID:-}" ] && kill "$D58PID" 2>/dev/null || true | ||
| 1463 | [ -n "${D59PID:-}" ] && kill "$D59PID" 2>/dev/null || true | ||
| 1464 | [ -n "${D60PID:-}" ] && kill "$D60PID" 2>/dev/null || true | ||
| 1465 | [ -n "${D61PID:-}" ] && kill "$D61PID" 2>/dev/null || true | ||
| 1466 | [ -n "${D62PID:-}" ] && kill "$D62PID" 2>/dev/null || true | ||
| 1467 | [ -n "${D63PID:-}" ] && kill "$D63PID" 2>/dev/null || true | ||
| 1468 | [ -n "${D64PID:-}" ] && kill "$D64PID" 2>/dev/null || true | ||
| 1469 | [ -n "${D65PID:-}" ] && kill "$D65PID" 2>/dev/null || true | ||
| 1470 | [ -n "${D66PID:-}" ] && kill "$D66PID" 2>/dev/null || true | ||
| 1471 | # The upgrade legs' daemons. CONT first for AGENT48PID's reason turned | ||
| 1472 | # on a daemon: the non-executable-candidate refusal holds this one under | ||
| 1473 | # SIGSTOP while it takes the exec bit off the candidate, and a run that | ||
| 1474 | # dies inside that window leaves a process no SIGTERM can reach. | ||
| 1475 | [ -n "${D69PID:-}" ] && kill -CONT "$D69PID" 2>/dev/null || true | ||
| 1476 | [ -n "${D69PID:-}" ] && kill "$D69PID" 2>/dev/null || true | ||
| 1477 | [ -n "${D70PID:-}" ] && kill "$D70PID" 2>/dev/null || true | ||
| 1478 | [ -n "${D71PID:-}" ] && kill "$D71PID" 2>/dev/null || true | ||
| 1479 | [ -n "${D72PID:-}" ] && kill "$D72PID" 2>/dev/null || true | ||
| 1480 | [ -n "${D73PID:-}" ] && kill "$D73PID" 2>/dev/null || true | ||
| 1481 | [ -n "${UPPCPID:-}" ] && kill "$UPPCPID" 2>/dev/null || true | ||
| 1482 | [ -n "${UPCPID:-}" ] && kill "$UPCPID" 2>/dev/null || true | ||
| 1483 | # The ssh-agents the forwarding legs start. Not mux processes and so not | ||
| 1484 | # the leak sweep's business, but they are daemons this file forked: left | ||
| 1485 | # alive they outlive the suite holding a private key, which is the one | ||
| 1486 | # kind of leak worth chasing even on a green run. | ||
| 1487 | # CONT first: the mute-offerer leg holds this agent under SIGSTOP, and | ||
| 1488 | # a stopped process does not see SIGTERM until it runs again. | ||
| 1489 | [ -n "$AGENT48PID" ] && kill -CONT "$AGENT48PID" 2>/dev/null || true | ||
| 1490 | [ -n "$AGENT48PID" ] && kill "$AGENT48PID" 2>/dev/null || true | ||
| 1491 | [ -n "$AGENT49APID" ] && kill "$AGENT49APID" 2>/dev/null || true | ||
| 1492 | [ -n "$AGENT49BPID" ] && kill "$AGENT49BPID" 2>/dev/null || true | ||
| 1493 | [ -n "${UPAGPID:-}" ] && kill "$UPAGPID" 2>/dev/null || true | ||
| 1494 | # The stops still precede the socket rm below, like SOCK14-17 above: | ||
| 1495 | # unlinking a socket first would leave a live daemon nothing could reach | ||
| 1496 | # by path. | 1516 | # by path. |
| 1497 | [ -S "$SOCK18" ] && "$MUXD" stop --sock "$SOCK18" 2>/dev/null || true | 1517 | for _cs in $E2E_SOCK; do |
| 1498 | [ -S "$SOCK19" ] && "$MUXD" stop --sock "$SOCK19" 2>/dev/null || true | 1518 | if [ -S "$_cs" ] && [ -n "${MUXD:-}" ]; then |
| 1499 | [ -S "$SOCK20" ] && "$MUXD" stop --sock "$SOCK20" 2>/dev/null || true | 1519 | "$MUXD" stop --sock "$_cs" > /dev/null 2>&1 || true |
| 1500 | [ -S "$SOCK25" ] && "$MUXD" stop --sock "$SOCK25" 2>/dev/null || true | 1520 | fi |
| 1501 | [ -S "$SOCK26" ] && "$MUXD" stop --sock "$SOCK26" 2>/dev/null || true | 1521 | done |
| 1502 | [ -S "$SOCK27" ] && "$MUXD" stop --sock "$SOCK27" 2>/dev/null || true | 1522 | # Then every registered process. softkill rather than a plain `kill`, |
| 1503 | [ -S "$SOCK28" ] && "$MUXD" stop --sock "$SOCK28" 2>/dev/null || true | 1523 | # which is what this trap used to send: under the coverage harness the |
| 1504 | [ -S "$SOCK29" ] && "$MUXD" stop --sock "$SOCK29" 2>/dev/null || true | 1524 | # pid the suite holds is a kcov TRACER, and a signal sent to a tracer is |
| 1505 | [ -S "$SOCK30" ] && "$MUXD" stop --sock "$SOCK30" 2>/dev/null || true | 1525 | # dropped — measured on the hub leg, where `kill $W3PID` left both alive. |
| 1506 | [ -S "$SOCK31" ] && "$MUXD" stop --sock "$SOCK31" 2>/dev/null || true | 1526 | # TERM rather than hardkill's KILL, because a daemon writes its leak |
| 1507 | [ -S "$SOCK32" ] && "$MUXD" stop --sock "$SOCK32" 2>/dev/null || true | 1527 | # verdict on the way OUT and a SIGKILLed one writes nothing: the sweep |
| 1508 | [ -S "$SOCK33" ] && "$MUXD" stop --sock "$SOCK33" 2>/dev/null || true | 1528 | # below would then be reading a lifecycle that never ended. |
| 1509 | [ -S "$SOCK34" ] && "$MUXD" stop --sock "$SOCK34" 2>/dev/null || true | 1529 | # |
| 1510 | [ -S "$SOCK35" ] && "$MUXD" stop --sock "$SOCK35" 2>/dev/null || true | 1530 | # CONT first, and unconditionally: two legs hold their subject under |
| 1511 | [ -S "$SOCK36" ] && "$MUXD" stop --sock "$SOCK36" 2>/dev/null || true | 1531 | # SIGSTOP (the mute-offerer's agent, the refusal leg's daemon), and a |
| 1512 | [ -S "$SOCK37" ] && "$MUXD" stop --sock "$SOCK37" 2>/dev/null || true | 1532 | # stopped process does not see TERM until it runs again. On anything not |
| 1513 | [ -S "$SOCK38" ] && "$MUXD" stop --sock "$SOCK38" 2>/dev/null || true | 1533 | # stopped it is a no-op. |
| 1514 | [ -S "$SOCK39" ] && "$MUXD" stop --sock "$SOCK39" 2>/dev/null || true | 1534 | # |
| 1515 | [ -S "$SOCK40" ] && "$MUXD" stop --sock "$SOCK40" 2>/dev/null || true | 1535 | # `|| true` on both, for the reason every kill in this trap has always |
| 1516 | [ -S "$SOCK41" ] && "$MUXD" stop --sock "$SOCK41" 2>/dev/null || true | 1536 | # carried one: under `set -e` a signal to an already-dead pid would abort |
| 1517 | [ -S "$SOCK42" ] && "$MUXD" stop --sock "$SOCK42" 2>/dev/null || true | 1537 | # the trap itself and skip everything below it. |
| 1518 | [ -S "$SOCK43" ] && "$MUXD" stop --sock "$SOCK43" 2>/dev/null || true | 1538 | for _ck in $E2E_KILL; do |
| 1519 | [ -S "$SOCK44" ] && "$MUXD" stop --sock "$SOCK44" 2>/dev/null || true | 1539 | kill -CONT "$_ck" 2>/dev/null || true |
| 1520 | [ -S "$SOCK45" ] && "$MUXD" stop --sock "$SOCK45" 2>/dev/null || true | 1540 | softkill "$_ck" || true |
| 1521 | [ -S "$SOCK46" ] && "$MUXD" stop --sock "$SOCK46" 2>/dev/null || true | 1541 | done |
| 1522 | [ -S "$SOCK47" ] && "$MUXD" stop --sock "$SOCK47" 2>/dev/null || true | ||
| 1523 | [ -S "$SOCK48" ] && "$MUXD" stop --sock "$SOCK48" 2>/dev/null || true | ||
| 1524 | [ -S "$SOCK49" ] && "$MUXD" stop --sock "$SOCK49" 2>/dev/null || true | ||
| 1525 | [ -S "$SOCK50" ] && "$MUXD" stop --sock "$SOCK50" 2>/dev/null || true | ||
| 1526 | [ -S "$SOCK52" ] && "$MUXD" stop --sock "$SOCK52" 2>/dev/null || true | ||
| 1527 | [ -S "$SOCK53" ] && "$MUXD" stop --sock "$SOCK53" 2>/dev/null || true | ||
| 1528 | [ -S "$SOCK54" ] && "$MUXD" stop --sock "$SOCK54" 2>/dev/null || true | ||
| 1529 | [ -S "$SOCK55" ] && "$MUXD" stop --sock "$SOCK55" 2>/dev/null || true | ||
| 1530 | [ -S "$SOCK56" ] && "$MUXD" stop --sock "$SOCK56" 2>/dev/null || true | ||
| 1531 | [ -S "$SOCK57" ] && "$MUXD" stop --sock "$SOCK57" 2>/dev/null || true | ||
| 1532 | [ -S "$SOCK58" ] && "$MUXD" stop --sock "$SOCK58" 2>/dev/null || true | ||
| 1533 | [ -S "$SOCK59" ] && "$MUXD" stop --sock "$SOCK59" 2>/dev/null || true | ||
| 1534 | [ -S "$SOCK60" ] && "$MUXD" stop --sock "$SOCK60" 2>/dev/null || true | ||
| 1535 | [ -S "$SOCK61" ] && "$MUXD" stop --sock "$SOCK61" 2>/dev/null || true | ||
| 1536 | [ -S "$SOCK64" ] && "$MUXD" stop --sock "$SOCK64" 2>/dev/null || true | ||
| 1537 | [ -S "$SOCK66" ] && "$MUXD" stop --sock "$SOCK66" 2>/dev/null || true | ||
| 1538 | [ -S "$SOCK67" ] && "$MUXD" stop --sock "$SOCK67" 2>/dev/null || true | ||
| 1539 | [ -S "$SOCK68" ] && "$MUXD" stop --sock "$SOCK68" 2>/dev/null || true | ||
| 1540 | [ -S "$SOCK69" ] && "$MUXD" stop --sock "$SOCK69" 2>/dev/null || true | ||
| 1541 | [ -S "$SOCK70" ] && "$MUXD" stop --sock "$SOCK70" 2>/dev/null || true | ||
| 1542 | [ -S "$SOCK71" ] && "$MUXD" stop --sock "$SOCK71" 2>/dev/null || true | ||
| 1543 | [ -S "$SOCK72" ] && "$MUXD" stop --sock "$SOCK72" 2>/dev/null || true | ||
| 1544 | [ -S "$SOCK73" ] && "$MUXD" stop --sock "$SOCK73" 2>/dev/null || true | ||
| 1545 | |||
| 1546 | # ---- the leak sweep (hygiene kit, 6a) ---- | 1542 | # ---- the leak sweep (hygiene kit, 6a) ---- |
| 1547 | # Here rather than at the bottom of the file, which `set -e` reaches only | 1543 | # Here rather than at the bottom of the file, which `set -e` reaches only |
| 1548 | # on a passing run: a leak that arrives alongside a defect is reported | 1544 | # on a passing run: a leak that arrives alongside a defect is reported |
| 1549 | # with it. Between the kills above and the rms below, which is the one | 1545 | # with it. Between the kills above and the rms below, which is the one |
| 1550 | # window where every daemon has finished its exit path and every capture | 1546 | # window where every daemon has finished its exit path and every capture |
| 1551 | # still exists. | 1547 | # still exists. |
| 1552 | reap_briefly "${DPID:-}" "$D2PID" "$D3PID" "$D4PID" "$D5PID" "$D6PID" \ | 1548 | # |
| 1553 | "$D7PID" "$D9PID" "$D10PID" "$D12PID" "$D13PID" "$SPID" "$TPID" \ | 1549 | # A killed daemon writes its verdict on the way out, so the sweep waits |
| 1554 | "$GPID" "$APID" "$PAPID" "$HAPID" "$HDPID" \ | 1550 | # for the processes to be gone first. |
| 1555 | "$D14PID" "$D15PID" "$D16PID" "$D17PID" "$D18PID" "$D19PID" \ | 1551 | # shellcheck disable=SC2086 # IFS is a newline: each entry is one word |
| 1556 | "$D20PID" "$D21PID" "$D22PID" "$D23PID" "$D24PID" "$D25PID" \ | 1552 | reap_briefly $E2E_KILL |
| 1557 | "$D26PID" "$D27PID" "$D28PID" "$D29PID" "$D30PID" "$D31PID" \ | ||
| 1558 | "$D32PID" "$D33PID" "$D34PID" "$D35PID" "$D36PID" "$D37PID" \ | ||
| 1559 | "$D38PID" "$D39PID" "$D40PID" "$D41PID" "$D42PID" "$D43PID" "$D54PID" \ | ||
| 1560 | "$D55PID" "$D56PID" "$D57PID" "$D58PID" "$D59PID" \ | ||
| 1561 | "$D60PID" "$D61PID" "$D62PID" "$D63PID" "$D64PID" "$D65PID" \ | ||
| 1562 | "$D66PID" "$D67PID" "$D68PID" "$D69PID" "$D70PID" \ | ||
| 1563 | "$D71PID" "$D72PID" "$D73PID" | ||
| 1564 | _leak=0 | 1553 | _leak=0 |
| 1565 | leak_sweep "$_rc" || _leak=1 | 1554 | leak_sweep "$_rc" || _leak=1 |
| 1566 | 1555 | ||
| 1567 | rm -f "$SOCK8" "$SOCK8T" "$SOCK11" "$OUT.start" "$OUT.start2" "$OUT.s8" \ | 1556 | # The registered artifacts: sockets, keys, generated scripts, private |
| 1568 | "$OUT.ra" "$OUT.rb" "$OUT.goal" "$OUT.g9" "$OUT.dead" \ | 1557 | # HOMEs, state homes. Through rm_swept, so a registered FILE still banks |
| 1569 | "$SOCK9" "$SOCK10" "$OUT.env1" "$OUT.env2" \ | 1558 | # its leak verdict on the way out exactly as a mid-suite removal does; |
| 1570 | "$OUT.s8.err" "$OUT.race" "$OUT.g9.err" "$OUT.env1.err" "$OUT.env2.err" \ | 1559 | # directories go whole. |
| 1571 | "$OUT.m7.err" "$OUT.m7b.err" "$OUT.qc.err" "$OUT.qr.err" "$OUT.qk.err" \ | 1560 | for _cr in $E2E_SOCK $E2E_RM; do |
| 1572 | "$SOCK5" "$SOCK6" "$SOCK7" "$PWSH" \ | 1561 | if [ -d "$_cr" ]; then |
| 1573 | "$OUT.p1" "$OUT.p1.early" "$OUT.pb" "$OUT.pw" "$OUT.rw" "$OUT.rwl" "$OUT.pr" \ | 1562 | rm -rf "$_cr" |
| 1574 | "$OUT.p1.err" "$OUT.pb.err" "$OUT.pw.err" "$OUT.rw.err" "$OUT.rwl.err" "$OUT.pr.err" \ | 1563 | else |
| 1575 | "$OUT.p1.d" "$OUT.pw.d" "$OUT.rw.d" "$OUT.rwl.d" "$OUT.pr.d" \ | 1564 | rm_swept "$_cr" |
| 1576 | "$OUT.d1.d" "$OUT.d2.d" "$OUT.d3a.d" "$OUT.d3b.d" "$OUT.d4.d" \ | 1565 | fi |
| 1577 | "$OUT.d9.d" "$OUT.d10.d" "$OUT.d17.d" \ | 1566 | done |
| 1578 | "$SOCK" "$SOCK2" "$SOCK3" "$SOCK4" "$SOCK4.second" "$QKEY" "$QKEY.bad" \ | 1567 | IFS=$_oifs |
| 1579 | "$OUT" "$OUT.kill" "$OUT.re" "$OUT.a" "$OUT.st" \ | 1568 | |
| 1580 | "$OUT.b" "$OUT.via" "$OUT.dead" "$OUT.abort" "$OUT.m7" "$OUT.m7b" \ | 1569 | # ...and the captures, by the pattern leak_sweep just read them by rather |
| 1581 | "$OUT.q" "$OUT.qc" "$OUT.qr" "$OUT.qa" "$OUT.qk" "$QKEY.wrong" \ | 1570 | # than by a list of some 350 names. The list is what failed: every |
| 1582 | "$OUT.nokey" "$SOCK4.nokey" \ | 1571 | # capture had to be remembered in two places, 102 of them were not, and |
| 1583 | "$OUT.doctored" "$OUT.doctored.render" "$OUT.doctored.dump" \ | 1572 | # by 2026-08-19 `make soak` refused to start. A pattern cannot forget a |
| 1584 | "$OUT.doctored.render.n" "$OUT.doctored.dump.n" "$OUT.doctored.diff" \ | 1573 | # leg. |
| 1585 | "$OUT.doctored.rvt" "$OUT.doctored.dvt" | ||
| 1586 | # The M12 fixture controls, spelled from $OUT rather than from $PCLOG: | ||
| 1587 | # that variable is assigned mid-file, so on a failure above it "${PCLOG:-}.2" | ||
| 1588 | # would expand to a bare ".2" — an rm target in the CWD, not a temp file. | ||
| 1589 | rm -f "$OUT.pc" "$OUT.pc.err" "$OUT.pc2" "$OUT.pc2.err" "$OUT.pc3" "$OUT.pc3.err" \ | ||
| 1590 | "$OUT.pc.log" "$OUT.pc.log.2" "$OUT.pc.log.3" | ||
| 1591 | rm -f "$SOCK12" "$OUT.tp2.d" \ | ||
| 1592 | "$OUT.tp2a" "$OUT.tp2a.err" "$OUT.tp2a.log" \ | ||
| 1593 | "$OUT.tp2b" "$OUT.tp2b.err" "$OUT.tp2b.log" | ||
| 1594 | # tp1, including the doctored copy and the convergence residue its | ||
| 1595 | # cannot-fail control leaves behind BY DESIGN: that check passes when | ||
| 1596 | # converged_quiet fails, and a failing converged_quiet keeps its files. | ||
| 1597 | rm -f "$SOCK13" "$TP1SH" "$OUT.tp1.d" \ | ||
| 1598 | "$OUT.tp1" "$OUT.tp1.err" "$OUT.tp1.log" \ | ||
| 1599 | "$OUT.tp1.doc" "$OUT.tp1.doc.render" "$OUT.tp1.doc.dump" \ | ||
| 1600 | "$OUT.tp1.doc.render.n" "$OUT.tp1.doc.dump.n" "$OUT.tp1.doc.diff" \ | ||
| 1601 | "$OUT.tp1.doc.rvt" "$OUT.tp1.doc.dvt" | ||
| 1602 | # M13 auto-start + stop. | ||
| 1603 | rm -f "$SOCK14" "$SOCK15" \ | ||
| 1604 | "$OUT.as" "$OUT.as.err" "$OUT.as2" "$OUT.as2.err" \ | ||
| 1605 | "$OUT.stop" "$OUT.stop2" \ | ||
| 1606 | "$OUT.pa" "$OUT.pa.err" "$OUT.pa.log" | ||
| 1607 | # The side-channel leg: its capture, the fixture's log, and the script | ||
| 1608 | # the session runs. Spelled from $OUT rather than from a variable of its | ||
| 1609 | # own, for the reason the M12 controls above are. | ||
| 1610 | rm -f "$OUT.clip" "$OUT.clip.err" "$OUT.clip.log" "$OUT.clip.sh" | ||
| 1611 | # The title leg's identical four. Its own rm_swept runs only on success, | ||
| 1612 | # so without this line the residue survives exactly the runs where the | ||
| 1613 | # leg failed and somebody is looking at it. | ||
| 1614 | rm -f "$OUT.title" "$OUT.title.err" "$OUT.title.log" "$OUT.title.sh" | ||
| 1615 | # The wheel pair: two captures, two fixture logs, two session scripts | ||
| 1616 | # and the daemon logs beside them. | ||
| 1617 | rm -f "$OUT.whl" "$OUT.whl.err" "$OUT.whl.log" "$OUT.whl.d" "$WHEELSH" \ | ||
| 1618 | "$OUT.mse" "$OUT.mse.err" "$OUT.mse.log" "$OUT.mse.d" "$MOUSESH" \ | ||
| 1619 | "$SOCK41" "$OUT.zw.d" "$OUT.zwcap" "$OUT.zwcap.err" "$OUT.zwpc" \ | ||
| 1620 | "$OUT.zwcapg" "$OUT.zwstop" "$ZWHEELSH" \ | ||
| 1621 | "$SOCK42" "$OUT.zm2.d" "$OUT.zm2cap" "$OUT.zm2cap.err" "$OUT.zm2pc" \ | ||
| 1622 | "$OUT.zm2capg" "$OUT.zm2stop" "$ZMOUSESH" \ | ||
| 1623 | "$SOCK43" "$SOCK44" "$OUT.zh.da" "$OUT.zh.db" "$OUT.zhcap" \ | ||
| 1624 | "$OUT.zhcap.err" "$OUT.zhpc" "$OUT.zhstopa" "$OUT.zhstopb" \ | ||
| 1625 | "$ZHASH" "$ZHBSH" "$ZHFLAG" "$ZHSCRIPT" \ | ||
| 1626 | "$SOCK33" "$SOCK34" "$OUT.whlcap" "$OUT.msecap" \ | ||
| 1627 | "$OUT.whlstop" "$OUT.msestop" | ||
| 1628 | rm -f "$OUT.pgr" "$OUT.pgr.err" "$OUT.pgr.log" "$OUT.pgr.d" "$LESSSH" \ | ||
| 1629 | "$LESSDATA" "$OUT.pgrcap" "$OUT.pgrstop" "$SOCK35" \ | ||
| 1630 | "$OUT.pipe" "$OUT.pipe.d" "$OUT.pipecap" "$OUT.pipestop" "$SOCK36" \ | ||
| 1631 | "$OUT.sb2.d" "$OUT.sb2a" "$OUT.sb2a.err" "$OUT.sb2b" "$OUT.sb2b.err" \ | ||
| 1632 | "$OUT.sb2cap" "$OUT.sb2cap.err" "$OUT.sb2pc" "$OUT.sb2stop" "$SOCK53" \ | ||
| 1633 | "$OUT.fs.d" "$OUT.fsa" "$OUT.fsa.err" "$OUT.fsb" "$OUT.fsb.err" \ | ||
| 1634 | "$OUT.fscap" "$OUT.fscap.err" "$OUT.fspc" "$OUT.fsfa" "$OUT.fsfb" \ | ||
| 1635 | "$OUT.fsgrid" "$OUT.fsstop" "$SOCK54" \ | ||
| 1636 | "$OUT.rsz.d" "$OUT.rszcap" "$OUT.rszcap.err" "$OUT.rszpc" \ | ||
| 1637 | "$OUT.rsza" "$OUT.rsza.err" "$OUT.rszb" "$OUT.rszb.err" \ | ||
| 1638 | "$OUT.rszsta" "$OUT.rszstb" "$OUT.rszstop" "$SOCK55" \ | ||
| 1639 | "$OUT.spc.d" "$OUT.spca" "$OUT.spca.err" "$OUT.spcb" "$OUT.spcb.err" \ | ||
| 1640 | "$OUT.spccap" "$OUT.spccap.err" "$OUT.spcpc" "$OUT.spcgrid" \ | ||
| 1641 | "$OUT.spcstop" "$SOCK56" \ | ||
| 1642 | "$OUT.hjk.d" "$OUT.hjkcap" "$OUT.hjkcap.err" "$OUT.hjkpc" \ | ||
| 1643 | "$OUT.hjkfa" "$OUT.hjkfb" "$OUT.hjkfc" "$OUT.hjkstop" "$SOCK57" \ | ||
| 1644 | "$OUT.spl.d" "$OUT.splcap" "$OUT.splcap.err" "$OUT.splpc" \ | ||
| 1645 | "$OUT.splsta" "$OUT.splstop" "$SOCK58" \ | ||
| 1646 | "$OUT.lpr.d" "$OUT.lpra" "$OUT.lpra.err" "$OUT.lprb" "$OUT.lprb.err" \ | ||
| 1647 | "$OUT.lprcap1" "$OUT.lprcap1.err" "$OUT.lprpc1" \ | ||
| 1648 | "$OUT.lprcap2" "$OUT.lprcap2.err" "$OUT.lprpc2" \ | ||
| 1649 | "$OUT.lprfa" "$OUT.lprfb" "$OUT.lprstop" "$SOCK59" \ | ||
| 1650 | "$OUT.lph.d" "$OUT.lpha" "$OUT.lpha.err" "$OUT.lphb" "$OUT.lphb.err" \ | ||
| 1651 | "$OUT.lphc" "$OUT.lphc.err" "$OUT.lphcap1" "$OUT.lphcap1.err" \ | ||
| 1652 | "$OUT.lphpc1" "$OUT.lphcap2" "$OUT.lphcap2.err" "$OUT.lphpc2" \ | ||
| 1653 | "$OUT.lphfa" "$OUT.lphstop" "$SOCK60" \ | ||
| 1654 | "$OUT.lpd.d" "$OUT.lpda" "$OUT.lpda.err" \ | ||
| 1655 | "$OUT.lpdcap" "$OUT.lpdcap.err" "$OUT.lpdpc" \ | ||
| 1656 | "$OUT.lpdfa" "$OUT.lpdstop" "$SOCK61" \ | ||
| 1657 | "$OUT.pra.d" "$OUT.prb.d" "$OUT.pra" "$OUT.pra.err" "$OUT.prcap" "$OUT.prcap.err" \ | ||
| 1658 | "$OUT.prgrid" \ | ||
| 1659 | "$OUT.prpc" "$OUT.prfb" "$OUT.prastop" "$OUT.prbstop" "$SOCK62" "$SOCK63" \ | ||
| 1660 | "$OUT.hyd.d" "$OUT.hydcap" "$OUT.hydcap.err" "$OUT.hydpc" "$OUT.hydgrid" \ | ||
| 1661 | "$OUT.hydsta" "$OUT.hydstb" "$OUT.hydghost" "$OUT.hydpre" "$OUT.hydfa" \ | ||
| 1662 | "$OUT.hydstop" "$OUT.hydfcap" "$OUT.hydfcap.err" "$OUT.hydfpc" \ | ||
| 1663 | "$OUT.hydfold" "$OUT.hydfgrid" "$SOCK64" "$HYKEY" \ | ||
| 1664 | "$OUT.ref.d" "$OUT.refrun" "$OUT.refstatus" "$OUT.refsend" \ | ||
| 1665 | "$OUT.refalive" "$OUT.refstop" "$SOCK66" \ | ||
| 1666 | "$OUT.wg.d" "$OUT.wgh" "$OUT.wgws" "$OUT.wgws.err" \ | ||
| 1667 | "$OUT.wgws2" "$OUT.wgws2.err" "$OUT.wgpre" "$OUT.wgsta" \ | ||
| 1668 | "$OUT.wgghost" "$OUT.wgstop" "$OUT.wgsta0" "$OUT.wgexit" \ | ||
| 1669 | "$OUT.wgws3" "$OUT.wgws3.err" "$SOCK67" "$WGKEY" \ | ||
| 1670 | "$OUT.sp.d" "$OUT.sph" "$OUT.spws" "$OUT.spws.err" \ | ||
| 1671 | "$OUT.spghost" "$OUT.spstop" "$SOCK68" \ | ||
| 1672 | "$OUT.up.d" "$OUT.upcap" "$OUT.upcap.err" "$OUT.uppc" \ | ||
| 1673 | "$OUT.upm1" "$OUT.upm2" "$OUT.upm3" "$OUT.upst1" "$OUT.upst2" \ | ||
| 1674 | "$OUT.upref1" "$OUT.upref2" "$OUT.upok" "$OUT.upsta" "$OUT.upstop" \ | ||
| 1675 | "$SOCK69" "$UPBIN" \ | ||
| 1676 | "$OUT.url.d" "$OUT.urlm1" "$OUT.urlm2" "$OUT.urlup" "$OUT.urlstop" \ | ||
| 1677 | "$SOCK70" \ | ||
| 1678 | "$OUT.uag.d" "$OUT.uag" "$OUT.uag.err" "$OUT.uag.in" "$OUT.uagenv" \ | ||
| 1679 | "$OUT.uagup" "$OUT.uagstop" "$SOCK71" \ | ||
| 1680 | "$UPAGENT" "$UPAGKEY" "$UPAGKEY.pub" \ | ||
| 1681 | "$OUT.uqc.d" "$OUT.uqc" "$OUT.uqc.err" "$OUT.uqc.in" "$OUT.uqup" \ | ||
| 1682 | "$OUT.uqsta" "$OUT.uqstop" "$SOCK72" "$UPKEY" \ | ||
| 1683 | "$OUT.sg" "$OUT.sg.d" "$OUT.sg.stop" "$OUT.sg.sh" "$SOCK73" | ||
| 1684 | # The upgrade leg's private HOME, for the reason it has one: a session | ||
| 1685 | # shell that read the developer's rc files would set its own title. | ||
| 1686 | rm -rf "$UPHOME" | ||
| 1687 | # ...and the state homes those legs read their walls back out of, plus | ||
| 1688 | # the spin leg's shim dir (its dial log lives inside it). | ||
| 1689 | rm -rf "$HYSTATE" "$WGSTATE" "$SPSTATE" "$SPDIR" | ||
| 1690 | # ...and the non-tty capture that leg's session feeds. | ||
| 1691 | rm -f "$OUT.nogate" | ||
| 1692 | # ...and its other half: the paste capture and the file nvim wrote, which | ||
| 1693 | # IS that scenario's assertion rather than a log beside it. | ||
| 1694 | rm -f "$OUT.paste" "$OUT.paste.err" "$OUT.paste.log" "$OUT.pasted.txt" | ||
| 1695 | # ...and the bell leg's five, plus the daemon capture and socket, since | ||
| 1696 | # that leg runs a daemon of its own. | ||
| 1697 | # | 1574 | # |
| 1698 | # All six are ALSO rm_swept mid-suite on success, which is not a conflict: | 1575 | # Green runs only. A failing run keeps its captures — the .render/.dump/ |
| 1699 | # rm_swept banks a capture's LEAK verdict into $LEAKBANK before deleting | 1576 | # .diff files a failed assert_converged leaves behind are that failure's |
| 1700 | # it, and the sweep above reads the bank for everything that no longer | 1577 | # evidence, and soak moves the whole set into its failure dir for the |
| 1701 | # exists. So the daemon capture's verdict survives its own deletion, and | 1578 | # next run's sake. |
| 1702 | # this line is the backstop for the runs where that rm_swept never ran — | 1579 | if [ "$_rc" -eq 0 ]; then |
| 1703 | # the failing ones, which are exactly the runs somebody is looking at. The | 1580 | for _co in "$OUT" "$OUT".*; do |
| 1704 | # tp1 leg sweeps its own daemon capture the same way (see its rm_swept), | 1581 | [ -e "$_co" ] || continue |
| 1705 | # so this is that leg's convention rather than a new one. | 1582 | rm -rf "$_co" |
| 1706 | rm -f "$SOCK24" "$OUT.d21.d" \ | 1583 | done |
| 1707 | "$OUT.bell" "$OUT.bell.err" "$OUT.bell.log" "$OUT.bell.sh" | 1584 | fi |
| 1708 | # M14 handoff. The shim, both runtime dirs (each holding its daemon's | ||
| 1709 | # socket), the second key, the unusable config home, and the five | ||
| 1710 | # captures. | ||
| 1711 | rm -f "$HKEY" "$HCFGBAD" \ | ||
| 1712 | "$OUT.h1" "$OUT.h1.err" "$OUT.h2" "$OUT.h2.err" "$OUT.h3" "$OUT.h3.err" \ | ||
| 1713 | "$OUT.h4" "$OUT.h4.err" "$OUT.h5" "$OUT.h5.err" | ||
| 1714 | rm -rf "$SSHIM_DIR" "$HRUN" "$HRUN2" | ||
| 1715 | # M-web captures. Their hubs and daemons were killed with everyone | ||
| 1716 | # else's, up with the kills — every kill in this trap now precedes every | ||
| 1717 | # rm, so the leak sweep sitting between the two reads captures that are | ||
| 1718 | # still on disk and daemons that have already written their verdict. | ||
| 1719 | rm -f "$SOCK18" "$SOCK19" "$SOCK20" \ | ||
| 1720 | "$OUT.weba" "$OUT.weba.err" "$OUT.weba.d" \ | ||
| 1721 | "$OUT.web1x1" "$OUT.web1x1.err" "$OUT.web1x1.log" \ | ||
| 1722 | "$OUT.webb" "$OUT.webb.err" "$OUT.webb.d" "$OUT.webh" \ | ||
| 1723 | "$OUT.webws" "$OUT.webws.err" "$OUT.webws.n" "$OUT.webws.dump" \ | ||
| 1724 | "$OUT.webws.dump.n" "$OUT.webws.diff" "$OUT.webws.doc" \ | ||
| 1725 | "$OUT.webevil" "$OUT.webevil.err" \ | ||
| 1726 | "$OUT.webc" "$OUT.webc.err" "$OUT.webc.d" "$OUT.webc2" "$OUT.webc2.err" \ | ||
| 1727 | "$OUT.webc2.d" "$OUT.webh2" "$OUT.webws2" "$OUT.webws2.err" \ | ||
| 1728 | "$OUT.webws2.n" "$OUT.webws2.dump" "$OUT.webws2.dump.n" \ | ||
| 1729 | "$OUT.webws2.diff" "$OUT.webws2.doc" \ | ||
| 1730 | "$OUT.webstop" "$OUT.webstop2" "$OUT.webstop3" "$OUT.webstop4" | ||
| 1731 | # M18 captures, both blocks, including the files assert_ws_converged | ||
| 1732 | # derives from each stand-in's dump (.n/.dump/.dump.n/.diff/.doc). | ||
| 1733 | rm -f "$SOCK21" "$SOCK22" \ | ||
| 1734 | "$OUT.m18.d" "$OUT.m18a" "$OUT.m18a.err" "$OUT.m18b" "$OUT.m18b.err" \ | ||
| 1735 | "$OUT.m18ax" "$OUT.m18ax.err" "$OUT.m18stats" "$OUT.m18zz" \ | ||
| 1736 | "$OUT.m18mst" "$OUT.m18mcap" \ | ||
| 1737 | "$OUT.m18stop" "$OUT.m18w.d" "$OUT.m18wh" \ | ||
| 1738 | "$OUT.m18wa" "$OUT.m18wa.err" "$OUT.m18wb" "$OUT.m18wb.err" \ | ||
| 1739 | "$OUT.m18ws0" "$OUT.m18ws0.err" "$OUT.m18ws0.n" "$OUT.m18ws0.dump" \ | ||
| 1740 | "$OUT.m18ws0.dump.n" "$OUT.m18ws0.diff" "$OUT.m18ws0.doc" \ | ||
| 1741 | "$OUT.m18ws1" "$OUT.m18ws1.err" "$OUT.m18ws1.n" "$OUT.m18ws1.dump" \ | ||
| 1742 | "$OUT.m18ws1.dump.n" "$OUT.m18ws1.diff" "$OUT.m18ws1.doc" \ | ||
| 1743 | "$OUT.m18wstop" \ | ||
| 1744 | "$SOCK23" "$M18KEY" "$OUT.m18q.d" "$OUT.m18qa" "$OUT.m18qa.err" \ | ||
| 1745 | "$OUT.m18qb" "$OUT.m18qb.err" "$OUT.m18qx" "$OUT.m18qx.err" \ | ||
| 1746 | "$OUT.m18qstop" | ||
| 1747 | # The dynamic-wall leg: its daemon capture, the three hub captures (one | ||
| 1748 | # per incarnation, each kept apart so a failure names WHICH start went | ||
| 1749 | # wrong), the CLI and stand-in captures, and the state home holding the | ||
| 1750 | # wall file this leg reads back. | ||
| 1751 | rm -f "$SOCK25" "$OUT.dw.d" "$OUT.dwh" "$OUT.dwh2" "$OUT.dwh3" \ | ||
| 1752 | "$OUT.dwcli" "$OUT.dwcli.err" \ | ||
| 1753 | "$OUT.dwws" "$OUT.dwws.err" "$OUT.dwdead" "$OUT.dwdead.err" \ | ||
| 1754 | "$OUT.dwstop" | ||
| 1755 | rm -rf "$DWSTATE" | ||
| 1756 | # The attach-history block: its daemon capture, the client captures, and | ||
| 1757 | # the state home holding the wall file both its scenarios read back. | ||
| 1758 | rm -f "$SOCK40" "$OUT.wh.d" "$OUT.wh1" "$OUT.wh1.err" "$OUT.wh2" \ | ||
| 1759 | "$OUT.wh2.err" "$OUT.whb" "$OUT.whb.err" "$OUT.whc" "$OUT.whc.err" \ | ||
| 1760 | "$OUT.whro" "$OUT.whro.err" "$OUT.whadd" "$OUT.whrm" "$OUT.whst" \ | ||
| 1761 | "$OUT.whself" "$OUT.whph" \ | ||
| 1762 | "$OUT.whxpc" "$OUT.whxcap" "$OUT.whxcap.err" "$OUT.whxst" \ | ||
| 1763 | "$OUT.whxpc2" "$OUT.whxcap2" "$OUT.whxcap2.err" \ | ||
| 1764 | "$OUT.whxa" "$OUT.whxa.err" "$OUT.whxb" "$OUT.whxb.err" \ | ||
| 1765 | "$OUT.whstop" | ||
| 1766 | rm -rf "$WHSTATE" "$WHBAD" "$WHXSTATE" | ||
| 1767 | # fill_sessions' captures, one per filled name, and the scratch state | ||
| 1768 | # homes the fills write their own wall lines into. A glob rather than a | ||
| 1769 | # list because the names are generated: 28 per caller, and a list would | ||
| 1770 | # go stale the moment max_sessions moves again. | ||
| 1771 | rm -f "$OUT".fill.* | ||
| 1772 | rm -rf "$OUT.nswfill" "$OUT.whfill" | ||
| 1773 | # ...and the wall-chord leg's own state home, which holds the two-line | ||
| 1774 | # wall that leg builds and reads back. | ||
| 1775 | rm -rf "$M4STATE" | ||
| 1776 | # The convergence block: three daemons, three state homes, and the | ||
| 1777 | # captures each leg names in its own failures. | ||
| 1778 | rm -f "$SOCK45" "$OUT.cv.d" "$OUT.cvside" "$OUT.cvside.err" "$OUT.cvinj" \ | ||
| 1779 | "$OUT.cvcap" "$OUT.cvcap.err" "$OUT.cvpc" "$OUT.cvstop" | ||
| 1780 | rm -f "$SOCK46" "$OUT.rg.d" "$OUT.rgtwo" "$OUT.rgtwo.err" \ | ||
| 1781 | "$OUT.rgcap" "$OUT.rgcap.err" "$OUT.rgpc" "$OUT.rgcapt" "$OUT.rgcap0" \ | ||
| 1782 | "$OUT.rgstop" | ||
| 1783 | rm -f "$SOCK47" "$OUT.xe.d" "$OUT.xe1" "$OUT.xe1.err" \ | ||
| 1784 | "$OUT.xecap" "$OUT.xecap.err" "$OUT.xepc" "$OUT.xe2" "$OUT.xe2.err" \ | ||
| 1785 | "$OUT.xestop" | ||
| 1786 | rm -rf "$CVSTATE" "$RGSTATE" "$RGOTHER" "$XESTATE" | ||
| 1787 | # The agent legs. The private key and its public half go too: this file | ||
| 1788 | # made them, and a keypair left in $TMPDIR is litter with a lifetime. | ||
| 1789 | # The agent's own socket is unlinked by the ssh-agent killed above only | ||
| 1790 | # when it exits cleanly, so it is named here as well. | ||
| 1791 | rm -f "$SOCK48" "$AGENT48" "$AGENT48KEY" "$AGENT48KEY.pub" \ | ||
| 1792 | "$OUT.agt.d" "$OUT.agt.env" "$OUT.agt" "$OUT.agt.err" "$OUT.agt.log" \ | ||
| 1793 | "$OUT.agtn" "$OUT.agtn.err" "$OUT.agtn.log" "$OUT.agtn.d" "$OUT.agtstop" | ||
| 1794 | rm -f "$SOCK49" "$AGENT49A" "$AGENT49B" \ | ||
| 1795 | "$AGENT49AKEY" "$AGENT49AKEY.pub" "$AGENT49BKEY" "$AGENT49BKEY.pub" \ | ||
| 1796 | "$OUT.flip.d" \ | ||
| 1797 | "$OUT.flipa.env" "$OUT.flipa" "$OUT.flipa.err" "$OUT.flipa.log" \ | ||
| 1798 | "$OUT.flipb.env" "$OUT.flipb" "$OUT.flipb.err" "$OUT.flipb.log" | ||
| 1799 | # The M1-M6 prefix/wall captures and the agent legs' three. Absent | ||
| 1800 | # from this trap until 2026-08-22, which is why every green run since | ||
| 1801 | # those features landed left 102 files in $TMPDIR — enough, by 08-19, that | ||
| 1802 | # `make soak` refused to start and no soak had run since. The guard below | ||
| 1803 | # is what makes the next omission say so instead of accumulating. | ||
| 1804 | # agent forwarding: the nested-agent leg and the three no-offer captures. | ||
| 1805 | rm -f "$OUT.agtnest" "$OUT.agtnest.err" "$OUT.agtnest.log" "$OUT.anoag" \ | ||
| 1806 | "$OUT.anoag2" "$OUT.anoag3" | ||
| 1807 | # agent forwarding: the mute-offerer leg. | ||
| 1808 | rm -f "$OUT.agtmute" "$OUT.agtmute.err" "$OUT.agtmute.log" "$OUT.agtmute.env" \ | ||
| 1809 | "$OUT.agtmute.d" | ||
| 1810 | # the CLI wall (cw*) — captures, injections and stop files. | ||
| 1811 | rm -f "$OUT.cwa" "$OUT.cwa.err" "$OUT.cwall.d" "$OUT.cwb" "$OUT.cwb.err" \ | ||
| 1812 | "$OUT.cwcap" "$OUT.cwcap.err" "$OUT.cwinj" "$OUT.cwpc" "$OUT.cwst" \ | ||
| 1813 | "$OUT.cwstop" | ||
| 1814 | # the new-session-from-the-wall leg. | ||
| 1815 | rm -f "$OUT.nsw" "$OUT.nswcap" "$OUT.nswcap3" "$OUT.nsw.d" \ | ||
| 1816 | "$OUT.nsw.err" "$OUT.nsw.log" "$OUT.nswst" "$OUT.nswst4" \ | ||
| 1817 | "$OUT.nswstop" | ||
| 1818 | # the Ctrl-\ prefix leg. | ||
| 1819 | rm -f "$OUT.pfx" "$OUT.pfx.d" "$OUT.pfx.err" "$OUT.pfx.log" "$OUT.pfxst" \ | ||
| 1820 | "$OUT.pfxstop" | ||
| 1821 | # the bell leg's ring captures. | ||
| 1822 | rm -f "$OUT.ring" "$OUT.ringcap" "$OUT.ring.d" "$OUT.ring.err" \ | ||
| 1823 | "$OUT.ring.log" "$OUT.ringstop" | ||
| 1824 | # self-attach refusal, and the wall file it reads. | ||
| 1825 | rm -f "$OUT.sacap1" "$OUT.sacap2" "$OUT.sacap3" "$OUT.sa.d" "$OUT.saenv" \ | ||
| 1826 | "$OUT.saself" "$OUT.sast" "$OUT.sastop" "$OUT.sawall" | ||
| 1827 | # the dead-tile leg. | ||
| 1828 | rm -f "$OUT.zda" "$OUT.zda.err" "$OUT.zdcap" "$OUT.zdcap.err" \ | ||
| 1829 | "$OUT.zd.d" "$OUT.zdpc" "$OUT.zdstop" "$OUT.zdcapa" "$OUT.zdgrid" | ||
| 1830 | # focus skip, and its watchers. | ||
| 1831 | rm -f "$OUT.zsa" "$OUT.zsa.err" "$OUT.zsb" "$OUT.zsb.err" "$OUT.zscap" \ | ||
| 1832 | "$OUT.zscap.err" "$OUT.zs.d" "$OUT.zsfa" "$OUT.zsfb" "$OUT.zspc" \ | ||
| 1833 | "$OUT.zssta" "$OUT.zsstb" "$OUT.zsstop" "$OUT.zswatch" | ||
| 1834 | rm -f "$OUT.swcap" "$OUT.swcap.err" "$OUT.swpc" | ||
| 1835 | rm -f "$OUT.inband" "$OUT.inband.err" "$OUT.inband.log" "$OUT.inband.d" "$OUT.inbstop" | ||
| 1836 | # The cursor-ownership leg: its daemon socket, the three session pipe | ||
| 1837 | # clients, the ptyclient capture and the stop witness. | ||
| 1838 | rm -f "$SOCK52" "$OUT.cu.d" \ | ||
| 1839 | "$OUT.cua" "$OUT.cua.err" "$OUT.cub" "$OUT.cub.err" \ | ||
| 1840 | "$OUT.cuc" "$OUT.cuc.err" \ | ||
| 1841 | "$OUT.cucap" "$OUT.cucap.err" "$OUT.cupc" "$OUT.custop" | ||
| 1842 | rm -f "$SOCK50" "$OUT.wmse.d" "$OUT.wmsa" "$OUT.wmsa.err" "$OUT.wmsb" \ | ||
| 1843 | "$OUT.wmsb.err" "$OUT.wmcap" "$OUT.wmcap.err" "$OUT.wmpc" \ | ||
| 1844 | "$OUT.wmcap2" "$OUT.wmcap2.err" "$OUT.wmpc2" "$OUT.wmfa" "$OUT.wmfb" \ | ||
| 1845 | "$OUT.wmcap3" "$OUT.wmcap3.err" "$OUT.wmpc3" \ | ||
| 1846 | "$OUT.wmcap4" "$OUT.wmcap4.err" "$OUT.wmpc4" \ | ||
| 1847 | "$OUT.wmcap5" "$OUT.wmcap5.err" "$OUT.wmpc5" \ | ||
| 1848 | "$OUT.selcap" "$OUT.selcap.err" "$OUT.selpc" \ | ||
| 1849 | "$OUT.wmstop" | ||
| 1850 | # The convergence files a FAILING assert_converged leaves behind | ||
| 1851 | # (.render/.dump/.rvt/.dvt/.diff for that capture) are deliberately not | ||
| 1852 | # chased here: on a failing run they are the evidence. | ||
| 1853 | rm -rf "$XDG_CONFIG_HOME" "$XDG_STATE_HOME" "$XDG_CACHE_HOME" "${NOKEY_CFG:-}" | ||
| 1854 | rm -f "$LEAKBANK" | ||
| 1855 | # Residue, in the leak sweep's shape and for its reason: a run that PASSED | 1585 | # Residue, in the leak sweep's shape and for its reason: a run that PASSED |
| 1856 | # must leave nothing behind, and this trap is the last place that can | 1586 | # must leave nothing behind, and this trap is the last place that can |
| 1857 | # still say so. Matched by pattern rather than by the list above, because | 1587 | # still say so. Pinned to this run's pid so a suite running concurrently |
| 1858 | # the list is what failed — every capture has to be remembered in two | 1588 | # is never counted, and never deleted. |
| 1859 | # places, and 102 of them were not. Pinned to this run's pid so a suite | ||
| 1860 | # running concurrently is never counted, and never deleted. | ||
| 1861 | # | 1589 | # |
| 1862 | # Green runs only. A failing run keeps everything: the convergence files | 1590 | # What it catches now is a path that is neither registered nor spelled |
| 1863 | # noted above are its evidence, and soak sweeps them into its failure dir. | 1591 | # from $OUT — the one shape both mechanisms above are blind to. |
| 1864 | _stray=0 | 1592 | _stray=0 |
| 1865 | if [ "$_rc" -eq 0 ]; then | 1593 | if [ "$_rc" -eq 0 ]; then |
| 1866 | _left=$(find "${TMPDIR:-/tmp}" -maxdepth 1 \ | 1594 | _left=$(find "${TMPDIR:-/tmp}" -maxdepth 1 \ |
| @@ -1870,10 +1598,11 @@ cleanup() { | |||
| 1870 | if [ "$_n" -eq 1 ]; then _w=file; else _w=files; fi | 1598 | if [ "$_n" -eq 1 ]; then _w=file; else _w=files; fi |
| 1871 | echo "e2e FAIL: the suite passed but left $_n $_w in ${TMPDIR:-/tmp}:" | 1599 | echo "e2e FAIL: the suite passed but left $_n $_w in ${TMPDIR:-/tmp}:" |
| 1872 | printf '%s\n' "$_left" | sed 's/^/ /' | 1600 | printf '%s\n' "$_left" | sed 's/^/ /' |
| 1873 | echo " A capture is removed by the scenario that made it or" | 1601 | echo " A capture is spelled from \$OUT and swept by pattern;" |
| 1874 | echo " by this trap. One added to neither is invisible until" | 1602 | echo " anything else is registered where it is created, with" |
| 1875 | echo " soak refuses to start; that is what this catches." | 1603 | echo " defer_rm, defer_sock or start_daemon. A path that is" |
| 1876 | printf '%s\n' "$_left" | xargs -r rm -f | 1604 | echo " neither is invisible until soak refuses to start." |
| 1605 | printf '%s\n' "$_left" | xargs -r rm -rf | ||
| 1877 | _stray=1 | 1606 | _stray=1 |
| 1878 | fi | 1607 | fi |
| 1879 | fi | 1608 | fi |
| @@ -1915,10 +1644,8 @@ SUM2=$(sha256sum "$KEYOUT") | |||
| 1915 | [ "$SUM1" = "$SUM2" ] || { echo "e2e FAIL: refused keygen still changed the key"; exit 1; } | 1644 | [ "$SUM1" = "$SUM2" ] || { echo "e2e FAIL: refused keygen still changed the key"; exit 1; } |
| 1916 | ok "keygen creates once, 0600 in a 0700 dir, refuses twice" | 1645 | ok "keygen creates once, 0600 in a 0700 dir, refuses twice" |
| 1917 | 1646 | ||
| 1918 | "$MUXD" run --sock "$SOCK" --shell /bin/sh > "$OUT.d1.d" 2>&1 & | 1647 | start_daemon "$SOCK" "$OUT.d1.d" "socket never appeared" --shell /bin/sh |
| 1919 | DPID=$! | 1648 | D1PID=$DPID |
| 1920 | |||
| 1921 | wait_sock "$SOCK" "$OUT.d1.d" "socket never appeared" | ||
| 1922 | 1649 | ||
| 1923 | # Client with piped stdio: types a command, waits for its output, detaches | 1650 | # Client with piped stdio: types a command, waits for its output, detaches |
| 1924 | # with the Ctrl-\ chord (prefix, then prefix again for detach). | 1651 | # with the Ctrl-\ chord (prefix, then prefix again for detach). |
| @@ -1934,7 +1661,7 @@ pipe_detach | |||
| 1934 | } | 1661 | } |
| 1935 | 1662 | ||
| 1936 | # 3. Detach left the daemon running. | 1663 | # 3. Detach left the daemon running. |
| 1937 | kill -0 "$DPID" || { echo "e2e FAIL: daemon died on detach"; exit 1; } | 1664 | kill -0 "$D1PID" || { echo "e2e FAIL: daemon died on detach"; exit 1; } |
| 1938 | 1665 | ||
| 1939 | # 4. The M11 claim itself: the screen the client painted equals the | 1666 | # 4. The M11 claim itself: the screen the client painted equals the |
| 1940 | # screen the daemon holds — same engine, same formatter, both formats. | 1667 | # screen the daemon holds — same engine, same formatter, both formats. |
| @@ -1980,10 +1707,11 @@ ok "styled content survives the paint path" | |||
| 1980 | # mid-escape-sequence, so a half-drawn capture is the expected shape here. | 1707 | # mid-escape-sequence, so a half-drawn capture is the expected shape here. |
| 1981 | { printf 'seq 1 60\n'; sleep 2; } | "$MUX" --sock "$SOCK" > "$OUT.kill" & | 1708 | { printf 'seq 1 60\n'; sleep 2; } | "$MUX" --sock "$SOCK" > "$OUT.kill" & |
| 1982 | CPID=$! | 1709 | CPID=$! |
| 1710 | defer_kill "$CPID" | ||
| 1983 | sleep 1 | 1711 | sleep 1 |
| 1984 | hardkill "$CPID" | 1712 | hardkill "$CPID" |
| 1985 | sleep 1 | 1713 | sleep 1 |
| 1986 | kill -0 "$DPID" || { echo "e2e FAIL: daemon died after client kill -9"; exit 1; } | 1714 | kill -0 "$D1PID" || { echo "e2e FAIL: daemon died after client kill -9"; exit 1; } |
| 1987 | 1715 | ||
| 1988 | { sleep 1; printf '\034\034'; } | timeout 30 "$MUX" --sock "$SOCK" > "$OUT.re" | 1716 | { sleep 1; printf '\034\034'; } | timeout 30 "$MUX" --sock "$SOCK" > "$OUT.re" |
| 1989 | grep -q "60" "$OUT.re" || { | 1717 | grep -q "60" "$OUT.re" || { |
| @@ -1998,9 +1726,11 @@ rm_swept "$OUT.kill" "$OUT.re" | |||
| 1998 | { sleep 0.5; printf 'printf "m5-%%s\\n" both\n'; sleep 2.5; printf '\034\034'; } | \ | 1726 | { sleep 0.5; printf 'printf "m5-%%s\\n" both\n'; sleep 2.5; printf '\034\034'; } | \ |
| 1999 | "$MUX" --sock "$SOCK" > "$OUT.a" & | 1727 | "$MUX" --sock "$SOCK" > "$OUT.a" & |
| 2000 | APID=$! | 1728 | APID=$! |
| 1729 | defer_kill "$APID" | ||
| 2001 | { sleep 4; printf 'printf "m5-%%s\\n" after-a-left\n'; sleep 2.5; printf '\034\034'; } | \ | 1730 | { sleep 4; printf 'printf "m5-%%s\\n" after-a-left\n'; sleep 2.5; printf '\034\034'; } | \ |
| 2002 | "$MUX" --sock "$SOCK" > "$OUT.b" & | 1731 | "$MUX" --sock "$SOCK" > "$OUT.b" & |
| 2003 | BPID=$! | 1732 | BPID=$! |
| 1733 | defer_kill "$BPID" | ||
| 2004 | wait "$APID" "$BPID" | 1734 | wait "$APID" "$BPID" |
| 2005 | 1735 | ||
| 2006 | # The marker text never appears in the echoed command line ("m5-%s" plus a | 1736 | # The marker text never appears in the echoed command line ("m5-%s" plus a |
| @@ -2010,7 +1740,7 @@ grep -q "m5-both" "$OUT.b" || { echo "e2e FAIL: client B missing shared output"; | |||
| 2010 | grep -q "m5-after-a-left" "$OUT.b" || { | 1740 | grep -q "m5-after-a-left" "$OUT.b" || { |
| 2011 | echo "e2e FAIL: client B lost its input path after A detached"; exit 1; | 1741 | echo "e2e FAIL: client B lost its input path after A detached"; exit 1; |
| 2012 | } | 1742 | } |
| 2013 | kill -0 "$DPID" || { echo "e2e FAIL: daemon died in two-client scenario"; exit 1; } | 1743 | kill -0 "$D1PID" || { echo "e2e FAIL: daemon died in two-client scenario"; exit 1; } |
| 2014 | # B's capture, not A's: A detached before B's marker landed, so A's stream ends | 1744 | # B's capture, not A's: A detached before B's marker landed, so A's stream ends |
| 2015 | # on a grid the daemon has since moved past. B saw both, and its convergence | 1745 | # on a grid the daemon has since moved past. B saw both, and its convergence |
| 2016 | # covers the same grid. | 1746 | # covers the same grid. |
| @@ -2031,7 +1761,7 @@ pipe_mux "$OUT.via" "" env XDG_RUNTIME_DIR=/nonexistent-mux-e2e "$MUX" --via "$M | |||
| 2031 | pipe_send 'printf "m6-%%s\\n" via-pipe\n' | 1761 | pipe_send 'printf "m6-%%s\\n" via-pipe\n' |
| 2032 | await_out "$OUT.via" "m6-via-pipe" "--via transport" | 1762 | await_out "$OUT.via" "m6-via-pipe" "--via transport" |
| 2033 | pipe_detach | 1763 | pipe_detach |
| 2034 | kill -0 "$DPID" || { echo "e2e FAIL: daemon died in --via scenario"; exit 1; } | 1764 | kill -0 "$D1PID" || { echo "e2e FAIL: daemon died in --via scenario"; exit 1; } |
| 2035 | assert_converged "$OUT.via" "$SOCK" "via transport" | 1765 | assert_converged "$OUT.via" "$SOCK" "via transport" |
| 2036 | rm_swept "$OUT.via" | 1766 | rm_swept "$OUT.via" |
| 2037 | 1767 | ||
| @@ -2111,14 +1841,14 @@ rm_swept "$OUT.dead" "$OUT.long" "$OUT.longc" | |||
| 2111 | # of the transport would abort here instead (SIGABRT = 134). | 1841 | # of the transport would abort here instead (SIGABRT = 134). |
| 2112 | # No convergence: the client exits while reconnecting and its daemon is dead, | 1842 | # No convergence: the client exits while reconnecting and its daemon is dead, |
| 2113 | # so there is nothing left to dump against. | 1843 | # so there is nothing left to dump against. |
| 2114 | "$MUXD" run --sock "$SOCK2" --shell /bin/sh > "$OUT.d2.d" 2>&1 & | 1844 | start_daemon "$SOCK2" "$OUT.d2.d" "second socket never appeared" --shell /bin/sh |
| 2115 | D2PID=$! | 1845 | D2PID=$DPID |
| 2116 | wait_sock "$SOCK2" "$OUT.d2.d" "second socket never appeared" | ||
| 2117 | 1846 | ||
| 2118 | set +e | 1847 | set +e |
| 2119 | { printf 'echo m7-abort-live\n'; sleep 3; printf '\034'; sleep 2; } | \ | 1848 | { printf 'echo m7-abort-live\n'; sleep 3; printf '\034'; sleep 2; } | \ |
| 2120 | timeout 20 "$MUX" --sock "$SOCK2" > "$OUT.abort" 2>&1 & | 1849 | timeout 20 "$MUX" --sock "$SOCK2" > "$OUT.abort" 2>&1 & |
| 2121 | CLIPID=$! | 1850 | CLIPID=$! |
| 1851 | defer_kill "$CLIPID" | ||
| 2122 | # Let the session establish, then take the daemon away mid-session. | 1852 | # Let the session establish, then take the daemon away mid-session. |
| 2123 | sleep 2 | 1853 | sleep 2 |
| 2124 | hardkill "$D2PID" | 1854 | hardkill "$D2PID" |
| @@ -2160,7 +1890,7 @@ PPID_PROXY=$(proxy_pid "$SOCK") | |||
| 2160 | kill -9 "$PPID_PROXY" | 1890 | kill -9 "$PPID_PROXY" |
| 2161 | # The tear must have hit the transport only; the daemon is what we are | 1891 | # The tear must have hit the transport only; the daemon is what we are |
| 2162 | # proving survives, so say so out loud rather than inferring it later. | 1892 | # proving survives, so say so out loud rather than inferring it later. |
| 2163 | kill -0 "$DPID" || { echo "e2e FAIL: the tear killed the daemon, not the proxy"; exit 1; } | 1893 | kill -0 "$D1PID" || { echo "e2e FAIL: the tear killed the daemon, not the proxy"; exit 1; } |
| 2164 | 1894 | ||
| 2165 | await_repaint "$OUT.m7" "$PAINTS_BEFORE" "m7 client never resumed after the transport was killed" | 1895 | await_repaint "$OUT.m7" "$PAINTS_BEFORE" "m7 client never resumed after the transport was killed" |
| 2166 | pipe_send 'printf "m7-%%s\\n" after\n' | 1896 | pipe_send 'printf "m7-%%s\\n" after\n' |
| @@ -2181,9 +1911,8 @@ rm_swept "$OUT.m7" "$OUT.m7.err" | |||
| 2181 | # one on the same path. The seq the client holds belongs to a session that no | 1911 | # one on the same path. The seq the client holds belongs to a session that no |
| 2182 | # longer exists, so the epoch fence must refuse it and serve a snapshot of the | 1912 | # longer exists, so the epoch fence must refuse it and serve a snapshot of the |
| 2183 | # fresh session instead. Needs its own daemon, since this one gets killed. | 1913 | # fresh session instead. Needs its own daemon, since this one gets killed. |
| 2184 | "$MUXD" run --sock "$SOCK3" --shell /bin/sh > "$OUT.d3a.d" 2>&1 & | 1914 | start_daemon "$SOCK3" "$OUT.d3a.d" "restart-scenario socket never appeared" --shell /bin/sh |
| 2185 | D3PID=$! | 1915 | D3PID=$DPID |
| 2186 | wait_sock "$SOCK3" "$OUT.d3a.d" "restart-scenario socket never appeared" | ||
| 2187 | 1916 | ||
| 2188 | pipe_mux "$OUT.m7b" "$OUT.m7b.err" timeout 40 "$MUX" --sock "$SOCK3" | 1917 | pipe_mux "$OUT.m7b" "$OUT.m7b.err" timeout 40 "$MUX" --sock "$SOCK3" |
| 2189 | pipe_send 'printf "m7b-%%s\\n" pre-restart\n' | 1918 | pipe_send 'printf "m7b-%%s\\n" pre-restart\n' |
| @@ -2197,9 +1926,8 @@ wait_for "$OUT.m7b" "m7b-pre-restart" 20 || { | |||
| 2197 | PAINTS_BEFORE=$(repaints "$OUT.m7b") | 1926 | PAINTS_BEFORE=$(repaints "$OUT.m7b") |
| 2198 | hardkill "$D3PID" | 1927 | hardkill "$D3PID" |
| 2199 | sleep 0.5 | 1928 | sleep 0.5 |
| 2200 | "$MUXD" run --sock "$SOCK3" --shell /bin/sh > "$OUT.d3b.d" 2>&1 & | 1929 | start_daemon "$SOCK3" "$OUT.d3b.d" "daemon did not rebind the stale socket" --shell /bin/sh |
| 2201 | D3PID=$! | 1930 | D3PID=$DPID |
| 2202 | wait_sock "$SOCK3" "$OUT.d3b.d" "daemon did not rebind the stale socket" | ||
| 2203 | 1931 | ||
| 2204 | await_repaint "$OUT.m7b" "$PAINTS_BEFORE" "m7b client never resumed into the restarted daemon" | 1932 | await_repaint "$OUT.m7b" "$PAINTS_BEFORE" "m7b client never resumed into the restarted daemon" |
| 2205 | pipe_send 'printf "m7b-%%s\\n" post-restart\n' | 1933 | pipe_send 'printf "m7b-%%s\\n" post-restart\n' |
| @@ -2285,6 +2013,7 @@ chmod 644 "$QKEY.bad" | |||
| 2285 | # The no-key refusal must not find the suite's own keygen'd key, so it runs | 2013 | # The no-key refusal must not find the suite's own keygen'd key, so it runs |
| 2286 | # against a config home that has never had one written to it. | 2014 | # against a config home that has never had one written to it. |
| 2287 | NOKEY_CFG="${TMPDIR:-/tmp}/mux-e2e-nokey-$$" | 2015 | NOKEY_CFG="${TMPDIR:-/tmp}/mux-e2e-nokey-$$" |
| 2016 | defer_rm "$NOKEY_CFG" | ||
| 2288 | refuse 2 "$NOKEY_CFG" --quic "127.0.0.1:$QPORT" | 2017 | refuse 2 "$NOKEY_CFG" --quic "127.0.0.1:$QPORT" |
| 2289 | refuse 2 "$XDG_CONFIG_HOME" --key "$QKEY" | 2018 | refuse 2 "$XDG_CONFIG_HOME" --key "$QKEY" |
| 2290 | refuse 2 "$XDG_CONFIG_HOME" --quic "127.0.0.1:$QPORT" --key "$QKEY" --quic-idle-ms 0 | 2019 | refuse 2 "$XDG_CONFIG_HOME" --quic "127.0.0.1:$QPORT" --key "$QKEY" --quic-idle-ms 0 |
| @@ -2304,10 +2033,9 @@ rm -rf "$NOKEY_CFG" | |||
| 2304 | ok "no key anywhere is refused, and says how to make one" | 2033 | ok "no key anywhere is refused, and says how to make one" |
| 2305 | 2034 | ||
| 2306 | # The accepted case. | 2035 | # The accepted case. |
| 2307 | "$MUXD" run --sock "$SOCK4" --shell /bin/sh \ | 2036 | start_daemon "$SOCK4" "$OUT.d4.d" "--quic daemon never bound its session socket" --shell /bin/sh \ |
| 2308 | --quic "127.0.0.1:$QPORT" --key "$QKEY" --quic-idle-ms 3000 > "$OUT.d4.d" 2>&1 & | 2037 | --quic "127.0.0.1:$QPORT" --key "$QKEY" --quic-idle-ms 3000 |
| 2309 | D4PID=$! | 2038 | D4PID=$DPID |
| 2310 | wait_sock "$SOCK4" "$OUT.d4.d" "--quic daemon never bound its session socket" | ||
| 2311 | 2039 | ||
| 2312 | # The UDP port is actually held. /proc/net/udp rather than ss or lsof: it is | 2040 | # The UDP port is actually held. /proc/net/udp rather than ss or lsof: it is |
| 2313 | # always there on the platform this daemon runs on, and needs no privileges. | 2041 | # always there on the platform this daemon runs on, and needs no privileges. |
| @@ -2448,9 +2176,11 @@ grep -q "did not answer" "$OUT.qc" || { | |||
| 2448 | # A fifo rather than a pipeline, so what is timed is the CLIENT's exit and | 2176 | # A fifo rather than a pipeline, so what is timed is the CLIENT's exit and |
| 2449 | # not how long the writer happened to hang around afterwards. | 2177 | # not how long the writer happened to hang around afterwards. |
| 2450 | QFIFO="${TMPDIR:-/tmp}/mux-e2e-abort-fifo-$$" | 2178 | QFIFO="${TMPDIR:-/tmp}/mux-e2e-abort-fifo-$$" |
| 2179 | defer_rm "$QFIFO" | ||
| 2451 | mkfifo "$QFIFO" | 2180 | mkfifo "$QFIFO" |
| 2452 | ( sleep 0.3; printf '\034'; sleep 20 ) > "$QFIFO" & | 2181 | ( sleep 0.3; printf '\034'; sleep 20 ) > "$QFIFO" & |
| 2453 | QWPID=$! | 2182 | QWPID=$! |
| 2183 | defer_kill "$QWPID" | ||
| 2454 | QT0=$(date +%s%N) | 2184 | QT0=$(date +%s%N) |
| 2455 | set +e | 2185 | set +e |
| 2456 | timeout 30 "$MUX" "quic://127.0.0.1:$QPORT" --key "$QKEY.wrong" \ | 2186 | timeout 30 "$MUX" "quic://127.0.0.1:$QPORT" --key "$QKEY.wrong" \ |
| @@ -2534,16 +2264,15 @@ PAINTS_BEFORE=$(repaints "$OUT.qk") | |||
| 2534 | hardkill "$D4PID" | 2264 | hardkill "$D4PID" |
| 2535 | D4PID="" | 2265 | D4PID="" |
| 2536 | sleep 0.5 | 2266 | sleep 0.5 |
| 2537 | "$MUXD" run --sock "$SOCK4" --shell /bin/sh \ | 2267 | start_daemon "$SOCK4" "$OUT.q" "restarted --quic daemon never rebound its session socket" --shell /bin/sh \ |
| 2538 | --quic "127.0.0.1:$QPORT" --key "$QKEY" --quic-idle-ms 15000 > "$OUT.q" 2>&1 & | 2268 | --quic "127.0.0.1:$QPORT" --key "$QKEY" --quic-idle-ms 15000 |
| 2539 | D4PID=$! | 2269 | D4PID=$DPID |
| 2540 | # Nearly vacuous, and kept only because a MISSING file would still be worth | 2270 | # Nearly vacuous, and kept only because a MISSING file would still be worth |
| 2541 | # saying out loud: kill -9 leaves the old socket file behind, so this | 2271 | # saying out loud: kill -9 leaves the old socket file behind, so this |
| 2542 | # passes on the dead daemon's leavings. What proves the unix socket serves | 2272 | # passes on the dead daemon's leavings. What proves the unix socket serves |
| 2543 | # again is further down, where `muxd dump` and `muxd stats` answer on it; | 2273 | # again is further down, where `muxd dump` and `muxd stats` answer on it; |
| 2544 | # what proves the daemon serves SESSIONS again is the post-restart marker | 2274 | # what proves the daemon serves SESSIONS again is the post-restart marker |
| 2545 | # the resumed client gets back. | 2275 | # the resumed client gets back. |
| 2546 | wait_sock "$SOCK4" "$OUT.q" "restarted --quic daemon never rebound its session socket" | ||
| 2547 | # The UDP port really came back, and to THIS daemon. Without SO_REUSEADDR a | 2276 | # The UDP port really came back, and to THIS daemon. Without SO_REUSEADDR a |
| 2548 | # bind that collided would have failed loudly instead. | 2277 | # bind that collided would have failed loudly instead. |
| 2549 | # | 2278 | # |
| @@ -2609,6 +2338,7 @@ D4PID="" | |||
| 2609 | env MUX_KEY_FILE="$QKEY" "$MUXD" run --sock "$SOCK9" --shell /bin/sh \ | 2338 | env MUX_KEY_FILE="$QKEY" "$MUXD" run --sock "$SOCK9" --shell /bin/sh \ |
| 2610 | --quic "127.0.0.1:$QPORT2" --quic-idle-ms 3000 > "$OUT.d9.d" 2>&1 & | 2339 | --quic "127.0.0.1:$QPORT2" --quic-idle-ms 3000 > "$OUT.d9.d" 2>&1 & |
| 2611 | D9PID=$! | 2340 | D9PID=$! |
| 2341 | defer_kill "$D9PID" | ||
| 2612 | wait_sock "$SOCK9" "$OUT.d9.d" "MUX_KEY_FILE daemon never bound its session socket" | 2342 | wait_sock "$SOCK9" "$OUT.d9.d" "MUX_KEY_FILE daemon never bound its session socket" |
| 2613 | 2343 | ||
| 2614 | pipe_mux "$OUT.env1" "$OUT.env1.err" timeout 30 "$MUX" "quic://127.0.0.1:$QPORT2" --key "$QKEY" --quic-idle-ms 15000 | 2344 | pipe_mux "$OUT.env1" "$OUT.env1.err" timeout 30 "$MUX" "quic://127.0.0.1:$QPORT2" --key "$QKEY" --quic-idle-ms 15000 |
| @@ -2630,6 +2360,7 @@ D9PID="" | |||
| 2630 | env MUX_KEY_FILE="$QKEY.wrong" "$MUXD" run --sock "$SOCK10" --shell /bin/sh \ | 2360 | env MUX_KEY_FILE="$QKEY.wrong" "$MUXD" run --sock "$SOCK10" --shell /bin/sh \ |
| 2631 | --quic "127.0.0.1:$QPORT3" --key "$QKEY" --quic-idle-ms 3000 > "$OUT.d10.d" 2>&1 & | 2361 | --quic "127.0.0.1:$QPORT3" --key "$QKEY" --quic-idle-ms 3000 > "$OUT.d10.d" 2>&1 & |
| 2632 | D10PID=$! | 2362 | D10PID=$! |
| 2363 | defer_kill "$D10PID" | ||
| 2633 | wait_sock "$SOCK10" "$OUT.d10.d" "--key-beats-env daemon never bound its session socket" | 2364 | wait_sock "$SOCK10" "$OUT.d10.d" "--key-beats-env daemon never bound its session socket" |
| 2634 | 2365 | ||
| 2635 | pipe_mux "$OUT.env2" "$OUT.env2.err" timeout 30 "$MUX" "quic://127.0.0.1:$QPORT3" --key "$QKEY" --quic-idle-ms 15000 | 2366 | pipe_mux "$OUT.env2" "$OUT.env2.err" timeout 30 "$MUX" "quic://127.0.0.1:$QPORT3" --key "$QKEY" --quic-idle-ms 15000 |
| @@ -2664,6 +2395,7 @@ grep -q '^up (' "$OUT.start" || { | |||
| 2664 | # run, and closing it would mean parsing the pid before asserting the lines | 2395 | # run, and closing it would mean parsing the pid before asserting the lines |
| 2665 | # that prove the pid is there. | 2396 | # that prove the pid is there. |
| 2666 | SPID=$(sed -n 's/.* pid=\([0-9]*\).*/\1/p' "$OUT.start") | 2397 | SPID=$(sed -n 's/.* pid=\([0-9]*\).*/\1/p' "$OUT.start") |
| 2398 | defer_kill "$SPID" | ||
| 2667 | [ -n "$SPID" ] || { echo "e2e FAIL: up line carries no pid"; exit 1; } | 2399 | [ -n "$SPID" ] || { echo "e2e FAIL: up line carries no pid"; exit 1; } |
| 2668 | kill -0 "$SPID" || { echo "e2e FAIL: started daemon not alive"; exit 1; } | 2400 | kill -0 "$SPID" || { echo "e2e FAIL: started daemon not alive"; exit 1; } |
| 2669 | # Non-tty stderr: exactly two lines, no dots. | 2401 | # Non-tty stderr: exactly two lines, no dots. |
| @@ -2701,6 +2433,7 @@ dd if=/dev/zero bs=1024 count=8 2>/dev/null >> "$MUXLOG" | |||
| 2701 | PADDED=$(stat -c %s "$MUXLOG") | 2433 | PADDED=$(stat -c %s "$MUXLOG") |
| 2702 | "$MUXD" start --sock "$SOCK8T" 2> "$OUT.start" | 2434 | "$MUXD" start --sock "$SOCK8T" 2> "$OUT.start" |
| 2703 | TPID=$(sed -n 's/.* pid=\([0-9]*\).*/\1/p' "$OUT.start") | 2435 | TPID=$(sed -n 's/.* pid=\([0-9]*\).*/\1/p' "$OUT.start") |
| 2436 | defer_kill "$TPID" | ||
| 2704 | [ -n "$TPID" ] || { echo "e2e FAIL: truncation spawn reported no pid"; exit 1; } | 2437 | [ -n "$TPID" ] || { echo "e2e FAIL: truncation spawn reported no pid"; exit 1; } |
| 2705 | SHRUNK=$(stat -c %s "$MUXLOG") | 2438 | SHRUNK=$(stat -c %s "$MUXLOG") |
| 2706 | [ "$SHRUNK" -lt "$PADDED" ] || { | 2439 | [ "$SHRUNK" -lt "$PADDED" ] || { |
| @@ -2712,8 +2445,8 @@ TPID="" | |||
| 2712 | # survives — a second daemon on the path would have started a fresh shell). | 2445 | # survives — a second daemon on the path would have started a fresh shell). |
| 2713 | softkill "$SPID" && wait_gone "$SOCK8" | 2446 | softkill "$SPID" && wait_gone "$SOCK8" |
| 2714 | SPID="" | 2447 | SPID="" |
| 2715 | "$MUXD" start --sock "$SOCK8" 2> "$OUT.ra" & RA=$! | 2448 | "$MUXD" start --sock "$SOCK8" 2> "$OUT.ra" & RA=$!; defer_kill "$RA" |
| 2716 | "$MUXD" start --sock "$SOCK8" 2> "$OUT.rb" & RB=$! | 2449 | "$MUXD" start --sock "$SOCK8" 2> "$OUT.rb" & RB=$!; defer_kill "$RB" |
| 2717 | set +e | 2450 | set +e |
| 2718 | wait "$RA"; RCA=$? | 2451 | wait "$RA"; RCA=$? |
| 2719 | wait "$RB"; RCB=$? | 2452 | wait "$RB"; RCB=$? |
| @@ -2728,6 +2461,7 @@ pipe_detach | |||
| 2728 | echo "e2e FAIL: race: session unusable"; exit 1; } | 2461 | echo "e2e FAIL: race: session unusable"; exit 1; } |
| 2729 | SPID=$(cat "$OUT.ra" "$OUT.rb" | sed -n 's/.* pid=\([0-9]*\).*/\1/p' | while read -r p; do | 2462 | SPID=$(cat "$OUT.ra" "$OUT.rb" | sed -n 's/.* pid=\([0-9]*\).*/\1/p' | while read -r p; do |
| 2730 | kill -0 "$p" 2>/dev/null && echo "$p"; done | head -1) | 2463 | kill -0 "$p" 2>/dev/null && echo "$p"; done | head -1) |
| 2464 | defer_kill "$SPID" | ||
| 2731 | 2465 | ||
| 2732 | # What actually makes two concurrent starts safe is that the LOSER exits | 2466 | # What actually makes two concurrent starts safe is that the LOSER exits |
| 2733 | # instead of unlinking the winner's socket and binding over it. The race | 2467 | # instead of unlinking the winner's socket and binding over it. The race |
| @@ -2762,6 +2496,7 @@ ok "muxd start — spawn, no-op rerun, log truncation, race" | |||
| 2762 | # stdlib answers with `unreachable`, i.e. exit 134 and a stack trace. | 2496 | # stdlib answers with `unreachable`, i.e. exit 134 and a stack trace. |
| 2763 | # No convergence: the daemon under test is the one that died, so nothing to dump. | 2497 | # No convergence: the daemon under test is the one that died, so nothing to dump. |
| 2764 | DEADCFG="${TMPDIR:-/tmp}/mux-e2e-deadchild-$$" | 2498 | DEADCFG="${TMPDIR:-/tmp}/mux-e2e-deadchild-$$" |
| 2499 | defer_rm "$DEADCFG" | ||
| 2765 | set +e | 2500 | set +e |
| 2766 | env XDG_CONFIG_HOME="$DEADCFG" timeout 30 "$MUXD" start --sock "$SOCK8T" \ | 2501 | env XDG_CONFIG_HOME="$DEADCFG" timeout 30 "$MUXD" start --sock "$SOCK8T" \ |
| 2767 | --quic "127.0.0.1:1" --key /nonexistent > "$OUT.dead" 2>&1 | 2502 | --quic "127.0.0.1:1" --key /nonexistent > "$OUT.dead" 2>&1 |
| @@ -2793,6 +2528,7 @@ ok "a start whose daemon dies young says so, with the log path" | |||
| 2793 | # hermetic default path near the top of this suite. | 2528 | # hermetic default path near the top of this suite. |
| 2794 | "$MUXD" start --sock "$SOCK11" --quic "127.0.0.1:$QPORT4" 2> "$OUT.goal" | 2529 | "$MUXD" start --sock "$SOCK11" --quic "127.0.0.1:$QPORT4" 2> "$OUT.goal" |
| 2795 | GPID=$(sed -n 's/.* pid=\([0-9]*\).*/\1/p' "$OUT.goal") | 2530 | GPID=$(sed -n 's/.* pid=\([0-9]*\).*/\1/p' "$OUT.goal") |
| 2531 | defer_kill "$GPID" | ||
| 2796 | [ -n "$GPID" ] || { echo "e2e FAIL: goal start reported no pid"; cat "$OUT.goal"; exit 1; } | 2532 | [ -n "$GPID" ] || { echo "e2e FAIL: goal start reported no pid"; cat "$OUT.goal"; exit 1; } |
| 2797 | pipe_mux "$OUT.g9" "$OUT.g9.err" timeout 30 "$MUX" "quic://127.0.0.1:$QPORT4" | 2533 | pipe_mux "$OUT.g9" "$OUT.g9.err" timeout 30 "$MUX" "quic://127.0.0.1:$QPORT4" |
| 2798 | pipe_send 'printf "goal-%%s\\n" quic\n' | 2534 | pipe_send 'printf "goal-%%s\\n" quic\n' |
| @@ -2841,9 +2577,8 @@ ok "keygen + start --quic + mux quic:// with no --key anywhere" | |||
| 2841 | PDELAY=300 | 2577 | PDELAY=300 |
| 2842 | 2578 | ||
| 2843 | # Own file, not the client capture: the daemon's fd survives the client's truncation and would write into the replayed stream. | 2579 | # Own file, not the client capture: the daemon's fd survives the client's truncation and would write into the replayed stream. |
| 2844 | "$MUXD" run --sock "$SOCK5" --shell /bin/cat > "$OUT.p1.d" 2>&1 & | 2580 | start_daemon "$SOCK5" "$OUT.p1.d" "prediction daemon never bound" --shell /bin/cat |
| 2845 | D5PID=$! | 2581 | D5PID=$DPID |
| 2846 | wait_sock "$SOCK5" "$OUT.p1.d" "prediction daemon never bound" | ||
| 2847 | 2582 | ||
| 2848 | # 1. Line mode: the glyph is on screen before the round trip could have | 2583 | # 1. Line mode: the glyph is on screen before the round trip could have |
| 2849 | # delivered it. | 2584 | # delivered it. |
| @@ -2853,6 +2588,7 @@ set +e | |||
| 2853 | --via "$DELAYPIPE | $MUXD proxy --sock $SOCK5 | $DELAYPIPE" \ | 2588 | --via "$DELAYPIPE | $MUXD proxy --sock $SOCK5 | $DELAYPIPE" \ |
| 2854 | > "$OUT.p1" 2> "$OUT.p1.err" & | 2589 | > "$OUT.p1" 2> "$OUT.p1.err" & |
| 2855 | P1PID=$! | 2590 | P1PID=$! |
| 2591 | defer_kill "$P1PID" | ||
| 2856 | set -e | 2592 | set -e |
| 2857 | # Snapshot the client output 450ms after the keystroke: well | 2593 | # Snapshot the client output 450ms after the keystroke: well |
| 2858 | # before this 600ms round trip could bring the pty own echo back, and well | 2594 | # before this 600ms round trip could bring the pty own echo back, and well |
| @@ -2970,9 +2706,8 @@ read _hold | |||
| 2970 | PWEOF | 2706 | PWEOF |
| 2971 | chmod +x "$PWSH" | 2707 | chmod +x "$PWSH" |
| 2972 | 2708 | ||
| 2973 | "$MUXD" run --sock "$SOCK6" --shell "$PWSH" > "$OUT.pw.d" 2>&1 & | 2709 | start_daemon "$SOCK6" "$OUT.pw.d" "password daemon never bound" --shell "$PWSH" |
| 2974 | D6PID=$! | 2710 | D6PID=$DPID |
| 2975 | wait_sock "$SOCK6" "$OUT.pw.d" "password daemon never bound" | ||
| 2976 | 2711 | ||
| 2977 | # One character per write, and NOT as a single `printf hunter2`. A whole | 2712 | # One character per write, and NOT as a single `printf hunter2`. A whole |
| 2978 | # word in one write reaches the client as a multi-byte chunk, which is | 2713 | # word in one write reaches the client as a multi-byte chunk, which is |
| @@ -3024,9 +2759,8 @@ D6PID="" | |||
| 3024 | # earn/lose policy, which only a remote path lets through to the screen. | 2759 | # earn/lose policy, which only a remote path lets through to the screen. |
| 3025 | # Keys are 1s apart so each confirm (600ms) lands before the next key — | 2760 | # Keys are 1s apart so each confirm (600ms) lands before the next key — |
| 3026 | # at 0.5s `c` would find only `a` confirmed and stay hidden. | 2761 | # at 0.5s `c` would find only `a` confirmed and stay hidden. |
| 3027 | "$MUXD" run --sock "$SOCK7" --shell "$RAWMODE" > "$OUT.rw.d" 2>&1 & | 2762 | start_daemon "$SOCK7" "$OUT.rw.d" "rawmode daemon never bound" --shell "$RAWMODE" |
| 3028 | D7PID=$! | 2763 | D7PID=$DPID |
| 3029 | wait_sock "$SOCK7" "$OUT.rw.d" "rawmode daemon never bound" | ||
| 3030 | 2764 | ||
| 3031 | set +e | 2765 | set +e |
| 3032 | { sleep 2; for c in a b c; do printf '%s' "$c"; sleep 1; done; \ | 2766 | { sleep 2; for c in a b c; do printf '%s' "$c"; sleep 1; done; \ |
| @@ -3083,9 +2817,8 @@ assert_converged "$OUT.rw" "$SOCK7" "raw mode" | |||
| 3083 | softkill "$D7PID" || true | 2817 | softkill "$D7PID" || true |
| 3084 | wait "$D7PID" 2>/dev/null || true | 2818 | wait "$D7PID" 2>/dev/null || true |
| 3085 | rm -f "$SOCK7" | 2819 | rm -f "$SOCK7" |
| 3086 | "$MUXD" run --sock "$SOCK7" --shell "$RAWMODE" > "$OUT.rwl.d" 2>&1 & | 2820 | start_daemon "$SOCK7" "$OUT.rwl.d" "rawmode local daemon never bound" --shell "$RAWMODE" |
| 3087 | D7PID=$! | 2821 | D7PID=$DPID |
| 3088 | wait_sock "$SOCK7" "$OUT.rwl.d" "rawmode local daemon never bound" | ||
| 3089 | 2822 | ||
| 3090 | set +e | 2823 | set +e |
| 3091 | { sleep 2; for c in a b c; do printf '%s' "$c"; sleep 0.5; done; \ | 2824 | { sleep 2; for c in a b c; do printf '%s' "$c"; sleep 0.5; done; \ |
| @@ -3113,9 +2846,8 @@ D7PID="" | |||
| 3113 | # 5. A transport torn down with predictions outstanding. The overlay must | 2846 | # 5. A transport torn down with predictions outstanding. The overlay must |
| 3114 | # come back empty: what was queued was predicted against a connection | 2847 | # come back empty: what was queued was predicted against a connection |
| 3115 | # that no longer exists. | 2848 | # that no longer exists. |
| 3116 | "$MUXD" run --sock "$SOCK5" --shell /bin/cat > "$OUT.pr.d" 2>&1 & | 2849 | start_daemon "$SOCK5" "$OUT.pr.d" "reconnect daemon never bound" --shell /bin/cat |
| 3117 | D5PID=$! | 2850 | D5PID=$DPID |
| 3118 | wait_sock "$SOCK5" "$OUT.pr.d" "reconnect daemon never bound" | ||
| 3119 | 2851 | ||
| 3120 | set +e | 2852 | set +e |
| 3121 | { sleep 2; printf 'p'; sleep 5; printf 'q'; sleep 4; printf '\034\034'; } | \ | 2853 | { sleep 2; printf 'p'; sleep 5; printf 'q'; sleep 4; printf '\034\034'; } | \ |
| @@ -3123,6 +2855,7 @@ set +e | |||
| 3123 | --via "$DELAYPIPE | $MUXD proxy --sock $SOCK5 | $DELAYPIPE" \ | 2855 | --via "$DELAYPIPE | $MUXD proxy --sock $SOCK5 | $DELAYPIPE" \ |
| 3124 | > "$OUT.pr" 2> "$OUT.pr.err" & | 2856 | > "$OUT.pr" 2> "$OUT.pr.err" & |
| 3125 | PRPID=$! | 2857 | PRPID=$! |
| 2858 | defer_kill "$PRPID" | ||
| 3126 | set -e | 2859 | set -e |
| 3127 | # Kill the transport a tenth of a second after the keystroke, while its | 2860 | # Kill the transport a tenth of a second after the keystroke, while its |
| 3128 | # prediction is still outstanding — the round trip is 600ms, so it cannot | 2861 | # prediction is still outstanding — the round trip is 600ms, so it cannot |
| @@ -3262,9 +2995,8 @@ ok "ptyclient controls: pty echo roundtrips, impossible expect fails loudly, std | |||
| 3262 | # Hence: fill the screen, put a 95-wide row on it, then winch UP to | 2995 | # Hence: fill the screen, put a 95-wide row on it, then winch UP to |
| 3263 | # 100x30. With the prefix ignored the replica stays 90x28 and the repaint | 2996 | # 100x30. With the prefix ignored the replica stays 90x28 and the repaint |
| 3264 | # answering the resize reproduces the OLD geometry. | 2997 | # answering the resize reproduces the OLD geometry. |
| 3265 | "$MUXD" run --sock "$SOCK12" --shell /bin/sh > "$OUT.tp2.d" 2>&1 & | 2998 | start_daemon "$SOCK12" "$OUT.tp2.d" "tp2 daemon never bound" --shell /bin/sh |
| 3266 | D12PID=$! | 2999 | D12PID=$DPID |
| 3267 | wait_sock "$SOCK12" "$OUT.tp2.d" "tp2 daemon never bound" | ||
| 3268 | 3000 | ||
| 3269 | # Two rules govern every script below, and breaking either one produces a | 3001 | # Two rules govern every script below, and breaking either one produces a |
| 3270 | # capture that is honestly SHORT rather than wrong — a divergence whose | 3002 | # capture that is honestly SHORT rather than wrong — a divergence whose |
| @@ -3424,9 +3156,8 @@ seq 1 100 | |||
| 3424 | exec /bin/cat | 3156 | exec /bin/cat |
| 3425 | EOF | 3157 | EOF |
| 3426 | chmod +x "$TP1SH" | 3158 | chmod +x "$TP1SH" |
| 3427 | "$MUXD" run --sock "$SOCK13" --shell "$TP1SH" > "$OUT.tp1.d" 2>&1 & | 3159 | start_daemon "$SOCK13" "$OUT.tp1.d" "tp1 daemon never bound" --shell "$TP1SH" |
| 3428 | D13PID=$! | 3160 | D13PID=$DPID |
| 3429 | wait_sock "$SOCK13" "$OUT.tp1.d" "tp1 daemon never bound" | ||
| 3430 | # Attach only after seq finished: the client must be served a snapshot of | 3161 | # Attach only after seq finished: the client must be served a snapshot of |
| 3431 | # the TAIL, so the scrollback page it fetches later is content it has never | 3162 | # the TAIL, so the scrollback page it fetches later is content it has never |
| 3432 | # been sent. Observed at 80x24: the attach snapshot carries rows 78..100 and | 3163 | # been sent. Observed at 80x24: the attach snapshot carries rows 78..100 and |
| @@ -3479,6 +3210,7 @@ send \x1c\x1c | |||
| 3479 | waitexit 15000 | 3210 | waitexit 15000 |
| 3480 | EOF | 3211 | EOF |
| 3481 | TP1PID=$! | 3212 | TP1PID=$! |
| 3213 | defer_kill "$TP1PID" | ||
| 3482 | 3214 | ||
| 3483 | # The tear goes between verb 3 (the scroll view is on screen) and verb 4; | 3215 | # The tear goes between verb 3 (the scroll view is on screen) and verb 4; |
| 3484 | # the fixture's "done 3" line is the barrier. Every needle above is unique | 3216 | # the fixture's "done 3" line is the barrier. Every needle above is unique |
| @@ -3612,6 +3344,7 @@ grep -q '^muxd proxy: starting' "$OUT.as.err" || { | |||
| 3612 | # it is covered anyway: the trap also stops SOCK14/SOCK15 by PATH, which | 3344 | # it is covered anyway: the trap also stops SOCK14/SOCK15 by PATH, which |
| 3613 | # needs no pid. | 3345 | # needs no pid. |
| 3614 | APID=$(sed -n 's/.* pid=\([0-9]*\).*/\1/p' "$OUT.as.err" | head -1) | 3346 | APID=$(sed -n 's/.* pid=\([0-9]*\).*/\1/p' "$OUT.as.err" | head -1) |
| 3347 | defer_kill "$APID" | ||
| 3615 | [ -n "$APID" ] || { echo "e2e FAIL: proxy up-line carries no pid"; cat "$OUT.as.err"; exit 1; } | 3348 | [ -n "$APID" ] || { echo "e2e FAIL: proxy up-line carries no pid"; cat "$OUT.as.err"; exit 1; } |
| 3616 | kill -0 "$APID" || { echo "e2e FAIL: auto-started daemon not alive"; exit 1; } | 3349 | kill -0 "$APID" || { echo "e2e FAIL: auto-started daemon not alive"; exit 1; } |
| 3617 | assert_converged "$OUT.as" "$SOCK14" "auto-start via proxy" | 3350 | assert_converged "$OUT.as" "$SOCK14" "auto-start via proxy" |
| @@ -3710,6 +3443,7 @@ grep -q '^mux: starting' "$OUT.pa.err" || { | |||
| 3710 | echo "e2e FAIL: local auto-start printed no mux-prefixed starting line" | 3443 | echo "e2e FAIL: local auto-start printed no mux-prefixed starting line" |
| 3711 | cat "$OUT.pa.err"; exit 1; } | 3444 | cat "$OUT.pa.err"; exit 1; } |
| 3712 | PAPID=$(sed -n 's/.* pid=\([0-9]*\).*/\1/p' "$OUT.pa.err" | head -1) | 3445 | PAPID=$(sed -n 's/.* pid=\([0-9]*\).*/\1/p' "$OUT.pa.err" | head -1) |
| 3446 | defer_kill "$PAPID" | ||
| 3713 | [ -n "$PAPID" ] || { echo "e2e FAIL: mux up-line carries no pid"; cat "$OUT.pa.err"; exit 1; } | 3447 | [ -n "$PAPID" ] || { echo "e2e FAIL: mux up-line carries no pid"; cat "$OUT.pa.err"; exit 1; } |
| 3714 | assert_converged "$OUT.pa" "$SOCK15" "local mux auto-start" | 3448 | assert_converged "$OUT.pa" "$SOCK15" "local mux auto-start" |
| 3715 | # Same teardown, same reasons — and the stderr is captured rather than | 3449 | # Same teardown, same reasons — and the stderr is captured rather than |
| @@ -4059,9 +3793,8 @@ ok "a paste into nvim keeps its indentation" | |||
| 4059 | # than storing it, and this session paints a prompt, an echo and BELLDONE — | 3793 | # than storing it, and this session paints a prompt, an echo and BELLDONE — |
| 4060 | # but the two checks above are what make the count unambiguous, not a proof | 3794 | # but the two checks above are what make the count unambiguous, not a proof |
| 4061 | # that no other path to a BEL exists. | 3795 | # that no other path to a BEL exists. |
| 4062 | "$MUXD" run --sock "$SOCK24" --shell /bin/sh > "$OUT.d21.d" 2>&1 & | 3796 | start_daemon "$SOCK24" "$OUT.d21.d" "bell daemon socket never appeared" --shell /bin/sh |
| 4063 | D21PID=$! | 3797 | D21PID=$DPID |
| 4064 | wait_sock "$SOCK24" "$OUT.d21.d" "bell daemon socket never appeared" | ||
| 4065 | 3798 | ||
| 4066 | # Five rings in ONE printf, which is one write and so in practice one pty read | 3799 | # Five rings in ONE printf, which is one write and so in practice one pty read |
| 4067 | # and one drain — the line discipline is not going to split five bytes short of | 3800 | # and one drain — the line discipline is not going to split five bytes short of |
| @@ -4222,6 +3955,7 @@ grep -q '^muxd endpoint: starting' "$OUT.h1.err" || { | |||
| 4222 | echo "e2e FAIL: cold handoff printed no endpoint starting line" | 3955 | echo "e2e FAIL: cold handoff printed no endpoint starting line" |
| 4223 | cat "$OUT.h1.err"; exit 1; } | 3956 | cat "$OUT.h1.err"; exit 1; } |
| 4224 | HAPID=$(sed -n 's/.* pid=\([0-9]*\).*/\1/p' "$OUT.h1.err" | head -1) | 3957 | HAPID=$(sed -n 's/.* pid=\([0-9]*\).*/\1/p' "$OUT.h1.err" | head -1) |
| 3958 | defer_kill "$HAPID" | ||
| 4225 | [ -n "$HAPID" ] || { | 3959 | [ -n "$HAPID" ] || { |
| 4226 | echo "e2e FAIL: endpoint up-line carries no pid"; cat "$OUT.h1.err"; exit 1; } | 3960 | echo "e2e FAIL: endpoint up-line carries no pid"; cat "$OUT.h1.err"; exit 1; } |
| 4227 | kill -0 "$HAPID" 2>/dev/null || { | 3961 | kill -0 "$HAPID" 2>/dev/null || { |
| @@ -4383,10 +4117,9 @@ chmod 600 "$HKEY" | |||
| 4383 | # it here would suggest the ceiling's reasoning below depends on this | 4117 | # it here would suggest the ceiling's reasoning below depends on this |
| 4384 | # flag. It does not — the 15000 that bounds an overrunning dial is the | 4118 | # flag. It does not — the 15000 that bounds an overrunning dial is the |
| 4385 | # CLIENT's `quic_idle_ms_default`, which this daemon cannot influence. | 4119 | # CLIENT's `quic_idle_ms_default`, which this daemon cannot influence. |
| 4386 | "$MUXD" run --sock "$SOCK17" --shell /bin/sh \ | 4120 | start_daemon "$SOCK17" "$OUT.d17.d" "key-mismatch daemon never bound" --shell /bin/sh \ |
| 4387 | --quic "127.0.0.1:$HQPORT" --key "$HKEY" > "$OUT.d17.d" 2>&1 & | 4121 | --quic "127.0.0.1:$HQPORT" --key "$HKEY" |
| 4388 | HDPID=$! | 4122 | HDPID=$DPID |
| 4389 | wait_sock "$SOCK17" "$OUT.d17.d" "key-mismatch daemon never bound" | ||
| 4390 | HSHIMS_D=$(wc -l < "$SSHIM_PIDLOG") | 4123 | HSHIMS_D=$(wc -l < "$SSHIM_PIDLOG") |
| 4391 | HT0=$(date +%s%N) | 4124 | HT0=$(date +%s%N) |
| 4392 | pipe_mux "$OUT.h4" "$OUT.h4.err" env SHELL=/bin/sh XDG_RUNTIME_DIR="$HRUN2" PATH="$HPATH" timeout 40 \ | 4125 | pipe_mux "$OUT.h4" "$OUT.h4.err" env SHELL=/bin/sh XDG_RUNTIME_DIR="$HRUN2" PATH="$HPATH" timeout 40 \ |
| @@ -4540,9 +4273,8 @@ rm -rf "$SSHIM_DIR" "$HRUN" "$HRUN2" | |||
| 4540 | # would hang one of them with nothing printed — fifteen seconds into a | 4273 | # would hang one of them with nothing printed — fifteen seconds into a |
| 4541 | # scenario whose label says "WebSocket". This block reaches the same | 4274 | # scenario whose label says "WebSocket". This block reaches the same |
| 4542 | # resolver with a CLI in front of it, and fails there first. | 4275 | # resolver with a CLI in front of it, and fails there first. |
| 4543 | "$MUXD" run --sock "$SOCK21" --shell /bin/sh > "$OUT.m18.d" 2>&1 & | 4276 | start_daemon "$SOCK21" "$OUT.m18.d" "M18 multi-session daemon never bound" --shell /bin/sh |
| 4544 | D18PID=$! | 4277 | D18PID=$DPID |
| 4545 | wait_sock "$SOCK21" "$OUT.m18.d" "M18 multi-session daemon never bound" | ||
| 4546 | 4278 | ||
| 4547 | # Two clients, two names, one socket. Each plants a marker its own shell | 4279 | # Two clients, two names, one socket. Each plants a marker its own shell |
| 4548 | # has to EXPAND — the typed line reads `printf "m18a-%s\n" pin` and only | 4280 | # has to EXPAND — the typed line reads `printf "m18a-%s\n" pin` and only |
| @@ -4670,11 +4402,11 @@ ok "two sessions on one daemon are two shells; one dies without the other" | |||
| 4670 | # `#NAME` suffix, so the hub dials it twice and the two connections are | 4402 | # `#NAME` suffix, so the hub dials it twice and the two connections are |
| 4671 | # two sessions — the browser's spelling of everything the block above | 4403 | # two sessions — the browser's spelling of everything the block above |
| 4672 | # proved with a CLI. | 4404 | # proved with a CLI. |
| 4673 | "$MUXD" run --sock "$SOCK22" --shell /bin/sh > "$OUT.m18w.d" 2>&1 & | 4405 | start_daemon "$SOCK22" "$OUT.m18w.d" "M18 wall daemon never bound" --shell /bin/sh |
| 4674 | D19PID=$! | 4406 | D19PID=$DPID |
| 4675 | wait_sock "$SOCK22" "$OUT.m18w.d" "M18 wall daemon never bound" | ||
| 4676 | "$MUXWEB" --sock "$SOCK22#a" --sock "$SOCK22#b" --port "$WPORT3" > "$OUT.m18wh" 2>&1 & | 4407 | "$MUXWEB" --sock "$SOCK22#a" --sock "$SOCK22#b" --port "$WPORT3" > "$OUT.m18wh" 2>&1 & |
| 4677 | W3PID=$! | 4408 | W3PID=$! |
| 4409 | defer_kill "$W3PID" | ||
| 4678 | wait_for "$OUT.m18wh" "serving" 10 || { | 4410 | wait_for "$OUT.m18wh" "serving" 10 || { |
| 4679 | echo "e2e FAIL: M18 wall hub never reported serving"; cat "$OUT.m18wh"; exit 1; } | 4411 | echo "e2e FAIL: M18 wall hub never reported serving"; cat "$OUT.m18wh"; exit 1; } |
| 4680 | 4412 | ||
| @@ -4766,6 +4498,7 @@ while : ; do | |||
| 4766 | "$MUXD" run --sock "$SOCK23" --quic "127.0.0.1:$QPORT5" --key "$M18KEY" \ | 4498 | "$MUXD" run --sock "$SOCK23" --quic "127.0.0.1:$QPORT5" --key "$M18KEY" \ |
| 4767 | --quic-idle-ms 15000 --shell /bin/sh > "$OUT.m18q.d" 2>&1 & | 4499 | --quic-idle-ms 15000 --shell /bin/sh > "$OUT.m18q.d" 2>&1 & |
| 4768 | D20PID=$! | 4500 | D20PID=$! |
| 4501 | defer_kill "$D20PID" | ||
| 4769 | _i=0 | 4502 | _i=0 |
| 4770 | while [ ! -S "$SOCK23" ] && kill -0 "$D20PID" 2>/dev/null && [ "$_i" -lt 60 ]; do | 4503 | while [ ! -S "$SOCK23" ] && kill -0 "$D20PID" 2>/dev/null && [ "$_i" -lt 60 ]; do |
| 4771 | sleep 0.1; _i=$((_i + 1)) | 4504 | sleep 0.1; _i=$((_i + 1)) |
| @@ -4847,9 +4580,8 @@ ok "quic: two dials are two sessions, and one name is one session on either tran | |||
| 4847 | # string typed at 80 wide can only appear CONTIGUOUS in `muxd dump` if | 4580 | # string typed at 80 wide can only appear CONTIGUOUS in `muxd dump` if |
| 4848 | # the grid is still 80 wide — a 1-column grid puts every glyph on its | 4581 | # the grid is still 80 wide — a 1-column grid puts every glyph on its |
| 4849 | # own row, so grep itself is the geometry assertion. | 4582 | # own row, so grep itself is the geometry assertion. |
| 4850 | "$MUXD" run --sock "$SOCK18" --shell /bin/sh > "$OUT.weba.d" 2>&1 & | 4583 | start_daemon "$SOCK18" "$OUT.weba.d" "tiny attach daemon never bound" --shell /bin/sh |
| 4851 | D14PID=$! | 4584 | D14PID=$DPID |
| 4852 | wait_sock "$SOCK18" "$OUT.weba.d" "tiny attach daemon never bound" | ||
| 4853 | 4585 | ||
| 4854 | # The 80x24 client: types the first marker, holds the session open while | 4586 | # The 80x24 client: types the first marker, holds the session open while |
| 4855 | # the 1x1 attacher comes and goes, types the second marker (the geometry | 4587 | # the 1x1 attacher comes and goes, types the second marker (the geometry |
| @@ -4875,6 +4607,7 @@ send \x1c\x1c | |||
| 4875 | waitexit 10000 | 4607 | waitexit 10000 |
| 4876 | EOF | 4608 | EOF |
| 4877 | W1X1PID=$! | 4609 | W1X1PID=$! |
| 4610 | defer_kill "$W1X1PID" | ||
| 4878 | wait_for "$OUT.web1x1.log" "ptyclient: done 2" 20 || { | 4611 | wait_for "$OUT.web1x1.log" "ptyclient: done 2" 20 || { |
| 4879 | echo "e2e FAIL: tiny attach: the 1x1 client never got as far as its claim" | 4612 | echo "e2e FAIL: tiny attach: the 1x1 client never got as far as its claim" |
| 4880 | cat "$OUT.web1x1.log"; cat -v "$OUT.web1x1.err" 2>/dev/null; exit 1; } | 4613 | cat "$OUT.web1x1.log"; cat -v "$OUT.web1x1.err" 2>/dev/null; exit 1; } |
| @@ -4905,11 +4638,11 @@ D14PID="" | |||
| 4905 | ok "a 1x1 attach is refused the grid and can never claim it" | 4638 | ok "a 1x1 attach is refused the grid and can never claim it" |
| 4906 | 4639 | ||
| 4907 | # --- M-web (b): the hub pumps a real session; wrong Origin refused. | 4640 | # --- M-web (b): the hub pumps a real session; wrong Origin refused. |
| 4908 | "$MUXD" run --sock "$SOCK19" --shell /bin/sh > "$OUT.webb.d" 2>&1 & | 4641 | start_daemon "$SOCK19" "$OUT.webb.d" "web hub daemon never bound" --shell /bin/sh |
| 4909 | D15PID=$! | 4642 | D15PID=$DPID |
| 4910 | wait_sock "$SOCK19" "$OUT.webb.d" "web hub daemon never bound" | ||
| 4911 | "$MUXWEB" --sock "$SOCK19" --port "$WPORT" > "$OUT.webh" 2>&1 & | 4643 | "$MUXWEB" --sock "$SOCK19" --port "$WPORT" > "$OUT.webh" 2>&1 & |
| 4912 | W1PID=$! | 4644 | W1PID=$! |
| 4645 | defer_kill "$W1PID" | ||
| 4913 | wait_for "$OUT.webh" "serving" 10 || { | 4646 | wait_for "$OUT.webh" "serving" 10 || { |
| 4914 | echo "e2e FAIL: hub never reported serving"; cat "$OUT.webh"; exit 1; } | 4647 | echo "e2e FAIL: hub never reported serving"; cat "$OUT.webh"; exit 1; } |
| 4915 | 4648 | ||
| @@ -4972,11 +4705,11 @@ ok "hub pumps a real session; wrong origin refused" | |||
| 4972 | # epoch), say `up`, and the stand-in's re-attach — quoting coordinates | 4705 | # epoch), say `up`, and the stand-in's re-attach — quoting coordinates |
| 4973 | # the NEW daemon has never issued — must be answered with a snapshot | 4706 | # the NEW daemon has never issued — must be answered with a snapshot |
| 4974 | # that converges on the new session's content. | 4707 | # that converges on the new session's content. |
| 4975 | "$MUXD" run --sock "$SOCK20" --shell /bin/sh > "$OUT.webc.d" 2>&1 & | 4708 | start_daemon "$SOCK20" "$OUT.webc.d" "web tear daemon never bound" --shell /bin/sh |
| 4976 | D16PID=$! | 4709 | D16PID=$DPID |
| 4977 | wait_sock "$SOCK20" "$OUT.webc.d" "web tear daemon never bound" | ||
| 4978 | "$MUXWEB" --sock "$SOCK20" --port "$WPORT2" > "$OUT.webh2" 2>&1 & | 4710 | "$MUXWEB" --sock "$SOCK20" --port "$WPORT2" > "$OUT.webh2" 2>&1 & |
| 4979 | W2PID=$! | 4711 | W2PID=$! |
| 4712 | defer_kill "$W2PID" | ||
| 4980 | wait_for "$OUT.webh2" "serving" 10 || { | 4713 | wait_for "$OUT.webh2" "serving" 10 || { |
| 4981 | echo "e2e FAIL: tear hub never reported serving"; cat "$OUT.webh2"; exit 1; } | 4714 | echo "e2e FAIL: tear hub never reported serving"; cat "$OUT.webh2"; exit 1; } |
| 4982 | 4715 | ||
| @@ -4998,6 +4731,7 @@ settle 500 10000 | |||
| 4998 | dumpexit | 4731 | dumpexit |
| 4999 | EOF | 4732 | EOF |
| 5000 | WCLIPID=$! | 4733 | WCLIPID=$! |
| 4734 | defer_kill "$WCLIPID" | ||
| 5001 | # Let the stand-in reach its first expectgrid before the tear; the marker | 4735 | # Let the stand-in reach its first expectgrid before the tear; the marker |
| 5002 | # it waits for is already on the grid, so one settle-length is plenty. | 4736 | # it waits for is already on the grid, so one settle-length is plenty. |
| 5003 | sleep 1 | 4737 | sleep 1 |
| @@ -5005,9 +4739,8 @@ sleep 1 | |||
| 5005 | assert_stopped "$SOCK20" "$D16PID" "web tear: the first daemon, under a live tile" "$OUT.webstop3" | 4739 | assert_stopped "$SOCK20" "$D16PID" "web tear: the first daemon, under a live tile" "$OUT.webstop3" |
| 5006 | D16PID="" | 4740 | D16PID="" |
| 5007 | 4741 | ||
| 5008 | "$MUXD" run --sock "$SOCK20" --shell /bin/sh > "$OUT.webc2.d" 2>&1 & | 4742 | start_daemon "$SOCK20" "$OUT.webc2.d" "web tear restart never bound" --shell /bin/sh |
| 5009 | D17PID=$! | 4743 | D17PID=$DPID |
| 5010 | wait_sock "$SOCK20" "$OUT.webc2.d" "web tear restart never bound" | ||
| 5011 | 4744 | ||
| 5012 | pipe_mux "$OUT.webc2" "$OUT.webc2.err" timeout 30 "$MUX" --sock "$SOCK20" | 4745 | pipe_mux "$OUT.webc2" "$OUT.webc2.err" timeout 30 "$MUX" --sock "$SOCK20" |
| 5013 | pipe_send 'printf "web-%%s\\n" c2\n' | 4746 | pipe_send 'printf "web-%%s\\n" c2\n' |
| @@ -5040,12 +4773,12 @@ ok "hub narrates the tear; the replica re-attaches across an epoch" | |||
| 5040 | # restart. Every muxweb here runs with a state home of its own (see | 4773 | # restart. Every muxweb here runs with a state home of its own (see |
| 5041 | # $DWSTATE), so what this leg reads back is the wall this leg wrote — and | 4774 | # $DWSTATE), so what this leg reads back is the wall this leg wrote — and |
| 5042 | # never the developer's real one. | 4775 | # never the developer's real one. |
| 5043 | "$MUXD" run --sock "$SOCK25" --shell /bin/sh > "$OUT.dw.d" 2>&1 & | 4776 | start_daemon "$SOCK25" "$OUT.dw.d" "dyn wall daemon never bound" --shell /bin/sh |
| 5044 | D22PID=$! | 4777 | D22PID=$DPID |
| 5045 | wait_sock "$SOCK25" "$OUT.dw.d" "dyn wall daemon never bound" | ||
| 5046 | 4778 | ||
| 5047 | XDG_STATE_HOME="$DWSTATE" "$MUXWEB" --port "$WPORT4" > "$OUT.dwh" 2>&1 & | 4779 | XDG_STATE_HOME="$DWSTATE" "$MUXWEB" --port "$WPORT4" > "$OUT.dwh" 2>&1 & |
| 5048 | W4PID=$! | 4780 | W4PID=$! |
| 4781 | defer_kill "$W4PID" | ||
| 5049 | wait_for "$OUT.dwh" "serving" 10 || { | 4782 | wait_for "$OUT.dwh" "serving" 10 || { |
| 5050 | echo "e2e FAIL: dyn wall: hub never reported serving"; cat "$OUT.dwh"; exit 1; } | 4783 | echo "e2e FAIL: dyn wall: hub never reported serving"; cat "$OUT.dwh"; exit 1; } |
| 5051 | DWORIG="http://127.0.0.1:$WPORT4" | 4784 | DWORIG="http://127.0.0.1:$WPORT4" |
| @@ -5184,6 +4917,7 @@ softkill "$W4PID" || true | |||
| 5184 | wait_pid_gone "$W4PID" "dyn wall: first hub killed by tracked pid" | 4917 | wait_pid_gone "$W4PID" "dyn wall: first hub killed by tracked pid" |
| 5185 | XDG_STATE_HOME="$DWSTATE" "$MUXWEB" --port "$WPORT4" > "$OUT.dwh2" 2>&1 & | 4918 | XDG_STATE_HOME="$DWSTATE" "$MUXWEB" --port "$WPORT4" > "$OUT.dwh2" 2>&1 & |
| 5186 | W4PID=$! | 4919 | W4PID=$! |
| 4920 | defer_kill "$W4PID" | ||
| 5187 | wait_for "$OUT.dwh2" "serving" 10 || { | 4921 | wait_for "$OUT.dwh2" "serving" 10 || { |
| 5188 | echo "e2e FAIL: dyn wall: restored hub never reported serving"; cat "$OUT.dwh2"; exit 1; } | 4922 | echo "e2e FAIL: dyn wall: restored hub never reported serving"; cat "$OUT.dwh2"; exit 1; } |
| 5189 | curl -s "$DWORIG/tiles" | grep -q "^\[{\"id\":0,\"label\":\"--sock $SOCK25#b\"" || { | 4923 | curl -s "$DWORIG/tiles" | grep -q "^\[{\"id\":0,\"label\":\"--sock $SOCK25#b\"" || { |
| @@ -5204,6 +4938,7 @@ softkill "$W4PID" || true | |||
| 5204 | wait_pid_gone "$W4PID" "dyn wall: restored hub killed by tracked pid" | 4938 | wait_pid_gone "$W4PID" "dyn wall: restored hub killed by tracked pid" |
| 5205 | XDG_STATE_HOME="$DWSTATE" "$MUXWEB" "--sock $SOCK25" --port "$WPORT4" > "$OUT.dwh3" 2>&1 & | 4939 | XDG_STATE_HOME="$DWSTATE" "$MUXWEB" "--sock $SOCK25" --port "$WPORT4" > "$OUT.dwh3" 2>&1 & |
| 5206 | W4PID=$! | 4940 | W4PID=$! |
| 4941 | defer_kill "$W4PID" | ||
| 5207 | wait_for "$OUT.dwh3" "serving" 10 || { | 4942 | wait_for "$OUT.dwh3" "serving" 10 || { |
| 5208 | echo "e2e FAIL: dyn wall: overriding hub never reported serving"; cat "$OUT.dwh3"; exit 1; } | 4943 | echo "e2e FAIL: dyn wall: overriding hub never reported serving"; cat "$OUT.dwh3"; exit 1; } |
| 5209 | grep -qxF -- "--sock $SOCK25" "$DWSTATE/mux/wall" || { | 4944 | grep -qxF -- "--sock $SOCK25" "$DWSTATE/mux/wall" || { |
| @@ -5247,9 +4982,8 @@ ok "the wall is runtime state: add, remove, reorder, restore, argv adds" | |||
| 5247 | # The two tiles are spelled DIFFERENTLY on purpose: `--sock PATH` as two | 4982 | # The two tiles are spelled DIFFERENTLY on purpose: `--sock PATH` as two |
| 5248 | # arguments (muxweb's dialect) and as one quoted spelling (the wall file's). | 4983 | # arguments (muxweb's dialect) and as one quoted spelling (the wall file's). |
| 5249 | # Both must reach the same tile, so both are pinned by this one leg. | 4984 | # Both must reach the same tile, so both are pinned by this one leg. |
| 5250 | "$MUXD" run --sock "$SOCK26" --shell /bin/sh > "$OUT.cwall.d" 2>&1 & | 4985 | start_daemon "$SOCK26" "$OUT.cwall.d" "CLI wall daemon never bound" --shell /bin/sh |
| 5251 | D23PID=$! | 4986 | D23PID=$DPID |
| 5252 | wait_sock "$SOCK26" "$OUT.cwall.d" "CLI wall daemon never bound" | ||
| 5253 | 4987 | ||
| 5254 | pipe_mux "$OUT.cwa" "$OUT.cwa.err" timeout 40 "$MUX" --sock "$SOCK26" --session a | 4988 | pipe_mux "$OUT.cwa" "$OUT.cwa.err" timeout 40 "$MUX" --sock "$SOCK26" --session a |
| 5255 | pipe_send 'printf "cwa-%%s\\n" pin\n' | 4989 | pipe_send 'printf "cwa-%%s\\n" pin\n' |
| @@ -5265,6 +4999,7 @@ wait_grid "$SOCK26" "cwb-pin" "CLI wall: session b's marker" b | |||
| 5265 | ( sleep 5; "$MUXA" send 'printf "cwlive-%s\n" pin\n' \ | 4999 | ( sleep 5; "$MUXA" send 'printf "cwlive-%s\n" pin\n' \ |
| 5266 | --sock "$SOCK26" --session b > "$OUT.cwinj" 2>&1 ) & | 5000 | --sock "$SOCK26" --session b > "$OUT.cwinj" 2>&1 ) & |
| 5267 | CWINJPID=$! | 5001 | CWINJPID=$! |
| 5002 | defer_kill "$CWINJPID" | ||
| 5268 | set +e | 5003 | set +e |
| 5269 | timeout 40 "$PTYCLIENT" --cols 40 --rows 30 --out "$OUT.cwcap" --err "$OUT.cwcap.err" -- \ | 5004 | timeout 40 "$PTYCLIENT" --cols 40 --rows 30 --out "$OUT.cwcap" --err "$OUT.cwcap.err" -- \ |
| 5270 | "$MUX" wall --sock "$SOCK26#a" "--sock $SOCK26#b" > "$OUT.cwpc" 2>&1 <<'EOF' | 5005 | "$MUX" wall --sock "$SOCK26#a" "--sock $SOCK26#b" > "$OUT.cwpc" 2>&1 <<'EOF' |
| @@ -5312,9 +5047,8 @@ ok "mux wall: two sessions and a live delta on one terminal" | |||
| 5312 | # A real pty (ptyclient) rather than a pipeline: the shell only echoes what | 5047 | # A real pty (ptyclient) rather than a pipeline: the shell only echoes what |
| 5313 | # it was really given when there is a terminal to echo to, and the echo is | 5048 | # it was really given when there is a terminal to echo to, and the echo is |
| 5314 | # what carries the stray `z` if the layer leaks one. | 5049 | # what carries the stray `z` if the layer leaks one. |
| 5315 | "$MUXD" run --sock "$SOCK27" --shell /bin/sh > "$OUT.pfx.d" 2>&1 & | 5050 | start_daemon "$SOCK27" "$OUT.pfx.d" "prefix daemon never bound" --shell /bin/sh |
| 5316 | D24PID=$! | 5051 | D24PID=$DPID |
| 5317 | wait_sock "$SOCK27" "$OUT.pfx.d" "prefix daemon never bound" | ||
| 5318 | 5052 | ||
| 5319 | set +e | 5053 | set +e |
| 5320 | timeout 40 "$PTYCLIENT" --cols 80 --rows 24 --out "$OUT.pfx" --err "$OUT.pfx.err" \ | 5054 | timeout 40 "$PTYCLIENT" --cols 80 --rows 24 --out "$OUT.pfx" --err "$OUT.pfx.err" \ |
| @@ -5382,9 +5116,8 @@ ok "Ctrl-\\ prefix: an unknown chord is swallowed, Ctrl-\\ d detaches" | |||
| 5382 | # would go to the mailbox of the tile the user is leaving, which is the | 5116 | # would go to the mailbox of the tile the user is leaving, which is the |
| 5383 | # session they were typing in a moment ago and would silently swallow the | 5117 | # session they were typing in a moment ago and would silently swallow the |
| 5384 | # marker. | 5118 | # marker. |
| 5385 | "$MUXD" run --sock "$SOCK28" --shell /bin/sh > "$OUT.nsw.d" 2>&1 & | 5119 | start_daemon "$SOCK28" "$OUT.nsw.d" "new-session daemon never bound" --shell /bin/sh |
| 5386 | D25PID=$! | 5120 | D25PID=$DPID |
| 5387 | wait_sock "$SOCK28" "$OUT.nsw.d" "new-session daemon never bound" | ||
| 5388 | # The refusal this leg's fourth chord asserts needs a FULL table. The | 5121 | # The refusal this leg's fourth chord asserts needs a FULL table. The |
| 5389 | # chords make four (0, 1, 2, 3); the other 28 are filled here. `fillN` is | 5122 | # chords make four (0, 1, 2, 3); the other 28 are filled here. `fillN` is |
| 5390 | # not an integer, so nextFreeName still hands the chords 1, 2, 3 and | 5123 | # not an integer, so nextFreeName still hands the chords 1, 2, 3 and |
| @@ -5514,9 +5247,8 @@ ok "Ctrl-\\ c: a new session is created and switched to, the old one intact; a f | |||
| 5514 | # The captures afterwards pin which marker lives where — three sessions | 5247 | # The captures afterwards pin which marker lives where — three sessions |
| 5515 | # that each kept their own line, so the stepping moved the CLIENT and left | 5248 | # that each kept their own line, so the stepping moved the CLIENT and left |
| 5516 | # the sessions where they were. | 5249 | # the sessions where they were. |
| 5517 | "$MUXD" run --sock "$SOCK29" --shell /bin/sh > "$OUT.ring.d" 2>&1 & | 5250 | start_daemon "$SOCK29" "$OUT.ring.d" "session-ring daemon never bound" --shell /bin/sh |
| 5518 | D26PID=$! | 5251 | D26PID=$DPID |
| 5519 | wait_sock "$SOCK29" "$OUT.ring.d" "session-ring daemon never bound" | ||
| 5520 | 5252 | ||
| 5521 | set +e | 5253 | set +e |
| 5522 | # tall: Ctrl-\ c adds tiles at 80x24 (80 >= 48) | 5254 | # tall: Ctrl-\ c adds tiles at 80x24 (80 >= 48) |
| @@ -5606,9 +5338,8 @@ ok "Ctrl-\\ n / Ctrl-\\ p: the ring steps both ways and wraps at both ends" | |||
| 5606 | # mid-sentence and a correct refusal read as a missing one. Width is the fix | 5338 | # mid-sentence and a correct refusal read as a missing one. Width is the fix |
| 5607 | # that does not make the needle shorter than the claim. | 5339 | # that does not make the needle shorter than the claim. |
| 5608 | MUXABS=$(cd "$(dirname "$MUX")" && pwd)/$(basename "$MUX") | 5340 | MUXABS=$(cd "$(dirname "$MUX")" && pwd)/$(basename "$MUX") |
| 5609 | "$MUXD" run --sock "$SOCK31" --shell /bin/sh --cols 200 > "$OUT.sa.d" 2>&1 & | 5341 | start_daemon "$SOCK31" "$OUT.sa.d" "self-attach daemon never bound" --shell /bin/sh --cols 200 |
| 5610 | D28PID=$! | 5342 | D28PID=$DPID |
| 5611 | wait_sock "$SOCK31" "$OUT.sa.d" "self-attach daemon never bound" | ||
| 5612 | 5343 | ||
| 5613 | timeout 20 "$MUXA" send \ | 5344 | timeout 20 "$MUXA" send \ |
| 5614 | "[ \"\$MUX_SOCK\" = \"$SOCK31\" ] && printf 'ENV%s-%s' OK \"\$MUX_SESSION\"; echo\n" \ | 5345 | "[ \"\$MUX_SOCK\" = \"$SOCK31\" ] && printf 'ENV%s-%s' OK \"\$MUX_SESSION\"; echo\n" \ |
| @@ -5682,9 +5413,8 @@ seq 1 100 | |||
| 5682 | exec /bin/cat | 5413 | exec /bin/cat |
| 5683 | EOF | 5414 | EOF |
| 5684 | chmod +x "$WHEELSH" | 5415 | chmod +x "$WHEELSH" |
| 5685 | "$MUXD" run --sock "$SOCK33" --shell "$WHEELSH" > "$OUT.whl.d" 2>&1 & | 5416 | start_daemon "$SOCK33" "$OUT.whl.d" "wheel daemon never bound" --shell "$WHEELSH" |
| 5686 | D30PID=$! | 5417 | D30PID=$DPID |
| 5687 | wait_sock "$SOCK33" "$OUT.whl.d" "wheel daemon never bound" | ||
| 5688 | # Attach only once seq has finished, for tp1's reason: the page the wheel | 5418 | # Attach only once seq has finished, for tp1's reason: the page the wheel |
| 5689 | # fetches has to be content this client was never sent. | 5419 | # fetches has to be content this client was never sent. |
| 5690 | i=0 | 5420 | i=0 |
| @@ -5754,9 +5484,8 @@ printf 'app-holds-the-mouse\n' | |||
| 5754 | exec /bin/cat | 5484 | exec /bin/cat |
| 5755 | EOF | 5485 | EOF |
| 5756 | chmod +x "$MOUSESH" | 5486 | chmod +x "$MOUSESH" |
| 5757 | "$MUXD" run --sock "$SOCK34" --shell "$MOUSESH" > "$OUT.mse.d" 2>&1 & | 5487 | start_daemon "$SOCK34" "$OUT.mse.d" "app-mouse daemon never bound" --shell "$MOUSESH" |
| 5758 | D31PID=$! | 5488 | D31PID=$DPID |
| 5759 | wait_sock "$SOCK34" "$OUT.mse.d" "app-mouse daemon never bound" | ||
| 5760 | i=0 | 5489 | i=0 |
| 5761 | until "$MUXD" dump --sock "$SOCK34" | grep -q "app-holds-the-mouse"; do | 5490 | until "$MUXD" dump --sock "$SOCK34" | grep -q "app-holds-the-mouse"; do |
| 5762 | i=$((i+1)); [ "$i" -lt 100 ] || { echo "e2e FAIL: app-mouse session never armed"; exit 1; } | 5491 | i=$((i+1)); [ "$i" -lt 100 ] || { echo "e2e FAIL: app-mouse session never armed"; exit 1; } |
| @@ -5823,9 +5552,8 @@ export LESS | |||
| 5823 | exec less +G $LESSDATA | 5552 | exec less +G $LESSDATA |
| 5824 | EOF | 5553 | EOF |
| 5825 | chmod +x "$LESSSH" | 5554 | chmod +x "$LESSSH" |
| 5826 | "$MUXD" run --sock "$SOCK35" --shell "$LESSSH" > "$OUT.pgr.d" 2>&1 & | 5555 | start_daemon "$SOCK35" "$OUT.pgr.d" "pager daemon never bound" --shell "$LESSSH" |
| 5827 | D32PID=$! | 5556 | D32PID=$DPID |
| 5828 | wait_sock "$SOCK35" "$OUT.pgr.d" "pager daemon never bound" | ||
| 5829 | i=0 | 5557 | i=0 |
| 5830 | until "$MUXD" dump --sock "$SOCK35" | grep -qx "200"; do | 5558 | until "$MUXD" dump --sock "$SOCK35" | grep -qx "200"; do |
| 5831 | i=$((i+1)); [ "$i" -lt 100 ] || { | 5559 | i=$((i+1)); [ "$i" -lt 100 ] || { |
| @@ -5880,9 +5608,8 @@ ok "the wheel scrolls a pager on the alternate screen, as arrow keys" | |||
| 5880 | # | 5608 | # |
| 5881 | # `cat` as the session, so what arrives is echoed back and the grid IS the | 5609 | # `cat` as the session, so what arrives is echoed back and the grid IS the |
| 5882 | # assertion: the bytes reached the pty or they did not. | 5610 | # assertion: the bytes reached the pty or they did not. |
| 5883 | "$MUXD" run --sock "$SOCK36" --shell /bin/cat > "$OUT.pipe.d" 2>&1 & | 5611 | start_daemon "$SOCK36" "$OUT.pipe.d" "pipe-stdin daemon never bound" --shell /bin/cat |
| 5884 | D33PID=$! | 5612 | D33PID=$DPID |
| 5885 | wait_sock "$SOCK36" "$OUT.pipe.d" "pipe-stdin daemon never bound" | ||
| 5886 | # The detach chord is a SEPARATE write behind a sleep, and both halves of | 5613 | # The detach chord is a SEPARATE write behind a sleep, and both halves of |
| 5887 | # that are load-bearing. Without it the client stays attached after stdin | 5614 | # that are load-bearing. Without it the client stays attached after stdin |
| 5888 | # ends — a pipe closing is not a session ending — and the leg would prove | 5615 | # ends — a pipe closing is not a session ending — and the leg would prove |
| @@ -5938,9 +5665,8 @@ ok "a client with no terminal of its own forwards SGR-shaped bytes untouched" | |||
| 5938 | # tile, at wall startup. A `Ctrl-\ n` that re-dialled would be three or | 5665 | # tile, at wall startup. A `Ctrl-\ n` that re-dialled would be three or |
| 5939 | # more, and the cumulative counter says so however briefly the extra | 5666 | # more, and the cumulative counter says so however briefly the extra |
| 5940 | # connection lived. Focus is client-local and sends nothing on the wire. | 5667 | # connection lived. Focus is client-local and sends nothing on the wire. |
| 5941 | "$MUXD" run --sock "$SOCK37" --shell /bin/sh > "$OUT.zs.d" 2>&1 & | 5668 | start_daemon "$SOCK37" "$OUT.zs.d" "focus-skip daemon never bound" --shell /bin/sh |
| 5942 | D34PID=$! | 5669 | D34PID=$DPID |
| 5943 | wait_sock "$SOCK37" "$OUT.zs.d" "focus-skip daemon never bound" | ||
| 5944 | 5670 | ||
| 5945 | # Both sessions exist before the wall does, each with a marker so the wall | 5671 | # Both sessions exist before the wall does, each with a marker so the wall |
| 5946 | # has something to paint and this leg has an anchor to enter on. | 5672 | # has something to paint and this leg has an anchor to enter on. |
| @@ -6060,9 +5786,8 @@ seq 1 100 | sed 's/^/wln/' | |||
| 6060 | exec /bin/cat | 5786 | exec /bin/cat |
| 6061 | EOF | 5787 | EOF |
| 6062 | chmod +x "$ZWHEELSH" | 5788 | chmod +x "$ZWHEELSH" |
| 6063 | "$MUXD" run --sock "$SOCK41" --shell "$ZWHEELSH" > "$OUT.zw.d" 2>&1 & | 5789 | start_daemon "$SOCK41" "$OUT.zw.d" "wheel daemon never bound" --shell "$ZWHEELSH" |
| 6064 | D38PID=$! | 5790 | D38PID=$DPID |
| 6065 | wait_sock "$SOCK41" "$OUT.zw.d" "wheel daemon never bound" | ||
| 6066 | # The wall attaches only once seq has finished, scenario 42's reason: the | 5791 | # The wall attaches only once seq has finished, scenario 42's reason: the |
| 6067 | # page the wheel fetches has to be content this tile was never sent. | 5792 | # page the wheel fetches has to be content this tile was never sent. |
| 6068 | i=0 | 5793 | i=0 |
| @@ -6131,9 +5856,8 @@ printf 'mapp-holds-the-mouse\n' | |||
| 6131 | exec /bin/cat | 5856 | exec /bin/cat |
| 6132 | EOF | 5857 | EOF |
| 6133 | chmod +x "$ZMOUSESH" | 5858 | chmod +x "$ZMOUSESH" |
| 6134 | "$MUXD" run --sock "$SOCK42" --shell "$ZMOUSESH" > "$OUT.zm2.d" 2>&1 & | 5859 | start_daemon "$SOCK42" "$OUT.zm2.d" "app-mouse daemon never bound" --shell "$ZMOUSESH" |
| 6135 | D39PID=$! | 5860 | D39PID=$DPID |
| 6136 | wait_sock "$SOCK42" "$OUT.zm2.d" "app-mouse daemon never bound" | ||
| 6137 | i=0 | 5861 | i=0 |
| 6138 | until "$MUXD" dump --sock "$SOCK42" | grep -q "mapp-holds-the-mouse"; do | 5862 | until "$MUXD" dump --sock "$SOCK42" | grep -q "mapp-holds-the-mouse"; do |
| 6139 | i=$((i+1)); [ "$i" -lt 100 ] || { echo "e2e FAIL: app mouse: session never armed"; exit 1; } | 5863 | i=$((i+1)); [ "$i" -lt 100 ] || { echo "e2e FAIL: app mouse: session never armed"; exit 1; } |
| @@ -6197,9 +5921,8 @@ ok "an application in the focused tile gets the wheel, and the tile does not" | |||
| 6197 | # treatment. It must not — it still has a thread that will repaint its hot | 5921 | # treatment. It must not — it still has a thread that will repaint its hot |
| 6198 | # replica within a poll timeout, and the keyboard drawing over that would | 5922 | # replica within a poll timeout, and the keyboard drawing over that would |
| 6199 | # replace something true with something stale. | 5923 | # replace something true with something stale. |
| 6200 | "$MUXD" run --sock "$SOCK39" --shell /bin/sh > "$OUT.zd.d" 2>&1 & | 5924 | start_daemon "$SOCK39" "$OUT.zd.d" "dead-tile daemon never bound" --shell /bin/sh |
| 6201 | D36PID=$! | 5925 | D36PID=$DPID |
| 6202 | wait_sock "$SOCK39" "$OUT.zd.d" "dead-tile daemon never bound" | ||
| 6203 | pipe_mux "$OUT.zda" "$OUT.zda.err" timeout 40 "$MUX" --sock "$SOCK39" --session a | 5926 | pipe_mux "$OUT.zda" "$OUT.zda.err" timeout 40 "$MUX" --sock "$SOCK39" --session a |
| 6204 | pipe_send 'printf "zdlive-%%s\\n" pin\n' | 5927 | pipe_send 'printf "zdlive-%%s\\n" pin\n' |
| 6205 | await_out "$OUT.zda" "zdlive-pin" "zdlive-pin never reached the client" | 5928 | await_out "$OUT.zda" "zdlive-pin" "zdlive-pin never reached the client" |
| @@ -6298,9 +6021,8 @@ ok "a tile whose pump has died narrates on its bar and on its prompt, and the fo | |||
| 6298 | # Then the two failure faces: an unwritable wall file warns and does NOT | 6021 | # Then the two failure faces: an unwritable wall file warns and does NOT |
| 6299 | # stop the attach, and 'mux wall add' refuses a bad spelling by name | 6022 | # stop the attach, and 'mux wall add' refuses a bad spelling by name |
| 6300 | # without touching the file. | 6023 | # without touching the file. |
| 6301 | "$MUXD" run --sock "$SOCK40" --shell /bin/sh > "$OUT.wh.d" 2>&1 & | 6024 | start_daemon "$SOCK40" "$OUT.wh.d" "attach-history daemon never bound" --shell /bin/sh |
| 6302 | D37PID=$! | 6025 | D37PID=$DPID |
| 6303 | wait_sock "$SOCK40" "$OUT.wh.d" "attach-history daemon never bound" | ||
| 6304 | 6026 | ||
| 6305 | pipe_mux "$OUT.wh1" "$OUT.wh1.err" env XDG_STATE_HOME="$WHSTATE" timeout 40 "$MUX" --sock "$SOCK40" | 6027 | pipe_mux "$OUT.wh1" "$OUT.wh1.err" env XDG_STATE_HOME="$WHSTATE" timeout 40 "$MUX" --sock "$SOCK40" |
| 6306 | pipe_send 'printf "wh1-%%s\\n" pin\n' | 6028 | pipe_send 'printf "wh1-%%s\\n" pin\n' |
| @@ -6584,9 +6306,8 @@ ok "\\x1cx forgets a tile and leaves its session running; a refusal records noth | |||
| 6584 | # A state home of its own: the wall `Ctrl-\ w` folds in is the saved one, | 6306 | # A state home of its own: the wall `Ctrl-\ w` folds in is the saved one, |
| 6585 | # and the shared $XDG_STATE_HOME is every socket the suite has ever | 6307 | # and the shared $XDG_STATE_HOME is every socket the suite has ever |
| 6586 | # attached to. | 6308 | # attached to. |
| 6587 | "$MUXD" run --sock "$SOCK45" --shell /bin/sh > "$OUT.cv.d" 2>&1 & | 6309 | start_daemon "$SOCK45" "$OUT.cv.d" "convergence daemon never bound" --shell /bin/sh |
| 6588 | D45PID=$! | 6310 | D45PID=$DPID |
| 6589 | wait_sock "$SOCK45" "$OUT.cv.d" "convergence daemon never bound" | ||
| 6590 | 6311 | ||
| 6591 | # The tile that is already on the wall before this leg's client starts. A | 6312 | # The tile that is already on the wall before this leg's client starts. A |
| 6592 | # piped `mux`, so its attach writes the line and then goes: what the leg | 6313 | # piped `mux`, so its attach writes the line and then goes: what the leg |
| @@ -6611,6 +6332,7 @@ CVATT_BEFORE=$(attaches_now "$SOCK45") | |||
| 6611 | ( sleep 6; "$MUXA" send 'printf "cvret-%s\n" pin\n' \ | 6332 | ( sleep 6; "$MUXA" send 'printf "cvret-%s\n" pin\n' \ |
| 6612 | --sock "$SOCK45" --session 0 > "$OUT.cvinj" 2>&1 ) & | 6333 | --sock "$SOCK45" --session 0 > "$OUT.cvinj" 2>&1 ) & |
| 6613 | CVINJPID=$! | 6334 | CVINJPID=$! |
| 6335 | defer_kill "$CVINJPID" | ||
| 6614 | set +e | 6336 | set +e |
| 6615 | # tall: Ctrl-\ w folds in a saved tile, making two at 100x30 (100 >= 60); | 6337 | # tall: Ctrl-\ w folds in a saved tile, making two at 100x30 (100 >= 60); |
| 6616 | # 70x36 stays stacked (70 < 72) and fits the bar label the assertion greps | 6338 | # 70x36 stays stacked (70 < 72) and fits the bar label the assertion greps |
| @@ -6687,9 +6409,8 @@ ok "mux is the wall: Ctrl-\\ w folds in the saved tiles, the focus stays put, Ct | |||
| 6687 | # free. Sampled around the whole ptyclient run rather than around each | 6409 | # free. Sampled around the whole ptyclient run rather than around each |
| 6688 | # step, because a step that dialled and closed between two samples would | 6410 | # step, because a step that dialled and closed between two samples would |
| 6689 | # hide inside a gauge — the counter is cumulative and cannot. | 6411 | # hide inside a gauge — the counter is cumulative and cannot. |
| 6690 | "$MUXD" run --sock "$SOCK46" --shell /bin/sh > "$OUT.rg.d" 2>&1 & | 6412 | start_daemon "$SOCK46" "$OUT.rg.d" "ring-grow daemon never bound" --shell /bin/sh |
| 6691 | D46PID=$! | 6413 | D46PID=$DPID |
| 6692 | wait_sock "$SOCK46" "$OUT.rg.d" "ring-grow daemon never bound" | ||
| 6693 | 6414 | ||
| 6694 | # `two` exists on the DAEMON but not in this leg's wall: a separate state | 6415 | # `two` exists on the DAEMON but not in this leg's wall: a separate state |
| 6695 | # home is what makes the setup client's own tile invisible here, so the | 6416 | # home is what makes the setup client's own tile invisible here, so the |
| @@ -6787,9 +6508,8 @@ ok "Ctrl-\\ n grows the wall for a sibling with no tile, and is free for one tha | |||
| 6787 | # * two tiles and a PIPED client whose stdin has already gone. The case | 6508 | # * two tiles and a PIPED client whose stdin has already gone. The case |
| 6788 | # review reproduced as a hang, and the reason the rule's second half is | 6509 | # review reproduced as a hang, and the reason the rule's second half is |
| 6789 | # stated in `endAction` rather than at the read that notices EOF. | 6510 | # stated in `endAction` rather than at the read that notices EOF. |
| 6790 | "$MUXD" run --sock "$SOCK47" --shell /bin/sh > "$OUT.xe.d" 2>&1 & | 6511 | start_daemon "$SOCK47" "$OUT.xe.d" "exit-semantics daemon never bound" --shell /bin/sh |
| 6791 | D47PID=$! | 6512 | D47PID=$DPID |
| 6792 | wait_sock "$SOCK47" "$OUT.xe.d" "exit-semantics daemon never bound" | ||
| 6793 | 6513 | ||
| 6794 | # A wall it dropped to instead would read as 124: it never leaves, because | 6514 | # A wall it dropped to instead would read as 124: it never leaves, because |
| 6795 | # nothing closes its stdin under it. | 6515 | # nothing closes its stdin under it. |
| @@ -6885,9 +6605,8 @@ ok "a session ending in the focused tile exits mux alone, and leaves the focus t | |||
| 6885 | # fingerprint. What puts those 50 bytes on the terminal is the agent on this | 6605 | # fingerprint. What puts those 50 bytes on the terminal is the agent on this |
| 6886 | # machine answering a request that left the session, crossed the daemon, | 6606 | # machine answering a request that left the session, crossed the daemon, |
| 6887 | # reached the client, and came back. | 6607 | # reached the client, and came back. |
| 6888 | "$MUXD" run --sock "$SOCK48" --shell /bin/sh > "$OUT.agt.d" 2>&1 & | 6608 | start_daemon "$SOCK48" "$OUT.agt.d" "agent daemon never bound" --shell /bin/sh |
| 6889 | D42PID=$! | 6609 | D42PID=$DPID |
| 6890 | wait_sock "$SOCK48" "$OUT.agt.d" "agent daemon never bound" | ||
| 6891 | 6610 | ||
| 6892 | # The agent is started AFTER the daemon and its path is never exported, so | 6611 | # The agent is started AFTER the daemon and its path is never exported, so |
| 6893 | # the daemon cannot have inherited it: the only SSH_AUTH_SOCK a session on | 6612 | # the daemon cannot have inherited it: the only SSH_AUTH_SOCK a session on |
| @@ -6895,6 +6614,7 @@ wait_sock "$SOCK48" "$OUT.agt.d" "agent daemon never bound" | |||
| 6895 | # makes the fingerprint below evidence of a forward rather than of a leak. | 6614 | # makes the fingerprint below evidence of a forward rather than of a leak. |
| 6896 | ssh-agent -a "$AGENT48" > "$OUT.agt.env" 2>&1 | 6615 | ssh-agent -a "$AGENT48" > "$OUT.agt.env" 2>&1 |
| 6897 | AGENT48PID=$(sed -n 's/.*SSH_AGENT_PID=\([0-9]*\).*/\1/p' "$OUT.agt.env") | 6616 | AGENT48PID=$(sed -n 's/.*SSH_AGENT_PID=\([0-9]*\).*/\1/p' "$OUT.agt.env") |
| 6617 | defer_kill "$AGENT48PID" | ||
| 6898 | [ -n "$AGENT48PID" ] || { | 6618 | [ -n "$AGENT48PID" ] || { |
| 6899 | echo "e2e FAIL: agent: ssh-agent printed no pid for the trap to hold it by:" | 6619 | echo "e2e FAIL: agent: ssh-agent printed no pid for the trap to hold it by:" |
| 6900 | cat "$OUT.agt.env"; exit 1; } | 6620 | cat "$OUT.agt.env"; exit 1; } |
| @@ -7010,9 +6730,8 @@ ok "agent forwarding: -A with no agent is a usage error, not a silent no-op" | |||
| 7010 | # falls straight through to its other methods, where a connection accepted | 6730 | # falls straight through to its other methods, where a connection accepted |
| 7011 | # and left silent would make it wait out a timeout on every dial. | 6731 | # and left silent would make it wait out a timeout on every dial. |
| 7012 | wait_pid_gone "$D42PID" "agent forwarding: the positive leg's daemon outlived its last session" | 6732 | wait_pid_gone "$D42PID" "agent forwarding: the positive leg's daemon outlived its last session" |
| 7013 | "$MUXD" run --sock "$SOCK48" --shell /bin/sh > "$OUT.agtn.d" 2>&1 & | 6733 | start_daemon "$SOCK48" "$OUT.agtn.d" "agent-refusal daemon never bound" --shell /bin/sh |
| 7014 | D42PID=$! | 6734 | D42PID=$DPID |
| 7015 | wait_sock "$SOCK48" "$OUT.agtn.d" "agent-refusal daemon never bound" | ||
| 7016 | AR0=$(date +%s%N) | 6735 | AR0=$(date +%s%N) |
| 7017 | set +e | 6736 | set +e |
| 7018 | timeout 40 "$PTYCLIENT" --cols 100 --rows 30 --out "$OUT.agtn" --err "$OUT.agtn.err" \ | 6737 | timeout 40 "$PTYCLIENT" --cols 100 --rows 30 --out "$OUT.agtn" --err "$OUT.agtn.err" \ |
| @@ -7145,17 +6864,18 @@ ok "agent forwarding: no offerer means a fast refusal, not a hang (${AMS}ms)" | |||
| 7145 | # OWN key. `ssh-add -l` typed at one keyboard and then at the other has to | 6864 | # OWN key. `ssh-add -l` typed at one keyboard and then at the other has to |
| 7146 | # come back with two DIFFERENT fingerprints — that is the spec's "latest | 6865 | # come back with two DIFFERENT fingerprints — that is the spec's "latest |
| 7147 | # wins, applied to keys", and it is a claim only two agents can make. | 6866 | # wins, applied to keys", and it is a claim only two agents can make. |
| 7148 | "$MUXD" run --sock "$SOCK49" --shell /bin/sh > "$OUT.flip.d" 2>&1 & | 6867 | start_daemon "$SOCK49" "$OUT.flip.d" "agent-flip daemon never bound" --shell /bin/sh |
| 7149 | D43PID=$! | 6868 | D43PID=$DPID |
| 7150 | wait_sock "$SOCK49" "$OUT.flip.d" "agent-flip daemon never bound" | ||
| 7151 | 6869 | ||
| 7152 | # Both agents after the daemon, for the ordering reason the leg above gives: | 6870 | # Both agents after the daemon, for the ordering reason the leg above gives: |
| 7153 | # a path the daemon cannot have inherited is what makes a fingerprint | 6871 | # a path the daemon cannot have inherited is what makes a fingerprint |
| 7154 | # evidence of a forward rather than of a leak. | 6872 | # evidence of a forward rather than of a leak. |
| 7155 | ssh-agent -a "$AGENT49A" > "$OUT.flipa.env" 2>&1 | 6873 | ssh-agent -a "$AGENT49A" > "$OUT.flipa.env" 2>&1 |
| 7156 | AGENT49APID=$(sed -n 's/.*SSH_AGENT_PID=\([0-9]*\).*/\1/p' "$OUT.flipa.env") | 6874 | AGENT49APID=$(sed -n 's/.*SSH_AGENT_PID=\([0-9]*\).*/\1/p' "$OUT.flipa.env") |
| 6875 | defer_kill "$AGENT49APID" | ||
| 7157 | ssh-agent -a "$AGENT49B" > "$OUT.flipb.env" 2>&1 | 6876 | ssh-agent -a "$AGENT49B" > "$OUT.flipb.env" 2>&1 |
| 7158 | AGENT49BPID=$(sed -n 's/.*SSH_AGENT_PID=\([0-9]*\).*/\1/p' "$OUT.flipb.env") | 6877 | AGENT49BPID=$(sed -n 's/.*SSH_AGENT_PID=\([0-9]*\).*/\1/p' "$OUT.flipb.env") |
| 6878 | defer_kill "$AGENT49BPID" | ||
| 7159 | [ -n "$AGENT49APID" ] && [ -n "$AGENT49BPID" ] || { | 6879 | [ -n "$AGENT49APID" ] && [ -n "$AGENT49BPID" ] || { |
| 7160 | echo "e2e FAIL: agent-flip: an ssh-agent printed no pid for the trap to hold" | 6880 | echo "e2e FAIL: agent-flip: an ssh-agent printed no pid for the trap to hold" |
| 7161 | cat "$OUT.flipa.env" "$OUT.flipb.env"; exit 1; } | 6881 | cat "$OUT.flipa.env" "$OUT.flipb.env"; exit 1; } |
| @@ -7230,6 +6950,7 @@ send exit\n | |||
| 7230 | waitexit 20000 | 6950 | waitexit 20000 |
| 7231 | EOF | 6951 | EOF |
| 7232 | FLIPAPID=$! | 6952 | FLIPAPID=$! |
| 6953 | defer_kill "$FLIPAPID" | ||
| 7233 | # B settles before its first keystroke and A does not need to: a shell still | 6954 | # B settles before its first keystroke and A does not need to: a shell still |
| 7234 | # setting up its terminal can flush what was typed at it, and B's marker is | 6955 | # setting up its terminal can flush what was typed at it, and B's marker is |
| 7235 | # the only line typed before any shell has spoken. Every later send waits on | 6956 | # the only line typed before any shell has spoken. Every later send waits on |
| @@ -7298,9 +7019,8 @@ ok "agent forwarding: the agent that answers is whoever typed last" | |||
| 7298 | # with is gone — every click and drag routes to the focused tile's own | 7019 | # with is gone — every click and drag routes to the focused tile's own |
| 7299 | # Core, hit-tested by rect — so what remains here is the setup: a daemon, | 7020 | # Core, hit-tested by rect — so what remains here is the setup: a daemon, |
| 7300 | # a marker per session, and the tiles a `mux wall` over them paints. | 7021 | # a marker per session, and the tiles a `mux wall` over them paints. |
| 7301 | "$MUXD" run --sock "$SOCK50" --shell /bin/sh > "$OUT.wmse.d" 2>&1 & | 7022 | start_daemon "$SOCK50" "$OUT.wmse.d" "wall-cluster daemon never bound" --shell /bin/sh |
| 7302 | D48PID=$! | 7023 | D48PID=$DPID |
| 7303 | wait_sock "$SOCK50" "$OUT.wmse.d" "wall-cluster daemon never bound" | ||
| 7304 | { printf 'printf "wma-%%s\\n" pin\n'; sleep 2; printf '\034\034'; } | \ | 7024 | { printf 'printf "wma-%%s\\n" pin\n'; sleep 2; printf '\034\034'; } | \ |
| 7305 | timeout 40 "$MUX" --sock "$SOCK50" --session a > "$OUT.wmsa" 2> "$OUT.wmsa.err" | 7025 | timeout 40 "$MUX" --sock "$SOCK50" --session a > "$OUT.wmsa" 2> "$OUT.wmsa.err" |
| 7306 | wait_grid "$SOCK50" "wma-pin" "wall cluster: session a's marker" a | 7026 | wait_grid "$SOCK50" "wma-pin" "wall cluster: session a's marker" a |
| @@ -7533,9 +7253,8 @@ ok "a drag copies on release, and a click copies nothing" | |||
| 7533 | # so the report — INPUT to the app — lands on the grid as text. Two reports | 7253 | # so the report — INPUT to the app — lands on the grid as text. Two reports |
| 7534 | # are asserted, because they are two code paths: the one the mode-set | 7254 | # are asserted, because they are two code paths: the one the mode-set |
| 7535 | # itself owes (the app sizes itself from it), and the one each resize owes. | 7255 | # itself owes (the app sizes itself from it), and the one each resize owes. |
| 7536 | "$MUXD" run --sock "$SOCK51" --shell /bin/sh > "$OUT.inband.d" 2>&1 & | 7256 | start_daemon "$SOCK51" "$OUT.inband.d" "in-band daemon never bound" --shell /bin/sh |
| 7537 | D51PID=$! | 7257 | D51PID=$DPID |
| 7538 | wait_sock "$SOCK51" "$OUT.inband.d" "in-band daemon never bound" | ||
| 7539 | set +e | 7258 | set +e |
| 7540 | timeout 40 "$PTYCLIENT" --cols 100 --rows 30 --out "$OUT.inband" --err "$OUT.inband.err" -- \ | 7259 | timeout 40 "$PTYCLIENT" --cols 100 --rows 30 --out "$OUT.inband" --err "$OUT.inband.err" -- \ |
| 7541 | "$MUX" --sock "$SOCK51" > "$OUT.inband.log" 2>&1 <<'EOF' | 7260 | "$MUX" --sock "$SOCK51" > "$OUT.inband.log" 2>&1 <<'EOF' |
| @@ -7606,11 +7325,11 @@ ok "no XDG_RUNTIME_DIR: the default path is refused by name, --version is not" | |||
| 7606 | # channel for the client that would not), and the SECOND is refused in | 7325 | # channel for the client that would not), and the SECOND is refused in |
| 7607 | # milliseconds (the offer was taken away, so nobody routes to the mute | 7326 | # milliseconds (the offer was taken away, so nobody routes to the mute |
| 7608 | # client again and ssh pays nothing). | 7327 | # client again and ssh pays nothing). |
| 7609 | "$MUXD" run --sock "$SOCK48" --shell /bin/sh > "$OUT.agtmute.d" 2>&1 & | 7328 | start_daemon "$SOCK48" "$OUT.agtmute.d" "agent-mute daemon never bound" --shell /bin/sh |
| 7610 | D42PID=$! | 7329 | D42PID=$DPID |
| 7611 | wait_sock "$SOCK48" "$OUT.agtmute.d" "agent-mute daemon never bound" | ||
| 7612 | ssh-agent -a "$AGENT48" > "$OUT.agtmute.env" 2>&1 | 7330 | ssh-agent -a "$AGENT48" > "$OUT.agtmute.env" 2>&1 |
| 7613 | AGENT48PID=$(sed -n 's/.*SSH_AGENT_PID=\([0-9]*\).*/\1/p' "$OUT.agtmute.env") | 7331 | AGENT48PID=$(sed -n 's/.*SSH_AGENT_PID=\([0-9]*\).*/\1/p' "$OUT.agtmute.env") |
| 7332 | defer_kill "$AGENT48PID" | ||
| 7614 | [ -n "$AGENT48PID" ] || { | 7333 | [ -n "$AGENT48PID" ] || { |
| 7615 | echo "e2e FAIL: agent-mute: ssh-agent printed no pid to stop:" | 7334 | echo "e2e FAIL: agent-mute: ssh-agent printed no pid to stop:" |
| 7616 | cat "$OUT.agtmute.env"; exit 1; } | 7335 | cat "$OUT.agtmute.env"; exit 1; } |
| @@ -7683,9 +7402,8 @@ ok "agent forwarding: a mute offerer is hung up on, then no longer offered (${MU | |||
| 7683 | # never an echo of anything typed here). The ptyclient wall focuses tile 3, | 7402 | # never an echo of anything typed here). The ptyclient wall focuses tile 3, |
| 7684 | # settles, and detaches; the capture's last cursor-position escape is the | 7403 | # settles, and detaches; the capture's last cursor-position escape is the |
| 7685 | # witness. | 7404 | # witness. |
| 7686 | "$MUXD" run --sock "$SOCK52" --shell /bin/sh > "$OUT.cu.d" 2>&1 & | 7405 | start_daemon "$SOCK52" "$OUT.cu.d" "cursor-ownership daemon never bound" --shell /bin/sh |
| 7687 | D52PID=$! | 7406 | D52PID=$DPID |
| 7688 | wait_sock "$SOCK52" "$OUT.cu.d" "cursor-ownership daemon never bound" | ||
| 7689 | 7407 | ||
| 7690 | pipe_mux "$OUT.cua" "$OUT.cua.err" timeout 40 "$MUX" --sock "$SOCK52" --session a | 7408 | pipe_mux "$OUT.cua" "$OUT.cua.err" timeout 40 "$MUX" --sock "$SOCK52" --session a |
| 7691 | pipe_send 'printf "ma-%%s\\n" pin\n' | 7409 | pipe_send 'printf "ma-%%s\\n" pin\n' |
| @@ -7754,9 +7472,8 @@ ok "the cursor rests in the focused tile, whichever pump painted last" | |||
| 7754 | # pin and is never touched again. Both shells are /bin/sh and the content | 7472 | # pin and is never touched again. Both shells are /bin/sh and the content |
| 7755 | # is typed, the focus-skip leg's pattern — the neighbour's pin is the | 7473 | # is typed, the focus-skip leg's pattern — the neighbour's pin is the |
| 7756 | # session's own output, not an echo of the command that made it. | 7474 | # session's own output, not an echo of the command that made it. |
| 7757 | "$MUXD" run --sock "$SOCK53" --shell /bin/sh > "$OUT.sb2.d" 2>&1 & | 7475 | start_daemon "$SOCK53" "$OUT.sb2.d" "scrollback-rect daemon never bound" --shell /bin/sh |
| 7758 | D54PID=$! | 7476 | D54PID=$DPID |
| 7759 | wait_sock "$SOCK53" "$OUT.sb2.d" "scrollback-rect daemon never bound" | ||
| 7760 | 7477 | ||
| 7761 | # Session a: 100 lines of history, then cat. The wall attaches only once | 7478 | # Session a: 100 lines of history, then cat. The wall attaches only once |
| 7762 | # seq has finished, so the page the wheel fetches is content this tile was | 7479 | # seq has finished, so the page the wheel fetches is content this tile was |
| @@ -7817,9 +7534,9 @@ ok "a focused tile's scrollback page owns only its sub-rect, and the neighbour's | |||
| 7817 | # is only reached by a run that passed, and a leak deserves reporting on the | 7534 | # is only reached by a run that passed, and a leak deserves reporting on the |
| 7818 | # runs that did not (see leak_sweep). Everything below it is a pin, and the | 7535 | # runs that did not (see leak_sweep). Everything below it is a pin, and the |
| 7819 | # trap fires after all of them either way. | 7536 | # trap fires after all of them either way. |
| 7820 | softkill "$DPID" || true | 7537 | softkill "$D1PID" || true |
| 7821 | wait "$DPID" 2>/dev/null || true | 7538 | wait "$D1PID" 2>/dev/null || true |
| 7822 | DPID="" | 7539 | D1PID="" |
| 7823 | 7540 | ||
| 7824 | # The pins. Literals, not variables set from counting something else — | 7541 | # The pins. Literals, not variables set from counting something else — |
| 7825 | # "assert the literal, never the constant the code under test reads" | 7542 | # "assert the literal, never the constant the code under test reads" |
| @@ -7854,9 +7571,8 @@ DPID="" | |||
| 7854 | # | 7571 | # |
| 7855 | # No convergence point: `muxa capture` reads the daemon's grid, not the | 7572 | # No convergence point: `muxa capture` reads the daemon's grid, not the |
| 7856 | # terminal's, and the daemon's grid is the side channel this asserts on. | 7573 | # terminal's, and the daemon's grid is the side channel this asserts on. |
| 7857 | "$MUXD" run --sock "$SOCK54" --shell /bin/sh > "$OUT.fs.d" 2>&1 & | 7574 | start_daemon "$SOCK54" "$OUT.fs.d" "fullscreen daemon never bound" --shell /bin/sh |
| 7858 | D55PID=$! | 7575 | D55PID=$DPID |
| 7859 | wait_sock "$SOCK54" "$OUT.fs.d" "fullscreen daemon never bound" | ||
| 7860 | 7576 | ||
| 7861 | pipe_mux "$OUT.fsa" "$OUT.fsa.err" timeout 40 "$MUX" --sock "$SOCK54" --session a | 7577 | pipe_mux "$OUT.fsa" "$OUT.fsa.err" timeout 40 "$MUX" --sock "$SOCK54" --session a |
| 7862 | pipe_send 'printf "fs-%%s\\n" init-a\n' | 7578 | pipe_send 'printf "fs-%%s\\n" init-a\n' |
| @@ -7940,9 +7656,8 @@ ok "fullscreen gives the focused tile the terminal; focus follows; f restores" | |||
| 7940 | # | 7656 | # |
| 7941 | # No convergence point: the rail column is a terminal-capture assertion, | 7657 | # No convergence point: the rail column is a terminal-capture assertion, |
| 7942 | # not a daemon-grid comparison. | 7658 | # not a daemon-grid comparison. |
| 7943 | "$MUXD" run --sock "$SOCK55" --shell /bin/sh > "$OUT.rsz.d" 2>&1 & | 7659 | start_daemon "$SOCK55" "$OUT.rsz.d" "resize daemon never bound" --shell /bin/sh |
| 7944 | D56PID=$! | 7660 | D56PID=$DPID |
| 7945 | wait_sock "$SOCK55" "$OUT.rsz.d" "resize daemon never bound" | ||
| 7946 | 7661 | ||
| 7947 | pipe_mux "$OUT.rsza" "$OUT.rsza.err" timeout 40 "$MUX" --sock "$SOCK55" --session a | 7662 | pipe_mux "$OUT.rsza" "$OUT.rsza.err" timeout 40 "$MUX" --sock "$SOCK55" --session a |
| 7948 | pipe_send 'printf "rsz-%%s\\n" init-a\n' | 7663 | pipe_send 'printf "rsz-%%s\\n" init-a\n' |
| @@ -8020,9 +7735,8 @@ ok "Ctrl-\\ r trades cells between panes; Esc returns to prose" | |||
| 8020 | # still passes a byte grep, so the assertion replays the wall client's | 7735 | # still passes a byte grep, so the assertion replays the wall client's |
| 8021 | # FULL captured stdout through the render fixture (an engine, not a grep) | 7736 | # FULL captured stdout through the render fixture (an engine, not a grep) |
| 8022 | # and checks the right pane's marker text survives on the replayed grid. | 7737 | # and checks the right pane's marker text survives on the replayed grid. |
| 8023 | "$MUXD" run --sock "$SOCK56" --shell /bin/sh > "$OUT.spc.d" 2>&1 & | 7738 | start_daemon "$SOCK56" "$OUT.spc.d" "span-clear daemon never bound" --shell /bin/sh |
| 8024 | D57PID=$! | 7739 | D57PID=$DPID |
| 8025 | wait_sock "$SOCK56" "$OUT.spc.d" "span-clear daemon never bound" | ||
| 8026 | 7740 | ||
| 8027 | pipe_mux "$OUT.spca" "$OUT.spca.err" timeout 40 "$MUX" --sock "$SOCK56" --session a | 7741 | pipe_mux "$OUT.spca" "$OUT.spca.err" timeout 40 "$MUX" --sock "$SOCK56" --session a |
| 8028 | pipe_send 'printf "spc-%%s\\n" left-flood\n' | 7742 | pipe_send 'printf "spc-%%s\\n" left-flood\n' |
| @@ -8078,9 +7792,8 @@ ok "a span-clear flood in the left pane cannot blank the right pane's grid" | |||
| 8078 | # | 7792 | # |
| 8079 | # No convergence point: the assertion is per-session muxa capture, not a | 7793 | # No convergence point: the assertion is per-session muxa capture, not a |
| 8080 | # daemon-grid diff. | 7794 | # daemon-grid diff. |
| 8081 | "$MUXD" run --sock "$SOCK57" --shell /bin/sh > "$OUT.hjk.d" 2>&1 & | 7795 | start_daemon "$SOCK57" "$OUT.hjk.d" "hjkl daemon never bound" --shell /bin/sh |
| 8082 | D58PID=$! | 7796 | D58PID=$DPID |
| 8083 | wait_sock "$SOCK57" "$OUT.hjk.d" "hjkl daemon never bound" | ||
| 8084 | 7797 | ||
| 8085 | pipe_mux "$OUT.hjkcap" "$OUT.hjkcap.err" timeout 40 "$MUX" --sock "$SOCK57" --session a | 7798 | pipe_mux "$OUT.hjkcap" "$OUT.hjkcap.err" timeout 40 "$MUX" --sock "$SOCK57" --session a |
| 8086 | pipe_send 'printf "hjk-%%s\\n" origin\n' | 7799 | pipe_send 'printf "hjk-%%s\\n" origin\n' |
| @@ -8149,9 +7862,8 @@ ok "hjkl walks focus across panes in both axes" | |||
| 8149 | # daemon's session count rises to two, and the new pane's label bar sits | 7862 | # daemon's session count rises to two, and the new pane's label bar sits |
| 8150 | # at a column to the right of the rail (the rail paints as ESC[r;cH | 7863 | # at a column to the right of the rail (the rail paints as ESC[r;cH |
| 8151 | # ESC[7m — the same idiom the resize leg uses). | 7864 | # ESC[7m — the same idiom the resize leg uses). |
| 8152 | "$MUXD" run --sock "$SOCK58" --shell /bin/sh > "$OUT.spl.d" 2>&1 & | 7865 | start_daemon "$SOCK58" "$OUT.spl.d" "split-birth daemon never bound" --shell /bin/sh |
| 8153 | D59PID=$! | 7866 | D59PID=$DPID |
| 8154 | wait_sock "$SOCK58" "$OUT.spl.d" "split-birth daemon never bound" | ||
| 8155 | 7867 | ||
| 8156 | pipe_mux "$OUT.splcap" "$OUT.splcap.err" timeout 40 "$MUX" --sock "$SOCK58" --session a | 7868 | pipe_mux "$OUT.splcap" "$OUT.splcap.err" timeout 40 "$MUX" --sock "$SOCK58" --session a |
| 8157 | pipe_send 'printf "spl-%%s\\n" origin\n' | 7869 | pipe_send 'printf "spl-%%s\\n" origin\n' |
| @@ -8210,11 +7922,11 @@ ok "Ctrl-\\ | births a session beside; its label bar sits right of the rail" | |||
| 8210 | # right-resizes from a 40|40 split), and a marker typed into the restored | 7922 | # right-resizes from a 40|40 split), and a marker typed into the restored |
| 8211 | # wall lands in the focused session. | 7923 | # wall lands in the focused session. |
| 8212 | LPSTATE="${TMPDIR:-/tmp}/mux-e2e-lprrestore-state-$$" | 7924 | LPSTATE="${TMPDIR:-/tmp}/mux-e2e-lprrestore-state-$$" |
| 7925 | defer_rm "$LPSTATE" | ||
| 8213 | LPWALL="$LPSTATE/mux/wall" | 7926 | LPWALL="$LPSTATE/mux/wall" |
| 8214 | LPLAYOUT="$LPSTATE/mux/layout" | 7927 | LPLAYOUT="$LPSTATE/mux/layout" |
| 8215 | "$MUXD" run --sock "$SOCK59" --shell /bin/sh > "$OUT.lpr.d" 2>&1 & | 7928 | start_daemon "$SOCK59" "$OUT.lpr.d" "layout-restore daemon never bound" --shell /bin/sh |
| 8216 | D60PID=$! | 7929 | D60PID=$DPID |
| 8217 | wait_sock "$SOCK59" "$OUT.lpr.d" "layout-restore daemon never bound" | ||
| 8218 | 7930 | ||
| 8219 | pipe_mux "$OUT.lpra" "$OUT.lpra.err" timeout 40 "$MUX" --sock "$SOCK59" --session a | 7931 | pipe_mux "$OUT.lpra" "$OUT.lpra.err" timeout 40 "$MUX" --sock "$SOCK59" --session a |
| 8220 | pipe_send 'printf "lpr-%%s\\n" origin-a\n' | 7932 | pipe_send 'printf "lpr-%%s\\n" origin-a\n' |
| @@ -8335,11 +8047,11 @@ ok "a resized layout survives a detach/reattach round trip via the sidecar" | |||
| 8335 | # and the unmatched saved leaf collapses out. Two tiles, not three, and | 8047 | # and the unmatched saved leaf collapses out. Two tiles, not three, and |
| 8336 | # the wall did not refuse. | 8048 | # the wall did not refuse. |
| 8337 | LPHSTATE="${TMPDIR:-/tmp}/mux-e2e-lpheal-state-$$" | 8049 | LPHSTATE="${TMPDIR:-/tmp}/mux-e2e-lpheal-state-$$" |
| 8050 | defer_rm "$LPHSTATE" | ||
| 8338 | LPHWALL="$LPHSTATE/mux/wall" | 8051 | LPHWALL="$LPHSTATE/mux/wall" |
| 8339 | LPHLAYOUT="$LPHSTATE/mux/layout" | 8052 | LPHLAYOUT="$LPHSTATE/mux/layout" |
| 8340 | "$MUXD" run --sock "$SOCK60" --shell /bin/sh > "$OUT.lph.d" 2>&1 & | 8053 | start_daemon "$SOCK60" "$OUT.lph.d" "layout-heal daemon never bound" --shell /bin/sh |
| 8341 | D61PID=$! | 8054 | D61PID=$DPID |
| 8342 | wait_sock "$SOCK60" "$OUT.lph.d" "layout-heal daemon never bound" | ||
| 8343 | 8055 | ||
| 8344 | pipe_mux "$OUT.lpha" "$OUT.lpha.err" timeout 40 "$MUX" --sock "$SOCK60" --session a | 8056 | pipe_mux "$OUT.lpha" "$OUT.lpha.err" timeout 40 "$MUX" --sock "$SOCK60" --session a |
| 8345 | pipe_send 'printf "lph-%%s\\n" survivor-a\n' | 8057 | pipe_send 'printf "lph-%%s\\n" survivor-a\n' |
| @@ -8430,11 +8142,11 @@ ok "the layout heals on wall-file drift: survivor keeps its session, newcomer jo | |||
| 8430 | # session (the wall works), and the client's stderr never mentions | 8142 | # session (the wall works), and the client's stderr never mentions |
| 8431 | # "layout" (the degrade is silent). | 8143 | # "layout" (the degrade is silent). |
| 8432 | LPDSTATE="${TMPDIR:-/tmp}/mux-e2e-lpdegrade-state-$$" | 8144 | LPDSTATE="${TMPDIR:-/tmp}/mux-e2e-lpdegrade-state-$$" |
| 8145 | defer_rm "$LPDSTATE" | ||
| 8433 | LPDWALL="$LPDSTATE/mux/wall" | 8146 | LPDWALL="$LPDSTATE/mux/wall" |
| 8434 | LPDLAYOUT="$LPDSTATE/mux/layout" | 8147 | LPDLAYOUT="$LPDSTATE/mux/layout" |
| 8435 | "$MUXD" run --sock "$SOCK61" --shell /bin/sh > "$OUT.lpd.d" 2>&1 & | 8148 | start_daemon "$SOCK61" "$OUT.lpd.d" "layout-degrade daemon never bound" --shell /bin/sh |
| 8436 | D62PID=$! | 8149 | D62PID=$DPID |
| 8437 | wait_sock "$SOCK61" "$OUT.lpd.d" "layout-degrade daemon never bound" | ||
| 8438 | 8150 | ||
| 8439 | pipe_mux "$OUT.lpda" "$OUT.lpda.err" timeout 40 "$MUX" --sock "$SOCK61" --session a | 8151 | pipe_mux "$OUT.lpda" "$OUT.lpda.err" timeout 40 "$MUX" --sock "$SOCK61" --session a |
| 8440 | pipe_send 'printf "lpd-%%s\\n" origin\n' | 8152 | pipe_send 'printf "lpd-%%s\\n" origin\n' |
| @@ -8492,13 +8204,12 @@ ok "a corrupted sidecar degrades silently to the default layout" | |||
| 8492 | # label on the capture (the echo would match) but a marker typed AFTER | 8204 | # label on the capture (the echo would match) but a marker typed AFTER |
| 8493 | # the birth landing in daemon B's session b — a hit is B's shell's work. | 8205 | # the birth landing in daemon B's session b — a hit is B's shell's work. |
| 8494 | PRSTATE="${TMPDIR:-/tmp}/mux-e2e-prompt-state-$$" | 8206 | PRSTATE="${TMPDIR:-/tmp}/mux-e2e-prompt-state-$$" |
| 8207 | defer_rm "$PRSTATE" | ||
| 8495 | PRWALL="$PRSTATE/mux/wall" | 8208 | PRWALL="$PRSTATE/mux/wall" |
| 8496 | "$MUXD" run --sock "$SOCK62" --shell /bin/sh > "$OUT.pra.d" 2>&1 & | 8209 | start_daemon "$SOCK62" "$OUT.pra.d" "prompt daemon A never bound" --shell /bin/sh |
| 8497 | D63PID=$! | 8210 | D63PID=$DPID |
| 8498 | wait_sock "$SOCK62" "$OUT.pra.d" "prompt daemon A never bound" | 8211 | start_daemon "$SOCK63" "$OUT.prb.d" "prompt daemon B never bound" --shell /bin/sh |
| 8499 | "$MUXD" run --sock "$SOCK63" --shell /bin/sh > "$OUT.prb.d" 2>&1 & | 8212 | D64PID=$DPID |
| 8500 | D64PID=$! | ||
| 8501 | wait_sock "$SOCK63" "$OUT.prb.d" "prompt daemon B never bound" | ||
| 8502 | 8213 | ||
| 8503 | pipe_mux "$OUT.pra" "$OUT.pra.err" timeout 40 "$MUX" --sock "$SOCK62" --session a | 8214 | pipe_mux "$OUT.pra" "$OUT.pra.err" timeout 40 "$MUX" --sock "$SOCK62" --session a |
| 8504 | pipe_send 'printf "pr-%%s\\n" origin\n' | 8215 | pipe_send 'printf "pr-%%s\\n" origin\n' |
| @@ -8620,10 +8331,9 @@ ok "Ctrl-\\ : adds a tile by spelling: born on another daemon, recorded, refusal | |||
| 8620 | # loop, and the `Ctrl-\ w` half at the end of this leg runs `hydrate()`. | 8331 | # loop, and the `Ctrl-\ w` half at the end of this leg runs `hydrate()`. |
| 8621 | head -c 32 /dev/urandom > "$HYKEY" | 8332 | head -c 32 /dev/urandom > "$HYKEY" |
| 8622 | chmod 600 "$HYKEY" | 8333 | chmod 600 "$HYKEY" |
| 8623 | "$MUXD" run --sock "$SOCK64" --shell /bin/sh \ | 8334 | start_daemon "$SOCK64" "$OUT.hyd.d" "hydrate-create daemon never bound" --shell /bin/sh \ |
| 8624 | --quic "127.0.0.1:$HYPORT" --key "$HYKEY" --quic-idle-ms 15000 > "$OUT.hyd.d" 2>&1 & | 8335 | --quic "127.0.0.1:$HYPORT" --key "$HYKEY" --quic-idle-ms 15000 |
| 8625 | D65PID=$! | 8336 | D65PID=$DPID |
| 8626 | wait_sock "$SOCK64" "$OUT.hyd.d" "hydrate-create daemon never bound" | ||
| 8627 | 8337 | ||
| 8628 | # The wall file names three sessions this daemon does not have. Written by | 8338 | # The wall file names three sessions this daemon does not have. Written by |
| 8629 | # hand rather than earned by an attach, because an attach that earned the | 8339 | # hand rather than earned by an attach, because an attach that earned the |
| @@ -8781,6 +8491,7 @@ ok "a saved local line comes back as a fresh session, by wall and by fold; a rem | |||
| 8781 | mkdir -p "$REFSTATE" | 8491 | mkdir -p "$REFSTATE" |
| 8782 | XDG_STATE_HOME="$REFSTATE" "$MUXD" run --sock "$SOCK66" --shell /bin/sh > "$OUT.ref.d" 2>&1 & | 8492 | XDG_STATE_HOME="$REFSTATE" "$MUXD" run --sock "$SOCK66" --shell /bin/sh > "$OUT.ref.d" 2>&1 & |
| 8783 | D66PID=$! | 8493 | D66PID=$! |
| 8494 | defer_kill "$D66PID" | ||
| 8784 | wait_sock "$SOCK66" "$OUT.ref.d" "refused-attach daemon never bound" | 8495 | wait_sock "$SOCK66" "$OUT.ref.d" "refused-attach daemon never bound" |
| 8785 | 8496 | ||
| 8786 | # Each verb twice over: the words it must say, and the words it must not. | 8497 | # Each verb twice over: the words it must say, and the words it must not. |
| @@ -8868,10 +8579,9 @@ ok "muxa names a refused attach instead of a shell that never ran" | |||
| 8868 | # other half: one birth, not two, and nothing born for the remote line. | 8579 | # other half: one birth, not two, and nothing born for the remote line. |
| 8869 | head -c 32 /dev/urandom > "$WGKEY" | 8580 | head -c 32 /dev/urandom > "$WGKEY" |
| 8870 | chmod 600 "$WGKEY" | 8581 | chmod 600 "$WGKEY" |
| 8871 | "$MUXD" run --sock "$SOCK67" --shell /bin/sh \ | 8582 | start_daemon "$SOCK67" "$OUT.wg.d" "web-restore daemon never bound" --shell /bin/sh \ |
| 8872 | --quic "127.0.0.1:$WGQPORT" --key "$WGKEY" --quic-idle-ms 15000 > "$OUT.wg.d" 2>&1 & | 8583 | --quic "127.0.0.1:$WGQPORT" --key "$WGKEY" --quic-idle-ms 15000 |
| 8873 | D67PID=$! | 8584 | D67PID=$DPID |
| 8874 | wait_sock "$SOCK67" "$OUT.wg.d" "web-restore daemon never bound" | ||
| 8875 | 8585 | ||
| 8876 | # Written by hand for the hydrate leg's reason: a line the hub had earned | 8586 | # Written by hand for the hydrate leg's reason: a line the hub had earned |
| 8877 | # by attaching would name a session that already exists, and there would be | 8587 | # by attaching would name a session that already exists, and there would be |
| @@ -8892,6 +8602,7 @@ done | |||
| 8892 | XDG_STATE_HOME="$WGSTATE" "$MUXWEB" --port "$WGPORT" --key "$WGKEY" \ | 8602 | XDG_STATE_HOME="$WGSTATE" "$MUXWEB" --port "$WGPORT" --key "$WGKEY" \ |
| 8893 | --quic-idle-ms 15000 > "$OUT.wgh" 2>&1 & | 8603 | --quic-idle-ms 15000 > "$OUT.wgh" 2>&1 & |
| 8894 | W5PID=$! | 8604 | W5PID=$! |
| 8605 | defer_kill "$W5PID" | ||
| 8895 | wait_for "$OUT.wgh" "serving" 10 || { | 8606 | wait_for "$OUT.wgh" "serving" 10 || { |
| 8896 | echo "e2e FAIL: web-restore: hub never reported serving"; cat "$OUT.wgh"; exit 1; } | 8607 | echo "e2e FAIL: web-restore: hub never reported serving"; cat "$OUT.wgh"; exit 1; } |
| 8897 | 8608 | ||
| @@ -9056,9 +8767,8 @@ ok "the browser wall restores a saved local line too, and still joins a remote o | |||
| 9056 | # its own ssh, and the shim logs its pid before exec, so `wc -l` is a | 8767 | # its own ssh, and the shim logs its pid before exec, so `wc -l` is a |
| 9057 | # count of PROCESSES the OS made. A hub counter would be the code under | 8768 | # count of PROCESSES the OS made. A hub counter would be the code under |
| 9058 | # test grading its own homework. | 8769 | # test grading its own homework. |
| 9059 | "$MUXD" run --sock "$SOCK68" --shell /bin/sh > "$OUT.sp.d" 2>&1 & | 8770 | start_daemon "$SOCK68" "$OUT.sp.d" "refusal-spin daemon never bound" --shell /bin/sh |
| 9060 | D68PID=$! | 8771 | D68PID=$DPID |
| 9061 | wait_sock "$SOCK68" "$OUT.sp.d" "refusal-spin daemon never bound" | ||
| 9062 | 8772 | ||
| 9063 | # This shim ignores the remote command on purpose — it is not modelling | 8773 | # This shim ignores the remote command on purpose — it is not modelling |
| 9064 | # ssh (the M14 shim above does that), it is the dial's process signature | 8774 | # ssh (the M14 shim above does that), it is the dial's process signature |
| @@ -9084,6 +8794,7 @@ printf 'mux-spin@127.0.0.1#spinghost\n' > "$SPSTATE/mux/wall" | |||
| 9084 | XDG_STATE_HOME="$SPSTATE" XDG_CACHE_HOME="$SPSTATE/cache" PATH="$SPDIR:$PATH" \ | 8794 | XDG_STATE_HOME="$SPSTATE" XDG_CACHE_HOME="$SPSTATE/cache" PATH="$SPDIR:$PATH" \ |
| 9085 | "$MUXWEB" --port "$SPPORT" > "$OUT.sph" 2>&1 & | 8795 | "$MUXWEB" --port "$SPPORT" > "$OUT.sph" 2>&1 & |
| 9086 | W6PID=$! | 8796 | W6PID=$! |
| 8797 | defer_kill "$W6PID" | ||
| 9087 | wait_for "$OUT.sph" "serving" 10 || { | 8798 | wait_for "$OUT.sph" "serving" 10 || { |
| 9088 | echo "e2e FAIL: refusal-spin: hub never reported serving"; cat "$OUT.sph"; exit 1; } | 8799 | echo "e2e FAIL: refusal-spin: hub never reported serving"; cat "$OUT.sph"; exit 1; } |
| 9089 | 8800 | ||
| @@ -9163,6 +8874,7 @@ mkdir -p "$UPHOME" | |||
| 9163 | MUX_SHELL_INTEGRATION=1 HOME="$UPHOME" "$MUXD" run --sock "$SOCK69" \ | 8874 | MUX_SHELL_INTEGRATION=1 HOME="$UPHOME" "$MUXD" run --sock "$SOCK69" \ |
| 9164 | --shell /bin/bash > "$OUT.up.d" 2>&1 & | 8875 | --shell /bin/bash > "$OUT.up.d" 2>&1 & |
| 9165 | D69PID=$! | 8876 | D69PID=$! |
| 8877 | defer_kill "$D69PID" | ||
| 9166 | wait_sock "$SOCK69" "$OUT.up.d" "upgrade daemon never bound" | 8878 | wait_sock "$SOCK69" "$OUT.up.d" "upgrade daemon never bound" |
| 9167 | 8879 | ||
| 9168 | # Marks BEFORE the exec, so "marks after" is a comparison rather than a | 8880 | # Marks BEFORE the exec, so "marks after" is a comparison rather than a |
| @@ -9210,6 +8922,7 @@ send \x1cd | |||
| 9210 | waitexit 15000 | 8922 | waitexit 15000 |
| 9211 | EOF | 8923 | EOF |
| 9212 | UPPCPID=$! | 8924 | UPPCPID=$! |
| 8925 | defer_kill "$UPPCPID" | ||
| 9213 | 8926 | ||
| 9214 | # Daemon truth for the pid, and the number this leg is built around. The | 8927 | # Daemon truth for the pid, and the number this leg is built around. The |
| 9215 | # echoed command line spells `$$`, so only the shell's own answer has | 8928 | # echoed command line spells `$$`, so only the shell's own answer has |
| @@ -9254,6 +8967,7 @@ chmod 755 "$UPBIN" | |||
| 9254 | kill -STOP "$D69PID" | 8967 | kill -STOP "$D69PID" |
| 9255 | "$UPBIN" upgrade --sock "$SOCK69" --allow-same-version > "$OUT.upref2" 2>&1 & | 8968 | "$UPBIN" upgrade --sock "$SOCK69" --allow-same-version > "$OUT.upref2" 2>&1 & |
| 9256 | UPXPID=$! | 8969 | UPXPID=$! |
| 8970 | defer_kill "$UPXPID" | ||
| 9257 | _i=0 | 8971 | _i=0 |
| 9258 | while [ "$(readlink "/proc/$UPXPID/exe" 2>/dev/null)" != "$UPBIN" ]; do | 8972 | while [ "$(readlink "/proc/$UPXPID/exe" 2>/dev/null)" != "$UPBIN" ]; do |
| 9259 | _i=$((_i + 1)) | 8973 | _i=$((_i + 1)) |
| @@ -9439,9 +9153,8 @@ ok "muxd upgrade keeps the shell, its pid, its title, its marks and its counters | |||
| 9439 | # assertion below would pass just as well on an upgrade that simply worked. | 9153 | # assertion below would pass just as well on an upgrade that simply worked. |
| 9440 | mkdir -p "$UPHOME" | 9154 | mkdir -p "$UPHOME" |
| 9441 | MUX_SHELL_INTEGRATION=1 MUX_RESUME_FAIL_AT=session HOME="$UPHOME" \ | 9155 | MUX_SHELL_INTEGRATION=1 MUX_RESUME_FAIL_AT=session HOME="$UPHOME" \ |
| 9442 | "$MUXD" run --sock "$SOCK70" --shell /bin/bash > "$OUT.url.d" 2>&1 & | 9156 | start_daemon "$SOCK70" "$OUT.url.d" "rollback daemon never bound" --shell /bin/bash |
| 9443 | D70PID=$! | 9157 | D70PID=$DPID |
| 9444 | wait_sock "$SOCK70" "$OUT.url.d" "rollback daemon never bound" | ||
| 9445 | 9158 | ||
| 9446 | timeout 20 "$MUXA" run --sock "$SOCK70" --timeout 8000 'echo rollpid=$$' > "$OUT.urlm1" 2>&1 || { | 9159 | timeout 20 "$MUXA" run --sock "$SOCK70" --timeout 8000 'echo rollpid=$$' > "$OUT.urlm1" 2>&1 || { |
| 9447 | echo "e2e FAIL: rollback: muxa run failed before the upgrade:" | 9160 | echo "e2e FAIL: rollback: muxa run failed before the upgrade:" |
| @@ -9497,12 +9210,12 @@ ok "a candidate that cannot adopt execs the old binary back, session and marks i | |||
| 9497 | # Its own agent rather than the forwarding legs' AGENT48: that one is left | 9210 | # Its own agent rather than the forwarding legs' AGENT48: that one is left |
| 9498 | # under SIGSTOP by the mute-offerer leg, and a mute agent is exactly what | 9211 | # under SIGSTOP by the mute-offerer leg, and a mute agent is exactly what |
| 9499 | # this leg cannot tell from a broken listener. | 9212 | # this leg cannot tell from a broken listener. |
| 9500 | "$MUXD" run --sock "$SOCK71" --shell /bin/sh > "$OUT.uag.d" 2>&1 & | 9213 | start_daemon "$SOCK71" "$OUT.uag.d" "agent-upgrade daemon never bound" --shell /bin/sh |
| 9501 | D71PID=$! | 9214 | D71PID=$DPID |
| 9502 | wait_sock "$SOCK71" "$OUT.uag.d" "agent-upgrade daemon never bound" | ||
| 9503 | 9215 | ||
| 9504 | ssh-agent -a "$UPAGENT" > "$OUT.uagenv" 2>&1 | 9216 | ssh-agent -a "$UPAGENT" > "$OUT.uagenv" 2>&1 |
| 9505 | UPAGPID=$(sed -n 's/.*SSH_AGENT_PID=\([0-9]*\).*/\1/p' "$OUT.uagenv") | 9217 | UPAGPID=$(sed -n 's/.*SSH_AGENT_PID=\([0-9]*\).*/\1/p' "$OUT.uagenv") |
| 9218 | defer_kill "$UPAGPID" | ||
| 9506 | [ -n "$UPAGPID" ] || { | 9219 | [ -n "$UPAGPID" ] || { |
| 9507 | echo "e2e FAIL: agent-upgrade: ssh-agent printed no pid for the trap to hold it by:" | 9220 | echo "e2e FAIL: agent-upgrade: ssh-agent printed no pid for the trap to hold it by:" |
| 9508 | cat "$OUT.uagenv"; exit 1; } | 9221 | cat "$OUT.uagenv"; exit 1; } |
| @@ -9581,10 +9294,9 @@ ok "the session's agent socket crosses the exec: ssh-add -l answers again" | |||
| 9581 | # here: back in service in a fraction of `--quic-idle-ms`, not after it. | 9294 | # here: back in service in a fraction of `--quic-idle-ms`, not after it. |
| 9582 | head -c 32 /dev/urandom > "$UPKEY" | 9295 | head -c 32 /dev/urandom > "$UPKEY" |
| 9583 | chmod 600 "$UPKEY" | 9296 | chmod 600 "$UPKEY" |
| 9584 | "$MUXD" run --sock "$SOCK72" --shell /bin/sh \ | 9297 | start_daemon "$SOCK72" "$OUT.uqc.d" "quic-upgrade daemon never bound" --shell /bin/sh \ |
| 9585 | --quic "127.0.0.1:$UPQPORT" --key "$UPKEY" --quic-idle-ms 15000 > "$OUT.uqc.d" 2>&1 & | 9298 | --quic "127.0.0.1:$UPQPORT" --key "$UPKEY" --quic-idle-ms 15000 |
| 9586 | D72PID=$! | 9299 | D72PID=$DPID |
| 9587 | wait_sock "$SOCK72" "$OUT.uqc.d" "quic-upgrade daemon never bound" | ||
| 9588 | 9300 | ||
| 9589 | pipe_mux "$OUT.uqc" "$OUT.uqc.err" timeout 90 "$MUX" "quic://127.0.0.1:$UPQPORT" \ | 9301 | pipe_mux "$OUT.uqc" "$OUT.uqc.err" timeout 90 "$MUX" "quic://127.0.0.1:$UPQPORT" \ |
| 9590 | --key "$UPKEY" --quic-idle-ms 15000 | 9302 | --key "$UPKEY" --quic-idle-ms 15000 |
| @@ -9646,9 +9358,8 @@ ok "a QUIC client is served again within a breath of the exec, not after the idl | |||
| 9646 | # sessions make it a table's grace, not one shell's. | 9358 | # sessions make it a table's grace, not one shell's. |
| 9647 | printf '#!/bin/sh\ntrap "" HUP TERM\nwhile :; do sleep 1; done\n' > "$OUT.sg.sh" | 9359 | printf '#!/bin/sh\ntrap "" HUP TERM\nwhile :; do sleep 1; done\n' > "$OUT.sg.sh" |
| 9648 | chmod +x "$OUT.sg.sh" | 9360 | chmod +x "$OUT.sg.sh" |
| 9649 | "$MUXD" run --sock "$SOCK73" --shell "$OUT.sg.sh" > "$OUT.sg.d" 2>&1 & | 9361 | start_daemon "$SOCK73" "$OUT.sg.d" "stop-gone daemon never bound" --shell "$OUT.sg.sh" |
| 9650 | D73PID=$! | 9362 | D73PID=$DPID |
| 9651 | wait_sock "$SOCK73" "$OUT.sg.d" "stop-gone daemon never bound" | ||
| 9652 | pipe_mux "$OUT.sg" "" timeout 60 "$MUX" --sock "$SOCK73" --session second | 9363 | pipe_mux "$OUT.sg" "" timeout 60 "$MUX" --sock "$SOCK73" --session second |
| 9653 | sleep 0.5 | 9364 | sleep 0.5 |
| 9654 | pipe_detach "stop-gone: the second session's client" | 9365 | pipe_detach "stop-gone: the second session's client" |