Files
my-pi/pi-ssh/test/remote-probe.test.ts
T

58 lines
2.8 KiB
TypeScript

import assert from "node:assert/strict";
import test from "node:test";
import { parseRemotePathProbe, probeRemotePath } from "../src/remote-probe.ts";
import type { RemoteExecOptions, RemoteTransport } from "../src/ssh2-transport.ts";
class ProbeTransport implements RemoteTransport {
command = "";
cwd = "";
connect(): Promise<void> { return Promise.resolve(); }
dispose(): Promise<void> { return Promise.resolve(); }
exec(command: string, cwd: string, options: RemoteExecOptions): Promise<{ exitCode: number | null }> {
this.command = command;
this.cwd = cwd;
const start = command.match(/'(__PI_SSH_PROBE_[a-f0-9]+_START__)'/)?.[1];
const end = command.match(/'(__PI_SSH_PROBE_[a-f0-9]+_END__)'/)?.[1];
if (!start || !end) throw new Error("probe markers missing");
options.onData(Buffer.from(`login banner\n${start}/srv/project${end}\nlogout banner\n`));
return Promise.resolve({ exitCode: 0 });
}
capture(): Promise<{ exitCode: number | null; output: Buffer }> { throw new Error("not used"); }
readFile(): Promise<Buffer> { throw new Error("not used"); }
ensureReadable(): Promise<void> { throw new Error("not used"); }
ensureReadableWritable(): Promise<void> { throw new Error("not used"); }
detectImageMimeType(): Promise<string | null> { throw new Error("not used"); }
mkdir(): Promise<void> { throw new Error("not used"); }
writeFile(): Promise<void> { throw new Error("not used"); }
}
test("extracts one framed absolute path while ignoring shell startup output", async () => {
const transport = new ProbeTransport();
assert.equal(await probeRemotePath(transport, "cwd", "/srv"), "/srv/project");
assert.equal(transport.cwd, "/srv");
assert.match(transport.command, /pwd -P/);
});
test("rejects unframed, relative, multiline, and oversized path probes", () => {
assert.throws(() => parseRemotePathProbe(Buffer.from("/srv"), "START", "END", "cwd"), /invalid framed/);
assert.throws(() => parseRemotePathProbe(Buffer.from("STARTrelativeEND"), "START", "END", "cwd"), /absolute POSIX path/);
assert.throws(() => parseRemotePathProbe(Buffer.from("START/srv\notherEND"), "START", "END", "cwd"), /absolute POSIX path/);
assert.throws(
() => parseRemotePathProbe(Buffer.alloc(64 * 1024 + 1), "START", "END", "cwd"),
/exceeded 65536 bytes/,
);
});
test("forwards cancellation to the probe exec call", async () => {
const controller = new AbortController();
controller.abort();
const transport = new ProbeTransport();
const original = transport.exec.bind(transport);
transport.exec = (command, cwd, options) => {
assert.equal(options.signal, controller.signal);
if (options.signal?.aborted) return Promise.reject(new Error("SSH command aborted"));
return original(command, cwd, options);
};
await assert.rejects(probeRemotePath(transport, "home", ".", controller.signal), /SSH command aborted/);
});