51 lines
1.4 KiB
TypeScript
51 lines
1.4 KiB
TypeScript
|
|
import { afterEach, describe, expect, test } from "vitest";
|
||
|
|
import { check, reset } from "@/lib/rate-limit";
|
||
|
|
|
||
|
|
afterEach(() => reset());
|
||
|
|
|
||
|
|
describe("rate limiter", () => {
|
||
|
|
test("allows requests under the limit", () => {
|
||
|
|
for (let i = 0; i < 5; i++) {
|
||
|
|
const r = check("k", 5, 60_000);
|
||
|
|
expect(r.ok).toBe(true);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
test("blocks at the limit and reports retry-after", () => {
|
||
|
|
for (let i = 0; i < 5; i++) check("k", 5, 60_000);
|
||
|
|
const r = check("k", 5, 60_000);
|
||
|
|
expect(r.ok).toBe(false);
|
||
|
|
if (!r.ok) {
|
||
|
|
expect(r.retryAfterSec).toBeGreaterThan(0);
|
||
|
|
expect(r.retryAfterSec).toBeLessThanOrEqual(60);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
test("different keys are independent", () => {
|
||
|
|
for (let i = 0; i < 5; i++) check("a", 5, 60_000);
|
||
|
|
const r = check("b", 5, 60_000);
|
||
|
|
expect(r.ok).toBe(true);
|
||
|
|
});
|
||
|
|
|
||
|
|
test("window resets when expired", () => {
|
||
|
|
// Use a 10ms window so the test runs fast
|
||
|
|
for (let i = 0; i < 3; i++) check("k", 3, 10);
|
||
|
|
const blocked = check("k", 3, 10);
|
||
|
|
expect(blocked.ok).toBe(false);
|
||
|
|
return new Promise<void>((done) => {
|
||
|
|
setTimeout(() => {
|
||
|
|
const after = check("k", 3, 10);
|
||
|
|
expect(after.ok).toBe(true);
|
||
|
|
done();
|
||
|
|
}, 25);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
test("remaining count counts down", () => {
|
||
|
|
const r1 = check("k", 3, 60_000);
|
||
|
|
const r2 = check("k", 3, 60_000);
|
||
|
|
expect(r1.ok && r1.remaining).toBe(2);
|
||
|
|
expect(r2.ok && r2.remaining).toBe(1);
|
||
|
|
});
|
||
|
|
});
|