feat(infra): rate limit middlewares HTTP por IP y por key + tests
Implementa fase 2 del issue 0016: - rate_limit_middleware: limita por IP (X-Forwarded-For > X-Real-IP > RemoteAddr) - rate_limiter_by_key: middleware configurable con keyFunc custom (API key, user ID...) - Cuando se rechaza responde 429 con HTTPError JSON y headers Retry-After + X-RateLimit-* - Tests con httptest.NewRecorder cubriendo: limite, burst, IPs independientes, XFF prioritario, recarga temporal, JSON body, headers IETF, GC stop idempotente, key vacia salta limit
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
package infra
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestRateLimiterNew(t *testing.T) {
|
||||
t.Run("crea limiter con rate y burst configurados", func(t *testing.T) {
|
||||
rl := RateLimiterNew(10, 20)
|
||||
if rl == nil {
|
||||
t.Fatal("RateLimiterNew retorno nil")
|
||||
}
|
||||
if rl.rate != 10 {
|
||||
t.Errorf("rate=%v, want 10", rl.rate)
|
||||
}
|
||||
if rl.burst != 20 {
|
||||
t.Errorf("burst=%d, want 20", rl.burst)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("valores cero se sustituyen por 1", func(t *testing.T) {
|
||||
rl := RateLimiterNew(0, 0)
|
||||
if rl.rate != 1 {
|
||||
t.Errorf("rate=%v, want 1 (default)", rl.rate)
|
||||
}
|
||||
if rl.burst != 1 {
|
||||
t.Errorf("burst=%d, want 1 (default)", rl.burst)
|
||||
}
|
||||
|
||||
rl2 := RateLimiterNew(-5, -10)
|
||||
if rl2.rate != 1 || rl2.burst != 1 {
|
||||
t.Errorf("valores negativos no se normalizaron a 1: rate=%v burst=%d", rl2.rate, rl2.burst)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("el mapa de clientes empieza vacio", func(t *testing.T) {
|
||||
rl := RateLimiterNew(10, 20)
|
||||
if rl.clients == nil {
|
||||
t.Error("clients map es nil, deberia ser inicializado")
|
||||
}
|
||||
if len(rl.clients) != 0 {
|
||||
t.Errorf("clients len=%d, want 0", len(rl.clients))
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user