Files
HiveGrid-Wireframes/03 Quellen und Referenzen/hivegrid-cloud/apps/web/app/utils/services/rateLimitService.test.ts
T

50 lines
1.8 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { createSharedStore, MemoryAdapter } from "@hivegrid/shared-store";
import { __resetRateLimitStoreForTests, __setRateLimitStoreForTests, rateLimitByKey } from "./rateLimitService";
const input = {
apiKey: "api-key-1",
tenantId: "tenant-1",
tenantSubscription: null,
limitByMinute: 2,
limitBySecond: 100,
};
describe("legacy API shared rate limit", () => {
beforeEach(() => {
__setRateLimitStoreForTests(createSharedStore({ namespace: "legacy-api-rate-test", adapter: new MemoryAdapter() }));
});
afterEach(() => {
__resetRateLimitStoreForTests();
});
it("enforces one counter shared by every caller instead of a process-local LRU", async () => {
await expect(rateLimitByKey(input)).resolves.toEqual({ success: true, error: null });
await expect(rateLimitByKey(input)).resolves.toEqual({ success: true, error: null });
await expect(rateLimitByKey(input)).resolves.toMatchObject({
success: false,
error: expect.stringContaining("2 request/min"),
});
});
it("atomically caps a parallel burst", async () => {
const results = await Promise.all(Array.from({ length: 20 }, () => rateLimitByKey({ ...input, apiKey: "parallel-key", limitByMinute: 5 })));
expect(results.filter((result) => result.success)).toHaveLength(5);
expect(results.filter((result) => !result.success)).toHaveLength(15);
});
it("fails closed when the shared counter is unavailable", async () => {
const adapter = new MemoryAdapter();
await adapter.close();
__setRateLimitStoreForTests(createSharedStore({ namespace: "legacy-api-rate-closed", adapter }));
await expect(rateLimitByKey(input)).resolves.toEqual({
success: false,
error: "Rate limit service temporarily unavailable",
});
});
});