Files
9router/tests/unit/github-monthly-usage-lock.test.js
ryanngit 3292dfc102 fix(github): hold monthly-exhausted accounts until reset
Lock GitHub Copilot connections account-wide until 00:00 UTC on the
first of next month when the upstream 402 response indicates the
monthly additional-usage-limit was hit, instead of only cooling down
the requested model for 120s. Other GitHub 402 responses keep the
existing model-scoped cooldown.
2026-08-05 11:00:40 +07:00

87 lines
2.4 KiB
JavaScript

import { beforeEach, describe, expect, it, vi } from "vitest";
const dbMocks = vi.hoisted(() => ({
getProviderConnections: vi.fn(),
updateProviderConnection: vi.fn(),
}));
vi.mock("@/lib/localDb", () => dbMocks);
vi.mock("@/lib/network/connectionProxy", () => ({
pickProxyPoolId: vi.fn(),
resolveConnectionProxyConfig: vi.fn(),
}));
vi.mock("@/shared/constants/providers.js", () => ({
FREE_PROVIDERS: {},
resolveProviderId: (provider) => provider,
}));
vi.mock("@/sse/utils/logger.js", () => ({ debug: vi.fn(), info: vi.fn(), warn: vi.fn() }));
const { markAccountUnavailable } = await import("../../src/sse/services/auth.js");
beforeEach(() => {
vi.clearAllMocks();
dbMocks.getProviderConnections.mockResolvedValue([{
id: "github-a",
provider: "github",
name: "github-a",
backoffLevel: 4,
}]);
});
describe("GitHub monthly usage exhaustion", () => {
it("locks the whole account until the next UTC month", async () => {
vi.useFakeTimers();
vi.setSystemTime(new Date("2026-08-04T19:30:00.000Z"));
try {
await markAccountUnavailable(
"github-a",
402,
"You've reached your additional usage limit for your plan. Go to GitHub settings for details.",
"github",
"claude-fable-5",
);
expect(dbMocks.updateProviderConnection).toHaveBeenCalledWith(
"github-a",
expect.objectContaining({
modelLock___all: "2026-09-01T00:00:00.000Z",
testStatus: "unavailable",
errorCode: 402,
backoffLevel: 0,
}),
);
expect(dbMocks.updateProviderConnection.mock.calls[0][1])
.not.toHaveProperty("modelLock_claude-fable-5");
} finally {
vi.useRealTimers();
}
});
it("keeps unrelated GitHub 402 errors model-scoped", async () => {
vi.useFakeTimers();
vi.setSystemTime(new Date("2026-08-04T19:30:00.000Z"));
try {
await markAccountUnavailable(
"github-a",
402,
"Payment required",
"github",
"claude-fable-5",
);
expect(dbMocks.updateProviderConnection).toHaveBeenCalledWith(
"github-a",
expect.objectContaining({
"modelLock_claude-fable-5": "2026-08-04T19:32:00.000Z",
}),
);
expect(dbMocks.updateProviderConnection.mock.calls[0][1])
.not.toHaveProperty("modelLock___all");
} finally {
vi.useRealTimers();
}
});
});