483606dd
test: e2e gates the CLI wall — two sessions and a live delta, one pty
a73x 2026-08-19 17:17
Commit message
test/e2e.sh
| Old | New | ||
|---|---|---|---|
| @@ -242,6 +242,11 @@ DWSTATE="${TMPDIR:-/tmp}/mux-e2e-dynwall-state-$$" | |||
| 242 | D22PID="" | 242 | D22PID="" |
| 243 | W4PID="" | 243 | W4PID="" |
| 244 | 244 | ||
| 245 | # The CLI wall (`mux wall`): its own daemon, so its two sessions can't be | ||
| 246 | # confused with any other block's. | ||
| 247 | SOCK26="${TMPDIR:-/tmp}/muxd-e2e-cliwall-$$.sock" | ||
| 248 | D23PID="" | ||
| 249 | |||
| 245 | # One counter out of a MUX_PREDICT_STATS line. The client prints exactly one | 250 | # One counter out of a MUX_PREDICT_STATS line. The client prints exactly one |
| 246 | # such line on exit; every field is a key=value pair, so a rename or reorder | 251 | # such line on exit; every field is a key=value pair, so a rename or reorder |
| 247 | # in the client shows up here as an empty read rather than a wrong number. | 252 | # in the client shows up here as an empty read rather than a wrong number. |
| @@ -761,6 +766,7 @@ cleanup() { | |||
| 761 | # one the run died under. | 766 | # one the run died under. |
| 762 | [ -n "$W4PID" ] && kill "$W4PID" 2>/dev/null || true | 767 | [ -n "$W4PID" ] && kill "$W4PID" 2>/dev/null || true |
| 763 | [ -n "$D22PID" ] && kill "$D22PID" 2>/dev/null || true | 768 | [ -n "$D22PID" ] && kill "$D22PID" 2>/dev/null || true |
| 769 | [ -n "$D23PID" ] && kill "$D23PID" 2>/dev/null || true | ||
| 764 | # The stops still precede the socket rm below, like SOCK14-17 above: | 770 | # The stops still precede the socket rm below, like SOCK14-17 above: |
| 765 | # unlinking a socket first would leave a live daemon nothing could reach | 771 | # unlinking a socket first would leave a live daemon nothing could reach |
| 766 | # by path. | 772 | # by path. |
| @@ -768,6 +774,7 @@ cleanup() { | |||
| 768 | [ -S "$SOCK19" ] && "$MUXD" stop --sock "$SOCK19" 2>/dev/null || true | 774 | [ -S "$SOCK19" ] && "$MUXD" stop --sock "$SOCK19" 2>/dev/null || true |
| 769 | [ -S "$SOCK20" ] && "$MUXD" stop --sock "$SOCK20" 2>/dev/null || true | 775 | [ -S "$SOCK20" ] && "$MUXD" stop --sock "$SOCK20" 2>/dev/null || true |
| 770 | [ -S "$SOCK25" ] && "$MUXD" stop --sock "$SOCK25" 2>/dev/null || true | 776 | [ -S "$SOCK25" ] && "$MUXD" stop --sock "$SOCK25" 2>/dev/null || true |
| 777 | [ -S "$SOCK26" ] && "$MUXD" stop --sock "$SOCK26" 2>/dev/null || true | ||
| 771 | 778 | ||
| 772 | # ---- the leak sweep (hygiene kit, 6a) ---- | 779 | # ---- the leak sweep (hygiene kit, 6a) ---- |
| 773 | # Here rather than at the bottom of the file, which `set -e` reaches only | 780 | # Here rather than at the bottom of the file, which `set -e` reaches only |
| @@ -779,7 +786,7 @@ cleanup() { | |||
| 779 | "$D7PID" "$D9PID" "$D10PID" "$D12PID" "$D13PID" "$SPID" "$TPID" \ | 786 | "$D7PID" "$D9PID" "$D10PID" "$D12PID" "$D13PID" "$SPID" "$TPID" \ |
| 780 | "$GPID" "$APID" "$PAPID" "$HAPID" "$HDPID" \ | 787 | "$GPID" "$APID" "$PAPID" "$HAPID" "$HDPID" \ |
| 781 | "$D14PID" "$D15PID" "$D16PID" "$D17PID" "$D18PID" "$D19PID" \ | 788 | "$D14PID" "$D15PID" "$D16PID" "$D17PID" "$D18PID" "$D19PID" \ |
| 782 | "$D20PID" "$D21PID" "$D22PID" | 789 | "$D20PID" "$D21PID" "$D22PID" "$D23PID" |
| 783 | _leak=0 | 790 | _leak=0 |
| 784 | leak_sweep "$_rc" || _leak=1 | 791 | leak_sweep "$_rc" || _leak=1 |
| 785 | 792 | ||
| @@ -4334,6 +4341,71 @@ assert_stopped "$SOCK25" "$D22PID" "dyn wall" "$OUT.dwstop" | |||
| 4334 | D22PID="" | 4341 | D22PID="" |
| 4335 | ok "the wall is runtime state: add, remove, reorder, restore, argv overrides" | 4342 | ok "the wall is runtime state: add, remove, reorder, restore, argv overrides" |
| 4336 | 4343 | ||
| 4344 | # ---- the CLI wall: the hub's multiattach, in one terminal -------------- | ||
| 4345 | # One daemon, two named sessions, one `mux wall` on a real pty showing | ||
| 4346 | # both AT ONCE — the browser wall's claim, made by the CLI. Three facts, | ||
| 4347 | # each with its own witness: both sessions' markers painted (the snapshot | ||
| 4348 | # path), a line injected into b WHILE the wall is attached painted too | ||
| 4349 | # (the delta path — the wall is a live replica, not a capture), and `q` | ||
| 4350 | # ended the process with exit 0 (the wall left, not died). Markers are | ||
| 4351 | # shell-EXPANDED (`%s`+pin), the M18 trick: a hit is the shell's work, | ||
| 4352 | # never an echo of anything typed here. | ||
| 4353 | # | ||
| 4354 | # The expect ORDER leans on the injection, deliberately: tile threads | ||
| 4355 | # race, so b's snapshot bytes may land before a's and behind the expect | ||
| 4356 | # cursor. The injection at t+5s repaints b's whole stripe late in the | ||
| 4357 | # stream — snapshot marker and live marker in one ordered repaint — so | ||
| 4358 | # every needle below is downstream of the cwa-pin match by construction | ||
| 4359 | # (a's local-socket snapshot paints in well under 5s). | ||
| 4360 | "$MUXD" run --sock "$SOCK26" --shell /bin/sh > "$OUT.cwall.d" 2>&1 & | ||
| 4361 | D23PID=$! | ||
| 4362 | wait_sock "$SOCK26" "$OUT.cwall.d" "CLI wall daemon never bound" | ||
| 4363 | |||
| 4364 | { printf 'printf "cwa-%%s\\n" pin\n'; sleep 2; printf '\034'; } | \ | ||
| 4365 | timeout 40 "$MUX" --sock "$SOCK26" --session a > "$OUT.cwa" 2> "$OUT.cwa.err" | ||
| 4366 | wait_grid "$SOCK26" "cwa-pin" "CLI wall: session a's marker" a | ||
| 4367 | { printf 'printf "cwb-%%s\\n" pin\n'; sleep 2; printf '\034'; } | \ | ||
| 4368 | timeout 40 "$MUX" --sock "$SOCK26" --session b > "$OUT.cwb" 2> "$OUT.cwb.err" | ||
| 4369 | wait_grid "$SOCK26" "cwb-pin" "CLI wall: session b's marker" b | ||
| 4370 | |||
| 4371 | ( sleep 5; "$MUXA" send 'printf "cwlive-%s\n" pin\n' \ | ||
| 4372 | --sock "$SOCK26" --session b > "$OUT.cwinj" 2>&1 ) & | ||
| 4373 | CWINJPID=$! | ||
| 4374 | set +e | ||
| 4375 | timeout 40 "$PTYCLIENT" --cols 100 --rows 30 --out "$OUT.cwcap" --err "$OUT.cwcap.err" -- \ | ||
| 4376 | "$MUX" wall "--sock $SOCK26#a" "--sock $SOCK26#b" > "$OUT.cwpc" 2>&1 <<'EOF' | ||
| 4377 | expect cwa-pin 15000 | ||
| 4378 | expect cwb-pin 20000 | ||
| 4379 | expect cwlive-pin 5000 | ||
| 4380 | send q | ||
| 4381 | waitexit 10000 | ||
| 4382 | EOF | ||
| 4383 | RC=$? | ||
| 4384 | set -e | ||
| 4385 | wait "$CWINJPID" 2>/dev/null || true | ||
| 4386 | [ "$RC" -eq 0 ] || { | ||
| 4387 | echo "e2e FAIL: CLI wall: ptyclient leg exited $RC:" | ||
| 4388 | cat "$OUT.cwpc"; cat "$OUT.cwinj"; exit 1; } | ||
| 4389 | # The multiattach fact itself: both sessions' bytes in ONE process's | ||
| 4390 | # capture. Redundant with the expects above only until someone edits the | ||
| 4391 | # script block; a grep each keeps the claim standing on its own. | ||
| 4392 | grep -q "cwa-pin" "$OUT.cwcap" || { | ||
| 4393 | echo "e2e FAIL: CLI wall: a's marker never painted"; exit 1; } | ||
| 4394 | grep -q "cwb-pin" "$OUT.cwcap" || { | ||
| 4395 | echo "e2e FAIL: CLI wall: b's marker never painted"; exit 1; } | ||
| 4396 | grep -q "cwlive-pin" "$OUT.cwcap" || { | ||
| 4397 | echo "e2e FAIL: CLI wall: the live delta never painted"; exit 1; } | ||
| 4398 | # Passivity, M-web's negative twin: a wall of 0x0 attaches must never | ||
| 4399 | # have claimed either grid — the daemon still answers with the size the | ||
| 4400 | # creating clients set, not a degenerate one. | ||
| 4401 | "$MUXA" status --sock "$SOCK26" --session a > "$OUT.cwst" 2>&1 | ||
| 4402 | grep -q '"cols":80' "$OUT.cwst" || { | ||
| 4403 | echo "e2e FAIL: CLI wall: a 0x0 wall attach moved session a's grid:" | ||
| 4404 | cat "$OUT.cwst"; exit 1; } | ||
| 4405 | assert_stopped "$SOCK26" "$D23PID" "CLI wall" "$OUT.cwstop" | ||
| 4406 | D23PID="" | ||
| 4407 | ok "mux wall: two sessions and a live delta on one terminal, read-only" | ||
| 4408 | |||
| 4337 | # The long-lived daemon has served every scenario that wanted it; stop it | 4409 | # The long-lived daemon has served every scenario that wanted it; stop it |
| 4338 | # NOW so its allocator verdict is written while the suite is still running | 4410 | # NOW so its allocator verdict is written while the suite is still running |
| 4339 | # and can say so. SIGTERM runs the clean-shutdown path, so the defer chain | 4411 | # and can say so. SIGTERM runs the clean-shutdown path, so the defer chain |
| @@ -4349,7 +4421,7 @@ DPID="" | |||
| 4349 | 4421 | ||
| 4350 | # The pins. Literals, not variables set from counting something else — | 4422 | # The pins. Literals, not variables set from counting something else — |
| 4351 | # "assert the literal, never the constant the code under test reads" | 4423 | # "assert the literal, never the constant the code under test reads" |
| 4352 | # (decisions.md, M10). 32 scenario checkpoints; 35 convergence points. | 4424 | # (decisions.md, M10). 33 scenario checkpoints; 35 convergence points. |
| 4353 | # Anyone adding a scenario updates these by hand, on purpose. | 4425 | # Anyone adding a scenario updates these by hand, on purpose. |
| 4354 | # | 4426 | # |
| 4355 | # M18 added three checkpoints and no convergence points: its wall block | 4427 | # M18 added three checkpoints and no convergence points: its wall block |
| @@ -4370,9 +4442,11 @@ DPID="" | |||
| 4370 | # the dynamic wall, and no convergence point either: what it asserts on is | 4442 | # the dynamic wall, and no convergence point either: what it asserts on is |
| 4371 | # the hub's HTTP answers and the wall FILE — its one grid check rides on | 4443 | # the hub's HTTP answers and the wall FILE — its one grid check rides on |
| 4372 | # `expectgrid` inside the stand-in, which no more counts here than the M18 | 4444 | # `expectgrid` inside the stand-in, which no more counts here than the M18 |
| 4373 | # wall block's convergence does. | 4445 | # wall block's convergence does. The 33rd is the CLI wall, and no |
| 4374 | [ "$OK_COUNT" = "32" ] || { | 4446 | # convergence point for the M12 reason: it asserts on a ptyclient capture |
| 4375 | echo "e2e FAIL: $OK_COUNT scenario checkpoints ran, the pin says 32 —" | 4447 | # — bytes a wall painted to a terminal — which no grid dump can witness. |
| 4448 | [ "$OK_COUNT" = "33" ] || { | ||
| 4449 | echo "e2e FAIL: $OK_COUNT scenario checkpoints ran, the pin says 33 —" | ||
| 4376 | echo " a scenario was added (update the pin) or silently lost" | 4450 | echo " a scenario was added (update the pin) or silently lost" |
| 4377 | exit 1 | 4451 | exit 1 |
| 4378 | } | 4452 | } |
| @@ -4380,4 +4454,4 @@ DPID="" | |||
| 4380 | echo "e2e FAIL: $CONV_COUNT convergence points ran, the pin says 35" | 4454 | echo "e2e FAIL: $CONV_COUNT convergence points ran, the pin says 35" |
| 4381 | exit 1 | 4455 | exit 1 |
| 4382 | } | 4456 | } |
| 4383 | echo "e2e OK (32 scenarios, 35 convergence points)" | 4457 | echo "e2e OK (33 scenarios, 35 convergence points)" |