mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-19 11:28:38 +00:00
test: tighten port and map helper coverage
This commit is contained in:
39
src/infra/map-size.test.ts
Normal file
39
src/infra/map-size.test.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { pruneMapToMaxSize } from "./map-size.js";
|
||||||
|
|
||||||
|
describe("pruneMapToMaxSize", () => {
|
||||||
|
it("keeps the newest entries after flooring fractional limits", () => {
|
||||||
|
const map = new Map([
|
||||||
|
["a", 1],
|
||||||
|
["b", 2],
|
||||||
|
["c", 3],
|
||||||
|
]);
|
||||||
|
|
||||||
|
pruneMapToMaxSize(map, 2.9);
|
||||||
|
|
||||||
|
expect([...map.entries()]).toEqual([
|
||||||
|
["b", 2],
|
||||||
|
["c", 3],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("clears maps for zero or negative limits and leaves undersized maps untouched", () => {
|
||||||
|
const cleared = new Map([
|
||||||
|
["a", 1],
|
||||||
|
["b", 2],
|
||||||
|
]);
|
||||||
|
pruneMapToMaxSize(cleared, 0);
|
||||||
|
expect([...cleared.entries()]).toEqual([]);
|
||||||
|
|
||||||
|
const alsoCleared = new Map([
|
||||||
|
["a", 1],
|
||||||
|
["b", 2],
|
||||||
|
]);
|
||||||
|
pruneMapToMaxSize(alsoCleared, -4);
|
||||||
|
expect([...alsoCleared.entries()]).toEqual([]);
|
||||||
|
|
||||||
|
const unchanged = new Map([["a", 1]]);
|
||||||
|
pruneMapToMaxSize(unchanged, 5);
|
||||||
|
expect([...unchanged.entries()]).toEqual([["a", 1]]);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -7,6 +7,7 @@ const runCommandWithTimeoutMock = vi.hoisted(() => vi.fn());
|
|||||||
vi.mock("../process/exec.js", () => ({
|
vi.mock("../process/exec.js", () => ({
|
||||||
runCommandWithTimeout: (...args: unknown[]) => runCommandWithTimeoutMock(...args),
|
runCommandWithTimeout: (...args: unknown[]) => runCommandWithTimeoutMock(...args),
|
||||||
}));
|
}));
|
||||||
|
import { formatPortListener } from "./ports-format.js";
|
||||||
import { inspectPortUsage } from "./ports-inspect.js";
|
import { inspectPortUsage } from "./ports-inspect.js";
|
||||||
import {
|
import {
|
||||||
buildPortHints,
|
buildPortHints,
|
||||||
@@ -62,29 +63,75 @@ describe("ports helpers", () => {
|
|||||||
expect(messages.join("\n")).toContain("another OpenClaw instance is already running");
|
expect(messages.join("\n")).toContain("another OpenClaw instance is already running");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("classifies ssh and gateway listeners", () => {
|
it("classifies port listeners across gateway, ssh, and unknown cases", () => {
|
||||||
expect(
|
const cases = [
|
||||||
classifyPortListener({ commandLine: "ssh -N -L 18789:127.0.0.1:18789 user@host" }, 18789),
|
{
|
||||||
).toBe("ssh");
|
listener: { commandLine: "ssh -N -L 18789:127.0.0.1:18789 user@host" },
|
||||||
expect(
|
expected: "ssh",
|
||||||
classifyPortListener(
|
},
|
||||||
{
|
{
|
||||||
commandLine: "node /Users/me/Projects/openclaw/dist/entry.js gateway",
|
listener: { command: "ssh" },
|
||||||
},
|
expected: "ssh",
|
||||||
18789,
|
},
|
||||||
),
|
{
|
||||||
).toBe("gateway");
|
listener: { commandLine: "node /Users/me/Projects/openclaw/dist/entry.js gateway" },
|
||||||
|
expected: "gateway",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
listener: { commandLine: "python -m http.server 18789" },
|
||||||
|
expected: "unknown",
|
||||||
|
},
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
for (const testCase of cases) {
|
||||||
|
expect(
|
||||||
|
classifyPortListener(testCase.listener, 18789),
|
||||||
|
JSON.stringify(testCase.listener),
|
||||||
|
).toBe(testCase.expected);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it("formats port diagnostics with hints", () => {
|
it("builds ordered hints for mixed listener kinds and multiple listeners", () => {
|
||||||
const diagnostics = {
|
expect(
|
||||||
|
buildPortHints(
|
||||||
|
[
|
||||||
|
{ commandLine: "node dist/index.js openclaw gateway" },
|
||||||
|
{ commandLine: "ssh -N -L 18789:127.0.0.1:18789" },
|
||||||
|
{ commandLine: "python -m http.server 18789" },
|
||||||
|
],
|
||||||
|
18789,
|
||||||
|
),
|
||||||
|
).toEqual([
|
||||||
|
expect.stringContaining("Gateway already running locally."),
|
||||||
|
"SSH tunnel already bound to this port. Close the tunnel or use a different local port in -L.",
|
||||||
|
"Another process is listening on this port.",
|
||||||
|
expect.stringContaining("Multiple listeners detected"),
|
||||||
|
]);
|
||||||
|
expect(buildPortHints([], 18789)).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("formats port listeners and diagnostics for free and busy ports", () => {
|
||||||
|
expect(formatPortListener({ command: "ssh", address: "127.0.0.1:18789" })).toBe(
|
||||||
|
"pid ?: ssh (127.0.0.1:18789)",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
formatPortDiagnostics({
|
||||||
|
port: 18789,
|
||||||
|
status: "free",
|
||||||
|
listeners: [],
|
||||||
|
hints: [],
|
||||||
|
}),
|
||||||
|
).toEqual(["Port 18789 is free."]);
|
||||||
|
|
||||||
|
const lines = formatPortDiagnostics({
|
||||||
port: 18789,
|
port: 18789,
|
||||||
status: "busy" as const,
|
status: "busy",
|
||||||
listeners: [{ pid: 123, commandLine: "ssh -N -L 18789:127.0.0.1:18789" }],
|
listeners: [{ pid: 123, user: "alice", commandLine: "ssh -N -L 18789:127.0.0.1:18789" }],
|
||||||
hints: buildPortHints([{ pid: 123, commandLine: "ssh -N -L 18789:127.0.0.1:18789" }], 18789),
|
hints: buildPortHints([{ pid: 123, commandLine: "ssh -N -L 18789:127.0.0.1:18789" }], 18789),
|
||||||
};
|
});
|
||||||
const lines = formatPortDiagnostics(diagnostics);
|
|
||||||
expect(lines[0]).toContain("Port 18789 is already in use");
|
expect(lines[0]).toContain("Port 18789 is already in use");
|
||||||
|
expect(lines).toContain("- pid 123 alice: ssh -N -L 18789:127.0.0.1:18789");
|
||||||
expect(lines.some((line) => line.includes("SSH tunnel"))).toBe(true);
|
expect(lines.some((line) => line.includes("SSH tunnel"))).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user