github.com/juju/clock@v1.0.3/testclock/dilated_test.go (about) 1 // Copyright 2022 Canonical Ltd. 2 // Licensed under the LGPLv3, see LICENCE file for details. 3 4 package testclock_test 5 6 import ( 7 "math/rand" 8 "runtime" 9 "sync" 10 "time" 11 12 "github.com/juju/clock" 13 "github.com/juju/testing" 14 jc "github.com/juju/testing/checkers" 15 gc "gopkg.in/check.v1" 16 17 "github.com/juju/clock/testclock" 18 ) 19 20 const ( 21 halfSecond = 500 * time.Millisecond 22 doubleSecond = 2 * time.Second 23 ) 24 25 type dilatedClockSuite struct { 26 testing.LoggingSuite 27 } 28 29 var _ = gc.Suite(&dilatedClockSuite{}) 30 31 func (*dilatedClockSuite) TestSlowedAfter(c *gc.C) { 32 cl := testclock.NewDilatedWallClock(doubleSecond) 33 t0 := time.Now() 34 d0 := cl.Now() 35 d1 := <-cl.After(time.Second) 36 t1 := time.Now() 37 c.Assert(t1.Sub(t0).Seconds(), jc.GreaterThan, 1.9) 38 c.Assert(d1.Sub(d0).Seconds(), jc.GreaterThan, 0.9) 39 c.Assert(d1.Sub(d0).Seconds(), jc.LessThan, 1.1) 40 } 41 42 func (*dilatedClockSuite) TestFastAfter(c *gc.C) { 43 cl := testclock.NewDilatedWallClock(halfSecond) 44 t0 := time.Now() 45 d0 := cl.Now() 46 d1 := <-cl.After(time.Second) 47 t1 := time.Now() 48 c.Assert(t1.Sub(t0).Milliseconds(), jc.LessThan, 600) 49 c.Assert(d1.Sub(d0).Milliseconds(), jc.GreaterThan, 990) 50 c.Assert(d1.Sub(d0).Milliseconds(), jc.LessThan, 1010) 51 } 52 53 func (*dilatedClockSuite) TestSlowedAfterFunc(c *gc.C) { 54 t0 := time.Now() 55 cl := testclock.NewDilatedWallClock(doubleSecond) 56 mut := sync.Mutex{} 57 mut.Lock() 58 cl.AfterFunc(time.Second, func() { 59 defer mut.Unlock() 60 c.Check(time.Since(t0).Seconds(), jc.GreaterThan, 1.9) 61 }) 62 mut.Lock() 63 } 64 65 func (*dilatedClockSuite) TestFastAfterFunc(c *gc.C) { 66 t0 := time.Now() 67 cl := testclock.NewDilatedWallClock(halfSecond) 68 mut := sync.Mutex{} 69 mut.Lock() 70 cl.AfterFunc(time.Second, func() { 71 defer mut.Unlock() 72 c.Check(time.Since(t0).Milliseconds(), jc.LessThan, 600) 73 }) 74 mut.Lock() 75 } 76 77 func (*dilatedClockSuite) TestSlowedNow(c *gc.C) { 78 t0 := time.Now() 79 cl := testclock.NewDilatedWallClock(doubleSecond) 80 <-time.After(time.Second) 81 t2 := cl.Now() 82 c.Assert(t2.Sub(t0).Milliseconds(), jc.GreaterThan, 400) 83 c.Assert(t2.Sub(t0).Milliseconds(), jc.LessThan, 600) 84 <-time.After(time.Second) 85 t3 := cl.Now() 86 c.Assert(t3.Sub(t0).Milliseconds(), jc.GreaterThan, 900) 87 c.Assert(t3.Sub(t0).Milliseconds(), jc.LessThan, 1100) 88 } 89 90 func (*dilatedClockSuite) TestFastNow(c *gc.C) { 91 t0 := time.Now() 92 cl := testclock.NewDilatedWallClock(halfSecond) 93 <-time.After(time.Second) 94 t2 := cl.Now() 95 c.Assert(t2.Sub(t0).Milliseconds(), jc.GreaterThan, 1900) 96 c.Assert(t2.Sub(t0).Milliseconds(), jc.LessThan, 2100) 97 <-time.After(time.Second) 98 t3 := cl.Now() 99 c.Assert(t3.Sub(t0).Milliseconds(), jc.GreaterThan, 3900) 100 c.Assert(t3.Sub(t0).Milliseconds(), jc.LessThan, 4100) 101 } 102 103 func (*dilatedClockSuite) TestAdvance(c *gc.C) { 104 t0 := time.Now() 105 cl := testclock.NewDilatedWallClock(halfSecond) 106 first := cl.After(time.Second) 107 cl.Advance(halfSecond) 108 <-time.After(250 * time.Millisecond) 109 select { 110 case t := <-first: 111 c.Assert(t.Sub(t0).Milliseconds(), jc.GreaterThan, 249) 112 case <-time.After(shortWait): 113 c.Fatal("timer failed to trigger early") 114 } 115 } 116 117 func (*dilatedClockSuite) TestAdvanceMulti(c *gc.C) { 118 cl := testclock.NewDilatedWallClock(halfSecond) 119 first := cl.After(time.Second) 120 second := cl.After(2 * time.Second) 121 third := cl.After(1 * time.Hour) 122 123 done := time.After(longWait) 124 fourth := cl.After(12*time.Hour + longWait*2 + time.Second) 125 126 cl.Advance(12 * time.Hour) 127 128 n := 0 129 out: 130 for { 131 select { 132 case <-first: 133 n++ 134 case <-second: 135 n++ 136 case <-third: 137 n++ 138 case <-fourth: 139 c.Fatal("timer that fired that should not have") 140 case <-done: 141 break out 142 } 143 } 144 c.Assert(n, gc.Equals, 3) 145 } 146 147 func (*dilatedClockSuite) TestStop(c *gc.C) { 148 numGo := runtime.NumGoroutine() 149 cl := testclock.NewDilatedWallClock(halfSecond) 150 a := cl.NewTimer(time.Second) 151 time.Sleep(shortWait) 152 ok := a.Stop() 153 c.Assert(ok, jc.IsTrue) 154 ok = a.Stop() 155 c.Assert(ok, jc.IsFalse) 156 select { 157 case <-a.Chan(): 158 c.Fatal("stopped clock fired") 159 case <-time.After(time.Second): 160 } 161 for i := 0; i < 3; i++ { 162 if runtime.NumGoroutine() == numGo { 163 break 164 } 165 time.Sleep(shortWait) 166 } 167 c.Assert(runtime.NumGoroutine(), gc.Equals, numGo, gc.Commentf("clock goroutine still running")) 168 } 169 170 func (*dilatedClockSuite) TestReset(c *gc.C) { 171 numGo := runtime.NumGoroutine() 172 cl := testclock.NewDilatedWallClock(halfSecond) 173 a := cl.NewTimer(time.Second) 174 time.Sleep(250 * time.Millisecond) 175 ok := a.Reset(time.Second) 176 c.Assert(ok, jc.IsTrue) 177 <-time.After(halfSecond) 178 select { 179 case <-a.Chan(): 180 case <-time.After(shortWait): 181 c.Fatal("timer did not fire") 182 } 183 for i := 0; i < 3; i++ { 184 if runtime.NumGoroutine() == numGo { 185 break 186 } 187 time.Sleep(shortWait) 188 } 189 c.Assert(runtime.NumGoroutine(), gc.Equals, numGo, gc.Commentf("clock goroutine still running")) 190 } 191 192 func (*dilatedClockSuite) TestStopReset(c *gc.C) { 193 numGo := runtime.NumGoroutine() 194 cl := testclock.NewDilatedWallClock(halfSecond) 195 a := cl.NewTimer(time.Second) 196 time.Sleep(250 * time.Millisecond) 197 ok := a.Stop() 198 c.Assert(ok, jc.IsTrue) 199 ok = a.Reset(time.Second) 200 c.Assert(ok, jc.IsTrue) 201 <-time.After(halfSecond) 202 select { 203 case <-a.Chan(): 204 case <-time.After(shortWait): 205 c.Fatal("timer did not fire") 206 } 207 for i := 0; i < 3; i++ { 208 if runtime.NumGoroutine() == numGo { 209 break 210 } 211 time.Sleep(shortWait) 212 } 213 c.Assert(runtime.NumGoroutine(), gc.Equals, numGo, gc.Commentf("clock goroutine still running")) 214 } 215 216 func (*dilatedClockSuite) TestAdvanceAlreadyFired(c *gc.C) { 217 numGo := runtime.NumGoroutine() 218 cl := testclock.NewDilatedWallClock(time.Second) 219 t := cl.NewTimer(time.Millisecond) 220 time.Sleep(shortWait) 221 cl.Advance(time.Second) 222 select { 223 case <-t.Chan(): 224 case <-time.After(shortWait): 225 c.Fatal("timer did not fire") 226 } 227 for i := 0; i < 3; i++ { 228 if runtime.NumGoroutine() == numGo { 229 break 230 } 231 time.Sleep(shortWait) 232 } 233 c.Assert(runtime.NumGoroutine(), gc.Equals, numGo, gc.Commentf("clock goroutine still running")) 234 } 235 236 func (*dilatedClockSuite) TestAdvanceFast(c *gc.C) { 237 cl := testclock.NewDilatedWallClock(time.Minute) 238 timers := make([]clock.Timer, 0, 1000) 239 for i := time.Millisecond; i <= time.Second; i += time.Millisecond { 240 timers = append(timers, cl.NewTimer(i)) 241 } 242 for i := 0; i < 10000; i++ { 243 cl.Advance(100 * time.Microsecond) 244 } 245 deadline := time.After(10 * time.Second) 246 for _, timer := range timers { 247 select { 248 case <-timer.Chan(): 249 case <-deadline: 250 c.Fatal("timer did not fire by deadline") 251 } 252 } 253 } 254 255 func (*dilatedClockSuite) TestAdvanceReset(c *gc.C) { 256 cl := testclock.NewDilatedWallClock(time.Minute) 257 timers := make([]clock.Timer, 0, 10) 258 for i := 0; i < 10; i++ { 259 timers = append(timers, cl.NewTimer(time.Millisecond)) 260 } 261 deadline := time.After(10 * time.Second) 262 for i := 0; i < 1000; i++ { 263 cl.Advance(time.Millisecond) 264 for _, timer := range timers { 265 select { 266 case <-timer.Chan(): 267 case <-deadline: 268 c.Fatal("timer did not fire by deadline") 269 } 270 timer.Reset(time.Millisecond) 271 } 272 } 273 } 274 275 func (*dilatedClockSuite) TestAdvanceResetRacey(c *gc.C) { 276 cl := testclock.NewDilatedWallClock(time.Second) 277 timers := make([]clock.Timer, 0, 10) 278 for i := 0; i < 10; i++ { 279 timers = append(timers, cl.NewTimer(time.Millisecond)) 280 } 281 deadline := time.After(2 * time.Second) 282 for i := 0; i < 1000; i++ { 283 time.Sleep(999 * time.Microsecond) 284 cl.Advance(time.Microsecond * time.Duration(rand.Intn(2))) 285 for _, timer := range timers { 286 select { 287 case <-timer.Chan(): 288 case <-deadline: 289 c.Fatal("timer did not fire by deadline") 290 } 291 timer.Reset(time.Millisecond) 292 } 293 } 294 }