test: isolate gateway lock per run
This commit is contained in:
@@ -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",
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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 });
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user