diff --git a/test/integration/mesh.test.ts b/test/integration/mesh.test.ts index a3c3705..3522d55 100644 --- a/test/integration/mesh.test.ts +++ b/test/integration/mesh.test.ts @@ -66,11 +66,24 @@ function quote(s: string): string { } async function on(machine: string, command: string, timeoutMs?: number): Promise<{ out: string; ok: boolean }> { + // Each part on its own line, and stderr redirected once for the whole script. + // + // It was `${command} 2>&1; echo ...` on a single line, which quietly broke every command + // containing a heredoc: the terminator line became `MARKER 2>&1; echo ...`, matched nothing, and + // the heredoc swallowed the rest of the script — including the echo. `exec 2>&1` needs no + // trailing text on the command's last line, so a heredoc terminates where it says it does. const { stdout } = await exec(instanceId, machine, [ - "sh", "-c", `${command} 2>&1; echo "__exit=$?"`, + "sh", "-c", `exec 2>&1\n${command}\necho "__exit=$?"`, ], timeoutMs); const marker = stdout.lastIndexOf("__exit="); - return { out: stdout.slice(0, marker), ok: Number(stdout.slice(marker + 7).trim()) === 0 }; + if (marker < 0) { + // **Never success.** `Number("")` is 0, so a missing marker used to read as exit 0 — a + // command whose output was swallowed reported that it worked, which is the one answer a test + // harness must never give. + return { out: stdout, ok: false }; + } + const said = stdout.slice(marker + 7).trim(); + return { out: stdout.slice(0, marker), ok: said === "0" }; } async function must(machine: string, command: string, timeoutMs?: number): Promise {