| 1 | package relay |
| 2 | |
| 3 | import ( |
| 4 | "testing" |
| 5 | "time" |
| 6 | ) |
| 7 | |
| 8 | func TestAdmissionCaps(t *testing.T) { |
| 9 | now := time.Unix(1_800_000_000, 0) |
| 10 | clock := func() time.Time { return now } |
| 11 | l := DefaultLimits() |
| 12 | l.AppLive, l.AppPerMinute, l.AccountLive, l.BoxLive = 2, 100, 3, 100 |
| 13 | a := NewAdmission(l, clock) |
| 14 | meet := Identity{"abc", "meet"} |
| 15 | docs := Identity{"abc", "docs"} |
| 16 | for i := 0; i < 2; i++ { |
| 17 | if ok, r := a.Admit(meet); !ok { |
| 18 | t.Fatalf("admit %d refused: %s", i, r) |
| 19 | } |
| 20 | } |
| 21 | if ok, r := a.Admit(meet); ok || r != "app live" { |
| 22 | t.Fatalf("third meet = %v %q", ok, r) |
| 23 | } |
| 24 | if ok, _ := a.Admit(docs); !ok { |
| 25 | t.Fatal("docs first should pass") |
| 26 | } |
| 27 | if ok, r := a.Admit(docs); ok || r != "account live" { |
| 28 | t.Fatalf("account cap = %v %q", ok, r) |
| 29 | } |
| 30 | a.Release(meet) |
| 31 | if ok, _ := a.Admit(docs); !ok { |
| 32 | t.Fatal("after release, account has room") |
| 33 | } |
| 34 | } |
| 35 | |
| 36 | func TestAdmissionRate(t *testing.T) { |
| 37 | now := time.Unix(1_800_000_000, 0) |
| 38 | clock := func() time.Time { return now } |
| 39 | l := DefaultLimits() |
| 40 | l.AppPerMinute = 2 |
| 41 | a := NewAdmission(l, clock) |
| 42 | id := Identity{"abc", "meet"} |
| 43 | a.Admit(id) |
| 44 | a.Release(id) |
| 45 | a.Admit(id) |
| 46 | a.Release(id) |
| 47 | if ok, r := a.Admit(id); ok || r != "app rate" { |
| 48 | t.Fatalf("rate = %v %q", ok, r) |
| 49 | } |
| 50 | now = now.Add(61 * time.Second) |
| 51 | if ok, _ := a.Admit(id); !ok { |
| 52 | t.Fatal("rate window should have rolled") |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | func TestAdmissionBudgetRollsAndSeeds(t *testing.T) { |
| 57 | now := time.Unix(1_800_000_000, 0) |
| 58 | clock := func() time.Time { return now } |
| 59 | l := DefaultLimits() |
| 60 | l.AppBytesPerHour = 100 |
| 61 | a := NewAdmission(l, clock) |
| 62 | id := Identity{"abc", "meet"} |
| 63 | if a.AddBytes(id, 60) { |
| 64 | t.Fatal("60 under 100") |
| 65 | } |
| 66 | if !a.AddBytes(id, 50) { |
| 67 | t.Fatal("110 over 100") |
| 68 | } |
| 69 | now = now.Add(61 * time.Minute) |
| 70 | if a.OverBudget(id, now) { |
| 71 | t.Fatal("window rolled") |
| 72 | } |
| 73 | b := NewAdmission(l, clock) |
| 74 | b.Seed(id, now.Add(-30*time.Minute), 90) |
| 75 | if !b.AddBytes(id, 20) { |
| 76 | t.Fatal("seeded 90 + 20 over 100") |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | func TestBucket(t *testing.T) { |
| 81 | now := time.Unix(1_800_000_000, 0) |
| 82 | clock := func() time.Time { return now } |
| 83 | b := NewBucket(8000, clock) // 1000 bytes/s |
| 84 | if !b.Allow(1000) { |
| 85 | t.Fatal("first second's worth") |
| 86 | } |
| 87 | if b.Allow(1) { |
| 88 | t.Fatal("empty") |
| 89 | } |
| 90 | now = now.Add(500 * time.Millisecond) |
| 91 | if !b.Allow(500) || b.Allow(1) { |
| 92 | t.Fatal("refilled 500") |
| 93 | } |
| 94 | } |
| 95 | |