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

250 lines
11 KiB
TypeScript

/**
* tests/unit/quota-fair-share.test.ts
*
* 10 scenarios covering src/lib/quota/fairShare.ts:
* 1. Generous mode, key under fair_share → allow:ok
* 2. Generous mode, key over fair_share, policy=burst → allow:ok
* 3. Generous mode, key over fair_share, policy=hard, total under limit → allow:ok
* 4. Strict mode, key over fair_share, policy=hard → block:fair-share
* 5. Strict mode, key under fair_share → allow
* 6. Cap absolute reached → block:cap-absolute
* 7. Multi-dimension, A passes + B cap → block:cap-absolute
* 8. Soft policy, over fair_share with slack → allow:ok + penalized=true
* 9. Total >= limit, burst → block:global-saturated
* 10. Empty dimensions → allow:ok
*/
import test from "node:test";
import assert from "node:assert/strict";
const { decideFairShare } = await import("../../src/lib/quota/fairShare.ts");
const THRESHOLD = 0.5;
// Helper to make a minimal dimension
function dim(opts: {
poolId?: string;
unit?: string;
window?: string;
limit: number;
consumedTotal: number;
globalUsedPercent: number;
}) {
return {
key: {
poolId: opts.poolId ?? "pool1",
unit: (opts.unit ?? "tokens") as "tokens" | "requests" | "percent" | "usd",
window: (opts.window ?? "hourly") as "hourly" | "5h" | "daily" | "weekly" | "monthly",
},
limit: opts.limit,
consumedTotal: opts.consumedTotal,
globalUsedPercent: opts.globalUsedPercent,
};
}
function alloc(weight: number, policy: "hard" | "soft" | "burst", capValue?: number, capUnit?: string) {
return {
weight,
policy,
...(capValue !== undefined ? { capValue, capUnit: (capUnit ?? "tokens") as "tokens" | "requests" | "percent" | "usd" } : {}),
};
}
// ─── Scenario 1 ─────────────────────────────────────────────────────────────
test("fairShare: generous mode, key under fair_share → allow:ok", () => {
// globalUsedPercent=0.2 < 0.5 threshold → generous
// weight=50, limit=1000 → fair_share=500
// consumed=200 < 500 → allow
const result = decideFairShare({
dimensions: [dim({ limit: 1000, consumedTotal: 200, globalUsedPercent: 0.2 })],
allocation: alloc(50, "hard"),
consumedByThisKey: { "pool1:tokens:hourly": 200 },
saturationThreshold: THRESHOLD,
});
assert.equal(result.kind, "allow");
assert.equal(result.reason, "ok");
});
// ─── Scenario 2 ─────────────────────────────────────────────────────────────
test("fairShare: generous mode, key over fair_share, policy=burst → allow:ok", () => {
// globalUsedPercent=0.3 < 0.5, consumedTotal=600 < 1000 → room exists
// consumed=600 > fair_share=500 → but policy=burst → allow
const result = decideFairShare({
dimensions: [dim({ limit: 1000, consumedTotal: 600, globalUsedPercent: 0.3 })],
allocation: alloc(50, "burst"),
consumedByThisKey: { "pool1:tokens:hourly": 600 },
saturationThreshold: THRESHOLD,
});
assert.equal(result.kind, "allow");
});
// ─── Scenario 3 ─────────────────────────────────────────────────────────────
test("fairShare: generous mode, key over fair_share, policy=hard, total under limit → allow:ok", () => {
// globalUsedPercent=0.4 < 0.5 → generous
// consumed=600 > fair_share=500, but consumedTotal=600 < 1000 → allow (borrowing)
const result = decideFairShare({
dimensions: [dim({ limit: 1000, consumedTotal: 600, globalUsedPercent: 0.4 })],
allocation: alloc(50, "hard"),
consumedByThisKey: { "pool1:tokens:hourly": 600 },
saturationThreshold: THRESHOLD,
});
assert.equal(result.kind, "allow");
});
// ─── Scenario 4 ─────────────────────────────────────────────────────────────
test("fairShare: strict mode, key over fair_share, policy=hard → block:fair-share", () => {
// globalUsedPercent=0.6 >= 0.5 → strict
// consumed=600 > fair_share=500 → block
const result = decideFairShare({
dimensions: [dim({ limit: 1000, consumedTotal: 700, globalUsedPercent: 0.6 })],
allocation: alloc(50, "hard"),
consumedByThisKey: { "pool1:tokens:hourly": 600 },
saturationThreshold: THRESHOLD,
});
assert.equal(result.kind, "block");
assert.equal(result.reason, "fair-share");
});
// ─── Scenario 5 ─────────────────────────────────────────────────────────────
test("fairShare: strict mode, key under fair_share → allow", () => {
// globalUsedPercent=0.7 >= 0.5 → strict
// consumed=300 < fair_share=500 → allow
const result = decideFairShare({
dimensions: [dim({ limit: 1000, consumedTotal: 700, globalUsedPercent: 0.7 })],
allocation: alloc(50, "hard"),
consumedByThisKey: { "pool1:tokens:hourly": 300 },
saturationThreshold: THRESHOLD,
});
assert.equal(result.kind, "allow");
});
// ─── Scenario 6 ─────────────────────────────────────────────────────────────
test("fairShare: cap absolute reached → block:cap-absolute regardless of policy", () => {
// capValue=100, consumed=100 → block:cap-absolute even in generous mode
const result = decideFairShare({
dimensions: [dim({ limit: 1000, consumedTotal: 100, globalUsedPercent: 0.1 })],
allocation: alloc(50, "burst", 100, "tokens"),
consumedByThisKey: { "pool1:tokens:hourly": 100 },
saturationThreshold: THRESHOLD,
});
assert.equal(result.kind, "block");
assert.equal(result.reason, "cap-absolute");
});
// ─── Scenario 7 ─────────────────────────────────────────────────────────────
test("fairShare: multi-dimension, A passes + B cap absolute → block:cap-absolute", () => {
const dimA = {
key: { poolId: "pool1", unit: "tokens" as const, window: "hourly" as const },
limit: 1000,
consumedTotal: 200,
globalUsedPercent: 0.2,
};
const dimB = {
key: { poolId: "pool1", unit: "requests" as const, window: "hourly" as const },
limit: 100,
consumedTotal: 50,
globalUsedPercent: 0.2,
};
const result = decideFairShare({
dimensions: [dimA, dimB],
allocation: {
weight: 50,
policy: "burst",
capValue: 10, // cap 10 requests
capUnit: "requests" as const,
},
consumedByThisKey: {
"pool1:tokens:hourly": 100,
"pool1:requests:hourly": 10, // at the cap
},
saturationThreshold: THRESHOLD,
});
assert.equal(result.kind, "block");
assert.equal(result.reason, "cap-absolute");
});
// ─── Scenario 8 ─────────────────────────────────────────────────────────────
test("fairShare: soft policy, over fair_share with slack → allow:ok + penalized=true", () => {
// generous mode (globalUsedPercent=0.3), consumed=600 > fair_share=500
// policy=soft → allow but penalized
const result = decideFairShare({
dimensions: [dim({ limit: 1000, consumedTotal: 600, globalUsedPercent: 0.3 })],
allocation: alloc(50, "soft"),
consumedByThisKey: { "pool1:tokens:hourly": 600 },
saturationThreshold: THRESHOLD,
});
assert.equal(result.kind, "allow");
assert.equal(result.penalized, true);
});
// ─── Scenario 9 ─────────────────────────────────────────────────────────────
test("fairShare: total >= limit, burst → block:global-saturated", () => {
// consumedTotal=1000 = limit → no room at all
const result = decideFairShare({
dimensions: [dim({ limit: 1000, consumedTotal: 1000, globalUsedPercent: 1.0 })],
allocation: alloc(50, "burst"),
consumedByThisKey: { "pool1:tokens:hourly": 500 },
saturationThreshold: THRESHOLD,
});
assert.equal(result.kind, "block");
assert.equal(result.reason, "global-saturated");
});
// ─── Scenario 10 ────────────────────────────────────────────────────────────
test("fairShare: empty dimensions → allow:ok", () => {
const result = decideFairShare({
dimensions: [],
allocation: alloc(50, "hard"),
consumedByThisKey: {},
saturationThreshold: THRESHOLD,
});
assert.equal(result.kind, "allow");
assert.equal(result.reason, "ok");
});
// ─── Guard A: unknown/garbage policy must fail SAFE (treated as hard) ─────────
// Defensive guard for issue #10: a policy value outside hard|soft|burst (e.g. a
// corrupted DB row read through `row.policy as Policy`) previously fell through
// every switch case in decideFairShare and returned a silent `allow`
// (fail-OPEN). It must be treated as the most restrictive policy (hard) so an
// unknown policy can never bypass fair-share enforcement.
test("fairShare: GUARD-A strict mode, unknown policy over fair_share → block:fair-share (treated as hard)", () => {
// globalUsedPercent=0.6 >= 0.5 → strict; consumed=600 > fair_share=500.
// policy is garbage ("bogus") — must behave like hard and BLOCK, not allow.
const result = decideFairShare({
dimensions: [dim({ limit: 1000, consumedTotal: 700, globalUsedPercent: 0.6 })],
// Cast through unknown to bypass the Policy type — simulates a corrupted row.
allocation: { weight: 50, policy: "bogus" as unknown as "hard" },
consumedByThisKey: { "pool1:tokens:hourly": 600 },
saturationThreshold: THRESHOLD,
});
assert.equal(result.kind, "block");
assert.equal(result.reason, "fair-share");
});
test("fairShare: GUARD-A strict mode, unknown policy UNDER fair_share → allow (hard semantics still allow under share)", () => {
// Treated as hard: under fair_share is allowed even in strict mode.
const result = decideFairShare({
dimensions: [dim({ limit: 1000, consumedTotal: 700, globalUsedPercent: 0.7 })],
allocation: { weight: 50, policy: "garbage" as unknown as "hard" },
consumedByThisKey: { "pool1:tokens:hourly": 300 },
saturationThreshold: THRESHOLD,
});
assert.equal(result.kind, "allow");
});
test("fairShare: GUARD-A generous mode, unknown policy → hard semantics (no soft penalize / no burst leniency)", () => {
// Generous mode (globalUsedPercent=0.3), consumed=600 > fair_share=500, but
// consumedTotal=600 < 1000 so hard allows borrowing. Must NOT be flagged as
// penalized (that would be soft) and must NOT block (key < global limit).
const result = decideFairShare({
dimensions: [dim({ limit: 1000, consumedTotal: 600, globalUsedPercent: 0.3 })],
allocation: { weight: 50, policy: "weird" as unknown as "hard" },
consumedByThisKey: { "pool1:tokens:hourly": 600 },
saturationThreshold: THRESHOLD,
});
assert.equal(result.kind, "allow");
assert.equal(result.penalized, undefined, "unknown policy must not get soft penalize semantics");
});