Files
diegosouzapw--omniroute/tests/unit/minimax-coding-plan-usage.test.ts
2026-07-13 13:39:12 +08:00

143 lines
5.3 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* tests/unit/minimax-coding-plan-usage.test.ts
*
* MiniMax Coding Plan keys (`sk-cp-…`) expose quota as a remaining-PERCENT on a
* model named "general" with zero request counts — both `token_plan/remains`
* and `coding_plan/remains` return identical Coding-Plan payloads. The fetcher
* previously (a) filtered "general" out and (b) computed only count-based
* quotas, so the Coding Plan showed no quota at all. These tests lock in the
* percent fallback and that Token Plan (count-based) behavior is unchanged.
*
* Response shape captured live from a real Coding Plan key (2026-06-02).
*/
import test from "node:test";
import assert from "node:assert/strict";
import { __testing } from "../../open-sse/services/usage.ts";
const {
getMiniMaxUsage,
isMiniMaxTextQuotaModel,
getMiniMaxRemainingPercent,
createMiniMaxQuotaFromPercent,
} = __testing;
type Quotas = Record<
string,
{ used: number; total: number; remaining?: number; remainingPercentage?: number }
>;
function mockFetchOnce(payload: unknown) {
const original = globalThis.fetch;
globalThis.fetch = (async () =>
new Response(JSON.stringify(payload), {
status: 200,
headers: { "content-type": "application/json" },
})) as typeof fetch;
return () => {
globalThis.fetch = original;
};
}
const CODING_PLAN_PAYLOAD = {
base_resp: { status_code: 0, status_msg: "success" },
model_remains: [
{
model_name: "general",
current_interval_total_count: 0,
current_interval_usage_count: 0,
current_weekly_total_count: 0,
current_weekly_usage_count: 0,
current_interval_remaining_percent: 99,
current_weekly_remaining_percent: 99,
remains_time: 13815408,
weekly_remains_time: 427670466,
current_interval_status: 1,
current_weekly_status: 1,
},
{
model_name: "video",
current_interval_total_count: 0,
current_weekly_total_count: 0,
current_interval_remaining_percent: 100,
current_weekly_remaining_percent: 100,
current_interval_status: 3,
current_weekly_status: 3,
},
],
};
test("getMiniMaxUsage: Coding Plan 'general' surfaces percent-based windows", async () => {
const restore = mockFetchOnce(CODING_PLAN_PAYLOAD);
try {
const result = (await getMiniMaxUsage("sk-cp-test", "minimax")) as { quotas?: Quotas; message?: string };
assert.ok(result.quotas, `expected quotas, got message: ${result.message}`);
const session = result.quotas["session (5h)"];
const weekly = result.quotas["weekly (7d)"];
assert.ok(session, "session window must be present");
assert.ok(weekly, "weekly window must be present");
assert.equal(session.remainingPercentage, 99, "session = 99% remaining");
assert.equal(weekly.remainingPercentage, 99, "weekly = 99% remaining");
assert.equal(session.total, 100);
assert.equal(session.remaining, 99);
} finally {
restore();
}
});
test("getMiniMaxUsage: Token Plan stays count-based (regression guard)", async () => {
const restore = mockFetchOnce({
base_resp: { status_code: 0, status_msg: "success" },
model_remains: [
{
model_name: "minimax-m1",
current_interval_total_count: 1500,
current_interval_usage_count: 300,
current_weekly_total_count: 0,
current_weekly_usage_count: 0,
remains_time: 1000,
},
],
});
try {
const result = (await getMiniMaxUsage("sk-test", "minimax")) as { quotas?: Quotas; message?: string };
assert.ok(result.quotas, `expected quotas, got message: ${result.message}`);
const session = result.quotas["session (5h)"];
assert.ok(session, "session window present");
// token_plan/remains → countMeansRemaining=false → used = usage_count (300/1500 = 80% left)
assert.equal(session.total, 1500);
assert.equal(session.used, 300);
assert.equal(session.remainingPercentage, 80);
} finally {
restore();
}
});
test("isMiniMaxTextQuotaModel: accepts general + minimax-m, rejects media", () => {
assert.equal(isMiniMaxTextQuotaModel("general"), true);
assert.equal(isMiniMaxTextQuotaModel("General"), true);
assert.equal(isMiniMaxTextQuotaModel("minimax-m1"), true);
assert.equal(isMiniMaxTextQuotaModel("coding-plan-pro"), true);
assert.equal(isMiniMaxTextQuotaModel("video"), false);
assert.equal(isMiniMaxTextQuotaModel("image"), false);
assert.equal(isMiniMaxTextQuotaModel("music"), false);
});
test("getMiniMaxRemainingPercent: reads + clamps + handles missing/string", () => {
assert.equal(getMiniMaxRemainingPercent({ current_interval_remaining_percent: 99 }, "current_interval_remaining_percent", "x"), 99);
assert.equal(getMiniMaxRemainingPercent({ x: "42" }, "x", "y"), 42);
assert.equal(getMiniMaxRemainingPercent({ x: 150 }, "x", "y"), 100, "clamps above 100");
assert.equal(getMiniMaxRemainingPercent({ x: -5 }, "x", "y"), 0, "clamps below 0");
assert.equal(getMiniMaxRemainingPercent({}, "x", "y"), null, "missing → null");
assert.equal(getMiniMaxRemainingPercent({ x: "" }, "x", "y"), null, "empty string → null");
});
test("createMiniMaxQuotaFromPercent: 0100 percent window", () => {
const q = createMiniMaxQuotaFromPercent(99, null);
assert.equal(q.total, 100);
assert.equal(q.used, 1);
assert.equal(q.remaining, 99);
assert.equal(q.remainingPercentage, 99);
assert.equal(q.unlimited, false);
});