Files
openclaw/src/node-host/node-invoke-progress.test.ts
2026-07-14 00:49:54 -07:00

70 lines
2.2 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
import type { NodeHostClient } from "./client.js";
import { createNodeInvokeProgressWriter } from "./node-invoke-progress.js";
const frame = {
id: "invoke-1",
nodeId: "node-1",
command: "test.duplex",
paramsJSON: null,
timeoutMs: 0,
idempotencyKey: null,
};
describe("node invoke progress writer", () => {
it("chunks output to 16 KiB and pauses its producer for backpressure", async () => {
const request = vi.fn(async () => ({}));
const client = { request } as NodeHostClient;
const pausable = { pause: vi.fn(), resume: vi.fn() };
const writer = createNodeInvokeProgressWriter({
client,
frame,
idleTimeoutMs: 30_000,
onError: vi.fn(),
});
await writer.write("é".repeat(10_000), pausable);
expect(request).toHaveBeenCalledTimes(2);
expect(pausable.pause).toHaveBeenCalledOnce();
expect(pausable.resume).toHaveBeenCalledOnce();
for (const [, params] of request.mock.calls as unknown as Array<[string, { chunk: string }]>) {
expect(Buffer.byteLength(params.chunk, "utf8")).toBeLessThanOrEqual(16 * 1024);
}
});
it.each([
{ idleTimeoutMs: 100, heartbeatIntervalMs: 250 },
{ idleTimeoutMs: 2_000, heartbeatIntervalMs: 1_000 },
{ idleTimeoutMs: 60_000, heartbeatIntervalMs: 5_000 },
])(
"emits idle heartbeats every $heartbeatIntervalMs ms for a $idleTimeoutMs ms timeout",
async ({ idleTimeoutMs, heartbeatIntervalMs }) => {
vi.useFakeTimers();
try {
vi.setSystemTime(0);
const request = vi.fn(async () => ({}));
const writer = createNodeInvokeProgressWriter({
client: { request } as NodeHostClient,
frame,
idleTimeoutMs,
onError: vi.fn(),
});
writer.startHeartbeats();
await vi.advanceTimersByTimeAsync(heartbeatIntervalMs - 1);
expect(request).not.toHaveBeenCalled();
await vi.advanceTimersByTimeAsync(1);
expect(request).toHaveBeenCalledWith("node.invoke.progress", {
invokeId: "invoke-1",
nodeId: "node-1",
seq: 0,
chunk: "",
});
writer.stop();
await writer.flush();
} finally {
vi.useRealTimers();
}
},
);
});