1
17
18 package cache
19
20 import (
21 "strconv"
22 "sync"
23 "testing"
24 "time"
25
26 "google.golang.org/grpc/internal/grpctest"
27 )
28
29 const (
30 testCacheTimeout = 100 * time.Millisecond
31 )
32
33 type s struct {
34 grpctest.Tester
35 }
36
37 func Test(t *testing.T) {
38 grpctest.RunSubTests(t, s{})
39 }
40
41 func (c *TimeoutCache) getForTesting(key any) (*cacheEntry, bool) {
42 c.mu.Lock()
43 defer c.mu.Unlock()
44 r, ok := c.cache[key]
45 return r, ok
46 }
47
48
49
50
51 func (s) TestCacheExpire(t *testing.T) {
52 const k, v = 1, "1"
53 c := NewTimeoutCache(testCacheTimeout)
54
55 callbackChan := make(chan struct{})
56 c.Add(k, v, func() { close(callbackChan) })
57
58 if gotV, ok := c.getForTesting(k); !ok || gotV.item != v {
59 t.Fatalf("After Add(), before timeout, from cache got: %v, %v, want %v, %v", gotV.item, ok, v, true)
60 }
61 if l := c.Len(); l != 1 {
62 t.Fatalf("%d number of items in the cache, want 1", l)
63 }
64
65 select {
66 case <-callbackChan:
67 case <-time.After(testCacheTimeout * 2):
68 t.Fatalf("timeout waiting for callback")
69 }
70
71 if _, ok := c.getForTesting(k); ok {
72 t.Fatalf("After Add(), after timeout, from cache got: _, %v, want _, %v", ok, false)
73 }
74 if l := c.Len(); l != 0 {
75 t.Fatalf("%d number of items in the cache, want 0", l)
76 }
77 }
78
79
80
81
82 func (s) TestCacheRemove(t *testing.T) {
83 const k, v = 1, "1"
84 c := NewTimeoutCache(testCacheTimeout)
85
86 callbackChan := make(chan struct{})
87 c.Add(k, v, func() { close(callbackChan) })
88
89 if got, ok := c.getForTesting(k); !ok || got.item != v {
90 t.Fatalf("After Add(), before timeout, from cache got: %v, %v, want %v, %v", got.item, ok, v, true)
91 }
92 if l := c.Len(); l != 1 {
93 t.Fatalf("%d number of items in the cache, want 1", l)
94 }
95
96 time.Sleep(testCacheTimeout / 2)
97
98 gotV, gotOK := c.Remove(k)
99 if !gotOK || gotV != v {
100 t.Fatalf("After Add(), before timeout, Remove() got: %v, %v, want %v, %v", gotV, gotOK, v, true)
101 }
102
103 if _, ok := c.getForTesting(k); ok {
104 t.Fatalf("After Add(), before timeout, after Remove(), from cache got: _, %v, want _, %v", ok, false)
105 }
106 if l := c.Len(); l != 0 {
107 t.Fatalf("%d number of items in the cache, want 0", l)
108 }
109
110 select {
111 case <-callbackChan:
112 t.Fatalf("unexpected callback after retrieve")
113 case <-time.After(testCacheTimeout * 2):
114 }
115 }
116
117
118
119 func (s) TestCacheClearWithoutCallback(t *testing.T) {
120 var values []string
121 const itemCount = 3
122 for i := 0; i < itemCount; i++ {
123 values = append(values, strconv.Itoa(i))
124 }
125 c := NewTimeoutCache(testCacheTimeout)
126
127 done := make(chan struct{})
128 defer close(done)
129 callbackChan := make(chan struct{}, itemCount)
130
131 for i, v := range values {
132 callbackChanTemp := make(chan struct{})
133 c.Add(i, v, func() { close(callbackChanTemp) })
134 go func() {
135 select {
136 case <-callbackChanTemp:
137 callbackChan <- struct{}{}
138 case <-done:
139 }
140 }()
141 }
142
143 for i, v := range values {
144 if got, ok := c.getForTesting(i); !ok || got.item != v {
145 t.Fatalf("After Add(), before timeout, from cache got: %v, %v, want %v, %v", got.item, ok, v, true)
146 }
147 }
148 if l := c.Len(); l != itemCount {
149 t.Fatalf("%d number of items in the cache, want %d", l, itemCount)
150 }
151
152 time.Sleep(testCacheTimeout / 2)
153 c.Clear(false)
154
155 for i := range values {
156 if _, ok := c.getForTesting(i); ok {
157 t.Fatalf("After Add(), before timeout, after Remove(), from cache got: _, %v, want _, %v", ok, false)
158 }
159 }
160 if l := c.Len(); l != 0 {
161 t.Fatalf("%d number of items in the cache, want 0", l)
162 }
163
164 select {
165 case <-callbackChan:
166 t.Fatalf("unexpected callback after Clear")
167 case <-time.After(testCacheTimeout * 2):
168 }
169 }
170
171
172
173 func (s) TestCacheClearWithCallback(t *testing.T) {
174 var values []string
175 const itemCount = 3
176 for i := 0; i < itemCount; i++ {
177 values = append(values, strconv.Itoa(i))
178 }
179 c := NewTimeoutCache(time.Hour)
180
181 testDone := make(chan struct{})
182 defer close(testDone)
183
184 var wg sync.WaitGroup
185 wg.Add(itemCount)
186 for i, v := range values {
187 callbackChanTemp := make(chan struct{})
188 c.Add(i, v, func() { close(callbackChanTemp) })
189 go func() {
190 defer wg.Done()
191 select {
192 case <-callbackChanTemp:
193 case <-testDone:
194 }
195 }()
196 }
197
198 allGoroutineDone := make(chan struct{}, itemCount)
199 go func() {
200 wg.Wait()
201 close(allGoroutineDone)
202 }()
203
204 for i, v := range values {
205 if got, ok := c.getForTesting(i); !ok || got.item != v {
206 t.Fatalf("After Add(), before timeout, from cache got: %v, %v, want %v, %v", got.item, ok, v, true)
207 }
208 }
209 if l := c.Len(); l != itemCount {
210 t.Fatalf("%d number of items in the cache, want %d", l, itemCount)
211 }
212
213 time.Sleep(testCacheTimeout / 2)
214 c.Clear(true)
215
216 for i := range values {
217 if _, ok := c.getForTesting(i); ok {
218 t.Fatalf("After Add(), before timeout, after Remove(), from cache got: _, %v, want _, %v", ok, false)
219 }
220 }
221 if l := c.Len(); l != 0 {
222 t.Fatalf("%d number of items in the cache, want 0", l)
223 }
224
225 select {
226 case <-allGoroutineDone:
227 case <-time.After(testCacheTimeout * 2):
228 t.Fatalf("timeout waiting for all callbacks")
229 }
230 }
231
232
233
234
235 func (s) TestCacheRetrieveTimeoutRace(t *testing.T) {
236 c := NewTimeoutCache(time.Nanosecond)
237
238 done := make(chan struct{})
239 go func() {
240 for i := 0; i < 1000; i++ {
241
242
243 c.Add(i, strconv.Itoa(i), func() {})
244 c.Remove(i)
245 }
246 close(done)
247 }()
248
249 select {
250 case <-time.After(time.Second):
251 t.Fatalf("Test didn't finish within 1 second. Deadlock")
252 case <-done:
253 }
254 }
255
View as plain text