Files
2026-07-13 13:39:12 +08:00

157 lines
4.8 KiB
TypeScript

import test from "node:test";
import assert from "node:assert/strict";
// ═════════════════════════════════════════════════════
// Remaining Tasks Tests: Telemetry, Domain Extraction
// ═════════════════════════════════════════════════════
// ─── Request Telemetry (T-45) ────────────────────
import {
RequestTelemetry,
recordTelemetry,
getTelemetrySummary,
} from "../../src/shared/utils/requestTelemetry.ts";
test("RequestTelemetry: records phases", async () => {
const t = new RequestTelemetry("tel-1");
t.startPhase("parse");
t.endPhase();
t.startPhase("validate");
t.endPhase();
const summary = t.getSummary();
assert.equal(summary.phases.length, 2);
assert.equal(summary.phases[0].phase, "parse");
assert.equal(summary.phases[1].phase, "validate");
});
test("RequestTelemetry: measure() wraps async functions", async () => {
const t = new RequestTelemetry("tel-2");
const result = await t.measure("parse", async () => "parsed");
assert.equal(result, "parsed");
assert.equal(t.getSummary().phases.length, 1);
assert.equal(t.getSummary().phases[0].phase, "parse");
});
test("RequestTelemetry: measure() records errors", async () => {
const t = new RequestTelemetry("tel-3");
await assert.rejects(
() =>
t.measure("connect", async () => {
throw new Error("timeout");
}),
(err) => (err as any).message === "timeout"
);
assert.equal(t.getSummary().phases[0].error, "timeout");
});
test("RequestTelemetry: getTelemetrySummary returns valid output", () => {
const t = new RequestTelemetry("tel-4");
t.startPhase("parse");
t.endPhase();
recordTelemetry(t);
const summary = getTelemetrySummary();
assert.ok(summary.count > 0);
assert.ok(typeof summary.p50 === "number");
assert.ok(typeof summary.p95 === "number");
});
// ─── Combo Resolver (T-46) ──────────────────────
import { resolveComboModel, getComboFallbacks } from "../../src/domain/comboResolver.ts";
test("comboResolver: priority returns first model", () => {
const combo = {
name: "test-combo",
strategy: "priority",
models: ["gpt-4", "claude-3.5-sonnet", "gemini-pro"],
};
const result = resolveComboModel(combo);
assert.equal(result.model, "gpt-4");
assert.equal(result.index, 0);
});
test("comboResolver: random returns a valid model", () => {
const combo = {
name: "test-random",
strategy: "random",
models: ["a", "b", "c"],
};
const result = resolveComboModel(combo);
assert.ok(["a", "b", "c"].includes(result.model));
});
test("comboResolver: least-used picks model with lowest count", () => {
const combo = {
name: "test-least",
strategy: "least-used",
models: ["a", "b", "c"],
};
const result = resolveComboModel(combo, {
modelUsageCounts: { a: 10, b: 2, c: 5 },
});
assert.equal(result.model, "b");
});
test("comboResolver: throws on empty models", () => {
assert.throws(
() => resolveComboModel({ name: "empty", strategy: "priority", models: [] }),
/no models configured/
);
});
test("comboResolver: getComboFallbacks returns remaining models", () => {
const combo = { models: ["a", "b", "c", "d"] };
const fallbacks = getComboFallbacks(combo, 1); // primary = "b"
assert.deepEqual(fallbacks, ["c", "d", "a"]);
});
// ─── Lockout Policy (T-46) ──────────────────────
import {
checkLockout,
recordFailedAttempt,
recordSuccess,
forceUnlock,
} from "../../src/domain/lockoutPolicy.ts";
test("lockoutPolicy: initially not locked", () => {
const result = checkLockout("user-fresh");
assert.equal(result.locked, false);
});
test("lockoutPolicy: locks after max attempts", () => {
const config = { maxAttempts: 3, lockoutDurationMs: 60000, attemptWindowMs: 60000 };
const id = "user-lock-test-" + Date.now();
recordFailedAttempt(id, config);
recordFailedAttempt(id, config);
const result = recordFailedAttempt(id, config);
assert.equal(result.locked, true);
assert.ok(result.remainingMs > 0);
});
test("lockoutPolicy: recordSuccess clears state", () => {
const id = "user-success-" + Date.now();
recordFailedAttempt(id);
recordSuccess(id);
const result = checkLockout(id);
assert.equal(result.locked, false);
assert.equal(result.attempts, 0);
});
test("lockoutPolicy: forceUnlock works", () => {
const config = { maxAttempts: 1, lockoutDurationMs: 60000, attemptWindowMs: 60000 };
const id = "user-force-" + Date.now();
recordFailedAttempt(id, config);
forceUnlock(id);
const result = checkLockout(id);
assert.equal(result.locked, false);
});