test(gateway-lock): stabilize port-probe liveness coverage

This commit is contained in:
Peter Steinberger
2026-02-22 21:57:03 +01:00
parent ffb12397a8
commit c539782c09

View File

@@ -1,4 +1,5 @@
import { createHash } from "node:crypto"; import { createHash } from "node:crypto";
import { EventEmitter } from "node:events";
import fsSync from "node:fs"; import fsSync from "node:fs";
import fs from "node:fs/promises"; import fs from "node:fs/promises";
import net from "node:net"; import net from "node:net";
@@ -114,51 +115,6 @@ function createEaccesProcStatSpy() {
}); });
} }
async function acquireStaleLinuxLock(env: NodeJS.ProcessEnv) {
await writeLockFile(env, {
startTime: 111,
createdAt: new Date(0).toISOString(),
});
const staleProcSpy = createEaccesProcStatSpy();
const lock = await acquireForTest(env, {
staleMs: 1,
platform: "linux",
});
expect(lock).not.toBeNull();
await lock?.release();
staleProcSpy.mockRestore();
}
async function listenOnLoopbackPort() {
const server = net.createServer();
await new Promise<void>((resolve, reject) => {
server.once("error", reject);
server.listen(0, "127.0.0.1", () => {
server.off("error", reject);
resolve();
});
});
const address = server.address();
if (!address || typeof address === "string") {
throw new Error("failed to resolve loopback test port");
}
return {
port: address.port,
close: async () => {
await new Promise<void>((resolve, reject) => {
server.close((err) => {
if (err) {
reject(err);
return;
}
resolve();
});
});
},
};
}
describe("gateway lock", () => { describe("gateway lock", () => {
beforeAll(async () => { beforeAll(async () => {
fixtureRoot = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gateway-lock-")); fixtureRoot = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-gateway-lock-"));
@@ -233,7 +189,6 @@ describe("gateway lock", () => {
await expect(pending).rejects.toBeInstanceOf(GatewayLockError); await expect(pending).rejects.toBeInstanceOf(GatewayLockError);
spy.mockRestore(); spy.mockRestore();
await acquireStaleLinuxLock(env);
}); });
it("keeps lock when fs.stat fails until payload is stale", async () => { it("keeps lock when fs.stat fails until payload is stale", async () => {
@@ -253,7 +208,6 @@ describe("gateway lock", () => {
await expect(pending).rejects.toBeInstanceOf(GatewayLockError); await expect(pending).rejects.toBeInstanceOf(GatewayLockError);
procSpy.mockRestore(); procSpy.mockRestore();
await acquireStaleLinuxLock(env);
statSpy.mockRestore(); statSpy.mockRestore();
}); });
@@ -264,19 +218,25 @@ describe("gateway lock", () => {
startTime: 111, startTime: 111,
createdAt: new Date().toISOString(), createdAt: new Date().toISOString(),
}); });
const listener = await listenOnLoopbackPort(); const connectSpy = vi.spyOn(net, "createConnection").mockImplementation(() => {
const port = listener.port; const socket = new EventEmitter() as net.Socket;
await listener.close(); socket.destroy = vi.fn();
setImmediate(() => {
socket.emit("error", Object.assign(new Error("ECONNREFUSED"), { code: "ECONNREFUSED" }));
});
return socket;
});
const lock = await acquireForTest(env, { const lock = await acquireForTest(env, {
timeoutMs: 80, timeoutMs: 80,
pollIntervalMs: 5, pollIntervalMs: 5,
staleMs: 10_000, staleMs: 10_000,
platform: "darwin", platform: "darwin",
port, port: 18789,
}); });
expect(lock).not.toBeNull(); expect(lock).not.toBeNull();
await lock?.release(); await lock?.release();
connectSpy.mockRestore();
}); });
it("keeps lock when configured port is busy and owner pid is alive", async () => { it("keeps lock when configured port is busy and owner pid is alive", async () => {
@@ -286,18 +246,25 @@ describe("gateway lock", () => {
startTime: 111, startTime: 111,
createdAt: new Date().toISOString(), createdAt: new Date().toISOString(),
}); });
const listener = await listenOnLoopbackPort(); const connectSpy = vi.spyOn(net, "createConnection").mockImplementation(() => {
const socket = new EventEmitter() as net.Socket;
socket.destroy = vi.fn();
setImmediate(() => {
socket.emit("connect");
});
return socket;
});
try { try {
const pending = acquireForTest(env, { const pending = acquireForTest(env, {
timeoutMs: 20, timeoutMs: 20,
pollIntervalMs: 2, pollIntervalMs: 2,
staleMs: 10_000, staleMs: 10_000,
platform: "darwin", platform: "darwin",
port: listener.port, port: 18789,
}); });
await expect(pending).rejects.toBeInstanceOf(GatewayLockError); await expect(pending).rejects.toBeInstanceOf(GatewayLockError);
} finally { } finally {
await listener.close(); connectSpy.mockRestore();
} }
}); });