a0524f88
test: e2e — the first mux on a machine writes the wall it just started
a73x 2026-08-28 19:53
Commit message
test/e2e.sh
| Old | New | ||
|---|---|---|---|
| @@ -177,8 +177,8 @@ done | |||
| 177 | # one of those and adds a convergence point would be pinning a fact every | 177 | # one of those and adds a convergence point would be pinning a fact every |
| 178 | # leg above already establishes. | 178 | # leg above already establishes. |
| 179 | 179 | ||
| 180 | [ "$OK_COUNT" = "81" ] || { | 180 | [ "$OK_COUNT" = "82" ] || { |
| 181 | echo "e2e FAIL: $OK_COUNT scenario checkpoints ran, the pin says 81 —" | 181 | echo "e2e FAIL: $OK_COUNT scenario checkpoints ran, the pin says 82 —" |
| 182 | echo " a scenario was added (update the pin) or silently lost" | 182 | echo " a scenario was added (update the pin) or silently lost" |
| 183 | exit 1 | 183 | exit 1 |
| 184 | } | 184 | } |
test/e2e_09_hosts.sh
| Old | New | ||
|---|---|---|---|
| @@ -30,6 +30,15 @@ HARUN="${TMPDIR:-/tmp}/mux-e2e-hosts-run-$$" | |||
| 30 | defer_rm "$HARUN" | 30 | defer_rm "$HARUN" |
| 31 | HASOCK="$HARUN/muxd.sock" | 31 | HASOCK="$HARUN/muxd.sock" |
| 32 | defer_sock "$HASOCK" | 32 | defer_sock "$HASOCK" |
| 33 | # The empty-file leg: a state home with NO hosts file at all — a machine | ||
| 34 | # where `mux` has never run — and, like the auto-start leg, a runtime dir of | ||
| 35 | # its own so the daemon it starts is this leg's and not the developer's. | ||
| 36 | HESTATE="${TMPDIR:-/tmp}/mux-e2e-hosts-empty-$$" | ||
| 37 | defer_rm "$HESTATE" | ||
| 38 | HERUN="${TMPDIR:-/tmp}/mux-e2e-hosts-empty-run-$$" | ||
| 39 | defer_rm "$HERUN" | ||
| 40 | HESOCK="$HERUN/muxd.sock" | ||
| 41 | defer_sock "$HESOCK" | ||
| 33 | # The `x` leg builds and eats its own daemon's session, so it reads a wall | 42 | # The `x` leg builds and eats its own daemon's session, so it reads a wall |
| 34 | # of ONE host and gets a state home nothing else writes. | 43 | # of ONE host and gets a state home nothing else writes. |
| 35 | HXSTATE="${TMPDIR:-/tmp}/mux-e2e-hosts-x-state-$$" | 44 | HXSTATE="${TMPDIR:-/tmp}/mux-e2e-hosts-x-state-$$" |
| @@ -129,6 +138,62 @@ assert_stopped "$HASOCK" "$HAPID" "hosts auto-start" "$OUT.hastop" | |||
| 129 | HAPID="" | 138 | HAPID="" |
| 130 | ok "mux records the daemon on the wall, never a session, and starts a listed local one that is gone" | 139 | ok "mux records the daemon on the wall, never a session, and starts a listed local one that is gone" |
| 131 | 140 | ||
| 141 | # ---- the empty file: the first `mux` on a machine writes the wall -------- | ||
| 142 | # | ||
| 143 | # The other end of the auto-start rule, and the only leg where the file | ||
| 144 | # does not exist when `mux` starts. Bare `mux` with nothing listed is the | ||
| 145 | # local daemon: it starts one, attaches, and the attach writes the line | ||
| 146 | # that makes every later `mux` a wall. Nothing here pre-writes anything — | ||
| 147 | # a leg that seeds the file cannot see a `recordHost` that never ran. | ||
| 148 | mkdir -p "$HERUN" | ||
| 149 | [ ! -e "$HESTATE" ] || { echo "e2e FAIL: hosts: the empty-file leg's state home already exists"; exit 1; } | ||
| 150 | [ ! -S "$HESOCK" ] || { echo "e2e FAIL: hosts: the empty-file leg's socket is already served"; exit 1; } | ||
| 151 | set +e | ||
| 152 | SHELL=/bin/sh PATH="$(dirname "$MUXD"):$PATH" XDG_RUNTIME_DIR="$HERUN" \ | ||
| 153 | XDG_STATE_HOME="$HESTATE" timeout 60 "$PTYCLIENT" --cols 80 --rows 24 \ | ||
| 154 | --out "$OUT.hempty" --err "$OUT.hempty.err" -- "$MUX" > "$OUT.hempty.log" 2>&1 <<'EOF' | ||
| 155 | expect \x1b[?1049h 20000 | ||
| 156 | settle 600 20000 | ||
| 157 | send echo hepid=$$\n | ||
| 158 | expect hepid= 20000 | ||
| 159 | settle 600 20000 | ||
| 160 | send \x1cd | ||
| 161 | waitexit 10000 | ||
| 162 | EOF | ||
| 163 | RC=$? | ||
| 164 | set -e | ||
| 165 | [ "$RC" -eq 0 ] || { | ||
| 166 | echo "e2e FAIL: hosts: the empty-file leg exited $RC (did bare mux start a local daemon?):" | ||
| 167 | cat "$OUT.hempty.log"; cat "$OUT.hempty.err" 2>/dev/null; exit 1; } | ||
| 168 | HEPID=$(sed -n 's/.* pid=\([0-9]*\).*/\1/p' "$OUT.hempty.err" | head -1) | ||
| 169 | defer_kill "$HEPID" | ||
| 170 | [ -n "$HEPID" ] || { | ||
| 171 | echo "e2e FAIL: hosts: the empty-file leg printed no daemon pid to hold onto:" | ||
| 172 | cat "$OUT.hempty.err"; exit 1; } | ||
| 173 | # The file the attach wrote: the DAEMON it reached, and nothing else. One | ||
| 174 | # line, because a wall of one is what a machine with no file has. | ||
| 175 | [ -f "$HESTATE/mux/hosts" ] || { | ||
| 176 | echo "e2e FAIL: hosts: the first mux wrote no hosts file under $HESTATE"; exit 1; } | ||
| 177 | grep -qxF -- "--sock $HESOCK" "$HESTATE/mux/hosts" || { | ||
| 178 | echo "e2e FAIL: hosts: the empty file did not gain the local daemon's line:" | ||
| 179 | cat "$HESTATE/mux/hosts"; exit 1; } | ||
| 180 | [ "$(wc -l < "$HESTATE/mux/hosts")" = "1" ] || { | ||
| 181 | echo "e2e FAIL: hosts: the first mux wrote more than the daemon it attached to:" | ||
| 182 | cat "$HESTATE/mux/hosts"; exit 1; } | ||
| 183 | # ...and the session behind that line is a real shell, asked of the OS: the | ||
| 184 | # pid the grid shows is a live process whose parent is the daemon `mux` | ||
| 185 | # started. A daemon reporting on itself cannot catch itself being wrong. | ||
| 186 | HESH_PID=$("$MUXD" dump --sock "$HESOCK" | sed -n 's/.*hepid=\([0-9]*\).*/\1/p' | tail -1) | ||
| 187 | [ -n "$HESH_PID" ] || { | ||
| 188 | echo "e2e FAIL: hosts: the empty-file leg's grid shows no shell pid:" | ||
| 189 | "$MUXD" dump --sock "$HESOCK"; exit 1; } | ||
| 190 | [ "$(ps -o ppid= -p "$HESH_PID" 2>/dev/null | tr -d ' ')" = "$(real_pid "$HEPID")" ] || { | ||
| 191 | echo "e2e FAIL: hosts: the shell on the grid is not the auto-started daemon's child" | ||
| 192 | ps -o pid,ppid,args -p "$HESH_PID" 2>&1; exit 1; } | ||
| 193 | assert_stopped "$HESOCK" "$HEPID" "hosts empty file" "$OUT.hestop" | ||
| 194 | HEPID="" | ||
| 195 | ok "the first mux on a machine starts the local daemon and writes it down" | ||
| 196 | |||
| 132 | # ---- every live session of every listed daemon is a tile ---------------- | 197 | # ---- every live session of every listed daemon is a tile ---------------- |
| 133 | # | 198 | # |
| 134 | # The headline. Two daemons on the wall, four sessions between them, and | 199 | # The headline. Two daemons on the wall, four sessions between them, and |