import { assertEquals, assertStringIncludes } from "@std/assert"; import { BACKGROUND_CONTEXT as context } from "@earendil-works/chord/context"; import { until } from "@berry/util"; import { BOOTSTRAP, Connection, RemoteEnvironment, sshCommand } from "./connection.ts"; const destination = Deno.env.get("BERRY_TEST_SSH"); Deno.test({ name: "remote terminal I/O stays inside its channel and leaves the worker usable", ignore: !destination && !["linux", "windows"].includes(Deno.build.os), async fn() { const connection = await Connection.open( "pty-test", destination ? sshCommand(destination) : [Deno.execPath(), "eval", "--quiet", BOOTSTRAP], ); const env = new RemoteEnvironment("pty-test", connection, connection.hello.home); try { const pty = await env.pty( [ destination ? "deno" : Deno.execPath(), "eval", ` console.log('terminal=' + [Deno.stdin, Deno.stdout, Deno.stderr].every(s => s.isTerminal())); if (!Deno.stdin.isTerminal()) Deno.exit(2); Deno.stdin.setRaw(true); console.log('ready'); const buffer = new Uint8Array(1024); const decoder = new TextDecoder(); let input = ''; while (!input.includes('\\r')) { const n = await Deno.stdin.read(buffer); if (n === null) break; input += decoder.decode(buffer.subarray(0, n), { stream: true }); } console.log('received=' + input.trimEnd()); console.error('terminal-stderr'); console.log('size=' + JSON.stringify(Deno.consoleSize())); Deno.exit(17); `, ], { cols: 100, rows: 30 }, context, ); let output = ""; let readError: unknown; let exit: number | null | undefined; const drained = (async () => { const decoder = new TextDecoder(); for await (const chunk of pty.readable) output += decoder.decode(chunk, { stream: true }); })().catch((error) => readError = error); void pty.exited.then((code) => exit = code); const input = pty.writable.getWriter(); try { await until(() => { if (connection.lost) throw connection.lost; return output.includes("ready"); }); assertStringIncludes(output, "terminal=true"); pty.resize(90, 33); await input.write(new TextEncoder().encode("berry-pty-probe\r")); await until(() => exit !== undefined); assertEquals(exit, 17); await drained; assertEquals(readError, undefined); assertStringIncludes(output, "received=berry-pty-probe"); assertStringIncludes(output, "terminal-stderr"); assertStringIncludes(output, 'size={"columns":90,"rows":33}'); assertEquals((await env.fileInfo(env.home, context)).ok, true); } finally { pty.kill(); input.releaseLock(); } } finally { await connection.close(); } }, });