Files
diegosouzapw--omniroute/tests/unit/generic-quota-fetcher.test.ts
2026-07-13 13:39:12 +08:00

92 lines
3.9 KiB
TypeScript

import test from "node:test";
import assert from "node:assert/strict";
const genericModule = await import("../../open-sse/services/genericQuotaFetcher.ts");
const preflightModule = await import("../../open-sse/services/quotaPreflight.ts");
const { convertUsageToQuotaInfo, registerGenericQuotaFetchers } = genericModule;
const { getQuotaFetcher } = preflightModule;
test("convertUsageToQuotaInfo returns null on null/undefined input", () => {
assert.equal(convertUsageToQuotaInfo(null), null);
assert.equal(convertUsageToQuotaInfo(undefined), null);
});
test("convertUsageToQuotaInfo returns null when only an error message is present", () => {
// Auth-expired-style response from getUsageForProvider — fail open.
assert.equal(convertUsageToQuotaInfo({ message: "auth expired" }), null);
});
test("convertUsageToQuotaInfo maps remainingPercentage into per-window percentUsed", () => {
const result = convertUsageToQuotaInfo({
quotas: {
session: { remainingPercentage: 30, resetAt: "2026-05-14T20:00:00Z" },
weekly: { remainingPercentage: 10, resetAt: "2026-05-21T00:00:00Z" },
},
});
assert.ok(result);
assert.deepEqual(result!.windows, {
session: { percentUsed: 0.7, resetAt: "2026-05-14T20:00:00Z" },
weekly: { percentUsed: 0.9, resetAt: "2026-05-21T00:00:00Z" },
});
// Worst-case percentUsed mirrors what the legacy single-signal field needs.
assert.equal(result!.percentUsed, 0.9);
// Reset time should track the worst-case window so preflight can surface it.
assert.equal(result!.resetAt, "2026-05-21T00:00:00Z");
});
test("convertUsageToQuotaInfo falls back to used/total when remainingPercentage is absent", () => {
const result = convertUsageToQuotaInfo({
quotas: { session: { used: 45, total: 100, resetAt: null } },
});
assert.ok(result);
assert.equal(result!.windows!.session.percentUsed, 0.45);
});
test("convertUsageToQuotaInfo skips unlimited and unmeasurable windows", () => {
const result = convertUsageToQuotaInfo({
quotas: {
session: { remainingPercentage: 50, resetAt: null },
// No percentage and no used/total → skipped.
unknown_shape: { resetAt: null },
// Unlimited windows are intentionally ignored — preflight can't block on them.
unlimited_credits: { unlimited: true, remainingPercentage: 99 },
},
});
assert.ok(result);
assert.deepEqual(Object.keys(result!.windows || {}), ["session"]);
});
test("convertUsageToQuotaInfo returns null when no windows are measurable", () => {
const result = convertUsageToQuotaInfo({
quotas: { unlimited_thing: { unlimited: true } },
});
assert.equal(result, null);
});
test("convertUsageToQuotaInfo clamps remainingPercentage outside 0-100", () => {
const result = convertUsageToQuotaInfo({
quotas: {
a: { remainingPercentage: 150, resetAt: null }, // clamped to 100 → 0% used
b: { remainingPercentage: -10, resetAt: null }, // clamped to 0 → 100% used
},
});
assert.ok(result);
assert.equal(result!.windows!.a.percentUsed, 0);
assert.equal(result!.windows!.b.percentUsed, 1);
});
test("registerGenericQuotaFetchers registers Claude, GLM, and OpenCode Go via the generic adapter", () => {
registerGenericQuotaFetchers();
// Claude has no bespoke fetcher → should be registered.
assert.ok(getQuotaFetcher("claude"), "claude should be registered");
assert.ok(getQuotaFetcher("glm"), "glm should be registered");
assert.ok(getQuotaFetcher("zai"), "zai should be registered");
assert.ok(getQuotaFetcher("opencode-go"), "opencode-go should be registered");
// Codex has its own dedicated fetcher (registered by codexQuotaFetcher.ts,
// not by the generic registrar) — the generic registrar skips it. We can't
// assert "codex" here without first calling registerCodexQuotaFetcher,
// which would couple this test to chat.ts startup wiring. The skip list
// semantics are exercised by the source code review.
});