a73x

b55a35f9

test: e2e — every wall on a terminal gets a hosts file of its own

a73x   2026-08-28 19:53

Commit message
test: e2e — every wall on a terminal gets a hosts file of its own

The suite's shared `$XDG_STATE_HOME` is now a WALL: every `mux TARGET`
records the daemon it attached to, and every `mux` on a terminal opens on
every line it finds. By group 03 that file is a dozen daemons, all but
one of them stopped, so a pty leg's own tile arrived under a screenful of
`[unreachable]` stripes and the geometry it asserted was somebody else's.

`hostroom NAME` (e2e_lib.sh) spells a private state home for one leg, and
every pty leg that runs `mux` passes it. Per LEG and not per group: within
a group the earlier legs' daemons are stopped by the time the later ones
run, which is the same problem one scope in.

Three consequences of the model that the legs had to be told about:

  * a leg that asserts the DEFAULT cut removes any saved tree first. A
    wall on a terminal saves its tree on the way out, so a second
    ptyclient run in the same state home restores the first one's — and
    the aspect rule only applies when nothing is saved.
  * `exit` in the focused tile ends `mux` only when that tile was the
    wall. A daemon always holds its own default session, so a leg that
    named a second one has two tiles and leaves by chord instead; the
    legs whose daemon has exactly one session keep asserting the other
    half of the rule.
  * scenario 09's wall runs at 80 columns, not 100: the aspect rule cuts
    four stripes BESIDE at 100x44, twenty columns each, and `labelText`
    spends a narrow bar on the state word — the socket path those
    assertions grep for is the first thing to go.

`make e2e`: 81 scenarios, 37 convergence points, green.

