Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions tests/errors/appError.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ describe("Error classes", () => {
expect(err.message).toBe("already exists");
});

it("ConflictError usa mensagem default", () => {
const err = new ConflictError();

expect(err).toBeInstanceOf(AppError);
expect(err.statusCode).toBe(409);
expect(err.message).toBe("conflict");
});

it("UnauthorizedError usa status 401", () => {
const err = new UnauthorizedError();

Expand Down
41 changes: 41 additions & 0 deletions tests/middleware/rateLimiter.middleware.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,25 @@ describe("rateLimiter middleware", () => {
expect(err.code).toBe("TOO_MANY_REQUESTS");
});

it("resets memory bucket after window expiry", async () => {
process.env.REDIS_URL = "";
process.env.RATE_LIMIT_MAX_REQUESTS = "1";
process.env.RATE_LIMIT_WINDOW_MS = "1000";

const rateLimiter = loadRateLimiter();
const req = mockReq("10.10.0.22");
const next1 = mockNext();
const next2 = mockNext();

vi.spyOn(Date, "now").mockReturnValueOnce(0).mockReturnValueOnce(1001);

await rateLimiter(req, mockRes(), next1);
await rateLimiter(req, mockRes(), next2);

expect(next1).toHaveBeenCalledWith();
expect(next2).toHaveBeenCalledWith();
});

it("uses redis strategy and sets expiration on first hit", async () => {
process.env.REDIS_URL = originalRedisUrl || "redis://localhost:6379";

Expand Down Expand Up @@ -136,4 +155,26 @@ describe("rateLimiter middleware", () => {

expect(next).toHaveBeenCalledWith();
});

it("blocks when redis fails and memory fallback exceeds limit", async () => {
process.env.REDIS_URL = originalRedisUrl || "redis://localhost:6379";
process.env.RATE_LIMIT_MAX_REQUESTS = "1";

const rateLimiter = loadRateLimiter();
const { redisClient } = loadRedisConfig();
vi.spyOn(redisClient, "incr").mockRejectedValue(new Error("redis down"));

const req = mockReq("10.10.0.44");
const next1 = mockNext();
const next2 = mockNext();

await rateLimiter(req, mockRes(), next1);
await rateLimiter(req, mockRes(), next2);

const err = next2.mock.calls[0][0];
expect(err).toBeTruthy();
expect(err.message).toBe("too many requests");
expect(err.statusCode).toBe(429);
expect(err.code).toBe("TOO_MANY_REQUESTS");
});
});