Files
Jyotisha/frontend/tests/request-rate-limit.test.ts
T
jesse-uxandGrok (agent loop) 4c3485bc23 服务器长跑不再堆积取消监听,数据库少走几趟。
报告工人的等待到点就摘掉取消监听。本地数据库缓存表结构,并把设置身份合成一条语句,对照通过后默认打开,写成 off 仍走原来的语句。交付、重算和限流的内存表会过期。登录读缓存默认关闭,要开再设 IDENTITY_SESSION_COOKIE_CACHE=on。

自测:tsc 通过,lint 0 error,点名测试 134 通过,test:db 开关关和开都只有已知的 13 条失败,往返 49 降到 32。

Co-Authored-By: Grok (agent loop)
2026-10-14 03:32:39 +08:00

113 lines
2.7 KiB
TypeScript

import assert from "node:assert/strict";
import test from "node:test";
import {
consumeRequestRateLimit,
resetRequestRateLimitMaintenanceForTests,
} from "../src/lib/request-rate-limit.ts";
test("a user is allowed up to the window limit and then must wait", () => {
const store = new Map<string, number[]>();
const first = consumeRequestRateLimit({
key: "search:user-1",
limit: 2,
windowMs: 60_000,
now: 1_000,
store,
});
const second = consumeRequestRateLimit({
key: "search:user-1",
limit: 2,
windowMs: 60_000,
now: 2_000,
store,
});
const blocked = consumeRequestRateLimit({
key: "search:user-1",
limit: 2,
windowMs: 60_000,
now: 3_000,
store,
});
const otherUser = consumeRequestRateLimit({
key: "search:user-2",
limit: 2,
windowMs: 60_000,
now: 3_000,
store,
});
const afterWindow = consumeRequestRateLimit({
key: "search:user-1",
limit: 2,
windowMs: 60_000,
now: 61_500,
store,
});
assert.deepEqual(first, { ok: true });
assert.deepEqual(second, { ok: true });
assert.deepEqual(blocked, { ok: false, retryAfterSeconds: 58 });
assert.deepEqual(otherUser, { ok: true });
assert.deepEqual(afterWindow, { ok: true });
});
test("keys past the longest seen window are swept, and a one-hour key survives 61 seconds", () => {
resetRequestRateLimitMaintenanceForTests();
const shortWindow = new Map<string, number[]>();
consumeRequestRateLimit({
key: "old",
limit: 5,
windowMs: 60_000,
now: 0,
store: shortWindow,
});
for (let index = 0; index < 998; index += 1) {
consumeRequestRateLimit({
key: `pad:${index}`,
limit: 5,
windowMs: 60_000,
now: 0,
store: shortWindow,
});
}
consumeRequestRateLimit({
key: "trigger",
limit: 5,
windowMs: 60_000,
now: 61_000,
store: shortWindow,
});
assert.equal(shortWindow.has("old"), false);
assert.equal(shortWindow.get("old"), undefined);
assert.equal(shortWindow.has("trigger"), true);
assert.equal(shortWindow.size, 1);
resetRequestRateLimitMaintenanceForTests();
const mixed = new Map<string, number[]>();
consumeRequestRateLimit({
key: "synastry:person",
limit: 8,
windowMs: 60 * 60_000,
now: 0,
store: mixed,
});
consumeRequestRateLimit({
key: "ephemeris:person",
limit: 30,
windowMs: 60_000,
now: 0,
store: mixed,
});
for (let index = 0; index < 998; index += 1) {
consumeRequestRateLimit({
key: `later:${index}`,
limit: 5,
windowMs: 60_000,
now: 61_000,
store: mixed,
});
}
assert.equal(mixed.has("synastry:person"), true);
assert.equal(mixed.has("ephemeris:person"), true);
resetRequestRateLimitMaintenanceForTests();
});