git.iko.soy/typeable/oauth2-proxy
on ea261ca help sign in
380 lines 10 kB history raw
1package clock_test
3import (
4 "sync"
5 "sync/atomic"
6 "time"
8 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/clock"
9 . "github.com/onsi/ginkgo"
10 . "github.com/onsi/gomega"
13const (
14 testGlobalEpoch = 1000000000
15 testLocalEpoch = 1234567890
18var _ = Describe("Clock suite", func() {
19 var testClock = clock.Clock{}
21 AfterEach(func() {
22 clock.Reset()
23 testClock.Reset()
24 })
26 Context("Global time not overridden", func() {
27 It("errors when trying to Add", func() {
28 err := clock.Add(123 * time.Hour)
29 Expect(err).To(HaveOccurred())
30 })
32 Context("Clock not mocked via Set", func() {
33 const (
34 outsideTolerance = int32(0)
35 withinTolerance = int32(1)
36 )
38 It("uses time.After for After", func() {
39 var tolerance int32
40 go func() {
41 time.Sleep(10 * time.Millisecond)
42 atomic.StoreInt32(&tolerance, withinTolerance)
43 }()
44 go func() {
45 time.Sleep(30 * time.Millisecond)
46 atomic.StoreInt32(&tolerance, outsideTolerance)
47 }()
49 Expect(atomic.LoadInt32(&tolerance)).To(Equal(outsideTolerance))
51 <-testClock.After(20 * time.Millisecond)
52 Expect(atomic.LoadInt32(&tolerance)).To(Equal(withinTolerance))
54 <-testClock.After(20 * time.Millisecond)
55 Expect(atomic.LoadInt32(&tolerance)).To(Equal(outsideTolerance))
56 })
58 It("uses time.AfterFunc for AfterFunc", func() {
59 var tolerance int32
60 go func() {
61 time.Sleep(10 * time.Millisecond)
62 atomic.StoreInt32(&tolerance, withinTolerance)
63 }()
64 go func() {
65 time.Sleep(30 * time.Millisecond)
66 atomic.StoreInt32(&tolerance, outsideTolerance)
67 }()
69 Expect(atomic.LoadInt32(&tolerance)).To(Equal(outsideTolerance))
71 var wg sync.WaitGroup
72 wg.Add(1)
73 testClock.AfterFunc(20*time.Millisecond, func() {
74 wg.Done()
75 })
76 wg.Wait()
77 Expect(atomic.LoadInt32(&tolerance)).To(Equal(withinTolerance))
79 wg.Add(1)
80 testClock.AfterFunc(20*time.Millisecond, func() {
81 wg.Done()
82 })
83 wg.Wait()
84 Expect(atomic.LoadInt32(&tolerance)).To(Equal(outsideTolerance))
85 })
87 It("uses time.Now for Now", func() {
88 a := time.Now()
89 b := testClock.Now()
90 Expect(b.Sub(a).Round(10 * time.Millisecond)).To(Equal(0 * time.Millisecond))
91 })
93 It("uses time.Since for Since", func() {
94 past := time.Now().Add(-60 * time.Second)
95 Expect(time.Since(past).Round(10 * time.Millisecond)).
96 To(Equal(60 * time.Second))
97 })
99 It("uses time.Sleep for Sleep", func() {
100 var tolerance int32
101 go func() {
102 time.Sleep(10 * time.Millisecond)
103 atomic.StoreInt32(&tolerance, withinTolerance)
104 }()
105 go func() {
106 time.Sleep(30 * time.Millisecond)
107 atomic.StoreInt32(&tolerance, outsideTolerance)
108 }()
110 Expect(atomic.LoadInt32(&tolerance)).To(Equal(outsideTolerance))
112 testClock.Sleep(20 * time.Millisecond)
113 Expect(atomic.LoadInt32(&tolerance)).To(Equal(withinTolerance))
115 testClock.Sleep(20 * time.Millisecond)
116 Expect(atomic.LoadInt32(&tolerance)).To(Equal(outsideTolerance))
117 })
119 It("uses time.Tick for Tick", func() {
120 var tolerance int32
121 go func() {
122 time.Sleep(10 * time.Millisecond)
123 atomic.StoreInt32(&tolerance, withinTolerance)
124 }()
125 go func() {
126 time.Sleep(50 * time.Millisecond)
127 atomic.StoreInt32(&tolerance, outsideTolerance)
128 }()
130 ch := testClock.Tick(20 * time.Millisecond)
131 Expect(atomic.LoadInt32(&tolerance)).To(Equal(outsideTolerance))
132 <-ch
133 Expect(atomic.LoadInt32(&tolerance)).To(Equal(withinTolerance))
134 <-ch
135 Expect(atomic.LoadInt32(&tolerance)).To(Equal(withinTolerance))
136 <-ch
137 Expect(atomic.LoadInt32(&tolerance)).To(Equal(outsideTolerance))
138 })
140 It("uses time.Ticker for Ticker", func() {
141 var tolerance int32
142 go func() {
143 time.Sleep(10 * time.Millisecond)
144 atomic.StoreInt32(&tolerance, withinTolerance)
145 }()
146 go func() {
147 time.Sleep(50 * time.Millisecond)
148 atomic.StoreInt32(&tolerance, outsideTolerance)
149 }()
151 ticker := testClock.Ticker(20 * time.Millisecond)
152 Expect(atomic.LoadInt32(&tolerance)).To(Equal(outsideTolerance))
153 <-ticker.C
154 Expect(atomic.LoadInt32(&tolerance)).To(Equal(withinTolerance))
155 <-ticker.C
156 Expect(atomic.LoadInt32(&tolerance)).To(Equal(withinTolerance))
157 <-ticker.C
158 Expect(atomic.LoadInt32(&tolerance)).To(Equal(outsideTolerance))
159 })
161 It("errors if Add is used", func() {
162 err := testClock.Add(100 * time.Second)
163 Expect(err).To(HaveOccurred())
164 })
165 })
167 Context("Clock mocked via Set", func() {
168 var now = time.Unix(testLocalEpoch, 0)
170 BeforeEach(func() {
171 testClock.Set(now)
172 })
174 It("mocks After", func() {
175 var after int32
176 ready := make(chan struct{})
177 ch := testClock.After(10 * time.Second)
178 go func(ch <-chan time.Time) {
179 close(ready)
180 <-ch
181 atomic.StoreInt32(&after, 1)
182 }(ch)
183 <-ready
185 err := testClock.Add(9 * time.Second)
186 Expect(err).ToNot(HaveOccurred())
187 Expect(atomic.LoadInt32(&after)).To(Equal(int32(0)))
189 err = testClock.Add(1 * time.Second)
190 Expect(err).ToNot(HaveOccurred())
191 Expect(atomic.LoadInt32(&after)).To(Equal(int32(1)))
192 })
194 It("mocks AfterFunc", func() {
195 var after int32
196 testClock.AfterFunc(10*time.Second, func() {
197 atomic.StoreInt32(&after, 1)
198 })
200 err := testClock.Add(9 * time.Second)
201 Expect(err).ToNot(HaveOccurred())
202 Expect(atomic.LoadInt32(&after)).To(Equal(int32(0)))
204 err = testClock.Add(1 * time.Second)
205 Expect(err).ToNot(HaveOccurred())
206 Expect(atomic.LoadInt32(&after)).To(Equal(int32(1)))
207 })
209 It("mocks AfterFunc with a stopped timer", func() {
210 var after int32
211 timer := testClock.AfterFunc(10*time.Second, func() {
212 atomic.StoreInt32(&after, 1)
213 })
214 timer.Stop()
216 err := testClock.Add(11 * time.Second)
217 Expect(err).ToNot(HaveOccurred())
218 Expect(atomic.LoadInt32(&after)).To(Equal(int32(0)))
219 })
221 It("mocks Now", func() {
222 Expect(testClock.Now()).To(Equal(now))
223 err := testClock.Add(123 * time.Hour)
224 Expect(err).ToNot(HaveOccurred())
225 Expect(testClock.Now()).To(Equal(now.Add(123 * time.Hour)))
226 })
228 It("mocks Since", func() {
229 Expect(testClock.Since(time.Unix(testLocalEpoch-100, 0))).
230 To(Equal(100 * time.Second))
231 })
233 It("mocks Sleep", func() {
234 var after int32
235 ready := make(chan struct{})
236 go func() {
237 close(ready)
238 testClock.Sleep(10 * time.Second)
239 atomic.StoreInt32(&after, 1)
240 }()
241 <-ready
243 err := testClock.Add(9 * time.Second)
244 Expect(err).ToNot(HaveOccurred())
245 Expect(atomic.LoadInt32(&after)).To(Equal(int32(0)))
247 err = testClock.Add(1 * time.Second)
248 Expect(err).ToNot(HaveOccurred())
249 Expect(atomic.LoadInt32(&after)).To(Equal(int32(1)))
250 })
252 It("mocks Tick", func() {
253 var ticks int32
254 ready := make(chan struct{})
255 go func() {
256 close(ready)
257 tick := testClock.Tick(10 * time.Second)
258 for ticks < 5 {
259 <-tick
260 atomic.AddInt32(&ticks, 1)
261 }
262 }()
263 <-ready
265 Expect(atomic.LoadInt32(&ticks)).To(Equal(int32(0)))
267 err := testClock.Add(9 * time.Second)
268 Expect(err).ToNot(HaveOccurred())
269 Expect(atomic.LoadInt32(&ticks)).To(Equal(int32(0)))
271 err = testClock.Add(1 * time.Second)
272 Expect(err).ToNot(HaveOccurred())
273 Expect(atomic.LoadInt32(&ticks)).To(Equal(int32(1)))
275 err = testClock.Add(30 * time.Second)
276 Expect(err).ToNot(HaveOccurred())
277 Expect(atomic.LoadInt32(&ticks)).To(Equal(int32(4)))
279 err = testClock.Add(10 * time.Second)
280 Expect(err).ToNot(HaveOccurred())
281 Expect(atomic.LoadInt32(&ticks)).To(Equal(int32(5)))
282 })
284 It("mocks Ticker", func() {
285 var ticks int32
286 ready := make(chan struct{})
287 go func() {
288 ticker := testClock.Ticker(10 * time.Second)
289 close(ready)
290 for ticks < 5 {
291 <-ticker.C
292 atomic.AddInt32(&ticks, 1)
293 }
294 }()
295 <-ready
297 Expect(atomic.LoadInt32(&ticks)).To(Equal(int32(0)))
299 err := testClock.Add(9 * time.Second)
300 Expect(err).ToNot(HaveOccurred())
301 Expect(atomic.LoadInt32(&ticks)).To(Equal(int32(0)))
303 err = testClock.Add(1 * time.Second)
304 Expect(err).ToNot(HaveOccurred())
305 Expect(atomic.LoadInt32(&ticks)).To(Equal(int32(1)))
307 err = testClock.Add(30 * time.Second)
308 Expect(err).ToNot(HaveOccurred())
309 Expect(atomic.LoadInt32(&ticks)).To(Equal(int32(4)))
311 err = testClock.Add(10 * time.Second)
312 Expect(err).ToNot(HaveOccurred())
313 Expect(atomic.LoadInt32(&ticks)).To(Equal(int32(5)))
314 })
316 It("mocks Timer", func() {
317 var after int32
318 ready := make(chan struct{})
319 go func() {
320 timer := testClock.Timer(10 * time.Second)
321 close(ready)
322 <-timer.C
323 atomic.AddInt32(&after, 1)
324 }()
325 <-ready
327 err := testClock.Add(9 * time.Second)
328 Expect(err).ToNot(HaveOccurred())
329 Expect(atomic.LoadInt32(&after)).To(Equal(int32(0)))
331 err = testClock.Add(1 * time.Second)
332 Expect(err).ToNot(HaveOccurred())
333 Expect(atomic.LoadInt32(&after)).To(Equal(int32(1)))
334 })
335 })
336 })
338 Context("Global time overridden", func() {
339 var (
340 globalNow = time.Unix(testGlobalEpoch, 0)
341 localNow = time.Unix(testLocalEpoch, 0)
342 )
344 BeforeEach(func() {
345 clock.Set(globalNow)
346 })
348 Context("Clock not mocked via Set", func() {
349 It("uses globally mocked Now", func() {
350 Expect(testClock.Now()).To(Equal(globalNow))
351 err := clock.Add(123 * time.Hour)
352 Expect(err).ToNot(HaveOccurred())
353 Expect(testClock.Now()).To(Equal(globalNow.Add(123 * time.Hour)))
354 })
356 It("errors when Add is called on the local Clock", func() {
357 err := testClock.Add(100 * time.Hour)
358 Expect(err).To(HaveOccurred())
359 })
360 })
362 Context("Clock is mocked via Set", func() {
363 BeforeEach(func() {
364 testClock.Set(localNow)
365 })
367 It("uses the local mock and ignores the global", func() {
368 Expect(testClock.Now()).To(Equal(localNow))
370 err := clock.Add(456 * time.Hour)
371 Expect(err).ToNot(HaveOccurred())
373 err = testClock.Add(123 * time.Hour)
374 Expect(err).ToNot(HaveOccurred())
376 Expect(testClock.Now()).To(Equal(localNow.Add(123 * time.Hour)))
377 })
378 })
379 })
380})