Files
seiche/server/tests/rate-limit.test.ts
T

46 lines
1.5 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { RateLimiter } from "../src/auth/rate-limit";
const T0 = new Date("2026-01-01T00:00:00Z");
const at = (ms: number) => new Date(T0.getTime() + ms);
describe("RateLimiter (fenêtre glissante)", () => {
it("autorise jusqu'à maxHits puis bloque", () => {
const rl = new RateLimiter(3, 60_000);
expect(rl.hit("a", T0)).toBe(true);
expect(rl.hit("a", at(1000))).toBe(true);
expect(rl.hit("a", at(2000))).toBe(true);
expect(rl.hit("a", at(3000))).toBe(false);
});
it("les hits anciens sortent de la fenêtre", () => {
const rl = new RateLimiter(2, 60_000);
expect(rl.hit("a", T0)).toBe(true);
expect(rl.hit("a", at(30_000))).toBe(true);
expect(rl.hit("a", at(31_000))).toBe(false);
// Le hit de T0 a expiré de la fenêtre (60 s).
expect(rl.hit("a", at(61_001))).toBe(true);
});
it("reset vide la clé", () => {
const rl = new RateLimiter(1, 60_000);
expect(rl.hit("a", T0)).toBe(true);
expect(rl.hit("a", at(1000))).toBe(false);
rl.reset("a");
expect(rl.hit("a", at(2000))).toBe(true);
});
it("remaining reflète les tentatives restantes", () => {
const rl = new RateLimiter(2, 60_000);
expect(rl.remaining("a", T0)).toBe(2);
rl.hit("a", T0);
expect(rl.remaining("a", at(1000))).toBe(1);
});
it("les clés sont isolées", () => {
const rl = new RateLimiter(1, 60_000);
expect(rl.hit("a", T0)).toBe(true);
expect(rl.hit("b", T0)).toBe(true);
});
});