import { describe, expect, it } from "@suaveplan/testing/runner"; import { FixedWindowOptionsSchema, MemoryStorageOptionsSchema, RateLimitConditionSchema, RateLimitConfigSchema, RateLimitContextSchema, RateLimiterOptionsSchema, RateLimitRuleSchema, SlidingWindowOptionsSchema, TokenBucketOptionsSchema, } from "./rate-limiter.schemas.js"; describe("RateLimitConfigSchema", () => { it("validates valid config", { timeout: 5000 }, () => { expect( RateLimitConfigSchema.safeParse({ limit: 100, window: 60_000 }) .success ).toBe(true); }); it("rejects missing limit", { timeout: 5000 }, () => { expect(RateLimitConfigSchema.safeParse({ window: 1000 }).success).toBe( false ); }); it("rejects non-integer limit", { timeout: 5000 }, () => { expect( RateLimitConfigSchema.safeParse({ limit: 1.5, window: 1000 }) .success ).toBe(false); }); it("accepts optional id and description", { timeout: 5000 }, () => { const r = RateLimitConfigSchema.safeParse({ limit: 10, window: 1000, id: "my-rule", description: "test", }); expect(r.success).toBe(true); }); }); describe("RateLimitConditionSchema", () => { it("validates eq condition", { timeout: 5000 }, () => { expect( RateLimitConditionSchema.safeParse({ field: "userId", operator: "eq", value: "admin", }).success ).toBe(true); }); it("rejects unknown operator", { timeout: 5000 }, () => { expect( RateLimitConditionSchema.safeParse({ field: "x", operator: "gt", value: 1, }).success ).toBe(false); }); it("accepts all operators", { timeout: 5000 }, () => { for (const op of ["eq", "neq", "in", "nin", "matches"]) { expect( RateLimitConditionSchema.safeParse({ field: "f", operator: op, value: "v", }).success ).toBe(true); } }); }); describe("RateLimitRuleSchema", () => { it("validates rule with bypass", { timeout: 5000 }, () => { const r = RateLimitRuleSchema.safeParse({ limit: 0, window: 1000, bypass: true, priority: 100, }); expect(r.success).toBe(true); }); it("validates rule with conditions", { timeout: 5000 }, () => { const r = RateLimitRuleSchema.safeParse({ limit: 5, window: 1000, conditions: [{ field: "ip", operator: "eq", value: "1.2.3.4" }], }); expect(r.success).toBe(true); }); }); describe("RateLimitContextSchema", () => { it("validates minimal context", { timeout: 5000 }, () => { expect( RateLimitContextSchema.safeParse({ key: "user:1" }).success ).toBe(true); }); it("rejects empty key", { timeout: 5000 }, () => { expect(RateLimitContextSchema.safeParse({ key: "" }).success).toBe( false ); }); it("validates full context", { timeout: 5000 }, () => { expect( RateLimitContextSchema.safeParse({ key: "k", tenantId: "acme", userId: "u1", ip: "1.1.1.1", path: "/api", method: "GET", metadata: { custom: 1 }, }).success ).toBe(true); }); }); describe("RateLimiterOptionsSchema", () => { it("validates minimal options", { timeout: 5000 }, () => { expect( RateLimiterOptionsSchema.safeParse({ defaultConfig: { limit: 10, window: 1000 }, }).success ).toBe(true); }); it("validates full options", { timeout: 5000 }, () => { expect( RateLimiterOptionsSchema.safeParse({ defaultConfig: { limit: 100, window: 60_000 }, rules: [], enableTenantLimits: true, tenantMultipliers: { enterprise: 5 }, keyPrefix: "rl", }).success ).toBe(true); }); }); describe("TokenBucketOptionsSchema", () => { it("validates valid options", { timeout: 5000 }, () => { expect( TokenBucketOptionsSchema.safeParse({ capacity: 100, refillRate: 0.1, }).success ).toBe(true); }); it("accepts initialTokens", { timeout: 5000 }, () => { expect( TokenBucketOptionsSchema.safeParse({ capacity: 100, refillRate: 0.1, initialTokens: 50, }).success ).toBe(true); }); it("rejects negative capacity", { timeout: 5000 }, () => { expect( TokenBucketOptionsSchema.safeParse({ capacity: -1, refillRate: 0.1, }).success ).toBe(false); }); }); describe("SlidingWindowOptionsSchema", () => { it("validates valid options", { timeout: 5000 }, () => { expect( SlidingWindowOptionsSchema.safeParse({ limit: 100, windowMs: 60_000, }).success ).toBe(true); }); }); describe("FixedWindowOptionsSchema", () => { it("validates valid options", { timeout: 5000 }, () => { expect( FixedWindowOptionsSchema.safeParse({ limit: 100, windowMs: 60_000, }).success ).toBe(true); }); }); describe("MemoryStorageOptionsSchema", () => { it("validates empty options", { timeout: 5000 }, () => { expect(MemoryStorageOptionsSchema.safeParse({}).success).toBe(true); }); it("validates maxSize", { timeout: 5000 }, () => { expect( MemoryStorageOptionsSchema.safeParse({ maxSize: 5000 }).success ).toBe(true); }); it("rejects non-positive maxSize", { timeout: 5000 }, () => { expect( MemoryStorageOptionsSchema.safeParse({ maxSize: 0 }).success ).toBe(false); }); });