test/e2e_02_predict.sh
Old New
@@ -497,7 +497,8 @@ D12PID=$DPID
497 # prompt is assertable: it is the quiesce signal that would otherwise 497 # prompt is assertable: it is the quiesce signal that would otherwise
498 # have to be a sleep. 498 # have to be a sleep.
499 set +e 499 set +e
500 timeout 40 "$PTYCLIENT" --cols 100 --rows 30 --out "$OUT.tp2a" --err "$OUT.tp2a.err" -- \ 500 hostroom pty2a
501 XDG_STATE_HOME="$HOSTROOM" timeout 40 "$PTYCLIENT" --cols 100 --rows 30 --out "$OUT.tp2a" --err "$OUT.tp2a.err" -- \
501 "$MUX" --sock "$SOCK12" > "$OUT.tp2a.log" 2>&1 <<'EOF' 502 "$MUX" --sock "$SOCK12" > "$OUT.tp2a.log" 2>&1 <<'EOF'
502 expect \x1b[?1049h 10000 503 expect \x1b[?1049h 10000
503 send PS1=tp2rdy@\n 504 send PS1=tp2rdy@\n
@@ -584,7 +585,8 @@ assert_converged "$OUT.tp2a" "$SOCK12" "pty attach at 100x30" 100 30
584 # the session is already idle; straight after a resize the answering 585 # the session is already idle; straight after a resize the answering
585 # snapshot has not been generated yet. 586 # snapshot has not been generated yet.
586 set +e 587 set +e
587 timeout 40 "$PTYCLIENT" --cols 90 --rows 28 --out "$OUT.tp2b" --err "$OUT.tp2b.err" -- \ 588 hostroom pty2b
589 XDG_STATE_HOME="$HOSTROOM" timeout 40 "$PTYCLIENT" --cols 90 --rows 28 --out "$OUT.tp2b" --err "$OUT.tp2b.err" -- \
588 "$MUX" --sock "$SOCK12" > "$OUT.tp2b.log" 2>&1 <<'EOF' 590 "$MUX" --sock "$SOCK12" > "$OUT.tp2b.log" 2>&1 <<'EOF'
589 expect \x1b[?1049h 10000 591 expect \x1b[?1049h 10000
590 send seq 1 60; printf 'fill-%s\\n' done\n 592 send seq 1 60; printf 'fill-%s\\n' done\n
@@ -676,7 +678,8 @@ done
676 # because the whole-chunk mem.eql at client.zig:882 is what recognizes it — 678 # because the whole-chunk mem.eql at client.zig:882 is what recognizes it —
677 # split across two reads it matches nothing, falls through to the keystroke 679 # split across two reads it matches nothing, falls through to the keystroke
678 # path, and is both counted suppressed and forwarded to the shell as input. 680 # path, and is both counted suppressed and forwarded to the shell as input.
679 MUX_PREDICT_STATS=1 timeout 60 "$PTYCLIENT" --cols 80 --rows 24 \ 681 hostroom predict1
682 XDG_STATE_HOME="$HOSTROOM" MUX_PREDICT_STATS=1 timeout 60 "$PTYCLIENT" --cols 80 --rows 24 \
680 --out "$OUT.tp1" --err "$OUT.tp1.err" -- \ 683 --out "$OUT.tp1" --err "$OUT.tp1.err" -- \
681 "$MUX" --via "$MUXD proxy --sock $SOCK13" > "$OUT.tp1.log" 2>&1 <<'EOF' & 684 "$MUX" --via "$MUXD proxy --sock $SOCK13" > "$OUT.tp1.log" 2>&1 <<'EOF' &
682 expect \x1b[0m100 10000 685 expect \x1b[0m100 10000
test/e2e_03_side.sh
Old New
@@ -120,7 +120,8 @@ ok "attach auto-start via proxy; muxd stop tears it down"
120 # detaches on the output stops one frame short of the grid the daemon 120 # detaches on the output stops one frame short of the grid the daemon
121 # holds, and the convergence check below would blame the product for it. 121 # holds, and the convergence check below would blame the product for it.
122 set +e 122 set +e
123 SHELL=/bin/sh PATH="$(dirname "$MUXD"):$PATH" timeout 40 \ 123 hostroom autostart
124 SHELL=/bin/sh PATH="$(dirname "$MUXD"):$PATH" XDG_STATE_HOME="$HOSTROOM" timeout 40 \
124 "$PTYCLIENT" --cols 80 --rows 24 --out "$OUT.pa" --err "$OUT.pa.err" \ 125 "$PTYCLIENT" --cols 80 --rows 24 --out "$OUT.pa" --err "$OUT.pa.err" \
125 -- "$MUX" --sock "$SOCK15" > "$OUT.pa.log" 2>&1 <<'EOF' 126 -- "$MUX" --sock "$SOCK15" > "$OUT.pa.log" 2>&1 <<'EOF'
126 expect \x1b[?1049h 15000 127 expect \x1b[?1049h 15000
@@ -191,7 +192,8 @@ CLIPSH
191 # verb has to carry $OUT's per-run path. Nothing else in it needs expanding 192 # verb has to carry $OUT's per-run path. Nothing else in it needs expanding
192 # — `\n` and `\x1c` are not escapes the shell touches. 193 # — `\n` and `\x1c` are not escapes the shell touches.
193 set +e 194 set +e
194 timeout 40 "$PTYCLIENT" --cols 80 --rows 24 --out "$OUT.clip" --err "$OUT.clip.err" \ 195 hostroom clip
196 XDG_STATE_HOME="$HOSTROOM" timeout 40 "$PTYCLIENT" --cols 80 --rows 24 --out "$OUT.clip" --err "$OUT.clip.err" \
195 -- "$MUX" --sock "$SOCK" > "$OUT.clip.log" 2>&1 <<EOF 197 -- "$MUX" --sock "$SOCK" > "$OUT.clip.log" 2>&1 <<EOF
196 expect \x1b[?1049h 15000 198 expect \x1b[?1049h 15000
197 settle 400 15000 199 settle 400 15000
@@ -247,7 +249,8 @@ printf '\033[?2004h'
247 printf 'TITLEDONE\n' 249 printf 'TITLEDONE\n'
248 TITLESH 250 TITLESH
249 set +e 251 set +e
250 timeout 40 "$PTYCLIENT" --cols 80 --rows 24 --out "$OUT.title" --err "$OUT.title.err" \ 252 hostroom title
253 XDG_STATE_HOME="$HOSTROOM" timeout 40 "$PTYCLIENT" --cols 80 --rows 24 --out "$OUT.title" --err "$OUT.title.err" \
251 -- "$MUX" --sock "$SOCK" > "$OUT.title.log" 2>&1 <<EOF 254 -- "$MUX" --sock "$SOCK" > "$OUT.title.log" 2>&1 <<EOF
252 expect \x1b[?1049h 15000 255 expect \x1b[?1049h 15000
253 settle 400 15000 256 settle 400 15000
@@ -402,7 +405,8 @@ ok "a client that takes no terminal over changes no terminal state"
402 # fixture dump would. The cost is real — 124 loses the "last N bytes 405 # fixture dump would. The cost is real — 124 loses the "last N bytes
403 # received" line — so anything raised here should raise this too. 406 # received" line — so anything raised here should raise this too.
404 set +e 407 set +e
405 timeout 60 "$PTYCLIENT" --cols 80 --rows 24 --out "$OUT.paste" --err "$OUT.paste.err" \ 408 hostroom paste
409 XDG_STATE_HOME="$HOSTROOM" timeout 60 "$PTYCLIENT" --cols 80 --rows 24 --out "$OUT.paste" --err "$OUT.paste.err" \
406 -- "$MUX" --sock "$SOCK" > "$OUT.paste.log" 2>&1 <<EOF 410 -- "$MUX" --sock "$SOCK" > "$OUT.paste.log" 2>&1 <<EOF
407 expect \x1b[?1049h 15000 411 expect \x1b[?1049h 15000
408 settle 400 15000 412 settle 400 15000
@@ -515,7 +519,8 @@ printf '\007\007\007\007\007'
515 printf 'BELLDONE\n' 519 printf 'BELLDONE\n'
516 BELLSH 520 BELLSH
517 set +e 521 set +e
518 timeout 40 "$PTYCLIENT" --cols 80 --rows 24 --out "$OUT.bell" --err "$OUT.bell.err" \ 522 hostroom bell
523 XDG_STATE_HOME="$HOSTROOM" timeout 40 "$PTYCLIENT" --cols 80 --rows 24 --out "$OUT.bell" --err "$OUT.bell.err" \
519 -- "$MUX" --sock "$SOCK24" > "$OUT.bell.log" 2>&1 <<EOF 524 -- "$MUX" --sock "$SOCK24" > "$OUT.bell.log" 2>&1 <<EOF
520 expect \x1b[?1049h 15000 525 expect \x1b[?1049h 15000
521 settle 400 15000 526 settle 400 15000
test/e2e_06_web.sh
Old New
@@ -61,7 +61,8 @@ wait_grid "$SOCK18" "wall-pin" "tiny attach: the first marker"
61 # landed, so the grid it could have wrecked was live the whole time. The 61 # landed, so the grid it could have wrecked was live the whole time. The
62 # marker is typed only after the fixture reports its claim sent (`done 2`), 62 # marker is typed only after the fixture reports its claim sent (`done 2`),
63 # so the ordering is witnessed rather than paced. 63 # so the ordering is witnessed rather than paced.
64 timeout 40 "$PTYCLIENT" --cols 1 --rows 1 --out "$OUT.web1x1" --err "$OUT.web1x1.err" \ 64 hostroom web1x1
65 XDG_STATE_HOME="$HOSTROOM" timeout 40 "$PTYCLIENT" --cols 1 --rows 1 --out "$OUT.web1x1" --err "$OUT.web1x1.err" \
65 -- "$MUX" --sock "$SOCK18" > "$OUT.web1x1.log" 2>&1 <<'EOF' & 66 -- "$MUX" --sock "$SOCK18" > "$OUT.web1x1.log" 2>&1 <<'EOF' &
66 expect \x1b[?1049h 15000 67 expect \x1b[?1049h 15000
67 send \x20 68 send \x20
test/e2e_07_wallcli.sh
Old New
@@ -77,9 +77,10 @@ wait_grid "$SOCK26" "cwb-pin" "CLI wall: session b's marker" b
77 CWINJPID=$! 77 CWINJPID=$!
78 defer_kill "$CWINJPID" 78 defer_kill "$CWINJPID"
79 set +e 79 set +e
80 # No saved tree: this leg asserts the DEFAULT cut, and every wall that 80 # No saved tree: this leg asserts the DEFAULT cut, and a wall ON A
81 # came before it saved a sidecar on its way out. The aspect rule applies 81 # TERMINAL saves its tree on the way out — so a ptyclient leg sharing this
82 # only when nothing is saved. 82 # state home has already left one. The aspect rule applies only when
83 # nothing is saved.
83 rm -f "$CWSTATE/mux/layout" 84 rm -f "$CWSTATE/mux/layout"
84 XDG_STATE_HOME="$CWSTATE" timeout 40 "$PTYCLIENT" --cols 40 --rows 30 \ 85 XDG_STATE_HOME="$CWSTATE" timeout 40 "$PTYCLIENT" --cols 40 --rows 30 \
85 --out "$OUT.cwcap" --err "$OUT.cwcap.err" -- \ 86 --out "$OUT.cwcap" --err "$OUT.cwcap.err" -- \
@@ -132,9 +133,10 @@ start_daemon "$SOCK27" "$OUT.pfx.d" "prefix daemon never bound" --shell /bin/sh
132 D24PID=$DPID 133 D24PID=$DPID
133 134
134 set +e 135 set +e
135 # No saved tree: this leg asserts the DEFAULT cut, and every wall that 136 # No saved tree: this leg asserts the DEFAULT cut, and a wall ON A
136 # came before it saved a sidecar on its way out. The aspect rule applies 137 # TERMINAL saves its tree on the way out — so a ptyclient leg sharing this
137 # only when nothing is saved. 138 # state home has already left one. The aspect rule applies only when
139 # nothing is saved.
138 rm -f "$PFXSTATE/mux/layout" 140 rm -f "$PFXSTATE/mux/layout"
139 XDG_STATE_HOME="$PFXSTATE" timeout 40 "$PTYCLIENT" --cols 80 --rows 24 \ 141 XDG_STATE_HOME="$PFXSTATE" timeout 40 "$PTYCLIENT" --cols 80 --rows 24 \
140 --out "$OUT.pfx" --err "$OUT.pfx.err" \ 142 --out "$OUT.pfx" --err "$OUT.pfx.err" \
@@ -202,9 +204,10 @@ start_daemon "$SOCK28" "$OUT.nsw.d" "new-session daemon never bound" --shell /bi
202 D25PID=$DPID 204 D25PID=$DPID
203 205
204 set +e 206 set +e
205 # No saved tree: this leg asserts the DEFAULT cut, and every wall that 207 # No saved tree: this leg asserts the DEFAULT cut, and a wall ON A
206 # came before it saved a sidecar on its way out. The aspect rule applies 208 # TERMINAL saves its tree on the way out — so a ptyclient leg sharing this
207 # only when nothing is saved. 209 # state home has already left one. The aspect rule applies only when
210 # nothing is saved.
208 rm -f "$NSWSTATE/mux/layout" 211 rm -f "$NSWSTATE/mux/layout"
209 XDG_STATE_HOME="$NSWSTATE" timeout 40 "$PTYCLIENT" --cols 40 --rows 24 \ 212 XDG_STATE_HOME="$NSWSTATE" timeout 40 "$PTYCLIENT" --cols 40 --rows 24 \
210 --out "$OUT.nsw" --err "$OUT.nsw.err" \ 213 --out "$OUT.nsw" --err "$OUT.nsw.err" \
@@ -253,9 +256,10 @@ fill_sessions "$SOCK28" "$OUT.nswfill" fill 2 7
253 wait_sessions "$SOCK28" 8 "new session: the wall's terminal should be exactly full" 256 wait_sessions "$SOCK28" 8 "new session: the wall's terminal should be exactly full"
254 257
255 set +e 258 set +e
256 # No saved tree: this leg asserts the DEFAULT cut, and every wall that 259 # No saved tree: this leg asserts the DEFAULT cut, and a wall ON A
257 # came before it saved a sidecar on its way out. The aspect rule applies 260 # TERMINAL saves its tree on the way out — so a ptyclient leg sharing this
258 # only when nothing is saved. 261 # state home has already left one. The aspect rule applies only when
262 # nothing is saved.
259 rm -f "$NSWSTATE/mux/layout" 263 rm -f "$NSWSTATE/mux/layout"
260 XDG_STATE_HOME="$NSWSTATE" timeout 60 "$PTYCLIENT" --cols 40 --rows 24 \ 264 XDG_STATE_HOME="$NSWSTATE" timeout 60 "$PTYCLIENT" --cols 40 --rows 24 \
261 --out "$OUT.nsw2" --err "$OUT.nsw2.err" \ 265 --out "$OUT.nsw2" --err "$OUT.nsw2.err" \
@@ -351,9 +355,10 @@ D26PID=$DPID
351 355
352 set +e 356 set +e
353 # tall: Ctrl-\ c adds tiles at 80x24 (80 >= 48) 357 # tall: Ctrl-\ c adds tiles at 80x24 (80 >= 48)
354 # No saved tree: this leg asserts the DEFAULT cut, and every wall that 358 # No saved tree: this leg asserts the DEFAULT cut, and a wall ON A
355 # came before it saved a sidecar on its way out. The aspect rule applies 359 # TERMINAL saves its tree on the way out — so a ptyclient leg sharing this
356 # only when nothing is saved. 360 # state home has already left one. The aspect rule applies only when
361 # nothing is saved.
357 rm -f "$RINGSTATE/mux/layout" 362 rm -f "$RINGSTATE/mux/layout"
358 XDG_STATE_HOME="$RINGSTATE" timeout 60 "$PTYCLIENT" --cols 40 --rows 24 \ 363 XDG_STATE_HOME="$RINGSTATE" timeout 60 "$PTYCLIENT" --cols 40 --rows 24 \
359 --out "$OUT.ring" --err "$OUT.ring.err" \ 364 --out "$OUT.ring" --err "$OUT.ring.err" \
test/e2e_08_mouse.sh
Old New
@@ -98,7 +98,8 @@ done
98 # writes that pair. (Measured: with the plain needle this leg passes on the 98 # writes that pair. (Measured: with the plain needle this leg passes on the
99 # mode enable and sends the wheel before the snapshot has landed.) 99 # mode enable and sends the wheel before the snapshot has landed.)
100 set +e 100 set +e
101 timeout 40 "$PTYCLIENT" --cols 80 --rows 24 --out "$OUT.whl" --err "$OUT.whl.err" \ 101 hostroom wheel
102 XDG_STATE_HOME="$HOSTROOM" timeout 40 "$PTYCLIENT" --cols 80 --rows 24 --out "$OUT.whl" --err "$OUT.whl.err" \
102 -- "$MUX" --sock "$SOCK33" > "$OUT.whl.log" 2>&1 <<'EOF' 103 -- "$MUX" --sock "$SOCK33" > "$OUT.whl.log" 2>&1 <<'EOF'
103 expect \x1b[0m100 15000 104 expect \x1b[0m100 15000
104 send \x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M 105 send \x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M
@@ -166,7 +167,8 @@ done
166 # is the assertion: cat is in canonical mode with ECHOCTL, so bytes that 167 # is the assertion: cat is in canonical mode with ECHOCTL, so bytes that
167 # reach the pty come back as `^[[<64;10;5M` and bytes that do not, do not. 168 # reach the pty come back as `^[[<64;10;5M` and bytes that do not, do not.
168 set +e 169 set +e
169 timeout 40 "$PTYCLIENT" --cols 80 --rows 24 --out "$OUT.mse" --err "$OUT.mse.err" \ 170 hostroom appmouse
171 XDG_STATE_HOME="$HOSTROOM" timeout 40 "$PTYCLIENT" --cols 80 --rows 24 --out "$OUT.mse" --err "$OUT.mse.err" \
170 -- "$MUX" --sock "$SOCK34" > "$OUT.mse.log" 2>&1 <<'EOF' 172 -- "$MUX" --sock "$SOCK34" > "$OUT.mse.log" 2>&1 <<'EOF'
171 expect app-holds-the-mouse 15000 173 expect app-holds-the-mouse 15000
172 send \x1b[<64;10;5M 174 send \x1b[<64;10;5M
@@ -232,7 +234,8 @@ until "$MUXD" dump --sock "$SOCK35" | grep -qx "200"; do
232 sleep 0.1 234 sleep 0.1
233 done 235 done
234 set +e 236 set +e
235 timeout 40 "$PTYCLIENT" --cols 80 --rows 24 --out "$OUT.pgr" --err "$OUT.pgr.err" \ 237 hostroom pager
238 XDG_STATE_HOME="$HOSTROOM" timeout 40 "$PTYCLIENT" --cols 80 --rows 24 --out "$OUT.pgr" --err "$OUT.pgr.err" \
236 -- "$MUX" --sock "$SOCK35" > "$OUT.pgr.log" 2>&1 <<'EOF' 239 -- "$MUX" --sock "$SOCK35" > "$OUT.pgr.log" 2>&1 <<'EOF'
237 expect 199 15000 240 expect 199 15000
238 send \x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M 241 send \x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M\x1b[<64;10;5M
@@ -361,9 +364,10 @@ ZSATT_BEFORE=$(attaches_now "$SOCK37")
361 watch_clients "$SOCK37" "$OUT.zswatch" 364 watch_clients "$SOCK37" "$OUT.zswatch"
362 set +e 365 set +e
363 # tall: the aspect rule would cut columns at 92x30 (92 >= 60) 366 # tall: the aspect rule would cut columns at 92x30 (92 >= 60)
364 # No saved tree: this leg asserts the DEFAULT cut, and every wall that 367 # No saved tree: this leg asserts the DEFAULT cut, and a wall ON A
365 # came before it saved a sidecar on its way out. The aspect rule applies 368 # TERMINAL saves its tree on the way out — so a ptyclient leg sharing this
366 # only when nothing is saved. 369 # state home has already left one. The aspect rule applies only when
370 # nothing is saved.
367 rm -f "$ZSSTATE/mux/layout" 371 rm -f "$ZSSTATE/mux/layout"
368 XDG_STATE_HOME="$ZSSTATE" timeout 90 "$PTYCLIENT" --cols 40 --rows 30 \ 372 XDG_STATE_HOME="$ZSSTATE" timeout 90 "$PTYCLIENT" --cols 40 --rows 30 \
369 --out "$OUT.zscap" --err "$OUT.zscap.err" -- \ 373 --out "$OUT.zscap" --err "$OUT.zscap.err" -- \
@@ -477,9 +481,10 @@ until "$MUXD" dump --sock "$SOCK41" | grep -q "wln100"; do
477 sleep 0.1 481 sleep 0.1
478 done 482 done
479 set +e 483 set +e
480 # No saved tree: this leg asserts the DEFAULT cut, and every wall that 484 # No saved tree: this leg asserts the DEFAULT cut, and a wall ON A
481 # came before it saved a sidecar on its way out. The aspect rule applies 485 # TERMINAL saves its tree on the way out — so a ptyclient leg sharing this
482 # only when nothing is saved. 486 # state home has already left one. The aspect rule applies only when
487 # nothing is saved.
483 rm -f "$ZWSTATE/mux/layout" 488 rm -f "$ZWSTATE/mux/layout"
484 XDG_STATE_HOME="$ZWSTATE" timeout 90 "$PTYCLIENT" --cols 80 --rows 24 \ 489 XDG_STATE_HOME="$ZWSTATE" timeout 90 "$PTYCLIENT" --cols 80 --rows 24 \
485 --out "$OUT.zwcap" --err "$OUT.zwcap.err" -- \ 490 --out "$OUT.zwcap" --err "$OUT.zwcap.err" -- \
@@ -554,9 +559,10 @@ done
554 # not. The tile claims the terminal on its first pass, so the modes are 559 # not. The tile claims the terminal on its first pass, so the modes are
555 # level-set before the wheel is sent. 560 # level-set before the wheel is sent.
556 set +e 561 set +e
557 # No saved tree: this leg asserts the DEFAULT cut, and every wall that 562 # No saved tree: this leg asserts the DEFAULT cut, and a wall ON A
558 # came before it saved a sidecar on its way out. The aspect rule applies 563 # TERMINAL saves its tree on the way out — so a ptyclient leg sharing this
559 # only when nothing is saved. 564 # state home has already left one. The aspect rule applies only when
565 # nothing is saved.
560 rm -f "$ZM2STATE/mux/layout" 566 rm -f "$ZM2STATE/mux/layout"
561 XDG_STATE_HOME="$ZM2STATE" timeout 90 "$PTYCLIENT" --cols 80 --rows 24 \ 567 XDG_STATE_HOME="$ZM2STATE" timeout 90 "$PTYCLIENT" --cols 80 --rows 24 \
562 --out "$OUT.zm2cap" --err "$OUT.zm2cap.err" -- \ 568 --out "$OUT.zm2cap" --err "$OUT.zm2cap.err" -- \
test/e2e_09_hosts.sh
Old New
@@ -165,9 +165,14 @@ wait_sessions "$SOCKH2" 2 "hosts: daemon 2 should hold 0 and c"
165 # wall's tiles come from the daemons, so a birth writes nothing down. 165 # wall's tiles come from the daemons, so a birth writes nothing down.
166 HFHASH=$(sha256sum "$HSTATE/mux/hosts" | cut -d' ' -f1) 166 HFHASH=$(sha256sum "$HSTATE/mux/hosts" | cut -d' ' -f1)
167 set +e 167 set +e
168 # Tall and wide: five tiles (four sessions plus the one `Ctrl-\ c` makes) 168 # Tall, and NOT wide: five tiles (four sessions plus the one `Ctrl-\ c`
169 # have to fit under the row floor a stripe's label bar leaves. 169 # makes) have to fit under the row floor a stripe's label bar leaves, and
170 XDG_STATE_HOME="$HSTATE" timeout 90 "$PTYCLIENT" --cols 100 --rows 44 \ 170 # 80 columns is under the aspect rule's `cols >= 2 * rows`, so the cut is
171 # stacked and every bar gets the full width. Beside, four stripes would
172 # each be twenty columns and `labelText` would spend them on the state
173 # word — the socket path these assertions grep for is the first thing a
174 # narrow bar drops.
175 XDG_STATE_HOME="$HSTATE" timeout 90 "$PTYCLIENT" --cols 80 --rows 44 \
171 --out "$OUT.hwcap" --err "$OUT.hwcap.err" -- "$MUX" > "$OUT.hwpc" 2>&1 <<'EOF' 176 --out "$OUT.hwcap" --err "$OUT.hwcap.err" -- "$MUX" > "$OUT.hwpc" 2>&1 <<'EOF'
172 expect hc-pin 25000 177 expect hc-pin 25000
173 settle 1500 25000 178 settle 1500 25000
@@ -216,7 +221,7 @@ HBORN=$(( $("$MUXD" stats --sock "$SOCKH1" | sed -n 's/.*sessions=\([0-9]*\).*/\
216 "$MUXD" stats --sock "$SOCKH1"; "$MUXD" stats --sock "$SOCKH2"; exit 1; } 221 "$MUXD" stats --sock "$SOCKH1"; "$MUXD" stats --sock "$SOCKH2"; exit 1; }
217 # ...and a SECOND wall finds it, with nothing having been written down. 222 # ...and a SECOND wall finds it, with nothing having been written down.
218 set +e 223 set +e
219 XDG_STATE_HOME="$HSTATE" timeout 90 "$PTYCLIENT" --cols 100 --rows 44 \ 224 XDG_STATE_HOME="$HSTATE" timeout 90 "$PTYCLIENT" --cols 80 --rows 44 \
220 --out "$OUT.hw2cap" --err "$OUT.hw2cap.err" -- "$MUX" > "$OUT.hw2pc" 2>&1 <<'EOF' 225 --out "$OUT.hw2cap" --err "$OUT.hw2cap.err" -- "$MUX" > "$OUT.hw2pc" 2>&1 <<'EOF'
221 expect [up] 25000 226 expect [up] 25000
222 settle 2000 25000 227 settle 2000 25000
@@ -348,7 +353,7 @@ ok "x refuses while others are attached, then ends; the other client sees the ex
348 assert_stopped "$SOCKH2" "$DH2PID" "hosts restart" "$OUT.h2stop" 353 assert_stopped "$SOCKH2" "$DH2PID" "hosts restart" "$OUT.h2stop"
349 DH2PID="" 354 DH2PID=""
350 set +e 355 set +e
351 XDG_STATE_HOME="$HSTATE" timeout 60 "$PTYCLIENT" --cols 100 --rows 44 \ 356 XDG_STATE_HOME="$HSTATE" timeout 60 "$PTYCLIENT" --cols 80 --rows 44 \
352 --out "$OUT.hdcap" --err "$OUT.hdcap.err" -- "$MUX" > "$OUT.hdpc" 2>&1 <<'EOF' 357 --out "$OUT.hdcap" --err "$OUT.hdcap.err" -- "$MUX" > "$OUT.hdpc" 2>&1 <<'EOF'
353 expect [unreachable] 25000 358 expect [unreachable] 25000
354 settle 1000 25000 359 settle 1000 25000
@@ -370,7 +375,7 @@ fi
370 start_daemon "$SOCKH2" "$OUT.h2b.d" "hosts daemon 2 never came back" --shell /bin/sh 375 start_daemon "$SOCKH2" "$OUT.h2b.d" "hosts daemon 2 never came back" --shell /bin/sh
371 DH2PID=$DPID 376 DH2PID=$DPID
372 set +e 377 set +e
373 XDG_STATE_HOME="$HSTATE" timeout 60 "$PTYCLIENT" --cols 100 --rows 44 \ 378 XDG_STATE_HOME="$HSTATE" timeout 60 "$PTYCLIENT" --cols 80 --rows 44 \
374 --out "$OUT.hrcap" --err "$OUT.hrcap.err" -- "$MUX" > "$OUT.hrpc" 2>&1 <<'EOF' 379 --out "$OUT.hrcap" --err "$OUT.hrcap.err" -- "$MUX" > "$OUT.hrpc" 2>&1 <<'EOF'
375 expect [up] 25000 380 expect [up] 25000
376 settle 2500 25000 381 settle 2500 25000
test/e2e_10_agent.sh
Old New
@@ -3,9 +3,12 @@
3 # the order they stand in; see the lib's header for what this file may 3 # the order they stand in; see the lib's header for what this file may
4 # assume and what it must register. 4 # assume and what it must register.
5 # Agent forwarding: one socket path, two daemons in turn. The positive leg 5 # Agent forwarding: one socket path, two daemons in turn. The positive leg
6 # ends by typing `exit`, which ends that daemon's only session and takes the 6 # ends by typing `exit`, which ends that daemon's ONLY session — a wall of
7 # daemon with it — so the refusal leg below starts its own on the freed path 7 # one tile ends with it, which is what takes the client and the daemon
8 # rather than inheriting one that is already gone. Both are $MUXD; neither 8 # down together. The legs whose daemon also holds its own default session
9 # leave by chord instead: there a tile is left standing, and the wall stays
10 # up. The refusal leg below starts its own daemon on the freed path rather
11 # than inheriting one that is already gone. Both are $MUXD; neither
9 # may be auto-started (see the $PATH note at the top of this file). 12 # may be auto-started (see the $PATH note at the top of this file).
10 # 13 #
11 # The agent lives beside the sockets rather than under $OUT: a unix path is 14 # The agent lives beside the sockets rather than under $OUT: a unix path is
@@ -85,7 +88,8 @@ esac
85 # to interpolate. Nothing else in the script needs expanding — `\n` and 88 # to interpolate. Nothing else in the script needs expanding — `\n` and
86 # `\x1b` are not escapes the shell touches. 89 # `\x1b` are not escapes the shell touches.
87 set +e 90 set +e
88 SSH_AUTH_SOCK="$AGENT48" timeout 40 "$PTYCLIENT" --cols 100 --rows 30 \ 91 hostroom agt48
92 XDG_STATE_HOME="$HOSTROOM" SSH_AUTH_SOCK="$AGENT48" timeout 40 "$PTYCLIENT" --cols 100 --rows 30 \
89 --out "$OUT.agt" --err "$OUT.agt.err" \ 93 --out "$OUT.agt" --err "$OUT.agt.err" \
90 -- "$MUX" -A --sock "$SOCK48" > "$OUT.agt.log" 2>&1 <<EOF 94 -- "$MUX" -A --sock "$SOCK48" > "$OUT.agt.log" 2>&1 <<EOF
91 expect \x1b[?1049h 15000 95 expect \x1b[?1049h 15000
@@ -182,7 +186,8 @@ start_daemon "$SOCK48" "$OUT.agtn.d" "agent-refusal daemon never bound" --shell
182 D42PID=$DPID 186 D42PID=$DPID
183 AR0=$(date +%s%N) 187 AR0=$(date +%s%N)
184 set +e 188 set +e
185 timeout 40 "$PTYCLIENT" --cols 100 --rows 30 --out "$OUT.agtn" --err "$OUT.agtn.err" \ 189 hostroom agtn
190 XDG_STATE_HOME="$HOSTROOM" timeout 40 "$PTYCLIENT" --cols 100 --rows 30 --out "$OUT.agtn" --err "$OUT.agtn.err" \
186 -- "$MUX" --sock "$SOCK48" --session noagent > "$OUT.agtn.log" 2>&1 <<'EOF' 191 -- "$MUX" --sock "$SOCK48" --session noagent > "$OUT.agtn.log" 2>&1 <<'EOF'
187 expect \x1b[?1049h 15000 192 expect \x1b[?1049h 15000
188 settle 400 15000 193 settle 400 15000
@@ -192,6 +197,11 @@ send ssh-add -l; echo agtrc=$?\n
192 expect agtrc= 15000 197 expect agtrc= 15000
193 settle 400 15000 198 settle 400 15000
194 send exit\n 199 send exit\n
200 settle 600 15000
201 # The session that ended is not the wall: this daemon holds its own default
202 # session too, so the tile vanishes and the focus falls to the neighbour.
203 # Leaving is the chord.
204 send \x1cd
195 waitexit 10000 205 waitexit 10000
196 EOF 206 EOF
197 RC=$? 207 RC=$?
@@ -266,13 +276,19 @@ grep -qE "agtrc=[1-9]" "$OUT.agtn" || {
266 # Unquoted heredoc, unlike the leg above: $MUX and $SOCK48 have to be 276 # Unquoted heredoc, unlike the leg above: $MUX and $SOCK48 have to be
267 # expanded by THIS shell, so `$?` is escaped to reach the session's. 277 # expanded by THIS shell, so `$?` is escaped to reach the session's.
268 set +e 278 set +e
269 timeout 40 "$PTYCLIENT" --cols 100 --rows 30 --out "$OUT.agtnest" --err "$OUT.agtnest.err" \ 279 hostroom agtnest
280 XDG_STATE_HOME="$HOSTROOM" timeout 40 "$PTYCLIENT" --cols 100 --rows 30 --out "$OUT.agtnest" --err "$OUT.agtnest.err" \
270 -- "$MUX" --sock "$SOCK48" --session noagent > "$OUT.agtnest.log" 2>&1 <<EOF 281 -- "$MUX" --sock "$SOCK48" --session noagent > "$OUT.agtnest.log" 2>&1 <<EOF
271 expect \x1b[?1049h 15000 282 expect \x1b[?1049h 15000
272 settle 400 15000 283 settle 400 15000
273 send $MUX -A --sock $SOCK48 --session noagent; echo nest=\$?\n 284 send $MUX -A --sock $SOCK48 --session noagent; echo nest=\$?\n
274 settle 1500 15000 285 settle 1500 15000
275 send exit\n 286 send exit\n
287 settle 600 15000
288 # The session that ended is not the wall: this daemon holds its own default
289 # session too, so the tile vanishes and the focus falls to the neighbour.
290 # Leaving is the chord.
291 send \x1cd
276 waitexit 10000 292 waitexit 10000
277 EOF 293 EOF
278 RC=$? 294 RC=$?
@@ -385,7 +401,8 @@ done
385 # Unquoted heredocs, like the positive leg's: $FPA and $FPB have to 401 # Unquoted heredocs, like the positive leg's: $FPA and $FPB have to
386 # interpolate, and nothing else in either script needs expanding. 402 # interpolate, and nothing else in either script needs expanding.
387 set +e 403 set +e
388 SSH_AUTH_SOCK="$AGENT49A" timeout 60 "$PTYCLIENT" --cols 100 --rows 30 \ 404 hostroom agt49a
405 XDG_STATE_HOME="$HOSTROOM" SSH_AUTH_SOCK="$AGENT49A" timeout 60 "$PTYCLIENT" --cols 100 --rows 30 \
389 --out "$OUT.flipa" --err "$OUT.flipa.err" \ 406 --out "$OUT.flipa" --err "$OUT.flipa.err" \
390 -- "$MUX" -A --sock "$SOCK49" > "$OUT.flipa.log" 2>&1 <<EOF & 407 -- "$MUX" -A --sock "$SOCK49" > "$OUT.flipa.log" 2>&1 <<EOF &
391 expect \x1b[?1049h 15000 408 expect \x1b[?1049h 15000
@@ -403,7 +420,8 @@ defer_kill "$FLIPAPID"
403 # setting up its terminal can flush what was typed at it, and B's marker is 420 # setting up its terminal can flush what was typed at it, and B's marker is
404 # the only line typed before any shell has spoken. Every later send waits on 421 # the only line typed before any shell has spoken. Every later send waits on
405 # a marker, which is a barrier a settle could only approximate. 422 # a marker, which is a barrier a settle could only approximate.
406 SSH_AUTH_SOCK="$AGENT49B" timeout 60 "$PTYCLIENT" --cols 100 --rows 30 \ 423 hostroom agt49b
424 XDG_STATE_HOME="$HOSTROOM" SSH_AUTH_SOCK="$AGENT49B" timeout 60 "$PTYCLIENT" --cols 100 --rows 30 \
407 --out "$OUT.flipb" --err "$OUT.flipb.err" \ 425 --out "$OUT.flipb" --err "$OUT.flipb.err" \
408 -- "$MUX" -A --sock "$SOCK49" > "$OUT.flipb.log" 2>&1 <<EOF 426 -- "$MUX" -A --sock "$SOCK49" > "$OUT.flipb.log" 2>&1 <<EOF
409 expect \x1b[?1049h 15000 427 expect \x1b[?1049h 15000
test/e2e_11_select.sh
Old New
@@ -56,8 +56,10 @@ wait_grid "$SOCK50" "wmb-pin" "wall cluster: session b's marker" b
56 # other way. A negative that cannot fail is not a test, so each carries the 56 # other way. A negative that cannot fail is not a test, so each carries the
57 # marker that MUST land in the focused session. 57 # marker that MUST land in the focused session.
58 set +e 58 set +e
59 # No saved tree: this leg asserts the DEFAULT cut, and every wall before 59 # No saved tree: this leg asserts the DEFAULT cut, and a wall ON A
60 # it saved a sidecar on its way out. 60 # TERMINAL saves its tree on the way out — so a ptyclient leg sharing this
61 # state home has already left one. The aspect rule applies only when
62 # nothing is saved.
61 rm -f "$WMSTATE/mux/layout" 63 rm -f "$WMSTATE/mux/layout"
62 XDG_STATE_HOME="$WMSTATE" timeout 60 "$PTYCLIENT" --cols 40 --rows 30 \ 64 XDG_STATE_HOME="$WMSTATE" timeout 60 "$PTYCLIENT" --cols 40 --rows 30 \
63 --out "$OUT.wmcap3" --err "$OUT.wmcap3.err" -- \ 65 --out "$OUT.wmcap3" --err "$OUT.wmcap3.err" -- \
@@ -89,8 +91,10 @@ grep -q "wm-three" "$OUT.wmfa" && {
89 # The other direction: focus b explicitly, then click a's content and watch 91 # The other direction: focus b explicitly, then click a's content and watch
90 # the focus come back to a. 92 # the focus come back to a.
91 set +e 93 set +e
92 # No saved tree: this leg asserts the DEFAULT cut, and every wall before 94 # No saved tree: this leg asserts the DEFAULT cut, and a wall ON A
93 # it saved a sidecar on its way out. 95 # TERMINAL saves its tree on the way out — so a ptyclient leg sharing this
96 # state home has already left one. The aspect rule applies only when
97 # nothing is saved.
94 rm -f "$WMSTATE/mux/layout" 98 rm -f "$WMSTATE/mux/layout"
95 XDG_STATE_HOME="$WMSTATE" timeout 60 "$PTYCLIENT" --cols 40 --rows 30 \ 99 XDG_STATE_HOME="$WMSTATE" timeout 60 "$PTYCLIENT" --cols 40 --rows 30 \
96 --out "$OUT.wmcap4" --err "$OUT.wmcap4.err" -- \ 100 --out "$OUT.wmcap4" --err "$OUT.wmcap4.err" -- \
@@ -128,8 +132,10 @@ ok "a click in a tile's rect focuses it, from wherever the focus was"
128 # test in rectHit earns its keep: focus starts on a (the left pane) and 132 # test in rectHit earns its keep: focus starts on a (the left pane) and
129 # the click must move it to b (the right pane). 133 # the click must move it to b (the right pane).
130 set +e 134 set +e
131 # No saved tree: this leg asserts the DEFAULT cut, and every wall before 135 # No saved tree: this leg asserts the DEFAULT cut, and a wall ON A
132 # it saved a sidecar on its way out. 136 # TERMINAL saves its tree on the way out — so a ptyclient leg sharing this
137 # state home has already left one. The aspect rule applies only when
138 # nothing is saved.
133 rm -f "$WMSTATE/mux/layout" 139 rm -f "$WMSTATE/mux/layout"
134 XDG_STATE_HOME="$WMSTATE" timeout 60 "$PTYCLIENT" --cols 100 --rows 30 \ 140 XDG_STATE_HOME="$WMSTATE" timeout 60 "$PTYCLIENT" --cols 100 --rows 30 \
135 --out "$OUT.wmcap5" --err "$OUT.wmcap5.err" -- \ 141 --out "$OUT.wmcap5" --err "$OUT.wmcap5.err" -- \
@@ -321,9 +327,13 @@ ok "a resize is reported in-band to an app that turned on mode 2048"
321 # uid, one box, two daemons. `env -u` rather than the harness environment: 327 # uid, one box, two daemons. `env -u` rather than the harness environment:
322 # on a box that HAS the variable the unset case is otherwise never taken. 328 # on a box that HAS the variable the unset case is otherwise never taken.
323 # No convergence: nothing gets far enough to attach. 329 # No convergence: nothing gets far enough to attach.
330 # An EMPTY hosts file, because that is the case that needs the default
331 # path: bare `mux` reaches for the local daemon only when nothing is
332 # listed, and the suite's shared file is every daemon it has attached to.
333 hostroom nort
324 for BIN in "$MUXD stats" "$MUX"; do 334 for BIN in "$MUXD stats" "$MUX"; do
325 # shellcheck disable=SC2086 # the two-word muxd form is deliberate 335 # shellcheck disable=SC2086 # the two-word muxd form is deliberate
326 if env -u XDG_RUNTIME_DIR $BIN > "$OUT.nort" 2>&1; then 336 if env -u XDG_RUNTIME_DIR XDG_STATE_HOME="$HOSTROOM" $BIN > "$OUT.nort" 2>&1; then
327 echo "e2e FAIL: '$BIN' with no XDG_RUNTIME_DIR did not refuse"; exit 1 337 echo "e2e FAIL: '$BIN' with no XDG_RUNTIME_DIR did not refuse"; exit 1
328 fi 338 fi
329 grep -q 'XDG_RUNTIME_DIR is unset' "$OUT.nort" || { 339 grep -q 'XDG_RUNTIME_DIR is unset' "$OUT.nort" || {
test/e2e_12_panes.sh
Old New
@@ -80,9 +80,10 @@ pipe_detach
80 wait_grid "$SOCK52" "mc-pin" "cursor: session c's marker" c 80 wait_grid "$SOCK52" "mc-pin" "cursor: session c's marker" c
81 81
82 set +e 82 set +e
83 # No saved tree: this leg asserts the DEFAULT cut, and the setup attaches 83 # No saved tree: this leg asserts the DEFAULT cut, and a wall ON A
84 # above are walls too — each of them saved a one-leaf sidecar on its way 84 # TERMINAL saves its tree on the way out — so a ptyclient leg sharing this
85 # out. The aspect rule applies only when nothing is saved. 85 # state home has already left one. The aspect rule applies only when
86 # nothing is saved.
86 rm -f "$CUSTATE/mux/layout" 87 rm -f "$CUSTATE/mux/layout"
87 XDG_STATE_HOME="$CUSTATE" timeout 40 "$PTYCLIENT" --cols 40 --rows 30 --out "$OUT.cucap" --err "$OUT.cucap.err" -- \ 88 XDG_STATE_HOME="$CUSTATE" timeout 40 "$PTYCLIENT" --cols 40 --rows 30 --out "$OUT.cucap" --err "$OUT.cucap.err" -- \
88 "$MUX" --sock "$SOCK52" > "$OUT.cupc" 2>&1 <<'EOF' 89 "$MUX" --sock "$SOCK52" > "$OUT.cupc" 2>&1 <<'EOF'
@@ -170,9 +171,10 @@ pipe_detach
170 wait_grid "$SOCK53" "sb2nbr" "scrollback-rect: session b's pin" b 171 wait_grid "$SOCK53" "sb2nbr" "scrollback-rect: session b's pin" b
171 172
172 set +e 173 set +e
173 # No saved tree: this leg asserts the DEFAULT cut, and the setup attaches 174 # No saved tree: this leg asserts the DEFAULT cut, and a wall ON A
174 # above are walls too — each of them saved a one-leaf sidecar on its way 175 # TERMINAL saves its tree on the way out — so a ptyclient leg sharing this
175 # out. The aspect rule applies only when nothing is saved. 176 # state home has already left one. The aspect rule applies only when
177 # nothing is saved.
176 rm -f "$SB2STATE/mux/layout" 178 rm -f "$SB2STATE/mux/layout"
177 XDG_STATE_HOME="$SB2STATE" timeout 90 "$PTYCLIENT" --cols 40 --rows 30 --out "$OUT.sb2cap" --err "$OUT.sb2cap.err" -- \ 179 XDG_STATE_HOME="$SB2STATE" timeout 90 "$PTYCLIENT" --cols 40 --rows 30 --out "$OUT.sb2cap" --err "$OUT.sb2cap.err" -- \
178 "$MUX" --sock "$SOCK53" > "$OUT.sb2pc" 2>&1 <<'EOF' 180 "$MUX" --sock "$SOCK53" > "$OUT.sb2pc" 2>&1 <<'EOF'
@@ -232,9 +234,10 @@ wait_grid "$SOCK54" "fs-init-b" "fullscreen: session b's marker" b
232 234
233 set +e 235 set +e
234 # wide: 80x24 trips the aspect rule (80 >= 48 → beside) 236 # wide: 80x24 trips the aspect rule (80 >= 48 → beside)
235 # No saved tree: this leg asserts the DEFAULT cut, and the setup attaches 237 # No saved tree: this leg asserts the DEFAULT cut, and a wall ON A
236 # above are walls too — each of them saved a one-leaf sidecar on its way 238 # TERMINAL saves its tree on the way out — so a ptyclient leg sharing this
237 # out. The aspect rule applies only when nothing is saved. 239 # state home has already left one. The aspect rule applies only when
240 # nothing is saved.
238 rm -f "$FSSTATE/mux/layout" 241 rm -f "$FSSTATE/mux/layout"
239 XDG_STATE_HOME="$FSSTATE" timeout 90 "$PTYCLIENT" --cols 80 --rows 24 --out "$OUT.fscap" --err "$OUT.fscap.err" -- \ 242 XDG_STATE_HOME="$FSSTATE" timeout 90 "$PTYCLIENT" --cols 80 --rows 24 --out "$OUT.fscap" --err "$OUT.fscap.err" -- \
240 "$MUX" --sock "$SOCK54" > "$OUT.fspc" 2>&1 <<'EOF' 243 "$MUX" --sock "$SOCK54" > "$OUT.fspc" 2>&1 <<'EOF'
@@ -323,9 +326,10 @@ set +e
323 # 80x24: aspect rule makes beside; two panes split 39/40 with the rail 326 # 80x24: aspect rule makes beside; two panes split 39/40 with the rail
324 # at column 40 (1-indexed). Three l presses grow the left pane by 3, 327 # at column 40 (1-indexed). Three l presses grow the left pane by 3,
325 # moving the rail to column 43. 328 # moving the rail to column 43.
326 # No saved tree: this leg asserts the DEFAULT cut, and the setup attaches 329 # No saved tree: this leg asserts the DEFAULT cut, and a wall ON A
327 # above are walls too — each of them saved a one-leaf sidecar on its way 330 # TERMINAL saves its tree on the way out — so a ptyclient leg sharing this
328 # out. The aspect rule applies only when nothing is saved. 331 # state home has already left one. The aspect rule applies only when
332 # nothing is saved.
329 rm -f "$RSZSTATE/mux/layout" 333 rm -f "$RSZSTATE/mux/layout"
330 XDG_STATE_HOME="$RSZSTATE" timeout 90 "$PTYCLIENT" --cols 80 --rows 24 --out "$OUT.rszcap" --err "$OUT.rszcap.err" -- \ 334 XDG_STATE_HOME="$RSZSTATE" timeout 90 "$PTYCLIENT" --cols 80 --rows 24 --out "$OUT.rszcap" --err "$OUT.rszcap.err" -- \
331 "$MUX" --sock "$SOCK55" > "$OUT.rszpc" 2>&1 <<'EOF' 335 "$MUX" --sock "$SOCK55" > "$OUT.rszpc" 2>&1 <<'EOF'
@@ -405,9 +409,10 @@ wait_grid "$SOCK56" "spc-right-survivor" "span-clear: right session's marker" b
405 set +e 409 set +e
406 # 80x24: aspect rule → beside. The wall client is a tty session: its 410 # 80x24: aspect rule → beside. The wall client is a tty session: its
407 # stdout is the terminal's full byte stream, captured by ptyclient. 411 # stdout is the terminal's full byte stream, captured by ptyclient.
408 # No saved tree: this leg asserts the DEFAULT cut, and the setup attaches 412 # No saved tree: this leg asserts the DEFAULT cut, and a wall ON A
409 # above are walls too — each of them saved a one-leaf sidecar on its way 413 # TERMINAL saves its tree on the way out — so a ptyclient leg sharing this
410 # out. The aspect rule applies only when nothing is saved. 414 # state home has already left one. The aspect rule applies only when
415 # nothing is saved.
411 rm -f "$SPCSTATE/mux/layout" 416 rm -f "$SPCSTATE/mux/layout"
412 XDG_STATE_HOME="$SPCSTATE" timeout 90 "$PTYCLIENT" --cols 80 --rows 24 --out "$OUT.spccap" --err "$OUT.spccap.err" -- \ 417 XDG_STATE_HOME="$SPCSTATE" timeout 90 "$PTYCLIENT" --cols 80 --rows 24 --out "$OUT.spccap" --err "$OUT.spccap.err" -- \
413 "$MUX" --sock "$SOCK56" > "$OUT.spcpc" 2>&1 <<'EOF' 418 "$MUX" --sock "$SOCK56" > "$OUT.spcpc" 2>&1 <<'EOF'
@@ -461,9 +466,10 @@ wait_grid "$SOCK57" "hjk-origin" "hjkl: origin marker"
461 set +e 466 set +e
462 # 80x24: aspect rule → beside for the first split; the second split goes 467 # 80x24: aspect rule → beside for the first split; the second split goes
463 # below, producing a 1 | (2 over 3) tree. 468 # below, producing a 1 | (2 over 3) tree.
464 # No saved tree: this leg asserts the DEFAULT cut, and the setup attaches 469 # No saved tree: this leg asserts the DEFAULT cut, and a wall ON A
465 # above are walls too — each of them saved a one-leaf sidecar on its way 470 # TERMINAL saves its tree on the way out — so a ptyclient leg sharing this
466 # out. The aspect rule applies only when nothing is saved. 471 # state home has already left one. The aspect rule applies only when
472 # nothing is saved.
467 rm -f "$HJKSTATE/mux/layout" 473 rm -f "$HJKSTATE/mux/layout"
468 XDG_STATE_HOME="$HJKSTATE" timeout 90 "$PTYCLIENT" --cols 80 --rows 24 --out "$OUT.hjkcap" --err "$OUT.hjkcap.err" -- \ 474 XDG_STATE_HOME="$HJKSTATE" timeout 90 "$PTYCLIENT" --cols 80 --rows 24 --out "$OUT.hjkcap" --err "$OUT.hjkcap.err" -- \
469 "$MUX" --sock "$SOCK57" > "$OUT.hjkpc" 2>&1 <<'EOF' 475 "$MUX" --sock "$SOCK57" > "$OUT.hjkpc" 2>&1 <<'EOF'
@@ -535,9 +541,10 @@ wait_grid "$SOCK58" "spl-origin" "split-birth: origin marker"
535 set +e 541 set +e
536 # 80x24: aspect rule → beside. One tile starts, then Ctrl-\ | births a 542 # 80x24: aspect rule → beside. One tile starts, then Ctrl-\ | births a
537 # second session to the right. 543 # second session to the right.
538 # No saved tree: this leg asserts the DEFAULT cut, and the setup attaches 544 # No saved tree: this leg asserts the DEFAULT cut, and a wall ON A
539 # above are walls too — each of them saved a one-leaf sidecar on its way 545 # TERMINAL saves its tree on the way out — so a ptyclient leg sharing this
540 # out. The aspect rule applies only when nothing is saved. 546 # state home has already left one. The aspect rule applies only when
547 # nothing is saved.
541 rm -f "$SPLSTATE/mux/layout" 548 rm -f "$SPLSTATE/mux/layout"
542 XDG_STATE_HOME="$SPLSTATE" timeout 90 "$PTYCLIENT" --cols 80 --rows 24 --out "$OUT.splcap" --err "$OUT.splcap.err" -- \ 549 XDG_STATE_HOME="$SPLSTATE" timeout 90 "$PTYCLIENT" --cols 80 --rows 24 --out "$OUT.splcap" --err "$OUT.splcap.err" -- \
543 "$MUX" --sock "$SOCK58" > "$OUT.splpc" 2>&1 <<'EOF' 550 "$MUX" --sock "$SOCK58" > "$OUT.splpc" 2>&1 <<'EOF'
@@ -608,9 +615,8 @@ wait_grid "$SOCK59" "lpr-origin-b" "layout-restore: session b marker" b
608 # until it asks. 615 # until it asks.
609 mkdir -p "$LPSTATE/mux" 616 mkdir -p "$LPSTATE/mux"
610 printf -- '--sock %s\n' "$SOCK59" > "$LPHOSTS" 617 printf -- '--sock %s\n' "$SOCK59" > "$LPHOSTS"
611 # ...and no saved tree yet: the setup attaches above are walls too, and 618 # ...and no saved tree yet: what this leg saves and restores has to be the
612 # each saved a one-leaf sidecar on its way out. What this leg saves and 619 # tree the FIRST ptyclient builds, not one an earlier terminal left here.
613 # restores has to be the tree the FIRST ptyclient builds.
614 rm -f "$LPLAYOUT" 620 rm -f "$LPLAYOUT"
615 621
616 set +e 622 set +e
test/e2e_13_birth.sh
Old New
@@ -83,8 +83,8 @@ wait_grid "$SOCK63" "pr-bmark" "prompt: daemon B's marker"
83 83
84 mkdir -p "$PRSTATE/mux" 84 mkdir -p "$PRSTATE/mux"
85 printf -- '--sock %s\n' "$SOCK62" > "$PRHOSTS" 85 printf -- '--sock %s\n' "$SOCK62" > "$PRHOSTS"
86 # No saved tree: the setup attaches are walls too, and each saved a 86 # No saved tree: a wall on a terminal saves its tree on the way out, and
87 # one-leaf sidecar on its way out. 87 # this leg asserts the default cut.
88 rm -f "$PRSTATE/mux/layout" 88 rm -f "$PRSTATE/mux/layout"
89 89
90 # The spelling goes in TWO sends with a settle between: the prompt paints 90 # The spelling goes in TWO sends with a settle between: the prompt paints
test/e2e_14_upgrade.sh
Old New
@@ -97,7 +97,8 @@ grep -qF '"mechanism":"marks"' "$OUT.upm1" || {
97 # sets would be gone by the next one. `unset` first because a scalar 97 # sets would be gone by the next one. `unset` first because a scalar
98 # assignment onto bash's array spelling lands on element 0 and leaves the 98 # assignment onto bash's array spelling lands on element 0 and leaves the
99 # rest. 99 # rest.
100 timeout 150 "$PTYCLIENT" --cols 100 --rows 30 \ 100 hostroom upgrade
101 XDG_STATE_HOME="$HOSTROOM" timeout 150 "$PTYCLIENT" --cols 100 --rows 30 \
101 --out "$OUT.upcap" --err "$OUT.upcap.err" -- \ 102 --out "$OUT.upcap" --err "$OUT.upcap.err" -- \
102 "$MUX" --sock "$SOCK69" > "$OUT.uppc" 2>&1 <<'EOF' & 103 "$MUX" --sock "$SOCK69" > "$OUT.uppc" 2>&1 <<'EOF' &
103 settle 1000 25000 104 settle 1000 25000
test/e2e_lib.sh
Old New
@@ -89,6 +89,25 @@ $E2E_SOCK"
89 done 89 done
90 } 90 }
91 91
92 # hostroom NAME — a hosts file of one leg's own, spelled into $HOSTROOM
93 # for the command that follows to pass as XDG_STATE_HOME.
94 #
95 # A wall is the hosts FILE now: every `mux TARGET` records the daemon it
96 # attached to, and every `mux` on a TERMINAL opens on every line it finds.
97 # The suite's shared state home is therefore every daemon the suite has
98 # ever attached to — most of them stopped — so a leg that read it would
99 # open on its own tile plus a screenful of `[unreachable]` stripes, and
100 # the geometry every pty leg asserts would be somebody else's.
101 #
102 # Per LEG and not per group: a group's earlier legs leave their own daemons
103 # running while the later ones attach, so a wall opened on a home the leg
104 # before it wrote shows that leg's sessions as tiles beside its own.
105 hostroom() {
106 HOSTROOM="${TMPDIR:-/tmp}/mux-e2e-room-$1-$$"
107 rm -rf "$HOSTROOM"
108 defer_rm "$HOSTROOM"
109 }
110
92 # defer_rm PATH... — an artifact the trap must remove: a key, a generated 111 # defer_rm PATH... — an artifact the trap must remove: a key, a generated
93 # script, a private HOME, a state home. Registered at the line that spells 112 # script, a private HOME, a state home. Registered at the line that spells
94 # the path, so the two can never drift apart. Files go out through the leak 113 # the path, so the two can never drift apart. Files go out through the leak
@@ -929,15 +948,43 @@ leak_sweep() {
929 cat "$LEAKBANK" 948 cat "$LEAKBANK"
930 _lsbad=1 949 _lsbad=1
931 fi 950 fi
932 # The detached (`muxd start`) daemons log via XDG_STATE_HOME; the file is 951 # The detached (`muxd start`) daemons log via XDG_STATE_HOME — and every
933 # truncated at every spawn, so this asserts the LAST such daemon only — 952 # wall on a terminal now runs under a state home of its OWN (hostroom,
934 # stated, not hidden. 953 # and the per-leg $*STATE dirs), so reading the suite's shared home alone
935 if [ -f "$XDG_STATE_HOME/mux/muxd.log" ] && 954 # swept none of the daemons those legs start: the local auto-start, the
936 grep -q "LEAK:" "$XDG_STATE_HOME/mux/muxd.log"; then 955 # empty-file wall, the no-start boxes. A gate keyed to a variable legs are
937 echo "e2e FAIL: a detached daemon reported leaked allocations:" 956 # expected to override is a gate that stops running without saying so.
938 grep -H "LEAK:" "$XDG_STATE_HOME/mux/muxd.log" || true 957 #
939 _lsbad=1 958 # The REGISTER is the list, not a glob: a state home is a directory, and
940 fi 959 # every directory a leg creates goes through defer_rm at the line that
960 # spells it. One that skipped the register would fail the residue guard in
961 # cleanup instead, so there is no third place for a home to hide.
962 #
963 # The file is truncated at every spawn, so each home asserts the LAST
964 # daemon started under it — stated, not hidden.
965 _lsoifs=$IFS
966 IFS='
967 '
968 _lsseen=""
969 # shellcheck disable=SC2086 # IFS is a newline: each entry is one path
970 for _lsd in "$XDG_STATE_HOME" $E2E_RM; do
971 _lslog="$_lsd/mux/muxd.log"
972 [ -f "$_lslog" ] || continue
973 case "
974 $_lsseen" in
975 *"
976 $_lslog
977 "*) continue ;;
978 esac
979 _lsseen="$_lslog
980 $_lsseen"
981 if grep -q "LEAK:" "$_lslog"; then
982 echo "e2e FAIL: a detached daemon reported leaked allocations:"
983 grep -H "LEAK:" "$_lslog" || true
984 _lsbad=1
985 fi
986 done
987 IFS=$_lsoifs
941 [ "$_lsbad" -eq 0 ] 988 [ "$_lsbad" -eq 0 ]
942 } 989 }
943 990