You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
58 lines
1.9 KiB
TypeScript
58 lines
1.9 KiB
TypeScript
import { describe, it, expect, beforeEach } from 'bun:test';
|
|
import { RateLimiter } from '../../../src/services/rate-limit';
|
|
|
|
describe('RateLimiter - token bucket básico', () => {
|
|
beforeEach(() => {
|
|
RateLimiter.reset();
|
|
// No dependemos de NODE_ENV aquí; testea la clase aislada.
|
|
process.env.RATE_LIMIT_PER_MIN = '15';
|
|
process.env.RATE_LIMIT_BURST = '15';
|
|
});
|
|
|
|
it('permite hasta el burst inicial y bloquea al exceder', () => {
|
|
const user = '1234567890';
|
|
const t0 = 0;
|
|
|
|
// 15 primeros deben pasar
|
|
for (let i = 0; i < 15; i++) {
|
|
const ok = RateLimiter.checkAndConsume(user, t0);
|
|
expect(ok).toBe(true);
|
|
}
|
|
|
|
// 16º sin tiempo transcurrido debe bloquear
|
|
const denied = RateLimiter.checkAndConsume(user, t0);
|
|
expect(denied).toBe(false);
|
|
});
|
|
|
|
it('recupera tokens con el tiempo (refill lineal por minuto)', () => {
|
|
const user = '1234567890';
|
|
const t0 = 0;
|
|
|
|
// Agotar bucket
|
|
for (let i = 0; i < 15; i++) {
|
|
expect(RateLimiter.checkAndConsume(user, t0)).toBe(true);
|
|
}
|
|
expect(RateLimiter.checkAndConsume(user, t0)).toBe(false); // agotado
|
|
|
|
// Tras 60s debe haberse recuperado capacidad suficiente para permitir de nuevo
|
|
const t1 = 60_000;
|
|
expect(RateLimiter.checkAndConsume(user, t1)).toBe(true);
|
|
|
|
// Y puede consumir varios más (hasta ~15 por minuto)
|
|
let count = 1;
|
|
while (RateLimiter.checkAndConsume(user, t1)) {
|
|
count++;
|
|
if (count > 20) break; // seguridad
|
|
}
|
|
expect(count).toBeGreaterThan(1);
|
|
});
|
|
|
|
it('shouldNotify limita el aviso a como mucho 1/min por usuario', () => {
|
|
const user = 'u1';
|
|
const t0 = 0;
|
|
expect(RateLimiter.shouldNotify(user, t0)).toBe(true); // primera vez notifica
|
|
expect(RateLimiter.shouldNotify(user, t0 + 10_000)).toBe(false); // dentro de la ventana
|
|
expect(RateLimiter.shouldNotify(user, t0 + 60_000)).toBe(true); // pasado el cooldown
|
|
});
|
|
});
|