@@ -5,6 +5,7 @@ import { WebSocket, WebSocketServer } from "ws";
|
5 | 5 | import { GatewayClient, resolveGatewayClientConnectChallengeTimeoutMs } from "./client.js"; |
6 | 6 | import { |
7 | 7 | DEFAULT_PREAUTH_HANDSHAKE_TIMEOUT_MS, |
| 8 | +MAX_SAFE_TIMEOUT_DELAY_MS, |
8 | 9 | MAX_CONNECT_CHALLENGE_TIMEOUT_MS, |
9 | 10 | MIN_CONNECT_CHALLENGE_TIMEOUT_MS, |
10 | 11 | } from "./timeouts.js"; |
@@ -418,6 +419,33 @@ describe("GatewayClient", () => {
|
418 | 419 | } |
419 | 420 | }); |
420 | 421 | |
| 422 | +test("clamps oversized stopAndWait timeouts before scheduling", async () => { |
| 423 | +vi.useFakeTimers(); |
| 424 | +try { |
| 425 | +const client = new GatewayClient({}); |
| 426 | +const ws = { |
| 427 | +readyState: WebSocket.OPEN, |
| 428 | +close: vi.fn(), |
| 429 | +terminate: vi.fn(), |
| 430 | +}; |
| 431 | +(client as unknown as { ws: unknown }).ws = ws; |
| 432 | +const setTimeoutSpy = vi.spyOn(globalThis, "setTimeout"); |
| 433 | + |
| 434 | +const stopPromise = client.stopAndWait({ timeoutMs: Number.MAX_SAFE_INTEGER }); |
| 435 | + |
| 436 | +await vi.advanceTimersByTimeAsync(1); |
| 437 | +expect(ws.terminate).not.toHaveBeenCalled(); |
| 438 | +expect(setTimeoutSpy).toHaveBeenCalledWith(expect.any(Function), MAX_SAFE_TIMEOUT_DELAY_MS); |
| 439 | + |
| 440 | +await vi.advanceTimersByTimeAsync(249); |
| 441 | +await expect(stopPromise).resolves.toBeUndefined(); |
| 442 | +expect(ws.terminate).toHaveBeenCalledTimes(1); |
| 443 | +} finally { |
| 444 | +vi.useRealTimers(); |
| 445 | +vi.restoreAllMocks(); |
| 446 | +} |
| 447 | +}); |
| 448 | + |
421 | 449 | test("rejects mismatched tls fingerprint", async () => { |
422 | 450 | const key = [ |
423 | 451 | "-----BEGIN PRIVATE KEY-----", // pragma: allowlist secret |
|