mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-14 19:02:17 +03:00
`main` has been red since b342c1a361 on the vitest and integration gates:
✖ tests/unit/autoCombo/provider-family-combos.test.ts > auto/<family>
✖ chat pipeline applies Codex OAuth fingerprint and priority tier inside combos
Both call resetStorage() from beforeEach, which does an fs.rmSync(TEST_DATA_DIR,
{recursive: true, force: true}) with no retry, and intermittently loses the race
with a not-yet-released SQLite handle (ENOTEMPTY).
release/v3.8.51 fixed this in #11968 with a mechanical codemod adding
maxRetries/retryDelay to every recursive rm/rmSync/rmdirSync under tests/, but
that PR landed only on the release branch. Because main only receives work at
the release squash, it stayed broken for the whole cycle — and repo-wide gates
then turn every open PR into main red on checks unrelated to their diff.
This is the --base main twin: re-runs the same codemod that already shipped on
the release branch (scripts/ad-hoc/codemod-rm-maxretries.mjs), so the two
branches converge on identical test-teardown semantics. Test-only; no product
logic is touched.
The remaining three failures reported on #12133 (unit full suite exceeding its
4800s ceiling, package-artifact exceeding 1200s, and the boot-smoke that is
skipped as a consequence) are runner-contention timeouts, not code defects —
validate-release-green.mjs runs those heavy gates concurrently on one shared
hosted runner. There is no fix to port for those.
437 lines
12 KiB
TypeScript
437 lines
12 KiB
TypeScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import fs from "node:fs";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
|
|
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-api-key-usage-limits-"));
|
|
process.env.DATA_DIR = TEST_DATA_DIR;
|
|
process.env.API_KEY_SECRET = process.env.API_KEY_SECRET || "usage-limit-test-secret";
|
|
|
|
const core = await import("../../src/lib/db/core.ts");
|
|
const localDb = await import("../../src/lib/localDb.ts");
|
|
const apiKeysDb = await import("../../src/lib/db/apiKeys.ts");
|
|
const usageHistory = await import("../../src/lib/usage/usageHistory.ts");
|
|
const usageLimits = await import("../../src/lib/usage/apiKeyUsageLimits.ts");
|
|
|
|
const NOW = Date.parse("2026-06-19T20:00:00.000Z");
|
|
|
|
async function resetStorage() {
|
|
core.resetDbInstance();
|
|
apiKeysDb.resetApiKeyState();
|
|
usageHistory.clearPendingRequests();
|
|
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
|
|
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
|
|
}
|
|
|
|
test.beforeEach(async () => {
|
|
await resetStorage();
|
|
});
|
|
|
|
test.after(() => {
|
|
core.resetDbInstance();
|
|
apiKeysDb.resetApiKeyState();
|
|
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
|
|
});
|
|
|
|
test("API key USD usage limits persist and default off", async () => {
|
|
const created = await apiKeysDb.createApiKey("Usage Limit Key", "machine-limit-01");
|
|
|
|
let metadata = await apiKeysDb.getApiKeyMetadata(created.key);
|
|
assert.equal(metadata?.usageLimitEnabled, false);
|
|
assert.equal(metadata?.dailyUsageLimitUsd, null);
|
|
assert.equal(metadata?.weeklyUsageLimitUsd, null);
|
|
|
|
await apiKeysDb.updateApiKeyPermissions(created.id, {
|
|
usageLimitEnabled: true,
|
|
dailyUsageLimitUsd: 10.5,
|
|
weeklyUsageLimitUsd: 50,
|
|
});
|
|
apiKeysDb.clearApiKeyCaches();
|
|
|
|
metadata = await apiKeysDb.getApiKeyMetadata(created.key);
|
|
assert.equal(metadata?.usageLimitEnabled, true);
|
|
assert.equal(metadata?.dailyUsageLimitUsd, 10.5);
|
|
assert.equal(metadata?.weeklyUsageLimitUsd, 50);
|
|
});
|
|
|
|
test("getApiKeyUsageLimitStatus aligns weekly USD spend with provider resetAt when available", async () => {
|
|
await localDb.updatePricing({
|
|
claude: {
|
|
"claude-opus-4-8": {
|
|
input: 1,
|
|
cached: 1,
|
|
output: 1,
|
|
reasoning: 1,
|
|
cache_creation: 1,
|
|
},
|
|
},
|
|
});
|
|
|
|
const created = await apiKeysDb.createApiKey("Metered Key", "machine-limit-02");
|
|
await apiKeysDb.updateApiKeyPermissions(created.id, {
|
|
usageLimitEnabled: true,
|
|
dailyUsageLimitUsd: 10,
|
|
weeklyUsageLimitUsd: 20,
|
|
});
|
|
|
|
await usageHistory.saveRequestUsage({
|
|
provider: "claude",
|
|
model: "claude-opus-4-8",
|
|
apiKeyId: created.id,
|
|
apiKeyName: "Metered Key",
|
|
tokens: { input: 2_000_000, output: 0 },
|
|
success: true,
|
|
timestamp: "2026-06-19T12:00:00.000Z",
|
|
});
|
|
await usageHistory.saveRequestUsage({
|
|
provider: "claude",
|
|
model: "claude-opus-4-8",
|
|
apiKeyId: created.id,
|
|
apiKeyName: "Metered Key",
|
|
tokens: { input: 3_000_000, output: 0 },
|
|
success: true,
|
|
timestamp: "2026-06-18T21:00:00.000Z",
|
|
});
|
|
await usageHistory.saveRequestUsage({
|
|
provider: "claude",
|
|
model: "claude-opus-4-8",
|
|
apiKeyId: created.id,
|
|
apiKeyName: "Metered Key",
|
|
tokens: { input: 7_000_000, output: 0 },
|
|
success: true,
|
|
timestamp: "2026-06-18T12:00:00.000Z",
|
|
});
|
|
|
|
const metadata = await apiKeysDb.getApiKeyMetadata(created.key);
|
|
assert.ok(metadata);
|
|
|
|
const weeklyResetAt = "2026-06-25T20:00:00.000Z";
|
|
const status = await usageLimits.getApiKeyUsageLimitStatus(
|
|
{ ...metadata, allowedConnections: ["conn-claude"] },
|
|
{
|
|
now: () => NOW,
|
|
getProviderConnectionById: async () => ({
|
|
id: "conn-claude",
|
|
provider: "claude",
|
|
isActive: true,
|
|
}),
|
|
getProviderConnections: async () => [],
|
|
getProviderLimitsCache: () => ({
|
|
plan: "Claude Max",
|
|
quotas: {
|
|
"weekly (7d)": {
|
|
used: 27,
|
|
total: 100,
|
|
resetAt: weeklyResetAt,
|
|
},
|
|
},
|
|
message: null,
|
|
fetchedAt: new Date(NOW).toISOString(),
|
|
}),
|
|
getAllProviderLimitsCache: () => ({}),
|
|
}
|
|
);
|
|
|
|
assert.equal(status.enabled, true);
|
|
assert.equal(status.dailySpentUsd, 2);
|
|
assert.equal(status.weeklySpentUsd, 5);
|
|
assert.equal(status.dailyLimitUsd, 10);
|
|
assert.equal(status.weeklyLimitUsd, 20);
|
|
assert.equal(status.dailyResetAtIso, "2026-06-20T03:00:00.000Z");
|
|
assert.equal(status.weeklyWindowStartIso, "2026-06-18T20:00:00.000Z");
|
|
assert.equal(status.weeklyResetAtIso, weeklyResetAt);
|
|
assert.equal(status.dailyExceeded, false);
|
|
assert.equal(status.weeklyExceeded, false);
|
|
});
|
|
|
|
test("getApiKeyUsageLimitStatus cuts weekly USD spend at observed provider quota reset", async () => {
|
|
await localDb.updatePricing({
|
|
claude: {
|
|
"claude-opus-4-8": {
|
|
input: 1,
|
|
cached: 1,
|
|
output: 1,
|
|
reasoning: 1,
|
|
cache_creation: 1,
|
|
},
|
|
},
|
|
});
|
|
|
|
const created = await apiKeysDb.createApiKey("Reset Cut Key", "machine-limit-reset");
|
|
await apiKeysDb.updateApiKeyPermissions(created.id, {
|
|
usageLimitEnabled: true,
|
|
dailyUsageLimitUsd: 10,
|
|
weeklyUsageLimitUsd: 20,
|
|
});
|
|
|
|
await usageHistory.saveRequestUsage({
|
|
provider: "claude",
|
|
model: "claude-opus-4-8",
|
|
apiKeyId: created.id,
|
|
apiKeyName: "Reset Cut Key",
|
|
tokens: { input: 7_000_000, output: 0 },
|
|
success: true,
|
|
timestamp: "2026-06-19T23:30:00.000Z",
|
|
});
|
|
await usageHistory.saveRequestUsage({
|
|
provider: "claude",
|
|
model: "claude-opus-4-8",
|
|
apiKeyId: created.id,
|
|
apiKeyName: "Reset Cut Key",
|
|
tokens: { input: 2_000_000, output: 0 },
|
|
success: true,
|
|
timestamp: "2026-06-20T02:00:00.000Z",
|
|
});
|
|
|
|
const db = core.getDbInstance();
|
|
const insertSnapshot = db.prepare(`
|
|
INSERT INTO quota_snapshots (
|
|
provider,
|
|
connection_id,
|
|
window_key,
|
|
remaining_percentage,
|
|
is_exhausted,
|
|
next_reset_at,
|
|
window_duration_ms,
|
|
raw_data,
|
|
created_at
|
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
`);
|
|
insertSnapshot.run(
|
|
"claude",
|
|
"conn-claude",
|
|
"weekly (7d)",
|
|
72,
|
|
0,
|
|
"2026-06-25T23:00:00.000Z",
|
|
null,
|
|
null,
|
|
"2026-06-19T23:55:00.000Z"
|
|
);
|
|
insertSnapshot.run(
|
|
"claude",
|
|
"conn-claude",
|
|
"weekly (7d)",
|
|
100,
|
|
0,
|
|
"2026-06-25T23:00:00.000Z",
|
|
null,
|
|
null,
|
|
"2026-06-20T01:42:52.590Z"
|
|
);
|
|
insertSnapshot.run(
|
|
"claude",
|
|
"conn-claude",
|
|
"weekly (7d)",
|
|
99,
|
|
0,
|
|
"2026-06-25T23:00:00.000Z",
|
|
null,
|
|
null,
|
|
"2026-06-20T02:10:00.000Z"
|
|
);
|
|
db.prepare(
|
|
`
|
|
INSERT INTO provider_quota_reset_events
|
|
(provider, connection_id, window_key, window_started_at, window_resets_at,
|
|
observed_at, previous_remaining_percentage, new_remaining_percentage,
|
|
previous_used_percentage, new_used_percentage, raw_data)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
`
|
|
).run(
|
|
"claude",
|
|
"conn-claude",
|
|
"weekly (7d)",
|
|
"2026-06-18T23:00:00.000Z",
|
|
"2026-06-25T23:00:00.000Z",
|
|
"2026-06-18T23:04:00.000Z",
|
|
0,
|
|
100,
|
|
100,
|
|
0,
|
|
null
|
|
);
|
|
|
|
const metadata = await apiKeysDb.getApiKeyMetadata(created.key);
|
|
assert.ok(metadata);
|
|
|
|
const weeklyResetAt = "2026-06-25T23:00:00.000Z";
|
|
const status = await usageLimits.getApiKeyUsageLimitStatus(
|
|
{ ...metadata, allowedConnections: ["conn-claude"] },
|
|
{
|
|
now: () => Date.parse("2026-06-20T14:30:00.000Z"),
|
|
getProviderConnectionById: async () => ({
|
|
id: "conn-claude",
|
|
provider: "claude",
|
|
isActive: true,
|
|
}),
|
|
getProviderConnections: async () => [],
|
|
getProviderLimitsCache: () => ({
|
|
plan: "Claude Max",
|
|
quotas: {
|
|
"weekly (7d)": {
|
|
used: 5,
|
|
total: 100,
|
|
resetAt: weeklyResetAt,
|
|
},
|
|
},
|
|
message: null,
|
|
fetchedAt: "2026-06-20T14:30:00.000Z",
|
|
}),
|
|
getAllProviderLimitsCache: () => ({}),
|
|
}
|
|
);
|
|
|
|
assert.equal(status.weeklyWindowStartIso, "2026-06-20T01:42:52.590Z");
|
|
assert.equal(status.weeklySpentUsd, 2);
|
|
});
|
|
|
|
test("buildApiKeyUsageLimitText returns API-key quota spend percentage and reset lines", async () => {
|
|
const text = usageLimits.buildApiKeyUsageLimitText(
|
|
{
|
|
enabled: true,
|
|
dailyLimitUsd: 10,
|
|
weeklyLimitUsd: 50,
|
|
dailySpentUsd: 2,
|
|
weeklySpentUsd: 5.25,
|
|
dailyWindowStartIso: "2026-06-19T03:00:00.000Z",
|
|
dailyResetAtIso: "2026-06-20T03:00:00.000Z",
|
|
weeklyWindowStartIso: "2026-06-12T20:00:00.000Z",
|
|
weeklyResetAtIso: "2026-06-25T20:00:00.000Z",
|
|
dailyExceeded: false,
|
|
weeklyExceeded: false,
|
|
},
|
|
Date.parse("2026-06-19T20:00:00.000Z")
|
|
);
|
|
|
|
assert.equal(
|
|
text,
|
|
[
|
|
"Daily quota",
|
|
"$10.00",
|
|
"Daily spent",
|
|
"$2.00",
|
|
"Daily used",
|
|
"20%",
|
|
"Resets in 7h 0m",
|
|
"",
|
|
"Weekly quota",
|
|
"$50.00",
|
|
"Weekly spent",
|
|
"$5.25",
|
|
"Weekly used",
|
|
"11%",
|
|
"Resets in 6d 0h 0m",
|
|
].join("\n")
|
|
);
|
|
});
|
|
|
|
test("buildApiKeyUsageLimitPercentText returns remaining percentages only", () => {
|
|
const text = usageLimits.buildApiKeyUsageLimitPercentText(
|
|
{
|
|
enabled: true,
|
|
dailyLimitUsd: 10,
|
|
weeklyLimitUsd: 50,
|
|
dailySpentUsd: 2,
|
|
weeklySpentUsd: 5.25,
|
|
dailyWindowStartIso: "2026-06-19T03:00:00.000Z",
|
|
dailyResetAtIso: "2026-06-20T03:00:00.000Z",
|
|
weeklyWindowStartIso: "2026-06-12T20:00:00.000Z",
|
|
weeklyResetAtIso: "2026-06-25T20:00:00.000Z",
|
|
dailyExceeded: false,
|
|
weeklyExceeded: false,
|
|
},
|
|
Date.parse("2026-06-19T20:00:00.000Z")
|
|
);
|
|
|
|
assert.equal(
|
|
text,
|
|
["Daily", "80% left", "⏱ reset in 7h 0m", "", "Weekly", "90% left", "⏱ reset in 6d 0h 0m"].join(
|
|
"\n"
|
|
)
|
|
);
|
|
});
|
|
|
|
test("buildApiKeyUsageLimitRejection includes over-quota percentage and reset hint", async () => {
|
|
const response = usageLimits.buildApiKeyUsageLimitRejection(
|
|
new Request("http://localhost/v1/messages", {
|
|
headers: { "anthropic-version": "2023-06-01" },
|
|
}),
|
|
{
|
|
enabled: true,
|
|
dailyLimitUsd: 10,
|
|
weeklyLimitUsd: 1,
|
|
dailySpentUsd: 0.25,
|
|
weeklySpentUsd: 1.09,
|
|
dailyWindowStartIso: "2026-06-19T03:00:00.000Z",
|
|
dailyResetAtIso: "2026-06-20T03:00:00.000Z",
|
|
weeklyWindowStartIso: "2026-06-12T20:00:00.000Z",
|
|
weeklyResetAtIso: "2026-06-25T20:00:00.000Z",
|
|
dailyExceeded: false,
|
|
weeklyExceeded: true,
|
|
},
|
|
Date.parse("2026-06-19T20:00:00.000Z")
|
|
);
|
|
|
|
assert.equal(response.status, 400);
|
|
const body = (await response.json()) as { error: { message: string } };
|
|
assert.equal(
|
|
body.error.message,
|
|
"This API key reached its weekly USD usage quota ($1.09 of $1.00, 109%). Resets in 6d 0h 0m. Choose another allowed model after reset."
|
|
);
|
|
});
|
|
|
|
test("buildApiKeyUsageLimitRejection can hide USD amounts for client-facing policy errors", async () => {
|
|
const response = usageLimits.buildApiKeyUsageLimitRejection(
|
|
new Request("http://localhost/v1/messages", {
|
|
headers: { "anthropic-version": "2023-06-01" },
|
|
}),
|
|
{
|
|
enabled: true,
|
|
dailyLimitUsd: 10,
|
|
weeklyLimitUsd: 1,
|
|
dailySpentUsd: 0.25,
|
|
weeklySpentUsd: 1.09,
|
|
dailyWindowStartIso: "2026-06-19T03:00:00.000Z",
|
|
dailyResetAtIso: "2026-06-20T03:00:00.000Z",
|
|
weeklyWindowStartIso: "2026-06-12T20:00:00.000Z",
|
|
weeklyResetAtIso: "2026-06-25T20:00:00.000Z",
|
|
dailyExceeded: false,
|
|
weeklyExceeded: true,
|
|
},
|
|
Date.parse("2026-06-19T20:00:00.000Z"),
|
|
{ showUsd: false }
|
|
);
|
|
|
|
assert.equal(response.status, 400);
|
|
const body = (await response.json()) as { error: { message: string } };
|
|
assert.equal(
|
|
body.error.message,
|
|
"This API key reached its weekly usage quota (109%). Resets in 6d 0h 0m. Choose another allowed model after reset."
|
|
);
|
|
});
|
|
|
|
test("buildApiKeyUsageLimitRejection uses 400 so Claude Code does not trigger login", () => {
|
|
const response = usageLimits.buildApiKeyUsageLimitRejection(
|
|
new Request("http://localhost/v1/messages", {
|
|
headers: { "anthropic-version": "2023-06-01" },
|
|
}),
|
|
{
|
|
enabled: true,
|
|
dailyLimitUsd: 10,
|
|
weeklyLimitUsd: 50,
|
|
dailySpentUsd: 12,
|
|
weeklySpentUsd: 20,
|
|
dailyWindowStartIso: "2026-06-19T03:00:00.000Z",
|
|
dailyResetAtIso: "2026-06-20T03:00:00.000Z",
|
|
weeklyWindowStartIso: "2026-06-12T20:00:00.000Z",
|
|
weeklyResetAtIso: "2026-06-19T20:00:00.000Z",
|
|
dailyExceeded: true,
|
|
weeklyExceeded: false,
|
|
}
|
|
);
|
|
|
|
assert.equal(response.status, 400);
|
|
});
|