package ratelimit import ( "testing" "time" ) func TestAllowRequestDaily(t *testing.T) { l := New() if !l.AllowRequestDaily(1, 2) { t.Fatal("first request should be allowed") } if !l.AllowRequestDaily(1, 2) { t.Fatal("second request should be allowed") } if l.AllowRequestDaily(1, 2) { t.Fatal("third request should be blocked") } // 另一个 key 不受影响 if !l.AllowRequestDaily(2, 2) { t.Fatal("other key should be allowed") } } func TestTokensDaily(t *testing.T) { l := New() l.AddTokens(1, 100) l.AddTokens(1, 50) if got := l.TokensUsed(1); got != 150 { t.Fatalf("tokens = %d, want 150", got) } if got := l.TokensUsed(2); got != 0 { t.Fatalf("other key tokens = %d, want 0", got) } // 配额检查语义:已达 150 再设配额 150 应拒绝 l.AddTokens(3, 150) if l.TokensUsed(3) >= 150 { // 注意:>= 表示已达上限,Auth 层据此拒绝 } } func TestAllowUserRate(t *testing.T) { l := New() // limit=1:立即第二次应被拒绝 if !l.AllowUserRate(9, 1) { t.Fatal("first should be allowed") } if l.AllowUserRate(9, 1) { t.Fatal("second in same second should be blocked") } // limit<=0 不限制 if !l.AllowUserRate(9, 0) { t.Fatal("limit 0 should always allow") } } // 超过阈值时清扫:旧日期的日计数条目和窗口内无命中的用户条目被回收。 func TestSweepRemovesStaleEntries(t *testing.T) { l := New() l.AllowRequestDaily(1, 0) l.AddTokens(1, 100) l.AllowUserRate(2, 5) // 人为把日计数条目改成"昨天",模拟跨天后的陈旧条目 l.mu.Lock() for _, c := range l.reqDaily { c.date = "2000-01-01" } for _, c := range l.tokDaily { c.date = "2000-01-01" } // 用户速率条目:命中时间回溯到窗口外,模拟久未活动的用户 if w, ok := l.userHits[2]; ok { w.times = []time.Time{time.Now().Add(-time.Hour)} } l.mu.Unlock() for i := 0; i < dailySweepThreshold+1; i++ { l.AllowRequestDaily(uint64(100+i), 0) } l.mu.Lock() _, reqStale := l.reqDaily[1] _, tokStale := l.tokDaily[1] _, userStale := l.userHits[2] l.mu.Unlock() if reqStale || tokStale { t.Error("陈旧的日计数条目应被清扫") } if userStale { t.Error("无命中的用户速率条目应被清扫") } }