mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
fix(e2e): bound ClickClack fixture plugin fetch requests (#108826)
* fix(e2e): bound ClickClack fixture plugin fetch requests * test(e2e): exercise ClickClack response deadline --------- Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
@@ -103,6 +103,7 @@ async function requestJson(account, method, pathname, body) {
|
||||
...(body == null ? {} : { "content-type": "application/json" }),
|
||||
},
|
||||
...(body == null ? {} : { body: JSON.stringify(body) }),
|
||||
signal: AbortSignal.timeout(30_000),
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(\`ClickClack fixture \${response.status}: \${await response.text()}\`);
|
||||
|
||||
@@ -4,14 +4,27 @@ import fs from "node:fs";
|
||||
import { createServer, type Server } from "node:http";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import { MAX_TIMER_TIMEOUT_MS } from "@openclaw/normalization-core/number-coercion";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { createBoundedChildOutput } from "../helpers/bounded-child-output.js";
|
||||
|
||||
const browserFixturePath = "scripts/e2e/lib/browser-cdp-snapshot/fixture-server.mjs";
|
||||
const clickclackFixturePath = "scripts/e2e/lib/release-user-journey/clickclack-fixture.mjs";
|
||||
const clickclackPluginWritePath =
|
||||
"scripts/e2e/lib/release-user-journey/write-clickclack-plugin.mjs";
|
||||
const httpProbePath = "scripts/e2e/lib/openwebui/http-probe.mjs";
|
||||
|
||||
type ClickClackFixturePlugin = {
|
||||
outbound: {
|
||||
sendText(ctx: {
|
||||
cfg: { channels: { clickclack: { baseUrl: string; token: string } } };
|
||||
text: string;
|
||||
to: string;
|
||||
}): Promise<unknown>;
|
||||
};
|
||||
};
|
||||
|
||||
function runScript(scriptPath: string, args: string[] = [], env: Record<string, string> = {}) {
|
||||
return spawnSync(process.execPath, [scriptPath, ...args], {
|
||||
encoding: "utf8",
|
||||
@@ -265,4 +278,58 @@ describe("e2e helper numeric env limits", () => {
|
||||
}),
|
||||
).resolves.toBe(true);
|
||||
});
|
||||
|
||||
it("bounds generated ClickClack plugin response bodies", async () => {
|
||||
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-clickclack-plugin-"));
|
||||
let headersSentResolve: (() => void) | undefined;
|
||||
const headersSent = new Promise<void>((resolve) => {
|
||||
headersSentResolve = resolve;
|
||||
});
|
||||
const server = createServer((_request, response) => {
|
||||
response.writeHead(200, { "content-type": "application/json" });
|
||||
response.flushHeaders();
|
||||
headersSentResolve?.();
|
||||
});
|
||||
const baseUrl = await listen(server);
|
||||
const realTimeout = AbortSignal.timeout;
|
||||
const timeoutSpy = vi.spyOn(AbortSignal, "timeout").mockImplementation(() => realTimeout(200));
|
||||
try {
|
||||
const result = runScript(clickclackPluginWritePath, [tempDir]);
|
||||
expect(result.status).toBe(0);
|
||||
const generated = (await import(pathToFileURL(path.join(tempDir, "index.mjs")).href)) as {
|
||||
default: {
|
||||
register(api: {
|
||||
registerChannel(entry: { plugin: ClickClackFixturePlugin }): void;
|
||||
}): void;
|
||||
};
|
||||
};
|
||||
let plugin: ClickClackFixturePlugin | undefined;
|
||||
generated.default.register({
|
||||
registerChannel: ({ plugin: registeredPlugin }) => {
|
||||
plugin = registeredPlugin;
|
||||
},
|
||||
});
|
||||
if (!plugin) {
|
||||
throw new Error("generated ClickClack plugin did not register a channel");
|
||||
}
|
||||
|
||||
const startedAt = Date.now();
|
||||
const request = plugin.outbound.sendText({
|
||||
cfg: { channels: { clickclack: { baseUrl, token: "x" } } },
|
||||
text: "hello",
|
||||
to: "channel:general",
|
||||
});
|
||||
const rejection = expect(request).rejects.toMatchObject({ name: "TimeoutError" });
|
||||
await headersSent;
|
||||
await rejection;
|
||||
|
||||
expect(timeoutSpy).toHaveBeenCalledWith(30_000);
|
||||
expect(Date.now() - startedAt).toBeLessThan(2_000);
|
||||
} finally {
|
||||
timeoutSpy.mockRestore();
|
||||
server.closeAllConnections();
|
||||
await new Promise<void>((resolve) => server.close(() => resolve()));
|
||||
fs.rmSync(tempDir, { force: true, recursive: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user