diff --git a/tests/management-api-logs-metrics.test.ts b/tests/management-api-logs-metrics.test.ts index b24b9e6d3..f7077a895 100644 --- a/tests/management-api-logs-metrics.test.ts +++ b/tests/management-api-logs-metrics.test.ts @@ -1,5 +1,9 @@ -import { afterEach, describe, expect, test } from "bun:test"; +import { afterEach, beforeEach, describe, expect, test } from "bun:test"; +import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; import { handleManagementAPI } from "../src/server/management-api"; +import { usageLogPath } from "../src/usage/log"; import { addRequestLog, clearRequestLogsForTests, @@ -10,7 +14,24 @@ import type { OcxConfig } from "../src/types"; const config = { providers: [] } as unknown as OcxConfig; -afterEach(() => clearRequestLogsForTests()); +let testDir = ""; +let previousHome: string | undefined; + +beforeEach(() => { + // addRequestLog persists to usage.jsonl; without a scratch OPENCODEX_HOME a bare + // `bun test ` run from outside the repo (no bunfig preload) writes these + // fixture rows into the real ~/.opencodex log and poisons the GUI Usage page. + previousHome = process.env.OPENCODEX_HOME; + testDir = mkdtempSync(join(tmpdir(), "ocx-logs-metrics-")); + process.env.OPENCODEX_HOME = testDir; +}); + +afterEach(() => { + clearRequestLogsForTests(); + if (previousHome === undefined) delete process.env.OPENCODEX_HOME; + else process.env.OPENCODEX_HOME = previousHome; + if (testDir) rmSync(testDir, { recursive: true, force: true }); +}); async function readLogs(): Promise>> { const url = new URL("http://localhost/api/logs"); @@ -154,5 +175,33 @@ describe("GET /api/logs display metrics", () => { const [dto] = await readLogs(); expect(dto!.displayMetrics.cost).toEqual({ kind: "unavailable", reason: "invalid_cache_breakdown" }); }); + + test("fixture usage rows land in the scratch home, never the default location", () => { + // Pins the safety property this file's isolation exists for: addRequestLog + // persists to usage.jsonl, so if the scratch-home hook is ever dropped (or a + // future test logs before it runs), a bare `bun test ` from outside the + // repo writes fixture rows into the developer's real ~/.opencodex log. + const requestId = "safety-pin-usage-log-target"; + addRequestLog(baseEntry({ requestId })); + + const resolvedTarget = usageLogPath(); + expect(resolvedTarget).toBe(join(testDir, "usage.jsonl")); + expect(readFileSync(resolvedTarget, "utf-8")).toContain(requestId); + + // The default location (what the resolver returns with no OPENCODEX_HOME + // override) must never be the write target for this suite. + const previousHome = process.env.OPENCODEX_HOME; + delete process.env.OPENCODEX_HOME; + try { + const defaultTarget = usageLogPath(); + expect(defaultTarget).not.toBe(resolvedTarget); + if (existsSync(defaultTarget)) { + expect(readFileSync(defaultTarget, "utf-8")).not.toContain(requestId); + } + } finally { + if (previousHome === undefined) delete process.env.OPENCODEX_HOME; + else process.env.OPENCODEX_HOME = previousHome; + } + }); }); import { ManagementRequest as Request } from "./helpers/management-auth";