import { describe, it, expect, beforeEach, vi } from "vitest"; import { ExecutionContext } from "@nestjs/common"; import { ThrottlerException, ThrottlerModuleOptions, ThrottlerStorage } from "@nestjs/throttler"; import { Reflector } from "@nestjs/core"; import { OrchestratorThrottlerGuard } from "./throttler.guard"; describe("OrchestratorThrottlerGuard", () => { let guard: OrchestratorThrottlerGuard; beforeEach(() => { // Create guard with minimal mocks for testing protected methods const options: ThrottlerModuleOptions = { throttlers: [{ name: "default", ttl: 60000, limit: 100 }], }; const storageService = {} as ThrottlerStorage; const reflector = {} as Reflector; guard = new OrchestratorThrottlerGuard(options, storageService, reflector); }); describe("getTracker", () => { it("should extract IP from X-Forwarded-For header", async () => { const req = { headers: { "x-forwarded-for": "192.168.1.1, 10.0.0.1", }, ip: "127.0.0.1", }; // Access protected method for testing const tracker = await ( guard as unknown as { getTracker: (req: unknown) => Promise } ).getTracker(req); expect(tracker).toBe("192.168.1.1"); }); it("should handle X-Forwarded-For as array", async () => { const req = { headers: { "x-forwarded-for": ["192.168.1.1, 10.0.0.1"], }, ip: "127.0.0.1", }; const tracker = await ( guard as unknown as { getTracker: (req: unknown) => Promise } ).getTracker(req); expect(tracker).toBe("192.168.1.1"); }); it("should fallback to request IP when no X-Forwarded-For", async () => { const req = { headers: {}, ip: "192.168.2.2", }; const tracker = await ( guard as unknown as { getTracker: (req: unknown) => Promise } ).getTracker(req); expect(tracker).toBe("192.168.2.2"); }); it("should fallback to connection remoteAddress when no IP", async () => { const req = { headers: {}, connection: { remoteAddress: "192.168.3.3", }, }; const tracker = await ( guard as unknown as { getTracker: (req: unknown) => Promise } ).getTracker(req); expect(tracker).toBe("192.168.3.3"); }); it("should return 'unknown' when no IP available", async () => { const req = { headers: {}, }; const tracker = await ( guard as unknown as { getTracker: (req: unknown) => Promise } ).getTracker(req); expect(tracker).toBe("unknown"); }); }); describe("throwThrottlingException", () => { it("should throw ThrottlerException with endpoint info", () => { const mockRequest = { url: "/agents/spawn", }; const mockContext = { switchToHttp: vi.fn().mockReturnValue({ getRequest: vi.fn().mockReturnValue(mockRequest), }), } as unknown as ExecutionContext; expect(() => { ( guard as unknown as { throwThrottlingException: (context: ExecutionContext) => void } ).throwThrottlingException(mockContext); }).toThrow(ThrottlerException); try { ( guard as unknown as { throwThrottlingException: (context: ExecutionContext) => void } ).throwThrottlingException(mockContext); } catch (error) { expect(error).toBeInstanceOf(ThrottlerException); expect((error as ThrottlerException).message).toContain("/agents/spawn"); } }); }); });