6
6
"sync"
7
7
"testing"
8
8
"time"
9
+
10
+ "golang.org/x/sync/errgroup"
9
11
)
10
12
11
13
func TestLocalCounter (t * testing.T ) {
@@ -16,74 +18,128 @@ func TestLocalCounter(t *testing.T) {
16
18
windowLength : time .Second ,
17
19
}
18
20
19
- // Time = NOW()
20
21
currentWindow := time .Now ().UTC ().Truncate (time .Second )
21
22
previousWindow := currentWindow .Add (- time .Second )
22
23
23
- for i := 0 ; i < 5 ; i ++ {
24
- curr , prev , _ := limitCounter .Get (fmt .Sprintf ("key-%v" , i ), currentWindow , previousWindow )
25
- if curr != 0 {
26
- t .Errorf ("unexpected curr = %v, expected %v" , curr , 0 )
27
- }
28
- if prev != 0 {
29
- t .Errorf ("unexpected prev = %v, expected %v" , prev , 0 )
30
- }
31
-
32
- _ = limitCounter .IncrementBy (fmt .Sprintf ("key-%v" , i ), currentWindow , 1 )
33
- _ = limitCounter .IncrementBy (fmt .Sprintf ("key-%v" , i ), currentWindow , 99 )
34
-
35
- curr , prev , _ = limitCounter .Get (fmt .Sprintf ("key-%v" , i ), currentWindow , previousWindow )
36
- if curr != 100 {
37
- t .Errorf ("unexpected curr = %v, expected %v" , curr , 100 )
38
- }
39
- if prev != 0 {
40
- t .Errorf ("unexpected prev = %v, expected %v" , prev , 0 )
41
- }
24
+ type test struct {
25
+ name string // In each test do the following:
26
+ advanceTime time.Duration // 1. advance time
27
+ incrBy int // 2. increase counter
28
+ prev int // 3. check previous window counter
29
+ curr int // and current window counter
42
30
}
43
31
44
- // Time++
45
- currentWindow = currentWindow .Add (time .Second )
46
- previousWindow = previousWindow .Add (time .Second )
47
-
48
- for i := 0 ; i < 5 ; i ++ {
49
- curr , prev , _ := limitCounter .Get (fmt .Sprintf ("key-%v" , i ), currentWindow , previousWindow )
50
- if curr != 0 {
51
- t .Errorf ("unexpected curr = %v, expected %v" , curr , 0 )
52
- }
53
- if prev != 100 {
54
- t .Errorf ("unexpected prev = %v, expected %v" , prev , 100 )
55
- }
56
- _ = limitCounter .IncrementBy (fmt .Sprintf ("key-%v" , i ), currentWindow , 50 )
32
+ tests := []test {
33
+ {
34
+ name : "t=0s: init" ,
35
+ prev : 0 ,
36
+ curr : 0 ,
37
+ },
38
+ {
39
+ name : "t=0s: increment 1" ,
40
+ incrBy : 1 ,
41
+ prev : 0 ,
42
+ curr : 1 ,
43
+ },
44
+ {
45
+ name : "t=0s: increment by 99" ,
46
+ incrBy : 99 ,
47
+ prev : 0 ,
48
+ curr : 100 ,
49
+ },
50
+ {
51
+ name : "t=1s: move clock by 1s" ,
52
+ advanceTime : time .Second ,
53
+ prev : 100 ,
54
+ curr : 0 ,
55
+ },
56
+ {
57
+ name : "t=1s: increment by 20" ,
58
+ incrBy : 20 ,
59
+ prev : 100 ,
60
+ curr : 20 ,
61
+ },
62
+ {
63
+ name : "t=1s: increment by 20" ,
64
+ incrBy : 20 ,
65
+ prev : 100 ,
66
+ curr : 40 ,
67
+ },
68
+ {
69
+ name : "t=2s: move clock by 1s" ,
70
+ advanceTime : time .Second ,
71
+ prev : 40 ,
72
+ curr : 0 ,
73
+ },
74
+ {
75
+ name : "t=2s: incr++" ,
76
+ incrBy : 1 ,
77
+ prev : 40 ,
78
+ curr : 1 ,
79
+ },
80
+ {
81
+ name : "t=2s: incr+=9" ,
82
+ incrBy : 9 ,
83
+ prev : 40 ,
84
+ curr : 10 ,
85
+ },
86
+ {
87
+ name : "t=2s: incr+=20" ,
88
+ incrBy : 20 ,
89
+ prev : 40 ,
90
+ curr : 30 ,
91
+ },
92
+ {
93
+ name : "t=4s: move clock by 2s" ,
94
+ advanceTime : 2 * time .Second ,
95
+ prev : 0 ,
96
+ curr : 0 ,
97
+ },
57
98
}
58
99
59
- // Time++
60
- currentWindow = currentWindow .Add (time .Second )
61
- previousWindow = previousWindow .Add (time .Second )
100
+ concurrentRequests := 1000
62
101
63
- for i := 0 ; i < 5 ; i ++ {
64
- curr , prev , _ := limitCounter . Get ( fmt . Sprintf ( "key-%v" , i ), currentWindow , previousWindow )
65
- if curr != 0 {
66
- t . Errorf ( "unexpected curr = %v, expected %v" , curr , 0 )
102
+ for _ , tt := range tests {
103
+ if tt . advanceTime > 0 {
104
+ currentWindow = currentWindow . Add ( tt . advanceTime )
105
+ previousWindow = previousWindow . Add ( tt . advanceTime )
67
106
}
68
- if prev != 50 {
69
- t .Errorf ("unexpected prev = %v, expected %v" , prev , 50 )
70
- }
71
- _ = limitCounter .IncrementBy (fmt .Sprintf ("key-%v" , i ), currentWindow , 99 )
72
- }
73
107
74
- // Time += 10
75
- currentWindow = currentWindow .Add (10 * time .Second )
76
- previousWindow = previousWindow .Add (10 * time .Second )
108
+ if tt .incrBy > 0 {
109
+ var g errgroup.Group
110
+ for i := 0 ; i < concurrentRequests ; i ++ {
111
+ i := i
112
+ g .Go (func () error {
113
+ key := fmt .Sprintf ("key:%v" , i )
114
+ return limitCounter .IncrementBy (key , currentWindow , tt .incrBy )
115
+ })
116
+ }
117
+ if err := g .Wait (); err != nil {
118
+ t .Errorf ("%s: %v" , tt .name , err )
119
+ }
120
+ }
77
121
78
- for i := 0 ; i < 5 ; i ++ {
79
- curr , prev , _ := limitCounter .Get (fmt .Sprintf ("key-%v" , i ), currentWindow , previousWindow )
80
- if curr != 0 {
81
- t .Errorf ("unexpected curr = %v, expected %v" , curr , 0 )
122
+ var g errgroup.Group
123
+ for i := 0 ; i < concurrentRequests ; i ++ {
124
+ i := i
125
+ g .Go (func () error {
126
+ key := fmt .Sprintf ("key:%v" , i )
127
+ curr , prev , err := limitCounter .Get (key , currentWindow , previousWindow )
128
+ if err != nil {
129
+ return fmt .Errorf ("%q: %w" , key , err )
130
+ }
131
+ if curr != tt .curr {
132
+ return fmt .Errorf ("%q: unexpected curr = %v, expected %v" , key , curr , tt .curr )
133
+ }
134
+ if prev != tt .prev {
135
+ return fmt .Errorf ("%q: unexpected prev = %v, expected %v" , key , prev , tt .prev )
136
+ }
137
+ return nil
138
+ })
82
139
}
83
- if prev != 0 {
84
- t .Errorf ("unexpected prev = %v, expected %v" , prev , 0 )
140
+ if err := g . Wait (); err != nil {
141
+ t .Errorf ("%s: %v" , tt . name , err )
85
142
}
86
- _ = limitCounter .IncrementBy (fmt .Sprintf ("key-%v" , i ), currentWindow , 99 )
87
143
}
88
144
}
89
145
0 commit comments