open-design/apps/daemon/tests/daemon-url.test.ts
2026-05-14 16:35:46 +08:00

91 lines
2.9 KiB
TypeScript

import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { createJsonIpcServer, type JsonIpcServerHandle } from "@open-design/sidecar";
import { SIDECAR_ENV, SIDECAR_MESSAGES } from "@open-design/sidecar-proto";
import { resolveDaemonUrl, DEFAULT_DAEMON_URL } from "../src/daemon-url.js";
// Verifies the resolution chain: --daemon-url > OD_DAEMON_URL > sidecar
// IPC status discovery > legacy default. Each layer must short-circuit the next
// so `od` clients follow the live daemon across ephemeral-port restarts.
describe("resolveDaemonUrl", () => {
let ipcBaseDir: string;
beforeAll(() => {
ipcBaseDir = fs.mkdtempSync(path.join(os.tmpdir(), "od-mcp-resolve-"));
});
afterAll(() => {
fs.rmSync(ipcBaseDir, { recursive: true, force: true });
});
it("prefers the explicit --daemon-url flag", async () => {
const url = await resolveDaemonUrl({
flagUrl: "http://flag.example:1111",
env: {
OD_DAEMON_URL: "http://env.example:2222",
[SIDECAR_ENV.IPC_PATH]: path.join(ipcBaseDir, "daemon.sock"),
},
});
expect(url).toBe("http://flag.example:1111");
});
it("falls back to OD_DAEMON_URL when no flag given", async () => {
const url = await resolveDaemonUrl({
env: {
OD_DAEMON_URL: "http://env.example:2222",
[SIDECAR_ENV.IPC_PATH]: path.join(ipcBaseDir, "daemon.sock"),
},
});
expect(url).toBe("http://env.example:2222");
});
it("returns the legacy default when no flag/env/socket is available", async () => {
const url = await resolveDaemonUrl({
env: {
[SIDECAR_ENV.IPC_PATH]: path.join(ipcBaseDir, "missing.sock"),
},
timeoutMs: 200,
});
expect(url).toBe(DEFAULT_DAEMON_URL);
});
it("discovers the live daemon URL via the concrete sidecar IPC status endpoint", async () => {
const socketPath = process.platform === "win32"
? `\\\\.\\pipe\\open-design-daemon-url-${process.pid}-${Date.now()}`
: path.join(ipcBaseDir, "daemon.sock");
let ipc: JsonIpcServerHandle | null = null;
try {
ipc = await createJsonIpcServer({
socketPath,
handler: (message) => {
if (
message != null &&
typeof message === "object" &&
(message as { type?: unknown }).type === SIDECAR_MESSAGES.STATUS
) {
return {
pid: 4242,
state: "running",
updatedAt: new Date().toISOString(),
url: "http://127.0.0.1:54321",
};
}
throw new Error("unexpected message");
},
});
const url = await resolveDaemonUrl({
env: {
[SIDECAR_ENV.IPC_PATH]: socketPath,
},
timeoutMs: 1000,
});
expect(url).toBe("http://127.0.0.1:54321");
} finally {
await ipc?.close();
}
});
});