mirror of
https://bitbucket.org/siakitem/my-pi.git
synced 2026-08-28 08:35:57 +00:00
58 lines
2.8 KiB
TypeScript
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/);
|
|
});
|