package rate import ( "context" "fmt" "net/http" "testing" "time" ) // https://github.com/bwmarrin/discordgo/blob/master/ratelimit_test.go func mockRequest(t *testing.T, l *Limiter, path string, headers http.Header) { if err := l.Acquire(context.Background(), path); err != nil { t.Fatal("Failed to acquire lock:", err) } if err := l.Release(path, headers); err != nil { t.Fatal("Failed to release lock:", err) } } // This test takes ~2 seconds to run func TestRatelimitReset(t *testing.T) { l := NewLimiter("") const msToSec = time.Second / time.Millisecond until := time.Now().Add(2 * time.Second) reset := float64(until.UnixNano()/int64(time.Millisecond)) / float64(msToSec) headers := http.Header{} headers.Set("X-RateLimit-Remaining", "0") headers.Set("X-RateLimit-Reset", fmt.Sprintf("%.3f", reset)) headers.Set("Date", time.Now().Format(time.RFC850)) sent := time.Now() mockRequest(t, l, "/guilds/99/channels", headers) mockRequest(t, l, "/guilds/55/channels", headers) mockRequest(t, l, "/guilds/66/channels", headers) // call it again mockRequest(t, l, "/guilds/99/channels", headers) mockRequest(t, l, "/guilds/55/channels", headers) mockRequest(t, l, "/guilds/66/channels", headers) // We hit the same endpoint 2 times, so we should only be ratelimited 2 // second and always less than 4 seconds (unless you're on a stoneage // computer or using swap or something...) if since := time.Since(sent); since >= time.Second && since < time.Second*4 { t.Log("OK", since) } else { t.Error("did not ratelimit correctly, got:", since) } } // This test takes ~1 seconds to run func TestRatelimitGlobal(t *testing.T) { l := NewLimiter("") headers := http.Header{} headers.Set("X-RateLimit-Global", "1.002") // Reset for approx 1 seconds from now headers.Set("Retry-After", "1") sent := time.Now() // This should trigger a global ratelimit mockRequest(t, l, "/guilds/99/channels", headers) time.Sleep(time.Millisecond * 100) // This shouldn't go through in less than 1 second mockRequest(t, l, "/guilds/55/channels", headers) if time.Since(sent) >= time.Second && time.Since(sent) < time.Second*2 { t.Log("OK", time.Since(sent)) } else { t.Error("did not ratelimit correctly, got:", time.Since(sent)) } }