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