-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcounter_impl_test.go
140 lines (118 loc) · 2.71 KB
/
counter_impl_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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package metric
import (
"sync"
"testing"
"time"
"github.com/stretchr/testify/suite"
)
var (
// customized curTimestamp to control the timing
curTimestamp int64
)
func tick(d time.Duration) {
curTimestamp += int64(d)
}
// Test releated default value
const (
defaultWindow = time.Hour
defaultBucket = time.Minute
defaultBucketNum = int(defaultWindow / defaultBucket)
)
// TestCase counter
type SuiteCounter struct {
suite.Suite
counter *counterImpl
}
func (s *SuiteCounter) SetupSuite() {
timeNow = func() int64 {
return curTimestamp
}
}
func (s *SuiteCounter) SetupTest() {
c, _ := NewCounter(defaultWindow, defaultBucket)
s.counter = c.(*counterImpl)
}
func (s *SuiteCounter) TestCreate() {
_, err := NewCounter(time.Minute, 5*time.Second)
s.NoError(err)
// window must >= 1 minute
_, err = NewCounter(10*time.Second, 5*time.Second)
s.Error(err)
// bucket must >= 2 second
_, err = NewCounter(time.Minute, time.Second)
s.Error(err)
// window is multiple of bucket
_, err = NewCounter(time.Minute, 7*time.Second)
s.Error(err)
// window must >= bucket
_, err = NewCounter(time.Minute, 5*time.Minute)
s.Error(err)
}
func (s *SuiteCounter) TestConcurrent() {
c := s.counter
wg := sync.WaitGroup{}
wg.Add(100)
for i := 0; i < 100; i++ {
go func() {
c.Incr(3)
c.getBuckets()
wg.Done()
}()
}
wg.Wait()
s.Equal(c.buckets[c.curIdx].count, uint64(100))
s.Equal(c.buckets[c.curIdx].sum, 300.0)
}
type offset struct {
start int64
end int64
m float64
}
func (s *SuiteCounter) TestGetBucket() {
c := s.counter
bucketInterval := int64(defaultBucket)
now := timeNow()
end := now - now%bucketInterval + bucketInterval
record := []offset{}
for i := 0; i < defaultBucketNum; i++ {
// Tick of next bucket interval
m := float64(i + 1)
c.Incr(1 * m)
c.Incr(4 * m)
c.Incr(6 * m)
tick(defaultBucket)
record = append(record, offset{m: m, end: end})
end += bucketInterval
}
b := c.getBuckets()
s.Equal(len(b), defaultBucketNum)
for i := 0; i < len(b); i++ {
s.Equal(b[i].end, record[i].end)
s.Equal(b[i].count, uint64(3))
s.Equal(b[i].sum, 11*record[i].m)
s.Equal(b[i].min, 1*record[i].m)
s.Equal(b[i].max, 6*record[i].m)
}
}
func (s *SuiteCounter) TestGetBucketReadonly() {
c := s.counter
c.Incr(1)
tick(defaultBucket)
c.getBuckets()[0].count = 8
// change value of GetBucket() won't affect real counter value
s.Equal(c.getBuckets()[0].count, uint64(1))
}
func (s *SuiteCounter) TestSnapshot() {
c := s.counter
c.Incr(1)
tick(defaultBucket)
c.Incr(2)
tick(defaultBucket)
c.Incr(3)
tick(defaultBucket)
sh := c.Snapshot().(*counterSnapshot)
s.Equal(sh.buckets, c.getBuckets())
}
func TestRunSuiteCounter(t *testing.T) {
suite.Run(t, new(SuiteCounter))
}