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
 | |
|   });
 | |
| });
 |