Files
NixMsg/internal/auth/locks_test.go
T

61 lines
1.6 KiB
Go

package auth
import (
"fmt"
"testing"
"time"
)
func TestLoginLocksSweepExpiredKeepsLocked(t *testing.T) {
locks := NewLoginLocks()
now := time.Date(2026, 9, 30, 12, 0, 0, 0, time.UTC)
locks.SetClock(func() time.Time { return now })
for i := 0; i < 10000; i++ {
if locked, _ := locks.Fail(LockKey{Kind: LockRegisterIP, IP: fmt.Sprintf("2001:db8::%d", i)}); locked {
t.Fatalf("unexpected lock at i=%d", i)
}
}
if n := locks.entryCount(); n < 10000 {
t.Fatalf("want 10000 entries before sweep, got %d", n)
}
now = now.Add(4 * time.Minute)
keep := LockKey{Kind: LockRegisterIP, IP: "keep-locked"}
for i := 0; i < 10; i++ {
locks.Fail(keep)
}
if locked, _ := locks.Check(keep); !locked {
t.Fatal("keep-locked should be locked")
}
now = now.Add(2 * time.Minute) // 10k 已过 5 分钟窗口;keep 仍锁定至 +5min
if locked, _ := locks.Check(LockKey{Kind: LockRegisterIP, IP: "trigger-sweep"}); locked {
t.Fatal("trigger must not lock")
}
if n := locks.entryCount(); n != 1 {
t.Fatalf("want only locked entry after sweep, got %d", n)
}
if locked, _ := locks.Check(keep); !locked {
t.Fatal("locked entry must remain")
}
}
func TestLoginLocksCapDoesNotGrow(t *testing.T) {
locks := NewLoginLocks()
locks.maxEntries = 64
now := time.Date(2026, 9, 30, 15, 0, 0, 0, time.UTC)
locks.SetClock(func() time.Time { return now })
for i := 0; i < 200; i++ {
locks.Fail(LockKey{Kind: LockRegisterIP, IP: fmt.Sprintf("ip-%d", i)})
now = now.Add(time.Millisecond)
if n := locks.entryCount(); n > 64 {
t.Fatalf("entries=%d exceeded cap at i=%d", n, i)
}
}
if n := locks.entryCount(); n != 64 {
t.Fatalf("entries=%d want 64", n)
}
}