(new): v1.2 release
Golang lint / lint (push) Successful in 11m32s

This commit is contained in:
2026-08-19 14:58:25 +03:00
parent f03a081ed6
commit 29b208eeec
79 changed files with 7301 additions and 2060 deletions
+80
View File
@@ -61,6 +61,86 @@ func TestRateLimiterGlobalWaitRespectsContextCancellation(t *testing.T) {
}
}
func TestRateLimiterWaitDoesNotConsumeGlobalCapacityWhileChatIsBlocked(t *testing.T) {
rl := NewRateLimiter()
rl.SetGlobalRate(1)
if !rl.Allow(42) {
t.Fatal("expected initial request for chat 42 to succeed")
}
rl.globalMu.Lock()
rl.globalLimiter = rate.NewLimiter(1, 1)
rl.globalMu.Unlock()
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
defer cancel()
if err := rl.Wait(ctx, 42); err == nil {
t.Fatal("expected blocked chat wait to fail")
}
if !rl.GlobalAllow() {
t.Fatal("blocked chat wait consumed global capacity")
}
}
func TestRateLimiterWaitObservesExtendedCooldowns(t *testing.T) {
tests := []struct {
name string
wait func(*RateLimiter, context.Context) error
set func(*RateLimiter, time.Time)
}{
{
name: "global",
wait: func(rl *RateLimiter, ctx context.Context) error {
return rl.waitForGlobalUnlock(ctx)
},
set: func(rl *RateLimiter, until time.Time) {
rl.globalMu.Lock()
rl.globalLockUntil = until
rl.globalMu.Unlock()
},
},
{
name: "chat",
wait: func(rl *RateLimiter, ctx context.Context) error {
return rl.waitForChatUnlock(ctx, 42)
},
set: func(rl *RateLimiter, until time.Time) {
rl.chatMu.Lock()
rl.chatLocks[42] = until
rl.chatMu.Unlock()
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
rl := NewRateLimiter()
tt.set(rl, time.Now().Add(20*time.Millisecond))
started := time.Now()
done := make(chan error, 1)
go func() { done <- tt.wait(rl, context.Background()) }()
time.Sleep(5 * time.Millisecond)
tt.set(rl, time.Now().Add(70*time.Millisecond))
if err := <-done; err != nil {
t.Fatalf("wait returned error: %v", err)
}
if elapsed := time.Since(started); elapsed < 60*time.Millisecond {
t.Fatalf("wait ignored extended cooldown: %v", elapsed)
}
})
}
}
func TestRateLimiterCleanupIgnoresNonPositiveThreshold(t *testing.T) {
rl := NewRateLimiter()
want := rl.getChatLimiter(42)
rl.Cleanup(0)
if got := rl.getChatLimiter(42); got != want {
t.Fatal("Cleanup(0) replaced an active limiter")
}
}
// TestRateLimiterCleanupEvictsIdleChats guards the memory-leak fix: per-chat
// limiter and lastSeen state must be reclaimed by Cleanup once the entry has
// been idle for longer than the threshold, while still-active chats and