Christopher Wedgwood | 1e66428 | 2010-02-04 13:09:02 -0800 | [diff] [blame] | 1 | // Copyright 2009 The Go Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style |
| 3 | // license that can be found in the LICENSE file. |
| 4 | |
| 5 | package time_test |
| 6 | |
| 7 | import ( |
Russ Cox | eb69292 | 2011-11-01 22:05:34 -0400 | [diff] [blame] | 8 | "errors" |
Andrew Gerrand | d54c4ec | 2011-03-30 11:40:00 +1100 | [diff] [blame] | 9 | "fmt" |
Dmitriy Vyukov | dc6726b | 2011-11-14 21:59:48 +0300 | [diff] [blame] | 10 | "runtime" |
Roger Peppe | e2d1595 | 2010-12-06 14:19:30 -0500 | [diff] [blame] | 11 | "sort" |
Dmitriy Vyukov | dc6726b | 2011-11-14 21:59:48 +0300 | [diff] [blame] | 12 | "sync/atomic" |
Russ Cox | 965845a | 2011-11-02 15:54:16 -0400 | [diff] [blame] | 13 | "testing" |
Christopher Wedgwood | 1e66428 | 2010-02-04 13:09:02 -0800 | [diff] [blame] | 14 | . "time" |
| 15 | ) |
| 16 | |
| 17 | func TestSleep(t *testing.T) { |
Russ Cox | efe3d35 | 2011-11-30 11:59:44 -0500 | [diff] [blame] | 18 | const delay = 100 * Millisecond |
Christopher Wedgwood | 1e66428 | 2010-02-04 13:09:02 -0800 | [diff] [blame] | 19 | go func() { |
| 20 | Sleep(delay / 2) |
Russ Cox | 75d337e | 2011-08-26 15:15:23 -0400 | [diff] [blame] | 21 | Interrupt() |
Christopher Wedgwood | 1e66428 | 2010-02-04 13:09:02 -0800 | [diff] [blame] | 22 | }() |
Russ Cox | efe3d35 | 2011-11-30 11:59:44 -0500 | [diff] [blame] | 23 | start := Now() |
Christopher Wedgwood | 1e66428 | 2010-02-04 13:09:02 -0800 | [diff] [blame] | 24 | Sleep(delay) |
Russ Cox | efe3d35 | 2011-11-30 11:59:44 -0500 | [diff] [blame] | 25 | duration := Now().Sub(start) |
Christopher Wedgwood | 1e66428 | 2010-02-04 13:09:02 -0800 | [diff] [blame] | 26 | if duration < delay { |
Russ Cox | efe3d35 | 2011-11-30 11:59:44 -0500 | [diff] [blame] | 27 | t.Fatalf("Sleep(%s) slept for only %s", delay, duration) |
Christopher Wedgwood | 1e66428 | 2010-02-04 13:09:02 -0800 | [diff] [blame] | 28 | } |
| 29 | } |
Andrew Gerrand | 1e66a21 | 2010-10-11 13:45:26 +1100 | [diff] [blame] | 30 | |
Roger Peppe | 212e074 | 2011-01-10 11:51:38 -0800 | [diff] [blame] | 31 | // Test the basic function calling behavior. Correct queueing |
| 32 | // behavior is tested elsewhere, since After and AfterFunc share |
| 33 | // the same code. |
| 34 | func TestAfterFunc(t *testing.T) { |
| 35 | i := 10 |
| 36 | c := make(chan bool) |
| 37 | var f func() |
| 38 | f = func() { |
| 39 | i-- |
| 40 | if i >= 0 { |
| 41 | AfterFunc(0, f) |
David Symonds | 2949f3b | 2011-12-08 15:42:44 +1100 | [diff] [blame] | 42 | Sleep(1 * Second) |
Roger Peppe | 212e074 | 2011-01-10 11:51:38 -0800 | [diff] [blame] | 43 | } else { |
| 44 | c <- true |
| 45 | } |
| 46 | } |
| 47 | |
| 48 | AfterFunc(0, f) |
| 49 | <-c |
| 50 | } |
| 51 | |
Dmitriy Vyukov | dc6726b | 2011-11-14 21:59:48 +0300 | [diff] [blame] | 52 | func TestAfterStress(t *testing.T) { |
| 53 | stop := uint32(0) |
| 54 | go func() { |
| 55 | for atomic.LoadUint32(&stop) == 0 { |
| 56 | runtime.GC() |
Alex Brainman | e0aa26a | 2013-01-18 15:31:01 +1100 | [diff] [blame] | 57 | // Yield so that the OS can wake up the timer thread, |
| 58 | // so that it can generate channel sends for the main goroutine, |
| 59 | // which will eventually set stop = 1 for us. |
| 60 | Sleep(Nanosecond) |
Dmitriy Vyukov | dc6726b | 2011-11-14 21:59:48 +0300 | [diff] [blame] | 61 | } |
| 62 | }() |
| 63 | c := Tick(1) |
| 64 | for i := 0; i < 100; i++ { |
| 65 | <-c |
| 66 | } |
| 67 | atomic.StoreUint32(&stop, 1) |
| 68 | } |
| 69 | |
Roger Peppe | 212e074 | 2011-01-10 11:51:38 -0800 | [diff] [blame] | 70 | func BenchmarkAfterFunc(b *testing.B) { |
| 71 | i := b.N |
| 72 | c := make(chan bool) |
| 73 | var f func() |
| 74 | f = func() { |
| 75 | i-- |
| 76 | if i >= 0 { |
| 77 | AfterFunc(0, f) |
| 78 | } else { |
| 79 | c <- true |
| 80 | } |
| 81 | } |
| 82 | |
| 83 | AfterFunc(0, f) |
| 84 | <-c |
| 85 | } |
| 86 | |
Roger Peppe | 2ae953b | 2011-01-25 12:25:48 -0800 | [diff] [blame] | 87 | func BenchmarkAfter(b *testing.B) { |
| 88 | for i := 0; i < b.N; i++ { |
| 89 | <-After(1) |
| 90 | } |
| 91 | } |
| 92 | |
| 93 | func BenchmarkStop(b *testing.B) { |
| 94 | for i := 0; i < b.N; i++ { |
David Symonds | 2949f3b | 2011-12-08 15:42:44 +1100 | [diff] [blame] | 95 | NewTimer(1 * Second).Stop() |
Roger Peppe | 2ae953b | 2011-01-25 12:25:48 -0800 | [diff] [blame] | 96 | } |
| 97 | } |
| 98 | |
Andrew Gerrand | 1e66a21 | 2010-10-11 13:45:26 +1100 | [diff] [blame] | 99 | func TestAfter(t *testing.T) { |
Russ Cox | efe3d35 | 2011-11-30 11:59:44 -0500 | [diff] [blame] | 100 | const delay = 100 * Millisecond |
| 101 | start := Now() |
Andrew Gerrand | 1e66a21 | 2010-10-11 13:45:26 +1100 | [diff] [blame] | 102 | end := <-After(delay) |
Russ Cox | efe3d35 | 2011-11-30 11:59:44 -0500 | [diff] [blame] | 103 | if duration := Now().Sub(start); duration < delay { |
| 104 | t.Fatalf("After(%s) slept for only %d ns", delay, duration) |
Andrew Gerrand | 1e66a21 | 2010-10-11 13:45:26 +1100 | [diff] [blame] | 105 | } |
Russ Cox | efe3d35 | 2011-11-30 11:59:44 -0500 | [diff] [blame] | 106 | if min := start.Add(delay); end.Before(min) { |
| 107 | t.Fatalf("After(%s) expect >= %s, got %s", delay, min, end) |
Andrew Gerrand | 1e66a21 | 2010-10-11 13:45:26 +1100 | [diff] [blame] | 108 | } |
| 109 | } |
Roger Peppe | e2d1595 | 2010-12-06 14:19:30 -0500 | [diff] [blame] | 110 | |
| 111 | func TestAfterTick(t *testing.T) { |
Rémy Oudompheng | 2a6e699 | 2012-02-14 22:13:19 +0100 | [diff] [blame] | 112 | const Count = 10 |
| 113 | Delta := 100 * Millisecond |
| 114 | if testing.Short() { |
| 115 | Delta = 10 * Millisecond |
| 116 | } |
Russ Cox | efe3d35 | 2011-11-30 11:59:44 -0500 | [diff] [blame] | 117 | t0 := Now() |
Roger Peppe | e2d1595 | 2010-12-06 14:19:30 -0500 | [diff] [blame] | 118 | for i := 0; i < Count; i++ { |
| 119 | <-After(Delta) |
| 120 | } |
Russ Cox | efe3d35 | 2011-11-30 11:59:44 -0500 | [diff] [blame] | 121 | t1 := Now() |
| 122 | d := t1.Sub(t0) |
| 123 | target := Delta * Count |
Brad Fitzpatrick | 8c52905 | 2012-02-29 13:14:05 -0800 | [diff] [blame] | 124 | if d < target*9/10 { |
| 125 | t.Fatalf("%d ticks of %s too fast: took %s, expected %s", Count, Delta, d, target) |
| 126 | } |
| 127 | if !testing.Short() && d > target*30/10 { |
| 128 | t.Fatalf("%d ticks of %s too slow: took %s, expected %s", Count, Delta, d, target) |
Roger Peppe | e2d1595 | 2010-12-06 14:19:30 -0500 | [diff] [blame] | 129 | } |
| 130 | } |
| 131 | |
Roger Peppe | 2ae953b | 2011-01-25 12:25:48 -0800 | [diff] [blame] | 132 | func TestAfterStop(t *testing.T) { |
David Symonds | 2949f3b | 2011-12-08 15:42:44 +1100 | [diff] [blame] | 133 | AfterFunc(100*Millisecond, func() {}) |
| 134 | t0 := NewTimer(50 * Millisecond) |
Roger Peppe | 2ae953b | 2011-01-25 12:25:48 -0800 | [diff] [blame] | 135 | c1 := make(chan bool, 1) |
David Symonds | 2949f3b | 2011-12-08 15:42:44 +1100 | [diff] [blame] | 136 | t1 := AfterFunc(150*Millisecond, func() { c1 <- true }) |
| 137 | c2 := After(200 * Millisecond) |
Roger Peppe | 2ae953b | 2011-01-25 12:25:48 -0800 | [diff] [blame] | 138 | if !t0.Stop() { |
| 139 | t.Fatalf("failed to stop event 0") |
| 140 | } |
| 141 | if !t1.Stop() { |
| 142 | t.Fatalf("failed to stop event 1") |
| 143 | } |
| 144 | <-c2 |
Russ Cox | f4e76d8 | 2011-01-31 18:36:28 -0500 | [diff] [blame] | 145 | select { |
| 146 | case <-t0.C: |
| 147 | t.Fatalf("event 0 was not stopped") |
| 148 | case <-c1: |
| 149 | t.Fatalf("event 1 was not stopped") |
| 150 | default: |
Roger Peppe | 2ae953b | 2011-01-25 12:25:48 -0800 | [diff] [blame] | 151 | } |
| 152 | if t1.Stop() { |
| 153 | t.Fatalf("Stop returned true twice") |
| 154 | } |
| 155 | } |
| 156 | |
Andrew Gerrand | d54c4ec | 2011-03-30 11:40:00 +1100 | [diff] [blame] | 157 | func TestAfterQueuing(t *testing.T) { |
| 158 | // This test flakes out on some systems, |
| 159 | // so we'll try it a few times before declaring it a failure. |
| 160 | const attempts = 3 |
Russ Cox | eb69292 | 2011-11-01 22:05:34 -0400 | [diff] [blame] | 161 | err := errors.New("!=nil") |
Andrew Gerrand | d54c4ec | 2011-03-30 11:40:00 +1100 | [diff] [blame] | 162 | for i := 0; i < attempts && err != nil; i++ { |
| 163 | if err = testAfterQueuing(t); err != nil { |
| 164 | t.Logf("attempt %v failed: %v", i, err) |
| 165 | } |
| 166 | } |
| 167 | if err != nil { |
| 168 | t.Fatal(err) |
| 169 | } |
| 170 | } |
| 171 | |
Roger Peppe | e2d1595 | 2010-12-06 14:19:30 -0500 | [diff] [blame] | 172 | var slots = []int{5, 3, 6, 6, 6, 1, 1, 2, 7, 9, 4, 8, 0} |
| 173 | |
| 174 | type afterResult struct { |
| 175 | slot int |
Russ Cox | efe3d35 | 2011-11-30 11:59:44 -0500 | [diff] [blame] | 176 | t Time |
Roger Peppe | e2d1595 | 2010-12-06 14:19:30 -0500 | [diff] [blame] | 177 | } |
| 178 | |
Russ Cox | efe3d35 | 2011-11-30 11:59:44 -0500 | [diff] [blame] | 179 | func await(slot int, result chan<- afterResult, ac <-chan Time) { |
Roger Peppe | e2d1595 | 2010-12-06 14:19:30 -0500 | [diff] [blame] | 180 | result <- afterResult{slot, <-ac} |
| 181 | } |
| 182 | |
Russ Cox | eb69292 | 2011-11-01 22:05:34 -0400 | [diff] [blame] | 183 | func testAfterQueuing(t *testing.T) error { |
Rémy Oudompheng | 2a6e699 | 2012-02-14 22:13:19 +0100 | [diff] [blame] | 184 | Delta := 100 * Millisecond |
| 185 | if testing.Short() { |
| 186 | Delta = 20 * Millisecond |
| 187 | } |
Roger Peppe | e2d1595 | 2010-12-06 14:19:30 -0500 | [diff] [blame] | 188 | // make the result channel buffered because we don't want |
| 189 | // to depend on channel queueing semantics that might |
| 190 | // possibly change in the future. |
| 191 | result := make(chan afterResult, len(slots)) |
| 192 | |
Russ Cox | efe3d35 | 2011-11-30 11:59:44 -0500 | [diff] [blame] | 193 | t0 := Now() |
Roger Peppe | e2d1595 | 2010-12-06 14:19:30 -0500 | [diff] [blame] | 194 | for _, slot := range slots { |
Russ Cox | efe3d35 | 2011-11-30 11:59:44 -0500 | [diff] [blame] | 195 | go await(slot, result, After(Duration(slot)*Delta)) |
Roger Peppe | e2d1595 | 2010-12-06 14:19:30 -0500 | [diff] [blame] | 196 | } |
Andrew Gerrand | 5bcbcab3 | 2011-07-08 10:52:50 +1000 | [diff] [blame] | 197 | sort.Ints(slots) |
Roger Peppe | e2d1595 | 2010-12-06 14:19:30 -0500 | [diff] [blame] | 198 | for _, slot := range slots { |
| 199 | r := <-result |
| 200 | if r.slot != slot { |
Russ Cox | efe3d35 | 2011-11-30 11:59:44 -0500 | [diff] [blame] | 201 | return fmt.Errorf("after slot %d, expected %d", r.slot, slot) |
Roger Peppe | e2d1595 | 2010-12-06 14:19:30 -0500 | [diff] [blame] | 202 | } |
Russ Cox | efe3d35 | 2011-11-30 11:59:44 -0500 | [diff] [blame] | 203 | dt := r.t.Sub(t0) |
| 204 | target := Duration(slot) * Delta |
Russ Cox | fc7b9fc | 2011-12-12 18:33:47 -0500 | [diff] [blame] | 205 | if dt < target-Delta/2 || dt > target+Delta*10 { |
| 206 | return fmt.Errorf("After(%s) arrived at %s, expected [%s,%s]", target, dt, target-Delta/2, target+Delta*10) |
Roger Peppe | e2d1595 | 2010-12-06 14:19:30 -0500 | [diff] [blame] | 207 | } |
| 208 | } |
Andrew Gerrand | d54c4ec | 2011-03-30 11:40:00 +1100 | [diff] [blame] | 209 | return nil |
Roger Peppe | e2d1595 | 2010-12-06 14:19:30 -0500 | [diff] [blame] | 210 | } |
Dmitriy Vyukov | a899a46 | 2011-11-25 14:13:10 +0300 | [diff] [blame] | 211 | |
| 212 | func TestTimerStopStress(t *testing.T) { |
| 213 | if testing.Short() { |
| 214 | return |
| 215 | } |
| 216 | for i := 0; i < 100; i++ { |
| 217 | go func(i int) { |
David Symonds | 2949f3b | 2011-12-08 15:42:44 +1100 | [diff] [blame] | 218 | timer := AfterFunc(2*Second, func() { |
Dmitriy Vyukov | a899a46 | 2011-11-25 14:13:10 +0300 | [diff] [blame] | 219 | t.Fatalf("timer %d was not stopped", i) |
| 220 | }) |
David Symonds | 2949f3b | 2011-12-08 15:42:44 +1100 | [diff] [blame] | 221 | Sleep(1 * Second) |
Dmitriy Vyukov | a899a46 | 2011-11-25 14:13:10 +0300 | [diff] [blame] | 222 | timer.Stop() |
| 223 | }(i) |
| 224 | } |
David Symonds | 2949f3b | 2011-12-08 15:42:44 +1100 | [diff] [blame] | 225 | Sleep(3 * Second) |
Dmitriy Vyukov | a899a46 | 2011-11-25 14:13:10 +0300 | [diff] [blame] | 226 | } |
Dmitriy Vyukov | a0efca8 | 2012-05-29 22:30:56 +0400 | [diff] [blame] | 227 | |
| 228 | func TestSleepZeroDeadlock(t *testing.T) { |
| 229 | // Sleep(0) used to hang, the sequence of events was as follows. |
| 230 | // Sleep(0) sets G's status to Gwaiting, but then immediately returns leaving the status. |
| 231 | // Then the goroutine calls e.g. new and falls down into the scheduler due to pending GC. |
| 232 | // After the GC nobody wakes up the goroutine from Gwaiting status. |
| 233 | defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) |
| 234 | c := make(chan bool) |
| 235 | go func() { |
| 236 | for i := 0; i < 100; i++ { |
| 237 | runtime.GC() |
| 238 | } |
| 239 | c <- true |
| 240 | }() |
| 241 | for i := 0; i < 100; i++ { |
| 242 | Sleep(0) |
| 243 | tmp := make(chan bool, 1) |
| 244 | tmp <- true |
| 245 | <-tmp |
| 246 | } |
| 247 | <-c |
| 248 | } |
Volker Dobler | 44ff17e | 2013-01-17 14:41:53 +1100 | [diff] [blame] | 249 | |
Brad Fitzpatrick | 86a8d59 | 2013-01-22 17:25:58 -0800 | [diff] [blame] | 250 | func testReset(d Duration) error { |
| 251 | t0 := NewTimer(2 * d) |
| 252 | Sleep(d) |
| 253 | if t0.Reset(3*d) != true { |
| 254 | return errors.New("resetting unfired timer returned false") |
Volker Dobler | 44ff17e | 2013-01-17 14:41:53 +1100 | [diff] [blame] | 255 | } |
Brad Fitzpatrick | 86a8d59 | 2013-01-22 17:25:58 -0800 | [diff] [blame] | 256 | Sleep(2 * d) |
Volker Dobler | 44ff17e | 2013-01-17 14:41:53 +1100 | [diff] [blame] | 257 | select { |
| 258 | case <-t0.C: |
Brad Fitzpatrick | 86a8d59 | 2013-01-22 17:25:58 -0800 | [diff] [blame] | 259 | return errors.New("timer fired early") |
Volker Dobler | 44ff17e | 2013-01-17 14:41:53 +1100 | [diff] [blame] | 260 | default: |
| 261 | } |
Brad Fitzpatrick | 86a8d59 | 2013-01-22 17:25:58 -0800 | [diff] [blame] | 262 | Sleep(2 * d) |
Volker Dobler | 44ff17e | 2013-01-17 14:41:53 +1100 | [diff] [blame] | 263 | select { |
| 264 | case <-t0.C: |
| 265 | default: |
Brad Fitzpatrick | 86a8d59 | 2013-01-22 17:25:58 -0800 | [diff] [blame] | 266 | return errors.New("reset timer did not fire") |
Volker Dobler | 44ff17e | 2013-01-17 14:41:53 +1100 | [diff] [blame] | 267 | } |
| 268 | |
| 269 | if t0.Reset(50*Millisecond) != false { |
Brad Fitzpatrick | 86a8d59 | 2013-01-22 17:25:58 -0800 | [diff] [blame] | 270 | return errors.New("resetting expired timer returned true") |
Volker Dobler | 44ff17e | 2013-01-17 14:41:53 +1100 | [diff] [blame] | 271 | } |
Brad Fitzpatrick | 86a8d59 | 2013-01-22 17:25:58 -0800 | [diff] [blame] | 272 | return nil |
| 273 | } |
| 274 | |
| 275 | func TestReset(t *testing.T) { |
| 276 | // We try to run this test with increasingly larger multiples |
| 277 | // until one works so slow, loaded hardware isn't as flaky, |
| 278 | // but without slowing down fast machines unnecessarily. |
| 279 | const unit = 25 * Millisecond |
| 280 | tries := []Duration{ |
| 281 | 1 * unit, |
| 282 | 3 * unit, |
| 283 | 7 * unit, |
| 284 | 15 * unit, |
| 285 | } |
| 286 | var err error |
| 287 | for _, d := range tries { |
| 288 | err = testReset(d) |
| 289 | if err == nil { |
| 290 | t.Logf("passed using duration %v", d) |
| 291 | return |
| 292 | } |
| 293 | } |
| 294 | t.Error(err) |
Volker Dobler | 44ff17e | 2013-01-17 14:41:53 +1100 | [diff] [blame] | 295 | } |
Andrew Gerrand | 89cf67e | 2013-02-26 09:23:58 +1100 | [diff] [blame] | 296 | |
| 297 | // Test that sleeping for an interval so large it overflows does not |
| 298 | // result in a short sleep duration. |
| 299 | func TestOverflowSleep(t *testing.T) { |
| 300 | const timeout = 25 * Millisecond |
| 301 | const big = Duration(int64(1<<63 - 1)) |
| 302 | select { |
| 303 | case <-After(big): |
| 304 | t.Fatalf("big timeout fired") |
| 305 | case <-After(timeout): |
| 306 | // OK |
| 307 | } |
| 308 | const neg = Duration(-1 << 63) |
| 309 | select { |
| 310 | case <-After(neg): |
| 311 | // OK |
| 312 | case <-After(timeout): |
| 313 | t.Fatalf("negative timeout didn't fire") |
| 314 | } |
| 315 | } |