import { describe, it, expect } from 'vitest' import { createSlidingWindowLimiter } from '../src/security/rate-limit.js' describe('sliding-window rate limiter', () => { it('allows up to max, then blocks within the window', () => { let t = 0 const limiter = createSlidingWindowLimiter(3, 1000, () => t) expect(limiter.allow('ip')).toBe(true) expect(limiter.allow('ip')).toBe(true) expect(limiter.allow('ip')).toBe(true) expect(limiter.allow('ip')).toBe(false) }) it('does not record a rejected attempt (window frees up after it elapses)', () => { let t = 0 const limiter = createSlidingWindowLimiter(2, 1000, () => t) expect(limiter.allow('ip')).toBe(true) expect(limiter.allow('ip')).toBe(true) expect(limiter.allow('ip')).toBe(false) // blocked, NOT recorded t = 1001 // original two hits now outside the window expect(limiter.allow('ip')).toBe(true) expect(limiter.allow('ip')).toBe(true) }) it('tracks buckets independently per key', () => { let t = 0 const limiter = createSlidingWindowLimiter(1, 1000, () => t) expect(limiter.allow('a')).toBe(true) expect(limiter.allow('a')).toBe(false) expect(limiter.allow('b')).toBe(true) }) })