Skip to content

Commit ca6d52e

Browse files
committed
fix(e2e): bound bundled readyz diagnostics
1 parent 4c55e04 commit ca6d52e

2 files changed

Lines changed: 57 additions & 8 deletions

File tree

scripts/e2e/lib/bundled-plugin-install-uninstall/runtime-smoke.mjs

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import path from "node:path";
66
import process from "node:process";
77
import { setTimeout as delay } from "node:timers/promises";
88
import { fileURLToPath } from "node:url";
9+
import { readBoundedResponseText } from "../bounded-response-text.mjs";
910

1011
const TOKEN = "bundled-plugin-runtime-smoke-token";
1112
const RUNTIME_PORT_BASE_ENV = "OPENCLAW_BUNDLED_PLUGIN_RUNTIME_PORT_BASE";
@@ -31,6 +32,7 @@ const RPC_READY_TIMEOUT_MS = readPositiveIntEnv(
3132
);
3233
const COMMAND_TIMEOUT_MS = readPositiveIntEnv("OPENCLAW_BUNDLED_PLUGIN_RUNTIME_COMMAND_MS", 120000);
3334
const HTTP_PROBE_TIMEOUT_MS = readPositiveIntEnv("OPENCLAW_BUNDLED_PLUGIN_RUNTIME_HTTP_MS", 5000);
35+
const HTTP_PROBE_BODY_MAX_BYTES = 1024 * 1024;
3436
const GATEWAY_TEARDOWN_GRACE_MS = readPositiveIntEnv(
3537
"OPENCLAW_BUNDLED_PLUGIN_RUNTIME_TEARDOWN_GRACE_MS",
3638
10000,
@@ -693,18 +695,37 @@ export async function waitForReady(params) {
693695
async function fetchHttpProbeStatus(port, pathName, options = {}) {
694696
const { parseJson = false, timeoutMs = HTTP_PROBE_TIMEOUT_MS } = options;
695697
const controller = new AbortController();
696-
const clearProbeTimer = timeoutMs
697-
? setTimeout(() => {
698-
controller.abort();
699-
}, timeoutMs)
698+
const timeoutError = Object.assign(
699+
new Error(`${pathName} probe timed out after ${timeoutMs}ms`),
700+
{
701+
code: "ETIMEDOUT",
702+
},
703+
);
704+
let clearProbeTimer;
705+
const timeoutPromise = timeoutMs
706+
? new Promise((_, reject) => {
707+
clearProbeTimer = setTimeout(() => {
708+
controller.abort(timeoutError);
709+
reject(timeoutError);
710+
}, timeoutMs);
711+
clearProbeTimer.unref?.();
712+
})
700713
: undefined;
701714
try {
702-
const res = await fetch(`http://127.0.0.1:${port}${pathName}`, {
703-
signal: controller.signal,
704-
});
715+
const res = await Promise.race([
716+
fetch(`http://127.0.0.1:${port}${pathName}`, {
717+
signal: controller.signal,
718+
}),
719+
...(timeoutPromise ? [timeoutPromise] : []),
720+
]);
705721
const status = { ok: res.ok, status: res.status, body: undefined, bodyText: undefined };
706722
if (parseJson) {
707-
const text = await res.text();
723+
const text = await readBoundedResponseText(
724+
res,
725+
`${pathName} probe`,
726+
HTTP_PROBE_BODY_MAX_BYTES,
727+
timeoutPromise,
728+
);
708729
status.bodyText = text;
709730
if (text.trim()) {
710731
try {

test/scripts/bundled-plugin-install-uninstall-probe.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,6 +1062,34 @@ describe("bundled plugin install/uninstall probe", () => {
10621062
}
10631063
});
10641064

1065+
it("bounds readyz diagnostic response bodies", async () => {
1066+
const runtimeSmoke = await importRuntimeSmokeWithEnv({
1067+
OPENCLAW_BUNDLED_PLUGIN_RUNTIME_HTTP_MS: "100",
1068+
OPENCLAW_BUNDLED_PLUGIN_RUNTIME_RPC_READY_MS: "50",
1069+
});
1070+
const server = createHttpServer((_request, response) => {
1071+
response.writeHead(503, {
1072+
"content-length": String(1024 * 1024 + 1),
1073+
"content-type": "application/json",
1074+
});
1075+
response.end();
1076+
});
1077+
1078+
try {
1079+
const port = await listenOnLoopback(server);
1080+
1081+
await expect(
1082+
runtimeSmoke.assertReadyzProbe({
1083+
allowedDegradedReadyzFailures: ["qa-channel"],
1084+
pluginId: "qa-channel",
1085+
port,
1086+
}),
1087+
).rejects.toThrow("/readyz probe response body exceeded 1048576 bytes");
1088+
} finally {
1089+
await closeServer(server);
1090+
}
1091+
});
1092+
10651093
it("bounds stalled runtime HTTP probes", async () => {
10661094
const runtimeSmoke = await import(pathToFileURL(runtimeSmokePath).href);
10671095
const sockets = new Set<Socket>();

0 commit comments

Comments
 (0)