fix: 加固聊天限流与安全策略串行化
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { RedisService } from "../redis/redis.service.js";
|
||||
import { ChatRateLimiter } from "./chat-rate-limiter.js";
|
||||
|
||||
type FakeRedisClient = {
|
||||
isReady: boolean;
|
||||
isOpen: boolean;
|
||||
on: ReturnType<typeof vi.fn>;
|
||||
connect: ReturnType<typeof vi.fn>;
|
||||
eval: ReturnType<typeof vi.fn>;
|
||||
destroy: ReturnType<typeof vi.fn>;
|
||||
quit: ReturnType<typeof vi.fn>;
|
||||
};
|
||||
|
||||
function fakeClient(evalResult: Promise<unknown>): FakeRedisClient {
|
||||
return {
|
||||
isReady: true,
|
||||
isOpen: true,
|
||||
on: vi.fn(),
|
||||
connect: vi.fn(() => Promise.resolve()),
|
||||
eval: vi.fn(() => evalResult),
|
||||
destroy: vi.fn(),
|
||||
quit: vi.fn(() => Promise.resolve()),
|
||||
};
|
||||
}
|
||||
|
||||
describe("ChatRateLimiter Redis command deadline", () => {
|
||||
const previousTimeout = process.env.REDIS_OPERATION_TIMEOUT_MS;
|
||||
|
||||
afterEach(() => {
|
||||
if (previousTimeout === undefined)
|
||||
delete process.env.REDIS_OPERATION_TIMEOUT_MS;
|
||||
else process.env.REDIS_OPERATION_TIMEOUT_MS = previousTimeout;
|
||||
});
|
||||
|
||||
it("destroys a client whose eval never settles and recovers with a new client", async () => {
|
||||
process.env.REDIS_OPERATION_TIMEOUT_MS = "20";
|
||||
const stuck = fakeClient(new Promise(() => undefined));
|
||||
const healthy = fakeClient(Promise.resolve(1));
|
||||
const factory = vi
|
||||
.fn()
|
||||
.mockReturnValueOnce(stuck)
|
||||
.mockReturnValueOnce(healthy);
|
||||
const redis = new RedisService(factory as never);
|
||||
const limiter = new ChatRateLimiter(redis);
|
||||
|
||||
await expect(limiter.consume("account", "session")).rejects.toThrow(
|
||||
"Auth Redis operation timed out",
|
||||
);
|
||||
expect(stuck.destroy).toHaveBeenCalledOnce();
|
||||
|
||||
await expect(limiter.consume("account", "session")).resolves.toBe(true);
|
||||
expect(healthy.eval).toHaveBeenCalledOnce();
|
||||
expect(factory).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user