package auth import ( "errors" "testing" "time" "github.com/wormhole/wormhole/internal/config" ) func TestLoginLimiterBlocksAfterMaxAttempts(t *testing.T) { l := NewLoginLimiter(&config.AuthConfig{ LoginMaxAttempts: 3, LoginWindow: time.Minute, LoginLockout: 10 * time.Minute, }) ip := "192.168.1.1" user := "admin" for i := 0; i < 3; i++ { if _, blocked := l.IsBlocked(ip, user); blocked { t.Fatalf("unexpected block at attempt %d", i+1) } l.RecordFailure(ip, user) } retry, blocked := l.IsBlocked(ip, user) if !blocked || retry <= 0 { t.Fatalf("expected block after max attempts, retry=%v blocked=%v", retry, blocked) } } func TestLoginLimiterResetClearsBlock(t *testing.T) { l := NewLoginLimiter(&config.AuthConfig{ LoginMaxAttempts: 2, LoginWindow: time.Minute, LoginLockout: time.Minute, }) ip := "10.0.0.1" l.RecordFailure(ip, "u1") l.RecordFailure(ip, "u1") if _, blocked := l.IsBlocked(ip, "u1"); !blocked { t.Fatal("expected blocked") } l.Reset(ip, "u1") if _, blocked := l.IsBlocked(ip, "u1"); blocked { t.Fatal("expected unblocked after reset") } } func TestLoginBlockedError(t *testing.T) { err := &LoginBlockedError{RetryAfter: 30 * time.Second} if !errors.As(err, new(*LoginBlockedError)) { t.Fatal("LoginBlockedError should be detectable via errors.As") } }