github.com/mailgun/holster/v4@v4.20.0/clock/frozen_test.go (about) 1 package clock 2 3 import ( 4 "fmt" 5 "testing" 6 "time" 7 8 "github.com/stretchr/testify/suite" 9 ) 10 11 func TestFreezeUnfreeze(t *testing.T) { 12 Freeze(Now()).Unfreeze() 13 } 14 15 type FrozenSuite struct { 16 suite.Suite 17 epoch time.Time 18 } 19 20 func TestFrozenSuite(t *testing.T) { 21 suite.Run(t, new(FrozenSuite)) 22 } 23 24 func (s *FrozenSuite) SetupSuite() { 25 var err error 26 s.epoch, err = time.Parse(time.RFC3339, "2009-02-19T00:00:00Z") 27 s.Require().NoError(err) 28 } 29 30 func (s *FrozenSuite) SetupTest() { 31 Freeze(s.epoch) 32 } 33 34 func (s *FrozenSuite) TearDownTest() { 35 Unfreeze() 36 } 37 38 func (s *FrozenSuite) TestAdvanceNow() { 39 s.Require().Equal(s.epoch, Now()) 40 s.Require().Equal(42*time.Millisecond, Advance(42*time.Millisecond)) 41 s.Require().Equal(s.epoch.Add(42*time.Millisecond), Now()) 42 s.Require().Equal(55*time.Millisecond, Advance(13*time.Millisecond)) 43 s.Require().Equal(74*time.Millisecond, Advance(19*time.Millisecond)) 44 s.Require().Equal(s.epoch.Add(74*time.Millisecond), Now()) 45 } 46 47 func (s *FrozenSuite) TestSleep() { 48 s.T().Skip("TODO: fix DATA RACE and enable(https://github.com/mailgun/holster/issues/147)") 49 50 hits := make(chan int, 100) 51 52 delays := []int{60, 100, 90, 131, 999, 5} 53 for i, tc := range []struct { 54 desc string 55 fn func(delayMs int) 56 }{{ 57 desc: "Sleep", 58 fn: func(delay int) { 59 Sleep(time.Duration(delay) * time.Millisecond) 60 hits <- delay 61 }, 62 }, { 63 desc: "After", 64 fn: func(delay int) { 65 <-After(time.Duration(delay) * time.Millisecond) 66 hits <- delay 67 }, 68 }, { 69 desc: "AfterFunc", 70 fn: func(delay int) { 71 AfterFunc(time.Duration(delay)*time.Millisecond, 72 func() { 73 hits <- delay 74 }) 75 }, 76 }, { 77 desc: "NewTimer", 78 fn: func(delay int) { 79 t := NewTimer(time.Duration(delay) * time.Millisecond) 80 <-t.C() 81 hits <- delay 82 }, 83 }} { 84 fmt.Printf("Test case #%d: %s", i, tc.desc) 85 for _, delay := range delays { 86 go tc.fn(delay) 87 } 88 // Spin-wait for all goroutines to fall asleep. 89 ft := provider.(*frozenTime) 90 for { 91 if len(ft.timers) == len(delays) { 92 break 93 } 94 time.Sleep(10 * time.Millisecond) 95 } 96 97 runningMs := 0 98 for i, delayMs := range []int{5, 60, 90, 100, 131, 999} { 99 fmt.Printf("Checking timer #%d, delay=%d\n", i, delayMs) 100 delta := delayMs - runningMs - 1 101 Advance(time.Duration(delta) * time.Millisecond) 102 // Check before each timer deadline that it is not triggered yet. 103 s.assertHits(hits, []int{}) 104 105 // When 106 Advance(1 * time.Millisecond) 107 108 // Then 109 s.assertHits(hits, []int{delayMs}) 110 111 runningMs += delta + 1 112 } 113 114 Advance(1000 * time.Millisecond) 115 s.assertHits(hits, []int{}) 116 } 117 } 118 119 // Timers scheduled to trigger at the same time do that in the order they were 120 // created. 121 func (s *FrozenSuite) TestSameTime() { 122 var hits []int 123 124 AfterFunc(100, func() { hits = append(hits, 3) }) 125 AfterFunc(100, func() { hits = append(hits, 1) }) 126 AfterFunc(99, func() { hits = append(hits, 2) }) 127 AfterFunc(100, func() { hits = append(hits, 5) }) 128 AfterFunc(101, func() { hits = append(hits, 4) }) 129 AfterFunc(101, func() { hits = append(hits, 6) }) 130 131 // When 132 Advance(100) 133 134 // Then 135 s.Require().Equal([]int{2, 3, 1, 5}, hits) 136 } 137 138 func (s *FrozenSuite) TestTimerStop() { 139 hits := []int{} 140 141 AfterFunc(100, func() { hits = append(hits, 1) }) 142 t := AfterFunc(100, func() { hits = append(hits, 2) }) 143 AfterFunc(100, func() { hits = append(hits, 3) }) 144 Advance(99) 145 s.Require().Equal([]int{}, hits) 146 147 // When 148 active1 := t.Stop() 149 active2 := t.Stop() 150 151 // Then 152 s.Require().Equal(true, active1) 153 s.Require().Equal(false, active2) 154 Advance(1) 155 s.Require().Equal([]int{1, 3}, hits) 156 } 157 158 func (s *FrozenSuite) TestReset() { 159 hits := []int{} 160 161 t1 := AfterFunc(100, func() { hits = append(hits, 1) }) 162 t2 := AfterFunc(100, func() { hits = append(hits, 2) }) 163 AfterFunc(100, func() { hits = append(hits, 3) }) 164 Advance(99) 165 s.Require().Equal([]int{}, hits) 166 167 // When 168 active1 := t1.Reset(1) // Reset to the same time 169 active2 := t2.Reset(7) 170 171 // Then 172 s.Require().Equal(true, active1) 173 s.Require().Equal(true, active2) 174 175 Advance(1) 176 s.Require().Equal([]int{3, 1}, hits) 177 Advance(5) 178 s.Require().Equal([]int{3, 1}, hits) 179 Advance(1) 180 s.Require().Equal([]int{3, 1, 2}, hits) 181 } 182 183 // Reset to the same time just puts the timer at the end of the trigger list 184 // for the date. 185 func (s *FrozenSuite) TestResetSame() { 186 hits := []int{} 187 188 t := AfterFunc(100, func() { hits = append(hits, 1) }) 189 AfterFunc(100, func() { hits = append(hits, 2) }) 190 AfterFunc(100, func() { hits = append(hits, 3) }) 191 AfterFunc(101, func() { hits = append(hits, 4) }) 192 Advance(9) 193 194 // When 195 active := t.Reset(91) 196 197 // Then 198 s.Require().Equal(true, active) 199 200 Advance(90) 201 s.Require().Equal([]int{}, hits) 202 Advance(1) 203 s.Require().Equal([]int{2, 3, 1}, hits) 204 } 205 206 func (s *FrozenSuite) TestTicker() { 207 t := NewTicker(100) 208 209 Advance(99) 210 s.assertNotFired(t.C()) 211 Advance(1) 212 s.Require().Equal(<-t.C(), s.epoch.Add(100)) 213 Advance(750) 214 s.Require().Equal(<-t.C(), s.epoch.Add(200)) 215 Advance(49) 216 s.assertNotFired(t.C()) 217 Advance(1) 218 s.Require().Equal(<-t.C(), s.epoch.Add(900)) 219 220 t.Stop() 221 Advance(300) 222 s.assertNotFired(t.C()) 223 } 224 225 func (s *FrozenSuite) TestTickerZero() { 226 defer func() { 227 _ = recover() 228 }() 229 230 NewTicker(0) 231 s.Fail("Should panic") 232 } 233 234 func (s *FrozenSuite) TestTick() { 235 ch := Tick(100) 236 237 Advance(99) 238 s.assertNotFired(ch) 239 Advance(1) 240 s.Require().Equal(<-ch, s.epoch.Add(100)) 241 Advance(750) 242 s.Require().Equal(<-ch, s.epoch.Add(200)) 243 Advance(49) 244 s.assertNotFired(ch) 245 Advance(1) 246 s.Require().Equal(<-ch, s.epoch.Add(900)) 247 } 248 249 func (s *FrozenSuite) TestTickZero() { 250 ch := Tick(0) 251 s.Require().Nil(ch) 252 } 253 254 func (s *FrozenSuite) TestNewStoppedTimer() { 255 t := NewStoppedTimer() 256 257 // When/Then 258 select { 259 case <-t.C(): 260 s.Fail("Timer should not have fired") 261 default: 262 } 263 s.Require().Equal(false, t.Stop()) 264 } 265 266 func (s *FrozenSuite) TestWait4Scheduled() { 267 After(100 * Millisecond) 268 After(100 * Millisecond) 269 s.Require().Equal(false, Wait4Scheduled(3, 0)) 270 271 startedCh := make(chan struct{}) 272 resultCh := make(chan bool) 273 go func() { 274 close(startedCh) 275 resultCh <- Wait4Scheduled(3, 5*Second) 276 }() 277 // Allow some time for waiter to be set and start waiting for a signal. 278 <-startedCh 279 time.Sleep(50 * Millisecond) 280 281 // When 282 After(100 * Millisecond) 283 284 // Then 285 s.Require().Equal(true, <-resultCh) 286 } 287 288 // If there is enough timers scheduled already, then a shortcut execution path 289 // is taken and Wait4Scheduled returns immediately. 290 func (s *FrozenSuite) TestWait4ScheduledImmediate() { 291 After(100 * Millisecond) 292 After(100 * Millisecond) 293 // When/Then 294 s.Require().Equal(true, Wait4Scheduled(2, 0)) 295 } 296 297 func (s *FrozenSuite) TestSince() { 298 s.Require().Equal(Duration(0), Since(Now())) 299 s.Require().Equal(-Millisecond, Since(Now().Add(Millisecond))) 300 s.Require().Equal(Millisecond, Since(Now().Add(-Millisecond))) 301 } 302 303 func (s *FrozenSuite) TestUntil() { 304 s.Require().Equal(Duration(0), Until(Now())) 305 s.Require().Equal(Millisecond, Until(Now().Add(Millisecond))) 306 s.Require().Equal(-Millisecond, Until(Now().Add(-Millisecond))) 307 } 308 309 func (s *FrozenSuite) assertHits(got <-chan int, want []int) { 310 for i, w := range want { 311 var g int 312 select { 313 case g = <-got: 314 case <-time.After(100 * time.Millisecond): 315 s.Failf("Missing hit", "want=%v", w) 316 return 317 } 318 s.Require().Equal(w, g, "Hit #%d", i) 319 } 320 for { 321 select { 322 case g := <-got: 323 s.Failf("Unexpected hit", "got=%v", g) 324 default: 325 return 326 } 327 } 328 } 329 330 func (s *FrozenSuite) assertNotFired(ch <-chan time.Time) { 331 select { 332 case <-ch: 333 s.Fail("Premature fire") 334 default: 335 } 336 }