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