test: isolate gateway lock per run

This commit is contained in:
Peter Steinberger
2025-12-10 00:58:59 +00:00
parent cf8b00890f
commit 3907e9eedd
3 changed files with 37 additions and 15 deletions

View File

@@ -1,5 +1,8 @@
import { randomUUID } from "node:crypto";
import { type AddressInfo, createServer } from "node:net"; import { type AddressInfo, createServer } from "node:net";
import { describe, expect, test, vi } from "vitest"; import os from "node:os";
import path from "node:path";
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
import { WebSocket } from "ws"; import { WebSocket } from "ws";
import { emitAgentEvent } from "../infra/agent-events.js"; import { emitAgentEvent } from "../infra/agent-events.js";
import { startGatewayServer } from "./server.js"; import { startGatewayServer } from "./server.js";
@@ -24,6 +27,19 @@ vi.mock("../commands/agent.js", () => ({
process.env.CLAWDIS_SKIP_PROVIDERS = "1"; process.env.CLAWDIS_SKIP_PROVIDERS = "1";
const originalLockPath = process.env.CLAWDIS_GATEWAY_LOCK_PATH;
beforeEach(() => {
process.env.CLAWDIS_GATEWAY_LOCK_PATH = path.join(
os.tmpdir(),
`clawdis-gateway-${randomUUID()}.lock`,
);
});
afterEach(() => {
process.env.CLAWDIS_GATEWAY_LOCK_PATH = originalLockPath;
});
async function getFreePort(): Promise<number> { async function getFreePort(): Promise<number> {
return await new Promise((resolve, reject) => { return await new Promise((resolve, reject) => {
const server = createServer(); const server = createServer();
@@ -116,18 +132,22 @@ describe("gateway server", () => {
process.env.CLAWDIS_GATEWAY_TOKEN = prevToken; process.env.CLAWDIS_GATEWAY_TOKEN = prevToken;
}); });
test("closes silent handshakes after timeout", async () => { test(
const { server, ws } = await startServerWithClient(); "closes silent handshakes after timeout",
const closed = await new Promise<boolean>((resolve) => { { timeout: 15_000 },
const timer = setTimeout(() => resolve(false), 4000); async () => {
ws.once("close", () => { const { server, ws } = await startServerWithClient();
clearTimeout(timer); const closed = await new Promise<boolean>((resolve) => {
resolve(true); const timer = setTimeout(() => resolve(false), 12_000);
ws.once("close", () => {
clearTimeout(timer);
resolve(true);
});
}); });
}); expect(closed).toBe(true);
expect(closed).toBe(true); await server.close();
await server.close(); },
}); );
test( test(
"hello + health + presence + status succeed", "hello + health + presence + status succeed",

View File

@@ -97,7 +97,7 @@ function buildSnapshot(): Snapshot {
const MAX_PAYLOAD_BYTES = 512 * 1024; // cap incoming frame size const MAX_PAYLOAD_BYTES = 512 * 1024; // cap incoming frame size
const MAX_BUFFERED_BYTES = 1.5 * 1024 * 1024; // per-connection send buffer limit const MAX_BUFFERED_BYTES = 1.5 * 1024 * 1024; // per-connection send buffer limit
const HANDSHAKE_TIMEOUT_MS = 3_000; const HANDSHAKE_TIMEOUT_MS = 10_000;
const TICK_INTERVAL_MS = 30_000; const TICK_INTERVAL_MS = 30_000;
const HEALTH_REFRESH_INTERVAL_MS = 60_000; const HEALTH_REFRESH_INTERVAL_MS = 60_000;
const DEDUPE_TTL_MS = 5 * 60_000; const DEDUPE_TTL_MS = 5 * 60_000;

View File

@@ -4,7 +4,9 @@ import path from "node:path";
import { flockSync } from "fs-ext"; import { flockSync } from "fs-ext";
const DEFAULT_LOCK_PATH = path.join(os.tmpdir(), "clawdis-gateway.lock"); const defaultLockPath = () =>
process.env.CLAWDIS_GATEWAY_LOCK_PATH ??
path.join(os.tmpdir(), "clawdis-gateway.lock");
export class GatewayLockError extends Error {} export class GatewayLockError extends Error {}
@@ -20,7 +22,7 @@ const SIGNALS: NodeJS.Signals[] = ["SIGINT", "SIGTERM", "SIGHUP"];
* correctness relies solely on the kernel lock. * correctness relies solely on the kernel lock.
*/ */
export async function acquireGatewayLock( export async function acquireGatewayLock(
lockPath = DEFAULT_LOCK_PATH, lockPath = defaultLockPath(),
): Promise<ReleaseFn> { ): Promise<ReleaseFn> {
fs.mkdirSync(path.dirname(lockPath), { recursive: true }); fs.mkdirSync(path.dirname(lockPath), { recursive: true });