Files
openclaw/src/infra/ports-lsof.test.ts
2026-03-13 19:35:27 +00:00

68 lines
2.1 KiB
TypeScript

import fs from "node:fs";
import fsPromises from "node:fs/promises";
import { afterEach, describe, expect, it, vi } from "vitest";
import { resolveLsofCommand, resolveLsofCommandSync } from "./ports-lsof.js";
const LSOF_CANDIDATES =
process.platform === "darwin"
? ["/usr/sbin/lsof", "/usr/bin/lsof"]
: ["/usr/bin/lsof", "/usr/sbin/lsof"];
describe("lsof command resolution", () => {
afterEach(() => {
vi.restoreAllMocks();
});
it("prefers the first executable async candidate", async () => {
const accessSpy = vi.spyOn(fsPromises, "access").mockImplementation(async (target) => {
if (target === LSOF_CANDIDATES[0]) {
return;
}
throw new Error("unexpected");
});
await expect(resolveLsofCommand()).resolves.toBe(LSOF_CANDIDATES[0]);
expect(accessSpy).toHaveBeenCalledTimes(1);
});
it("falls through async candidates before using the shell fallback", async () => {
const accessSpy = vi.spyOn(fsPromises, "access").mockImplementation(async (target) => {
if (target === LSOF_CANDIDATES[0]) {
throw new Error("missing");
}
if (target === LSOF_CANDIDATES[1]) {
return;
}
throw new Error("unexpected");
});
await expect(resolveLsofCommand()).resolves.toBe(LSOF_CANDIDATES[1]);
expect(accessSpy).toHaveBeenCalledTimes(2);
accessSpy.mockImplementation(async () => {
throw new Error("missing");
});
await expect(resolveLsofCommand()).resolves.toBe("lsof");
});
it("mirrors candidate resolution for the sync helper", () => {
const accessSpy = vi.spyOn(fs, "accessSync").mockImplementation((target) => {
if (target === LSOF_CANDIDATES[0]) {
throw new Error("missing");
}
if (target === LSOF_CANDIDATES[1]) {
return undefined;
}
throw new Error("unexpected");
});
expect(resolveLsofCommandSync()).toBe(LSOF_CANDIDATES[1]);
expect(accessSpy).toHaveBeenCalledTimes(2);
accessSpy.mockImplementation(() => {
throw new Error("missing");
});
expect(resolveLsofCommandSync()).toBe("lsof");
});
});