perf/test: Build-Coalescing teilen, syncLibrary drosseln, API-Tests
- coalesce.js: generisches Serialisieren+Koaleszieren je Key; buildSite() in hugo.js nutzt es → Publish/Preview/Profil starten nie überlappende Hugo- Prozesse, schnelle Folge-Aufrufe lösen nur einen Trailing-Build aus - dialog-store: syncLibrary() gedrosselt (60s-TTL) statt bei jedem Forum-Read Filesystem-Walk + Upsert; Publish forciert Sync (force:true) - test/: node:test-Suite (19 Tests) für safeRel/normAuthors/urlFor/hasAccess, roleOf + lokale JWT-Verifikation, Rate-Limiter, Coalescing; npm test Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
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
|
||||
});
|
||||
Reference in New Issue
Block a user