test(gateway): tighten health e2e timeout ceilings

This commit is contained in:
Peter Steinberger
2026-02-21 23:12:02 +00:00
parent 8cdb184f10
commit c78ea8ec3f

View File

@@ -7,6 +7,10 @@ import { startGatewayServerHarness, type GatewayServerHarness } from "./server.e
import { installGatewayTestHooks, onceMessage } from "./test-helpers.js"; import { installGatewayTestHooks, onceMessage } from "./test-helpers.js";
installGatewayTestHooks({ scope: "suite" }); installGatewayTestHooks({ scope: "suite" });
const HEALTH_E2E_TIMEOUT_MS = 30_000;
const PRESENCE_EVENT_TIMEOUT_MS = 6_000;
const SHUTDOWN_EVENT_TIMEOUT_MS = 3_000;
const FINGERPRINT_TIMEOUT_MS = 3_000;
let harness: GatewayServerHarness; let harness: GatewayServerHarness;
@@ -29,39 +33,43 @@ afterAll(async () => {
}); });
describe("gateway server health/presence", () => { describe("gateway server health/presence", () => {
test("connect + health + presence + status succeed", { timeout: 60_000 }, async () => { test(
const { ws } = await harness.openClient(); "connect + health + presence + status succeed",
{ timeout: HEALTH_E2E_TIMEOUT_MS },
async () => {
const { ws } = await harness.openClient();
const healthP = onceMessage<GatewayFrame>(ws, (o) => o.type === "res" && o.id === "health1"); const healthP = onceMessage<GatewayFrame>(ws, (o) => o.type === "res" && o.id === "health1");
const statusP = onceMessage<GatewayFrame>(ws, (o) => o.type === "res" && o.id === "status1"); const statusP = onceMessage<GatewayFrame>(ws, (o) => o.type === "res" && o.id === "status1");
const presenceP = onceMessage<GatewayFrame>( const presenceP = onceMessage<GatewayFrame>(
ws, ws,
(o) => o.type === "res" && o.id === "presence1", (o) => o.type === "res" && o.id === "presence1",
); );
const channelsP = onceMessage<GatewayFrame>( const channelsP = onceMessage<GatewayFrame>(
ws, ws,
(o) => o.type === "res" && o.id === "channels1", (o) => o.type === "res" && o.id === "channels1",
); );
const sendReq = (id: string, method: string) => const sendReq = (id: string, method: string) =>
ws.send(JSON.stringify({ type: "req", id, method })); ws.send(JSON.stringify({ type: "req", id, method }));
sendReq("health1", "health"); sendReq("health1", "health");
sendReq("status1", "status"); sendReq("status1", "status");
sendReq("presence1", "system-presence"); sendReq("presence1", "system-presence");
sendReq("channels1", "channels.status"); sendReq("channels1", "channels.status");
const health = await healthP; const health = await healthP;
const status = await statusP; const status = await statusP;
const presence = await presenceP; const presence = await presenceP;
const channels = await channelsP; const channels = await channelsP;
expect(health.ok).toBe(true); expect(health.ok).toBe(true);
expect(status.ok).toBe(true); expect(status.ok).toBe(true);
expect(presence.ok).toBe(true); expect(presence.ok).toBe(true);
expect(channels.ok).toBe(true); expect(channels.ok).toBe(true);
expect(Array.isArray(presence.payload)).toBe(true); expect(Array.isArray(presence.payload)).toBe(true);
ws.close(); ws.close();
}); },
);
test("broadcasts heartbeat events and serves last-heartbeat", async () => { test("broadcasts heartbeat events and serves last-heartbeat", async () => {
type HeartbeatPayload = { type HeartbeatPayload = {
@@ -121,32 +129,36 @@ describe("gateway server health/presence", () => {
ws.close(); ws.close();
}); });
test("presence events carry seq + stateVersion", { timeout: 8000 }, async () => { test(
const { ws } = await harness.openClient(); "presence events carry seq + stateVersion",
{ timeout: PRESENCE_EVENT_TIMEOUT_MS },
async () => {
const { ws } = await harness.openClient();
const presenceEventP = onceMessage<GatewayFrame>( const presenceEventP = onceMessage<GatewayFrame>(
ws, ws,
(o) => o.type === "event" && o.event === "presence", (o) => o.type === "event" && o.event === "presence",
); );
ws.send( ws.send(
JSON.stringify({ JSON.stringify({
type: "req", type: "req",
id: "evt-1", id: "evt-1",
method: "system-event", method: "system-event",
params: { text: "note from test" }, params: { text: "note from test" },
}), }),
); );
const evt = await presenceEventP; const evt = await presenceEventP;
expect(typeof evt.seq).toBe("number"); expect(typeof evt.seq).toBe("number");
expect(evt.stateVersion?.presence).toBeGreaterThan(0); expect(evt.stateVersion?.presence).toBeGreaterThan(0);
const evtPayload = evt.payload as { presence?: unknown } | undefined; const evtPayload = evt.payload as { presence?: unknown } | undefined;
expect(Array.isArray(evtPayload?.presence)).toBe(true); expect(Array.isArray(evtPayload?.presence)).toBe(true);
ws.close(); ws.close();
}); },
);
test("agent events stream with seq", { timeout: 8000 }, async () => { test("agent events stream with seq", { timeout: PRESENCE_EVENT_TIMEOUT_MS }, async () => {
const { ws } = await harness.openClient(); const { ws } = await harness.openClient();
const runId = randomUUID(); const runId = randomUUID();
@@ -169,13 +181,13 @@ describe("gateway server health/presence", () => {
ws.close(); ws.close();
}); });
test("shutdown event is broadcast on close", { timeout: 8000 }, async () => { test("shutdown event is broadcast on close", { timeout: PRESENCE_EVENT_TIMEOUT_MS }, async () => {
const localHarness = await startGatewayServerHarness(); const localHarness = await startGatewayServerHarness();
const { ws } = await localHarness.openClient(); const { ws } = await localHarness.openClient();
const shutdownP = onceMessage<GatewayFrame>( const shutdownP = onceMessage<GatewayFrame>(
ws, ws,
(o) => o.type === "event" && o.event === "shutdown", (o) => o.type === "event" && o.event === "shutdown",
5000, SHUTDOWN_EVENT_TIMEOUT_MS,
); );
await localHarness.close(); await localHarness.close();
const evt = await shutdownP; const evt = await shutdownP;
@@ -183,33 +195,37 @@ describe("gateway server health/presence", () => {
expect(evtPayload?.reason).toBeDefined(); expect(evtPayload?.reason).toBeDefined();
}); });
test("presence broadcast reaches multiple clients", { timeout: 8000 }, async () => { test(
const clients = await Promise.all([ "presence broadcast reaches multiple clients",
harness.openClient(), { timeout: PRESENCE_EVENT_TIMEOUT_MS },
harness.openClient(), async () => {
harness.openClient(), const clients = await Promise.all([
]); harness.openClient(),
const waits = clients.map(({ ws }) => harness.openClient(),
onceMessage<GatewayFrame>(ws, (o) => o.type === "event" && o.event === "presence"), harness.openClient(),
); ]);
clients[0].ws.send( const waits = clients.map(({ ws }) =>
JSON.stringify({ onceMessage<GatewayFrame>(ws, (o) => o.type === "event" && o.event === "presence"),
type: "req", );
id: "broadcast", clients[0].ws.send(
method: "system-event", JSON.stringify({
params: { text: "fanout" }, type: "req",
}), id: "broadcast",
); method: "system-event",
const events = await Promise.all(waits); params: { text: "fanout" },
for (const evt of events) { }),
const evtPayload = evt.payload as { presence?: unknown[] } | undefined; );
expect(evtPayload?.presence?.length).toBeGreaterThan(0); const events = await Promise.all(waits);
expect(typeof evt.seq).toBe("number"); for (const evt of events) {
} const evtPayload = evt.payload as { presence?: unknown[] } | undefined;
for (const { ws } of clients) { expect(evtPayload?.presence?.length).toBeGreaterThan(0);
ws.close(); expect(typeof evt.seq).toBe("number");
} }
}); for (const { ws } of clients) {
ws.close();
}
},
);
test("presence includes client fingerprint", async () => { test("presence includes client fingerprint", async () => {
const role = "operator"; const role = "operator";
@@ -231,7 +247,7 @@ describe("gateway server health/presence", () => {
const presenceP = onceMessage<GatewayFrame>( const presenceP = onceMessage<GatewayFrame>(
ws, ws,
(o) => o.type === "res" && o.id === "fingerprint", (o) => o.type === "res" && o.id === "fingerprint",
4000, FINGERPRINT_TIMEOUT_MS,
); );
ws.send( ws.send(
JSON.stringify({ JSON.stringify({