Files
world-zap/ratelimit/ratelimit_test.go
zeekay dbc63e80a9 feat: initial world-zap ZAP gateway
Real-time Hanzo World feeds over ZAP binary protocol (9-byte header +
JSON payload) fronted by WebSockets at wss://zap.world.hanzo.ai/zap.

IAM bearer auth via Authorization header or ?token= query param.
Validator caches /oauth/userinfo for 5 minutes.

Topics (10): world.events.{all,conflicts,earthquakes,fires},
world.markets.{quotes,crypto}, world.ships.ais, world.aviation.opensky,
world.news.live, world.weather.alerts. Minimum plan enforced per topic.

Tools: subscribe, unsubscribe, list_topics. Admin-only publish for
internal service accounts.

Ingest: streams events from worldmonitor GET /v1/world/events?stream=1,
fans out via bounded-channel hub with drop-on-overflow semantics.

Per-user token bucket rate limits: free 30/min, pro 3000/min, team
15000/min, enterprise 60000/min.

Tests: all packages pass -race (proto, auth, hub, ratelimit, ingest,
handlers). Multi-arch image build wired to hanzoai/.github docker-build
workflow.
2026-04-18 12:07:47 -07:00

68 lines
1.3 KiB
Go

package ratelimit
import (
"testing"
)
func TestPlanCapacity(t *testing.T) {
cases := map[string]int{
"free": 30,
"pro": 3000,
"team": 15000,
"enterprise": 60000,
"": 30,
"unknown": 30,
}
for plan, want := range cases {
if got := PlanCapacity(plan); got != want {
t.Errorf("plan %q: got %d want %d", plan, got, want)
}
}
}
func TestFreeBurstThenBlock(t *testing.T) {
l := New()
for i := 0; i < 30; i++ {
d := l.TryAcquire("u", "free")
if !d.Allowed {
t.Fatalf("request %d denied: %+v", i, d)
}
}
d := l.TryAcquire("u", "free")
if d.Allowed {
t.Fatalf("31st request should be denied")
}
if d.RetryIn <= 0 {
t.Fatalf("expected retry hint")
}
}
func TestPerUserIsolation(t *testing.T) {
l := New()
for i := 0; i < 30; i++ {
l.TryAcquire("a", "free")
}
if l.TryAcquire("a", "free").Allowed {
t.Fatalf("a should be throttled")
}
if !l.TryAcquire("b", "free").Allowed {
t.Fatalf("b should be allowed")
}
}
func TestPlanUpgradeResetsBucket(t *testing.T) {
l := New()
// burn free tokens
for i := 0; i < 30; i++ {
l.TryAcquire("u", "free")
}
if l.TryAcquire("u", "free").Allowed {
t.Fatalf("free should be empty")
}
// Upgrade to pro; new bucket at pro capacity
d := l.TryAcquire("u", "pro")
if !d.Allowed {
t.Fatalf("pro upgrade should grant tokens: %+v", d)
}
}