Files
NetMesh/electron/plugins/terminalInterceptorTransport.test.cjs

125 lines
3.5 KiB
JavaScript
Raw Permalink Normal View History

"use strict";
const assert = require("node:assert/strict");
const test = require("node:test");
const { runInNewContext } = require("node:vm");
const {
TERMINAL_INTERCEPTOR_MAX_CHUNK_BYTES,
TERMINAL_INTERCEPTOR_MAX_WINDOW_BYTES,
createTerminalInterceptorEnvelope,
} = require("./terminalInterceptorTransport.cjs");
test("terminal interceptor envelopes validate canonical ready, chunk, and result frames", () => {
assert.deepEqual(createTerminalInterceptorEnvelope({
type: "netcatty:terminal-interceptor:ready",
sessionId: "session-1",
direction: "output",
windowBytes: TERMINAL_INTERCEPTOR_MAX_WINDOW_BYTES,
}), {
frame: {
type: "netcatty:terminal-interceptor:ready",
sessionId: "session-1",
direction: "output",
windowBytes: TERMINAL_INTERCEPTOR_MAX_WINDOW_BYTES,
},
});
const chunkData = new Uint8Array([1, 2, 3]).buffer;
const chunk = createTerminalInterceptorEnvelope({
type: "netcatty:terminal-interceptor:chunk",
sequence: 1,
direction: "input",
creditBytes: TERMINAL_INTERCEPTOR_MAX_CHUNK_BYTES,
byteLength: 3,
}, chunkData);
assert.equal(chunk.transfer, chunkData);
const resultData = runInNewContext("new Uint8Array([4, 5]).buffer");
const result = createTerminalInterceptorEnvelope({
type: "netcatty:terminal-interceptor:result",
sequence: Number.MAX_SAFE_INTEGER,
status: "ok",
creditBytes: 3,
byteLength: 2,
}, resultData);
assert.equal(result.transfer, resultData);
assert.deepEqual(createTerminalInterceptorEnvelope({
type: "netcatty:terminal-interceptor:result",
sequence: 2,
status: "failed",
}), {
frame: {
type: "netcatty:terminal-interceptor:result",
sequence: 2,
status: "failed",
},
});
});
test("terminal interceptor envelopes fail closed on schema or transfer mismatches", () => {
const data = new ArrayBuffer(4);
assert.throws(
() => createTerminalInterceptorEnvelope({
type: "netcatty:terminal-interceptor:chunk",
sequence: 0,
direction: "input",
creditBytes: 1,
byteLength: 4,
}, data),
/violates the plugin contract/,
);
assert.throws(
() => createTerminalInterceptorEnvelope({
type: "netcatty:terminal-interceptor:chunk",
sequence: 1,
direction: "input",
creditBytes: 1,
byteLength: 3,
}, data),
/byteLength mismatch/,
);
assert.throws(
() => createTerminalInterceptorEnvelope({
type: "netcatty:terminal-interceptor:result",
sequence: 1,
status: "ok",
creditBytes: 4,
byteLength: 4,
}),
/requires a transferred ArrayBuffer/,
);
assert.throws(
() => createTerminalInterceptorEnvelope({
type: "netcatty:terminal-interceptor:ready",
sessionId: "session-1",
direction: "input",
windowBytes: TERMINAL_INTERCEPTOR_MAX_CHUNK_BYTES,
extra: true,
}),
/violates the plugin contract/,
);
assert.throws(
() => createTerminalInterceptorEnvelope({
type: "netcatty:terminal-interceptor:result",
sequence: 1,
status: "failed",
}, data),
/must not include a transferred buffer/,
);
const detached = new ArrayBuffer(0);
structuredClone(detached, { transfer: [detached] });
assert.throws(
() => createTerminalInterceptorEnvelope({
type: "netcatty:terminal-interceptor:chunk",
sequence: 1,
direction: "input",
creditBytes: 1,
byteLength: 0,
}, detached),
/requires a real, attached ArrayBuffer/,
);
});