package infra import ( "testing" "time" ) func TestRateLimiterCleanup(t *testing.T) { t.Run("purga entries con lastSeen mas antiguo que maxAge", func(t *testing.T) { rl := RateLimiterNew(10, 20) // Inyectar manualmente una entry vieja rl.mu.Lock() rl.clients["old"] = &rateLimiterClient{tokens: 5, lastSeen: time.Now().Add(-time.Hour)} rl.clients["new"] = &rateLimiterClient{tokens: 5, lastSeen: time.Now()} rl.mu.Unlock() stop := RateLimiterCleanup(rl, 10*time.Minute, 30*time.Millisecond) defer stop() // Esperar al menos un tick time.Sleep(100 * time.Millisecond) rl.mu.Lock() _, oldExists := rl.clients["old"] _, newExists := rl.clients["new"] rl.mu.Unlock() if oldExists { t.Error("entry 'old' no fue purgada") } if !newExists { t.Error("entry 'new' fue purgada incorrectamente") } }) t.Run("no purga entries recientes", func(t *testing.T) { rl := RateLimiterNew(10, 20) RateLimiterCheck(rl, "fresh") stop := RateLimiterCleanup(rl, 10*time.Minute, 30*time.Millisecond) defer stop() time.Sleep(100 * time.Millisecond) rl.mu.Lock() _, exists := rl.clients["fresh"] rl.mu.Unlock() if !exists { t.Error("entry reciente fue purgada incorrectamente") } }) t.Run("stop detiene la goroutine sin panic", func(t *testing.T) { rl := RateLimiterNew(10, 20) stop := RateLimiterCleanup(rl, time.Second, 10*time.Millisecond) stop() // Si esto no panica, pasa time.Sleep(50 * time.Millisecond) }) t.Run("stop es idempotente", func(t *testing.T) { rl := RateLimiterNew(10, 20) stop := RateLimiterCleanup(rl, time.Second, 10*time.Millisecond) stop() stop() // segunda llamada no debe panic stop() // tercera tampoco }) }