github.com/rogpeppe/clock@v0.0.0-20190514195947-2896927a307a/testclock/clock_test.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the LGPLv3, see LICENCE file for details. 3 4 package testclock_test 5 6 import ( 7 "bytes" 8 "fmt" 9 "sync" 10 "testing" 11 "time" 12 13 qt "github.com/frankban/quicktest" 14 15 "github.com/rogpeppe/clock/testclock" 16 ) 17 18 func TestNow(t *testing.T) { 19 c := qt.New(t) 20 t0 := time.Now() 21 cl := testclock.NewClock(t0) 22 c.Assert(cl.Now(), qt.Equals, t0) 23 } 24 25 var ( 26 shortWait = 50 * time.Millisecond 27 longWait = time.Second 28 ) 29 30 func TestAdvanceLogs(t *testing.T) { 31 c := qt.New(t) 32 t0 := time.Now() 33 cl := testclock.NewClock(t0) 34 var logBuf bytes.Buffer 35 cl.SetLog(func(msg string) { 36 fmt.Fprintln(&logBuf, msg) 37 }) 38 39 // Shouldn't log anything. 40 tc := cl.After(time.Second) 41 cl.Advance(time.Minute) 42 <-tc 43 c.Check(logBuf.Bytes(), qt.HasLen, 0) 44 45 // Should log since nothing's waiting. 46 cl.Advance(time.Hour) 47 c.Check(logBuf.String(), qt.Equals, "advancing a clock that has nothing waiting: cf. https://github.com/juju/juju/wiki/Intermittent-failures\n") 48 } 49 50 func TestWaitAdvance(t *testing.T) { 51 c := qt.New(t) 52 t0 := time.Now() 53 cl := testclock.NewClock(t0) 54 55 // It is legal to just say 'nothing is waiting' 56 err := cl.WaitAdvance(0, 0, 0) 57 c.Check(err, qt.Equals, nil) 58 59 // Test that no timers errors out. 60 err = cl.WaitAdvance(time.Millisecond, 10*time.Millisecond, 1) 61 c.Check(err, qt.ErrorMatches, "got 0 timers added after waiting 10ms: wanted 1, stacks:\n") 62 63 // Test that a timer doesn't error. 64 _ = cl.After(time.Nanosecond) 65 err = cl.WaitAdvance(time.Millisecond, 10*time.Millisecond, 1) 66 c.Check(err, qt.Equals, nil) 67 } 68 69 func TestAdvanceWithAfter(t *testing.T) { 70 c := qt.New(t) 71 t0 := time.Now() 72 cl := testclock.NewClock(t0) 73 ch := cl.After(time.Second) 74 select { 75 case <-ch: 76 c.Fatalf("received unexpected event") 77 case <-time.After(shortWait): 78 } 79 80 cl.Advance(time.Second - 1) 81 82 select { 83 case <-ch: 84 c.Fatalf("received unexpected event") 85 case <-time.After(shortWait): 86 } 87 88 cl.Advance(1) 89 90 select { 91 case <-ch: 92 case <-time.After(longWait): 93 c.Fatalf("expected event to be triggered") 94 } 95 96 cl.Advance(time.Second) 97 select { 98 case <-ch: 99 c.Fatalf("received unexpected event") 100 case <-time.After(shortWait): 101 } 102 103 // Test that we can do it again 104 ch = cl.After(time.Second) 105 cl.Advance(2 * time.Second) 106 select { 107 case <-ch: 108 case <-time.After(longWait): 109 c.Fatalf("expected event to be triggered") 110 } 111 c.Assert(cl.Now().UTC(), qt.Equals, t0.Add(4*time.Second).UTC()) 112 } 113 114 func TestAdvanceWithAfterFunc(t *testing.T) { 115 c := qt.New(t) 116 // Most of the details have been checked in TestAdvanceWithAfter, 117 // so just check that AfterFunc is wired up correctly. 118 t0 := time.Now() 119 cl := testclock.NewClock(t0) 120 fired := make(chan struct{}) 121 cl.AfterFunc(time.Second, func() { 122 close(fired) 123 }) 124 cl.Advance(2 * time.Second) 125 select { 126 case <-fired: 127 case <-time.After(longWait): 128 c.Fatalf("expected event to be triggered") 129 } 130 } 131 132 func TestAfterFuncStop(t *testing.T) { 133 c := qt.New(t) 134 t0 := time.Now() 135 cl := testclock.NewClock(t0) 136 fired := make(chan struct{}) 137 timer := cl.AfterFunc(time.Second, func() { 138 close(fired) 139 }) 140 cl.Advance(50 * time.Millisecond) 141 timer.Stop() 142 select { 143 case <-fired: 144 c.Fatalf("received unexpected event") 145 case <-time.After(shortWait): 146 } 147 } 148 149 func TestNewTimerReset(t *testing.T) { 150 c := qt.New(t) 151 t0 := time.Now() 152 cl := testclock.NewClock(t0) 153 timer := cl.NewTimer(time.Second) 154 cl.Advance(time.Second) 155 select { 156 case t := <-timer.Chan(): 157 c.Assert(t.UTC(), qt.Equals, t0.Add(time.Second).UTC()) 158 case <-time.After(longWait): 159 c.Fatalf("expected event to be triggered") 160 } 161 162 timer.Reset(50 * time.Millisecond) 163 cl.Advance(100 * time.Millisecond) 164 select { 165 case t := <-timer.Chan(): 166 c.Assert(t.UTC(), qt.Equals, t0.Add(time.Second+100*time.Millisecond).UTC()) 167 case <-time.After(longWait): 168 c.Fatalf("expected event to be triggered") 169 } 170 } 171 172 func TestNewTimerAsyncReset(t *testing.T) { 173 c := qt.New(t) 174 t0 := time.Now() 175 clock := testclock.NewClock(t0) 176 timer := clock.NewTimer(time.Hour) 177 stop := make(chan struct{}) 178 stopped := make(chan struct{}) 179 var wg sync.WaitGroup 180 wg.Add(1) 181 go func() { 182 defer wg.Done() 183 select { 184 case <-stop: 185 case t := <-timer.Chan(): 186 c.Errorf("timer accidentally ticked at: %v", t) 187 case <-time.After(longWait): 188 c.Errorf("test took too long") 189 } 190 close(stopped) 191 }() 192 // Just our goroutine, but we don't go so far as to trigger the wakeup. 193 clock.WaitAdvance(1*time.Minute, 10*time.Millisecond, 1) 194 // Reset shouldn't trigger a wakeup, just move when it thinks it will wake up. 195 timer.Reset(time.Hour) 196 clock.WaitAdvance(1*time.Minute, 10*time.Millisecond, 1) 197 timer.Reset(time.Minute) 198 clock.WaitAdvance(30*time.Second, 10*time.Millisecond, 1) 199 // Now tell the goroutine to stop and start another one that *does* want to 200 // wake up 201 close(stop) 202 select { 203 case <-stopped: 204 case <-time.After(longWait): 205 c.Errorf("goroutine failed to stop") 206 } 207 wg.Add(1) 208 go func() { 209 defer wg.Done() 210 select { 211 case t := <-timer.Chan(): 212 c.Logf("timer successfully ticked: %v", t) 213 case <-time.After(longWait): 214 c.Errorf("timer took too long") 215 } 216 }() 217 // And advance the clock long enough to cause it to notice 218 clock.WaitAdvance(30*time.Second, 10*time.Millisecond, 1) 219 wg.Wait() 220 } 221 222 func TestNewTimerResetCausesWakeup(t *testing.T) { 223 c := qt.New(t) 224 t0 := time.Now() 225 clock := testclock.NewClock(t0) 226 timer1 := clock.NewTimer(time.Hour) 227 timer2 := clock.NewTimer(time.Hour) 228 timer3 := clock.NewTimer(time.Hour) 229 var wg sync.WaitGroup 230 wg.Add(1) 231 go func() { 232 defer wg.Done() 233 select { 234 case t := <-timer1.Chan(): 235 c.Check(t0, qt.Equals, t) 236 case <-time.After(longWait): 237 c.Errorf("timer1 took too long to wake up") 238 } 239 }() 240 wg.Add(1) 241 go func() { 242 defer wg.Done() 243 select { 244 case <-timer2.Chan(): 245 c.Errorf("timer2 should not wake up") 246 case <-time.After(shortWait): 247 c.Logf("timer2 succesfully slept for 50ms") 248 } 249 }() 250 wg.Add(1) 251 go func() { 252 defer wg.Done() 253 select { 254 case t := <-timer3.Chan(): 255 // Even though the reset was negative, it triggers at 'now' 256 c.Check(t0, qt.Equals, t) 257 case <-time.After(longWait): 258 c.Errorf("timer3 took too long to wake up") 259 } 260 }() 261 // Reseting the timer to a time <= 0 should cause it to wake up on its 262 // own, without needing an Advance or WaitAdvance to be done 263 timer1.Reset(0) 264 timer3.Reset(-1 * time.Second) 265 wg.Wait() 266 } 267 268 func TestMultipleWaiters(t *testing.T) { 269 c := qt.New(t) 270 var wg sync.WaitGroup 271 t0 := time.Date(2000, 01, 01, 01, 0, 0, 0, time.UTC) 272 cl := testclock.NewClock(t0) 273 274 total := 0 275 start := func(f func()) { 276 total++ 277 wg.Add(1) 278 go func() { 279 defer wg.Done() 280 f() 281 }() 282 } 283 start(func() { 284 <-cl.After(50 * time.Millisecond) 285 }) 286 start(func() { 287 ch := make(chan struct{}) 288 cl.AfterFunc(100*time.Millisecond, func() { 289 close(ch) 290 }) 291 <-ch 292 }) 293 start(func() { 294 timer := cl.NewTimer(150 * time.Millisecond) 295 <-timer.Chan() 296 timer.Reset(50 * time.Millisecond) 297 <-timer.Chan() 298 }) 299 300 done := make(chan struct{}) 301 go func() { 302 wg.Wait() 303 close(done) 304 }() 305 306 // Wait for all the alarms to be waited on. 307 for i := 0; i < total; i++ { 308 select { 309 case <-cl.Alarms(): 310 case <-time.After(longWait): 311 c.Fatalf("expected a notification on the alarms channel") 312 } 313 } 314 select { 315 case <-cl.Alarms(): 316 c.Fatalf("unexpected extra notification on alarms channel") 317 case <-time.After(shortWait): 318 } 319 320 cl.Advance(150 * time.Millisecond) 321 322 // Wait for the extra notification after reset. 323 select { 324 case <-cl.Alarms(): 325 case <-time.After(longWait): 326 c.Fatalf("expected a notification on the alarms channel") 327 } 328 329 cl.Advance(50 * time.Millisecond) 330 331 select { 332 case <-done: 333 case <-time.After(longWait): 334 c.Fatalf("expected all waits to complete") 335 } 336 337 }