bba1df32cb
git-subtree-dir: cms/core git-subtree-split: 59b9e2075ac48cf017db38009d54dbe56a98fffc
45 lines
1.8 KiB
JavaScript
45 lines
1.8 KiB
JavaScript
import { test } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
|
|
const { rateLimit } = await import('../src/ratelimit.js');
|
|
|
|
function fakeCtx() {
|
|
const headers = {};
|
|
return {
|
|
req: { header: () => undefined },
|
|
header: (k, v) => { headers[k] = v; },
|
|
json: (body, status = 200) => ({ __status: status, body }),
|
|
_headers: headers,
|
|
};
|
|
}
|
|
|
|
test('rateLimit: blockt nach Überschreiten mit 429 + Retry-After', async () => {
|
|
const mw = rateLimit({ max: 2, windowMs: 10_000, keyFn: () => 'fix' });
|
|
let calls = 0;
|
|
const run = async () => { const c = fakeCtx(); const r = await mw(c, async () => { calls++; }); return { c, r }; };
|
|
|
|
assert.equal((await run()).r, undefined); // 1 → durch (next, kein Return)
|
|
assert.equal((await run()).r, undefined); // 2 → durch
|
|
const { c, r } = await run(); // 3 → blockiert
|
|
assert.equal(r.__status, 429);
|
|
assert.ok(c._headers['Retry-After']);
|
|
assert.equal(calls, 2); // next nur zweimal aufgerufen
|
|
});
|
|
|
|
test('rateLimit: getrennte Schlüssel zählen getrennt', async () => {
|
|
let key = 'a';
|
|
const mw = rateLimit({ max: 1, windowMs: 10_000, keyFn: () => key });
|
|
assert.equal((await mw(fakeCtx(), async () => {})), undefined); // a:1 ok
|
|
assert.equal((await mw(fakeCtx(), async () => {})).__status, 429); // a:2 blockiert
|
|
key = 'b';
|
|
assert.equal((await mw(fakeCtx(), async () => {})), undefined); // b:1 ok
|
|
});
|
|
|
|
test('rateLimit: Fenster läuft ab → wieder frei', async () => {
|
|
const mw = rateLimit({ max: 1, windowMs: 30, keyFn: () => 'win' });
|
|
assert.equal((await mw(fakeCtx(), async () => {})), undefined);
|
|
assert.equal((await mw(fakeCtx(), async () => {})).__status, 429);
|
|
await new Promise((r) => setTimeout(r, 40));
|
|
assert.equal((await mw(fakeCtx(), async () => {})), undefined); // Fenster neu
|
|
});
|