- backend/explore/ratelimiter.go - backend/explore/cache.go - backend/database/sql/schemas/explore_cache.sql - backend/database/database.go
63 lines
1.2 KiB
Go
63 lines
1.2 KiB
Go
package explore
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestRateLimiterBurst(t *testing.T) {
|
|
rl := NewRateLimiter()
|
|
ctx := context.Background()
|
|
|
|
const n = 5
|
|
|
|
start := time.Now()
|
|
|
|
for i := range n {
|
|
if err := rl.Wait(ctx); err != nil {
|
|
t.Fatalf("Wait %d: %v", i, err)
|
|
}
|
|
}
|
|
|
|
elapsed := time.Since(start)
|
|
|
|
// First request is immediate; 4 more at 1/sec = ≥4s total.
|
|
if elapsed < 4*time.Second {
|
|
t.Errorf(
|
|
"elapsed %v, want ≥ 4s (rate limiter too fast)", elapsed,
|
|
)
|
|
}
|
|
|
|
// Generous upper bound to avoid CI flakes.
|
|
if elapsed > 7*time.Second {
|
|
t.Errorf(
|
|
"elapsed %v, want ≤ 7s (rate limiter too slow)", elapsed,
|
|
)
|
|
}
|
|
}
|
|
|
|
func TestRateLimiterContextCancel(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
rl := NewRateLimiter()
|
|
|
|
// Drain the initial token so the next Wait must block.
|
|
if err := rl.Wait(context.Background()); err != nil {
|
|
t.Fatalf("drain token: %v", err)
|
|
}
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
cancel() // cancel immediately
|
|
|
|
err := rl.Wait(ctx)
|
|
if err == nil {
|
|
t.Fatal("expected error from cancelled context, got nil")
|
|
}
|
|
|
|
if !errors.Is(err, context.Canceled) {
|
|
t.Errorf("error = %v, want context.Canceled", err)
|
|
}
|
|
}
|