chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
/**
|
||||
* Characterization + API-surface test: callLogs.ts god-file decomposition.
|
||||
*
|
||||
* The 10 pure formatting/sanitization helpers were extracted verbatim from
|
||||
* src/lib/usage/callLogs.ts into the pure leaf src/lib/usage/callLogs/format.ts
|
||||
* (no DB, no fs). The DB CRUD / disk-artifact / rotation code stays in the host.
|
||||
*
|
||||
* Verifies that:
|
||||
* 1. The pure helpers behave correctly (DB-free).
|
||||
* 2. The host callLogs.ts still exposes the FULL public API (10 functions).
|
||||
* 3. The format leaf exports its helpers directly.
|
||||
*
|
||||
* NOTE: helpers that call sanitizePII are exercised with non-PII text, since PII
|
||||
* redaction is opt-in / off by default (Hard Rule #20), so sanitizePII is a
|
||||
* pass-through here — the test pins the formatting logic, not PII behaviour.
|
||||
*/
|
||||
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import {
|
||||
asRecord,
|
||||
toNumber,
|
||||
toStringOrNull,
|
||||
truncateText,
|
||||
parseInlineError,
|
||||
normalizeDetailState,
|
||||
toStoredErrorSummary,
|
||||
buildRequestSummary,
|
||||
} from "../../src/lib/usage/callLogs/format.ts";
|
||||
|
||||
describe("callLogs/format — coercers", () => {
|
||||
it("asRecord keeps plain objects, rejects arrays/primitives/null", () => {
|
||||
const o = { a: 1 };
|
||||
assert.equal(asRecord(o), o);
|
||||
assert.deepEqual(asRecord([1, 2]), {});
|
||||
assert.deepEqual(asRecord("x"), {});
|
||||
assert.deepEqual(asRecord(null), {});
|
||||
});
|
||||
|
||||
it("toNumber parses finite numbers and numeric strings, else 0", () => {
|
||||
assert.equal(toNumber(5), 5);
|
||||
assert.equal(toNumber("42"), 42);
|
||||
assert.equal(toNumber(" 7 "), 7);
|
||||
assert.equal(toNumber("abc"), 0);
|
||||
assert.equal(toNumber(Infinity), 0);
|
||||
assert.equal(toNumber(null), 0);
|
||||
});
|
||||
|
||||
it("toStringOrNull keeps non-blank strings, else null", () => {
|
||||
assert.equal(toStringOrNull("hi"), "hi");
|
||||
assert.equal(toStringOrNull(" "), null);
|
||||
assert.equal(toStringOrNull(5), null);
|
||||
});
|
||||
|
||||
it("truncateText slices only when over the limit", () => {
|
||||
assert.equal(truncateText("hello", 10), "hello");
|
||||
assert.equal(truncateText("hello", 3), "hel");
|
||||
});
|
||||
});
|
||||
|
||||
describe("callLogs/format — parseInlineError", () => {
|
||||
it("returns null for non-string / blank", () => {
|
||||
assert.equal(parseInlineError(null), null);
|
||||
assert.equal(parseInlineError(" "), null);
|
||||
});
|
||||
it("parses valid JSON, falls back to the raw string on invalid JSON", () => {
|
||||
assert.deepEqual(parseInlineError('{"code":429}'), { code: 429 });
|
||||
assert.equal(parseInlineError("not json"), "not json");
|
||||
});
|
||||
});
|
||||
|
||||
describe("callLogs/format — normalizeDetailState", () => {
|
||||
it("passes through the four known states", () => {
|
||||
for (const s of ["ready", "missing", "corrupt", "legacy-inline"]) {
|
||||
assert.equal(normalizeDetailState(s), s);
|
||||
}
|
||||
});
|
||||
it("maps anything else to 'none'", () => {
|
||||
assert.equal(normalizeDetailState("bogus"), "none");
|
||||
assert.equal(normalizeDetailState(undefined), "none");
|
||||
});
|
||||
});
|
||||
|
||||
describe("callLogs/format — toStoredErrorSummary", () => {
|
||||
it("returns null for nullish error", () => {
|
||||
assert.equal(toStoredErrorSummary(null), null);
|
||||
assert.equal(toStoredErrorSummary(undefined), null);
|
||||
});
|
||||
it("stringifies a plain-text error (PII pass-through by default)", () => {
|
||||
assert.equal(toStoredErrorSummary("boom"), "boom");
|
||||
});
|
||||
it("JSON-stringifies an Error object's sanitized shape", () => {
|
||||
const out = toStoredErrorSummary(new Error("kaboom"));
|
||||
assert.equal(typeof out, "string");
|
||||
assert.ok(out.includes("kaboom"));
|
||||
assert.ok(out.includes("message"));
|
||||
});
|
||||
});
|
||||
|
||||
describe("callLogs/format — buildRequestSummary", () => {
|
||||
it("returns null for non-search request types", () => {
|
||||
assert.equal(buildRequestSummary("chat", { query: "x" }), null);
|
||||
assert.equal(buildRequestSummary(null, { query: "x" }), null);
|
||||
});
|
||||
it("summarizes a search request's query + non-query/provider filters", () => {
|
||||
const out = buildRequestSummary("search", { query: "cats", provider: "p", topK: 5 });
|
||||
assert.equal(typeof out, "string");
|
||||
const parsed = JSON.parse(out);
|
||||
assert.equal(parsed.query, "cats");
|
||||
assert.deepEqual(parsed.filters, { topK: 5 });
|
||||
assert.equal("provider" in (parsed.filters ?? {}), false);
|
||||
});
|
||||
it("returns null when a search request carries no summarizable fields", () => {
|
||||
assert.equal(buildRequestSummary("search", {}), null);
|
||||
assert.equal(buildRequestSummary("search", { provider: "only" }), null);
|
||||
});
|
||||
});
|
||||
|
||||
// ── host public API surface ──────────────────────────────────────────────────
|
||||
|
||||
const host = await import("../../src/lib/usage/callLogs.ts");
|
||||
|
||||
describe("callLogs.ts public API surface (10 functions)", () => {
|
||||
const expected = [
|
||||
"cleanupOrphanCallLogFiles",
|
||||
"cleanupOverflowCallLogFiles",
|
||||
"deleteCallLogsBefore",
|
||||
"exportCallLogsSince",
|
||||
"getCallLogById",
|
||||
"getCallLogs",
|
||||
"rotateCallLogs",
|
||||
"saveCallLog",
|
||||
"scheduleCallLogRotation",
|
||||
"trimCallLogsToMaxRows",
|
||||
];
|
||||
for (const name of expected) {
|
||||
it(`exposes ${name} as a function`, () => {
|
||||
assert.equal(typeof host[name], "function", `${name} must be a function on the host`);
|
||||
});
|
||||
}
|
||||
it("loses no public function in the split", () => {
|
||||
const missing = expected.filter((n) => typeof host[n] !== "function");
|
||||
assert.deepEqual(missing, [], `missing: ${missing.join(", ")}`);
|
||||
});
|
||||
});
|
||||
|
||||
describe("format.ts exports its helpers directly", () => {
|
||||
it("the moved helpers are functions on the leaf", async () => {
|
||||
const fmt = await import("../../src/lib/usage/callLogs/format.ts");
|
||||
for (const fn of [
|
||||
"asRecord",
|
||||
"toNumber",
|
||||
"sanitizeErrorForLog",
|
||||
"protectPipelinePayloads",
|
||||
"buildRequestSummary",
|
||||
]) {
|
||||
assert.equal(typeof fmt[fn], "function", fn);
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user