35504f14
test: the cold handoff is one ssh run, and the word is what says so
a73x 2026-08-29 14:38
Commit message
test/e2e_04_handoff.sh
| Old | New | ||
|---|---|---|---|
| @@ -7,9 +7,9 @@ | |||
| 7 | # per daemon: the handoff dials the DEFAULT socket on the far side, and the | 7 | # per daemon: the handoff dials the DEFAULT socket on the far side, and the |
| 8 | # far side is this box, so each scenario's default socket has to be one of | 8 | # far side is this box, so each scenario's default socket has to be one of |
| 9 | # ours rather than the operator's. Two daemons, no more — the one a cold | 9 | # ours rather than the operator's. Two daemons, no more — the one a cold |
| 10 | # attach starts by running `mux d start` over the shim, and the key-mismatch | 10 | # attach gets because its own `mux d endpoint --start` ensured it over the |
| 11 | # one that cannot be shared because it holds a key nothing else on this box | 11 | # shim, and the key-mismatch one that cannot be shared because it holds a |
| 12 | # has. | 12 | # key nothing else on this box has. |
| 13 | SSHIM_DIR="${TMPDIR:-/tmp}/muxd-e2e-sshim-$$" | 13 | SSHIM_DIR="${TMPDIR:-/tmp}/muxd-e2e-sshim-$$" |
| 14 | defer_rm "$SSHIM_DIR" | 14 | defer_rm "$SSHIM_DIR" |
| 15 | SSHIM_PIDLOG="$SSHIM_DIR/pids" | 15 | SSHIM_PIDLOG="$SSHIM_DIR/pids" |
| @@ -21,6 +21,12 @@ export SSHIM_PIDLOG | |||
| 21 | # name a shell in one of them. | 21 | # name a shell in one of them. |
| 22 | SSHIM_COMMLOG="$SSHIM_DIR/comms" | 22 | SSHIM_COMMLOG="$SSHIM_DIR/comms" |
| 23 | export SSHIM_COMMLOG | 23 | export SSHIM_COMMLOG |
| 24 | # The remote COMMAND each run was handed, one line per run. The pidlog says | ||
| 25 | # how many ssh runs there were and the commlog says what they were; neither | ||
| 26 | # can tell a reading dial from an asking one, and that distinction is now | ||
| 27 | # the whole of how a daemon comes to exist. | ||
| 28 | SSHIM_ARGLOG="$SSHIM_DIR/args" | ||
| 29 | export SSHIM_ARGLOG | ||
| 24 | HRUN="${TMPDIR:-/tmp}/mux-e2e-hrun-$$" | 30 | HRUN="${TMPDIR:-/tmp}/mux-e2e-hrun-$$" |
| 25 | defer_rm "$HRUN" | 31 | defer_rm "$HRUN" |
| 26 | HRUN2="${TMPDIR:-/tmp}/mux-e2e-hrun2-$$" | 32 | HRUN2="${TMPDIR:-/tmp}/mux-e2e-hrun2-$$" |
| @@ -77,11 +83,13 @@ HDEADPORT=$(( 16000 + ($$ % 4000) )) | |||
| 77 | mkdir -p "$SSHIM_DIR" "$HRUN" "$HRUN2" | 83 | mkdir -p "$SSHIM_DIR" "$HRUN" "$HRUN2" |
| 78 | : > "$SSHIM_PIDLOG" | 84 | : > "$SSHIM_PIDLOG" |
| 79 | : > "$SSHIM_COMMLOG" | 85 | : > "$SSHIM_COMMLOG" |
| 86 | : > "$SSHIM_ARGLOG" | ||
| 80 | ssh_shim_head "$SSHIM_DIR/ssh" | 87 | ssh_shim_head "$SSHIM_DIR/ssh" |
| 81 | cat >> "$SSHIM_DIR/ssh" <<'SHIM' | 88 | cat >> "$SSHIM_DIR/ssh" <<'SHIM' |
| 82 | echo $$ >> "${SSHIM_PIDLOG:?}" | 89 | echo $$ >> "${SSHIM_PIDLOG:?}" |
| 83 | printf '%s %s\n' "$(cat /proc/$$/comm)" "$(cat /proc/$PPID/comm)" >> "${SSHIM_COMMLOG:?}" | 90 | printf '%s %s\n' "$(cat /proc/$$/comm)" "$(cat /proc/$PPID/comm)" >> "${SSHIM_COMMLOG:?}" |
| 84 | shift | 91 | shift |
| 92 | printf '%s\n' "$*" >> "${SSHIM_ARGLOG:?}" | ||
| 85 | exec /bin/sh -c "$*" | 93 | exec /bin/sh -c "$*" |
| 86 | SHIM | 94 | SHIM |
| 87 | chmod +x "$SSHIM_DIR/ssh" | 95 | chmod +x "$SSHIM_DIR/ssh" |
| @@ -98,8 +106,9 @@ HPATH="$SSHIM_DIR:$(dirname "$MUX"):$PATH" | |||
| 98 | HHOST="mux-e2e@127.0.0.1" | 106 | HHOST="mux-e2e@127.0.0.1" |
| 99 | HCACHE="$XDG_CACHE_HOME/mux/hosts/$HHOST" | 107 | HCACHE="$XDG_CACHE_HOME/mux/hosts/$HHOST" |
| 100 | # (a) COLD: no daemon, no cache. The attach has to produce the daemon — | 108 | # (a) COLD: no daemon, no cache. The attach has to produce the daemon — |
| 101 | # `mux d endpoint` refuses a box that has none, and the CLIENT answers that | 109 | # the REMOTE does it, because an asked dial spells `mux d endpoint --start` |
| 102 | # by running `mux d start` over the shim — fetch coordinates over the shim, | 110 | # and that verb ensures a daemon before it announces — fetch coordinates |
| 111 | # over the shim, | ||
| 103 | # and END UP ON QUIC — and that last part is proven by observation rather than | 112 | # and END UP ON QUIC — and that last part is proven by observation rather than |
| 104 | # inference: the ssh the announce arrived on is killed by the client on | 113 | # inference: the ssh the announce arrived on is killed by the client on |
| 105 | # QUIC success, so once its pid is OBSERVED gone, a second marker still | 114 | # QUIC success, so once its pid is OBSERVED gone, a second marker still |
| @@ -116,18 +125,26 @@ wait_for "$OUT.h1" "cold-one" 25 || { | |||
| 116 | echo " A client that blocks here read no announce line off the ssh pipe." | 125 | echo " A client that blocks here read no announce line off the ssh pipe." |
| 117 | cat "$OUT.h1" "$OUT.h1.err" 2>/dev/null; exit 1; } | 126 | cat "$OUT.h1" "$OUT.h1.err" 2>/dev/null; exit 1; } |
| 118 | 127 | ||
| 119 | # Exactly three ssh runs, and the LAST one's pid, from the log rather than | 128 | # Exactly ONE ssh run, from the log rather than from ps. Three was the cold |
| 120 | # from ps. Three is the cold shape and it is bounded: `mux d endpoint` on a | 129 | # shape while the CLIENT decided to start: `mux d endpoint` refused an empty |
| 121 | # box with no daemon, then `mux d start`, then `mux d endpoint` again. Never | 130 | # box, the client reaped the exit code to tell that refusal from ssh's own |
| 122 | # a fourth — the ask buys one start and one retry — and the count is what | 131 | # 255, ran `mux d start`, and asked again. The remote decides now, so the |
| 123 | # says so: a client that looped would show four here, not a hang. | 132 | # run that starts the daemon is the run that announces it. |
| 124 | HSHIMS=$(wc -l < "$SSHIM_PIDLOG") | 133 | HSHIMS=$(wc -l < "$SSHIM_PIDLOG") |
| 125 | [ "$HSHIMS" -eq 3 ] || { | 134 | [ "$HSHIMS" -eq 1 ] || { |
| 126 | echo "e2e FAIL: cold handoff ran $HSHIMS ssh invocations, want exactly 3" | 135 | echo "e2e FAIL: cold handoff ran $HSHIMS ssh invocations, want exactly 1" |
| 127 | echo " (mux d endpoint on an empty box, mux d start, mux d endpoint)" | 136 | echo " (one mux d endpoint --start, which ensures and announces)" |
| 128 | cat "$SSHIM_PIDLOG"; exit 1; } | 137 | cat "$SSHIM_PIDLOG"; cat "$SSHIM_ARGLOG"; exit 1; } |
| 129 | # Asked of /proc, not of the client: every one of those three children was | 138 | # The WORD, not just the count. A client that spent its one run on the |
| 130 | # `ssh` itself, sitting directly under `mux`. What this does NOT catch is a | 139 | # reading verb would show the same 1 here and would have started nothing — |
| 140 | # it is the flag that makes this cold attach work at all, and the flag is | ||
| 141 | # the only thing separating this run from a wall poll's. | ||
| 142 | HASKS=$(grep -c -- 'mux d endpoint --start$' "$SSHIM_ARGLOG" || true) | ||
| 143 | [ "$HASKS" -eq 1 ] || { | ||
| 144 | echo "e2e FAIL: cold handoff ran the asking word $HASKS times, want exactly 1" | ||
| 145 | cat "$SSHIM_ARGLOG"; exit 1; } | ||
| 146 | # Asked of /proc, not of the client: that child was `ssh` itself, sitting | ||
| 147 | # directly under `mux`. What this does NOT catch is a | ||
| 131 | # `/bin/sh -c` line put back — bash and dash both exec a single simple | 148 | # `/bin/sh -c` line put back — bash and dash both exec a single simple |
| 132 | # command in place, so the shell is gone by the time /proc is read. That | 149 | # command in place, so the shell is gone by the time /proc is read. That |
| 133 | # regression is build.zig folder rule 5's, measured there; this leg pins the | 150 | # regression is build.zig folder rule 5's, measured there; this leg pins the |
| @@ -137,9 +154,8 @@ HBADCOMM=$(grep -cv '^ssh mux$' "$SSHIM_COMMLOG" || true) | |||
| 137 | echo "e2e FAIL: the handoff spawned something other than ssh straight off mux:" | 154 | echo "e2e FAIL: the handoff spawned something other than ssh straight off mux:" |
| 138 | cat "$SSHIM_COMMLOG"; exit 1; } | 155 | cat "$SSHIM_COMMLOG"; exit 1; } |
| 139 | ok "the handoff's child IS ssh, forked off mux with no shell between" | 156 | ok "the handoff's child IS ssh, forked off mux with no shell between" |
| 140 | # The LAST, not the first: the first two are the refusal and the start, and | 157 | # The one run there was, and the one that carried the announce: its death |
| 141 | # both are already dead by construction. The ssh whose death proves QUIC | 158 | # is what proves QUIC took over. |
| 142 | # took over is the one that carried the announce. | ||
| 143 | HSHIMPID=$(tail -1 "$SSHIM_PIDLOG") | 159 | HSHIMPID=$(tail -1 "$SSHIM_PIDLOG") |
| 144 | wait_pid_gone "$HSHIMPID" "cold handoff: QUIC took over, so ssh must be gone" | 160 | wait_pid_gone "$HSHIMPID" "cold handoff: QUIC took over, so ssh must be gone" |
| 145 | # The second marker is typed only now, after the death was OBSERVED, so its | 161 | # The second marker is typed only now, after the death was OBSERVED, so its |
| @@ -156,20 +172,21 @@ wait_for "$OUT.h1" "cold-two" 20 || { | |||
| 156 | cat "$OUT.h1" "$OUT.h1.err" 2>/dev/null; exit 1; } | 172 | cat "$OUT.h1" "$OUT.h1.err" 2>/dev/null; exit 1; } |
| 157 | pipe_detach "cold handoff client" | 173 | pipe_detach "cold handoff client" |
| 158 | 174 | ||
| 159 | # The daemon the CLIENT started, by the pid `mux d start`'s own up-line | 175 | # The daemon the REMOTE started, by the pid its own up-line reported — the |
| 160 | # reported — the only handle this suite has on a process that is nobody's | 176 | # only handle this suite has on a process that is nobody's child. The line |
| 161 | # child. The line is `mux d start`'s now, not `mux d endpoint`'s, and it | 177 | # is `mux d endpoint`'s now, and it reaches this file the way ssh's own |
| 162 | # reaches this file the same way ssh's own stderr does: inherited. Same | 178 | # stderr does: inherited, because the entry dial is not `quiet`. Same |
| 163 | # accepted gap as the M13 blocks: a failure above leaves it untracked, and | 179 | # accepted gap as the M13 blocks: a failure above leaves it untracked, and |
| 164 | # the trap's stop-by-socket is what covers that. | 180 | # the trap's stop-by-socket is what covers that. |
| 165 | grep -q '^mux d: starting' "$OUT.h1.err" || { | 181 | grep -q '^mux d endpoint: starting' "$OUT.h1.err" || { |
| 166 | echo "e2e FAIL: cold handoff printed no mux d start line — the client did not" | 182 | echo "e2e FAIL: cold handoff printed no starting line — mux d endpoint --start" |
| 167 | echo " start the daemon that mux d endpoint refused to" | 183 | echo " did not ensure the daemon it was asked for" |
| 168 | cat "$OUT.h1.err"; exit 1; } | 184 | cat "$OUT.h1.err"; exit 1; } |
| 169 | HAPID=$(sed -n 's/.* pid=\([0-9]*\).*/\1/p' "$OUT.h1.err" | head -1) | 185 | HAPID=$(sed -n 's/.* pid=\([0-9]*\).*/\1/p' "$OUT.h1.err" | head -1) |
| 170 | defer_kill "$HAPID" | 186 | defer_kill "$HAPID" |
| 171 | [ -n "$HAPID" ] || { | 187 | [ -n "$HAPID" ] || { |
| 172 | echo "e2e FAIL: mux d start's up-line carries no pid"; cat "$OUT.h1.err"; exit 1; } | 188 | echo "e2e FAIL: mux d endpoint --start's up-line carries no pid" |
| 189 | cat "$OUT.h1.err"; exit 1; } | ||
| 173 | kill -0 "$HAPID" 2>/dev/null || { | 190 | kill -0 "$HAPID" 2>/dev/null || { |
| 174 | echo "e2e FAIL: the handoff daemon (pid $HAPID) is not alive"; exit 1; } | 191 | echo "e2e FAIL: the handoff daemon (pid $HAPID) is not alive"; exit 1; } |
| 175 | 192 | ||
test/e2e_09_hosts.sh
| Old | New | ||
|---|---|---|---|
| @@ -911,14 +911,17 @@ ok "the picker births on the host a digit names, forgets a host without ending i | |||
| 911 | # nothing on it therefore got a daemon — and a shell in session 0 — from a | 911 | # nothing on it therefore got a daemon — and a shell in session 0 — from a |
| 912 | # READ, and a `mux d stop` typed on that box was undone a second later. | 912 | # READ, and a `mux d stop` typed on that box was undone a second later. |
| 913 | # | 913 | # |
| 914 | # The rule now: a daemon starts when somebody asks. `mux HOST` and the | 914 | # The rule now: a daemon starts when somebody asks, and the ask is a WORD. |
| 915 | # picker's Enter ask, and answer a refusal by running `mux d start` over the | 915 | # `mux HOST` and the picker's Enter spell `mux d endpoint --start`, which |
| 916 | # same ssh; the poller, `mux hosts` and every redial report `unreachable` | 916 | # ensures a daemon and announces in the same run; the poller, `mux hosts` |
| 917 | # and leave the box alone. | 917 | # and every redial spell the bare verb, which can start nothing whatever |
| 918 | # the client does with the answer. | ||
| 918 | # | 919 | # |
| 919 | # The oracle is the OS, never the daemon: the socket INODE on the far side, | 920 | # The oracle is the OS, never the daemon: the socket INODE on the far side, |
| 920 | # and a walk of /proc for a `mux d run` born under that box's runtime dir. A | 921 | # and a walk of /proc for a `mux d run` born under that box's runtime dir. A |
| 921 | # daemon asked whether it exists cannot answer no. | 922 | # daemon asked whether it exists cannot answer no. The shim log is the |
| 923 | # other half — it records the remote command, so "a read started nothing" | ||
| 924 | # is checked against the word that ran and not only against the outcome. | ||
| 922 | # | 925 | # |
| 923 | # Two fake boxes, because one cannot show that a birth landed on the row | 926 | # Two fake boxes, because one cannot show that a birth landed on the row |
| 924 | # the user chose: the shim reads the host word and hands the remote command | 927 | # the user chose: the shim reads the host word and hands the remote command |
| @@ -951,7 +954,7 @@ case "$1" in | |||
| 951 | *) exit 96 ;; | 954 | *) exit 96 ;; |
| 952 | esac | 955 | esac |
| 953 | export XDG_RUNTIME_DIR | 956 | export XDG_RUNTIME_DIR |
| 954 | echo "$1" >> "${NSHIMLOG:?}" | 957 | printf '%s\n' "$*" >> "${NSHIMLOG:?}" |
| 955 | shift | 958 | shift |
| 956 | exec /bin/sh -c "$*" | 959 | exec /bin/sh -c "$*" |
| 957 | SHIM | 960 | SHIM |
| @@ -960,10 +963,12 @@ NPATH="$NSHIM:$(cd "$(dirname "$MUX")" && pwd):$PATH" | |||
| 960 | printf 'nostart-a@127.0.0.1\nnostart-b@127.0.0.1\n' > "$NSTATE/mux/hosts" | 963 | printf 'nostart-a@127.0.0.1\nnostart-b@127.0.0.1\n' > "$NSTATE/mux/hosts" |
| 961 | 964 | ||
| 962 | # The /proc walk. `mux d run` and not any `mux` — the transient `mux d | 965 | # The /proc walk. `mux d run` and not any `mux` — the transient `mux d |
| 963 | # endpoint` and `mux d start` processes share the runtime dir and are not | 966 | # endpoint` processes share the runtime dir and are not daemons — and |
| 964 | # daemons — and `environ` rather than a name, because a daemon `mux d start` | 967 | # `environ` rather than the argv's `--sock`: the path the ensure forwards is |
| 965 | # spawns carries no --sock to grep for: it took the default from this | 968 | # whatever this variable resolved to, so the variable is the box's identity |
| 966 | # variable. The daemon spells `d run` because that is the argv spawn.zig | 969 | # and the argv is derived from it. The shim gives each fake host a runtime |
| 970 | # dir of its own, which is the whole of what makes them two machines. The | ||
| 971 | # daemon spells `d run` because that is the argv spawn.zig | ||
| 967 | # execs it with, which is also what makes `ps` legible. | 972 | # execs it with, which is also what makes `ps` legible. |
| 968 | nostart_daemons() { | 973 | nostart_daemons() { |
| 969 | _nd=0 | 974 | _nd=0 |
| @@ -1001,6 +1006,14 @@ nostart_empty "$NRUNB" "$NSOCKB" "mux hosts" | |||
| 1001 | # that never dialled: one line per box, at least. | 1006 | # that never dialled: one line per box, at least. |
| 1002 | grep -q 'nostart-a@' "$NSHIMLOG" && grep -q 'nostart-b@' "$NSHIMLOG" || { | 1007 | grep -q 'nostart-a@' "$NSHIMLOG" && grep -q 'nostart-b@' "$NSHIMLOG" || { |
| 1003 | echo "e2e FAIL: no-start: mux hosts dialled neither box:"; cat "$NSHIMLOG"; exit 1; } | 1008 | echo "e2e FAIL: no-start: mux hosts dialled neither box:"; cat "$NSHIMLOG"; exit 1; } |
| 1009 | # ...and it ran the READING word. The emptiness above is what a bare | ||
| 1010 | # `mux d endpoint` leaves behind; `--start` here would be a read that | ||
| 1011 | # starts, which is the whole bug, and it would leave the boxes empty only | ||
| 1012 | # by luck of the spawn failing. | ||
| 1013 | NSTARTS=$(grep -c -- '--start' "$NSHIMLOG" || true) | ||
| 1014 | [ "$NSTARTS" -eq 0 ] || { | ||
| 1015 | echo "e2e FAIL: no-start: mux hosts spelled the asking word $NSTARTS times:" | ||
| 1016 | cat "$NSHIMLOG"; exit 1; } | ||
| 1004 | 1017 | ||
| 1005 | # (2) and (3) in one wall. The wall polls both boxes once a second — three | 1018 | # (2) and (3) in one wall. The wall polls both boxes once a second — three |
| 1006 | # seconds of that must change nothing — and then Enter on ROW 2 asks, which | 1019 | # seconds of that must change nothing — and then Enter on ROW 2 asks, which |
| @@ -1036,6 +1049,17 @@ NCB=$(nostart_daemons "$NRUNB") | |||
| 1036 | echo "e2e FAIL: no-start: picker Enter left $NCB mux d run under $NRUNB, want 1"; exit 1; } | 1049 | echo "e2e FAIL: no-start: picker Enter left $NCB mux d run under $NRUNB, want 1"; exit 1; } |
| 1037 | [ -S "$NSOCKB" ] || { | 1050 | [ -S "$NSOCKB" ] || { |
| 1038 | echo "e2e FAIL: no-start: picker Enter started nothing on box B ($NSOCKB)"; exit 1; } | 1051 | echo "e2e FAIL: no-start: picker Enter started nothing on box B ($NSOCKB)"; exit 1; } |
| 1052 | # ONE ask in the whole run, and it is box B's. Three seconds of polling | ||
| 1053 | # both boxes ran the reading word many times over and the asking word | ||
| 1054 | # never; the Enter ran it once. A poll that had inherited the flag would | ||
| 1055 | # show a count here in the tens, and box A would not be empty above. | ||
| 1056 | NASKS=$(grep -c -- '--start' "$NSHIMLOG" || true) | ||
| 1057 | [ "$NASKS" -eq 1 ] || { | ||
| 1058 | echo "e2e FAIL: no-start: the picker leg spelled the asking word $NASKS times, want 1" | ||
| 1059 | grep -- '--start' "$NSHIMLOG"; exit 1; } | ||
| 1060 | grep -q -- 'nostart-b@.*--start' "$NSHIMLOG" || { | ||
| 1061 | echo "e2e FAIL: no-start: the one ask did not go to box B, the row Enter chose:" | ||
| 1062 | grep -- '--start' "$NSHIMLOG"; exit 1; } | ||
| 1039 | # ...and it is a real session, named `0` off the daemon's own empty list. | 1063 | # ...and it is a real session, named `0` off the daemon's own empty list. |
| 1040 | dump_session "$NSOCKB" 0 | grep -q 'ns-born-ok' || { | 1064 | dump_session "$NSOCKB" 0 | grep -q 'ns-born-ok' || { |
| 1041 | echo "e2e FAIL: no-start: box B's session 0 never ran the marker:" | 1065 | echo "e2e FAIL: no-start: box B's session 0 never ran the marker:" |
| @@ -1079,11 +1103,19 @@ set -e | |||
| 1079 | echo "e2e FAIL: no-start: the reconnect leg exited $RC:" | 1103 | echo "e2e FAIL: no-start: the reconnect leg exited $RC:" |
| 1080 | cat "$OUT.nspc2"; echo "--- stderr ---"; cat "$OUT.nscap2.err"; exit 1; } | 1104 | cat "$OUT.nspc2"; echo "--- stderr ---"; cat "$OUT.nscap2.err"; exit 1; } |
| 1081 | nostart_empty "$NRUNB" "$NSOCKB" "a picker-born tile reconnecting after mux d stop" | 1105 | nostart_empty "$NRUNB" "$NSOCKB" "a picker-born tile reconnecting after mux d stop" |
| 1106 | # Still ONE ask in the log. `nostart_empty` above says no daemon came back; | ||
| 1107 | # this says no redial even SPELLED the word that could have brought one — | ||
| 1108 | # the outcome and the argv, because a redial that asked and failed would | ||
| 1109 | # leave the box empty too and pass the check above vacuously. | ||
| 1110 | NASKS_3B=$(grep -c -- '--start' "$NSHIMLOG" || true) | ||
| 1111 | [ "$NASKS_3B" -eq 1 ] || { | ||
| 1112 | echo "e2e FAIL: no-start: a reconnect spelled the asking word — log holds $NASKS_3B, want 1" | ||
| 1113 | grep -- '--start' "$NSHIMLOG"; exit 1; } | ||
| 1082 | 1114 | ||
| 1083 | # (4) A cold `mux HOST` entry, on the box the wall left alone. One daemon, | 1115 | # (4) A cold `mux HOST` entry, on the box the wall left alone. One daemon, |
| 1084 | # and the client said so in its own voice — `mux d start`'s progress reaches | 1116 | # and the REMOTE said so in its own voice — `mux d endpoint --start`'s |
| 1085 | # the user's terminal over the same inherited stderr ssh's own diagnostics | 1117 | # progress reaches the user's terminal over the same inherited stderr ssh's |
| 1086 | # ride on. | 1118 | # own diagnostics ride on. |
| 1087 | pipe_mux "$OUT.nsa" "$OUT.nsa.err" env SHELL=/bin/sh XDG_STATE_HOME="$NSTATE" \ | 1119 | pipe_mux "$OUT.nsa" "$OUT.nsa.err" env SHELL=/bin/sh XDG_STATE_HOME="$NSTATE" \ |
| 1088 | PATH="$NPATH" timeout 60 "$MUX" "nostart-a@127.0.0.1" | 1120 | PATH="$NPATH" timeout 60 "$MUX" "nostart-a@127.0.0.1" |
| 1089 | pipe_send 'printf "ns-cold-%%s\\n" ok\n' | 1121 | pipe_send 'printf "ns-cold-%%s\\n" ok\n' |
| @@ -1095,9 +1127,25 @@ NCA=$(nostart_daemons "$NRUNA") | |||
| 1095 | cat "$OUT.nsa.err"; exit 1; } | 1127 | cat "$OUT.nsa.err"; exit 1; } |
| 1096 | [ -S "$NSOCKA" ] || { | 1128 | [ -S "$NSOCKA" ] || { |
| 1097 | echo "e2e FAIL: no-start: the cold entry started nothing on box A"; exit 1; } | 1129 | echo "e2e FAIL: no-start: the cold entry started nothing on box A"; exit 1; } |
| 1098 | [ "$(grep -c '^mux d: starting' "$OUT.nsa.err")" = "1" ] || { | 1130 | [ "$(grep -c '^mux d endpoint: starting' "$OUT.nsa.err")" = "1" ] || { |
| 1099 | echo "e2e FAIL: no-start: the cold entry did not run mux d start exactly once:" | 1131 | echo "e2e FAIL: no-start: the cold entry did not ensure a daemon exactly once:" |
| 1100 | cat "$OUT.nsa.err"; exit 1; } | 1132 | cat "$OUT.nsa.err"; exit 1; } |
| 1133 | # ...by ONE ssh run carrying the asking word at box A. The count is | ||
| 1134 | # cumulative over this whole block, so box B's picker ask above is the | ||
| 1135 | # other one. | ||
| 1136 | NASKS_A=$(grep -c -- 'nostart-a@.*--start' "$NSHIMLOG" || true) | ||
| 1137 | [ "$NASKS_A" -eq 1 ] || { | ||
| 1138 | echo "e2e FAIL: no-start: the cold entry spelled the asking word $NASKS_A times at box A, want 1" | ||
| 1139 | grep -- '--start' "$NSHIMLOG"; exit 1; } | ||
| 1140 | # TWO in the whole block, and no more: the picker Enter at box B and this | ||
| 1141 | # entry at box A. Every other line in that log — two `mux hosts` dials, some | ||
| 1142 | # seconds of two-host polling, and every redial of two walls — is the | ||
| 1143 | # reading word. The total is what says the count above is not one ask | ||
| 1144 | # hiding among several. | ||
| 1145 | NASKS_ALL=$(grep -c -- '--start' "$NSHIMLOG" || true) | ||
| 1146 | [ "$NASKS_ALL" -eq 2 ] || { | ||
| 1147 | echo "e2e FAIL: no-start: $NASKS_ALL asks in the whole block, want exactly 2" | ||
| 1148 | grep -- '--start' "$NSHIMLOG"; exit 1; } | ||
| 1101 | # ...and box A goes down by the daemon's own verb, which makes the teardown | 1149 | # ...and box A goes down by the daemon's own verb, which makes the teardown |
| 1102 | # one more assertion rather than a daemon handed to the trap: what a `mux d | 1150 | # one more assertion rather than a daemon handed to the trap: what a `mux d |
| 1103 | # stop` owes on a box somebody started is exactly what an untouched box | 1151 | # stop` owes on a box somebody started is exactly what an untouched box |