This repository has been archived by the owner on Mar 5, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 22
/
ratelimit_test.go
96 lines (80 loc) · 2.35 KB
/
ratelimit_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package main
import (
"io"
"io/ioutil"
"sync"
"testing"
"time"
"github.com/juju/ratelimit"
"github.com/stretchr/testify/assert"
)
// Test juju/ratelimit in a way similar to how we use it in our code base.
// The juju/ratelimit API we use here doesn't allow us to control the token bucket precisely.
// We cannot set the initial token bucket size and neither can we control how frequently
// it refills the token bucket. So we have to assume: 1) it sets the initial token bucket
// size to its capacity; 2) it refills the token bucket frequently enough.
const size = 1 * 1024 * 1024 // 1 MB
const rate = 4 * 1024 * 1024 // 4 MB/s
const delta = 0.15
// Set this to a small number but not too small.
// If we set this too big, the initial token bucket size may affect our measurement
// of the copy time. If we set it too small, we have to assume the token bucket is
// refilled very frequently.
const bucketCapacity = size / 128
type mockReader struct {
remain uint64
}
func (m *mockReader) Read(p []byte) (n int, err error) {
size := m.remain
if size == 0 {
return 0, io.EOF
}
if size > uint64(len(p)) {
size = uint64(len(p))
}
m.remain -= size
return int(size), nil
}
func testRead(t *testing.T, fileSize uint64, rateLimitBucket *ratelimit.Bucket) float64 {
in := &mockReader{fileSize}
out := ioutil.Discard
start := time.Now()
var rateLimitedIn io.Reader
if rateLimitBucket == nil {
rateLimitedIn = in
} else {
rateLimitedIn = ratelimit.Reader(in, rateLimitBucket)
}
_, err := io.Copy(out, rateLimitedIn)
assert.NoError(t, err)
return time.Now().Sub(start).Seconds()
}
func TestNoRateLimit(t *testing.T) {
t.Parallel()
dur := testRead(t, size, nil)
assert.InDelta(t, 0, dur, delta)
}
func TestRateLimit(t *testing.T) {
t.Parallel()
rateLimitBucket := ratelimit.NewBucketWithRate(float64(rate), bucketCapacity)
dur := testRead(t, size, rateLimitBucket)
assert.InDelta(t, float64(size)/rate, dur, delta)
}
func TestConcurrentRateLimit(t *testing.T) {
t.Parallel()
// goroutine count
cnt := 8
rateLimitBucket := ratelimit.NewBucketWithRate(float64(rate), bucketCapacity)
var wg sync.WaitGroup
wg.Add(cnt)
start := time.Now()
for i := 0; i < cnt; i++ {
go func() {
testRead(t, uint64(size/cnt), rateLimitBucket)
wg.Done()
}()
}
wg.Wait()
dur := time.Now().Sub(start).Seconds()
assert.InDelta(t, float64(size)/rate, dur, delta)
}