github.com/mtsmfm/go/src@v0.0.0-20221020090648-44bdcb9f8fde/time/tick_test.go (about) 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 ( 8 "fmt" 9 "runtime" 10 "testing" 11 . "time" 12 ) 13 14 func TestTicker(t *testing.T) { 15 // We want to test that a ticker takes as much time as expected. 16 // Since we don't want the test to run for too long, we don't 17 // want to use lengthy times. This makes the test inherently flaky. 18 // Start with a short time, but try again with a long one if the 19 // first test fails. 20 21 baseCount := 10 22 baseDelta := 20 * Millisecond 23 24 // On Darwin ARM64 the tick frequency seems limited. Issue 35692. 25 if (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && runtime.GOARCH == "arm64" { 26 // The following test will run ticker count/2 times then reset 27 // the ticker to double the duration for the rest of count/2. 28 // Since tick frequency is limited on Darwin ARM64, use even 29 // number to give the ticks more time to let the test pass. 30 // See CL 220638. 31 baseCount = 6 32 baseDelta = 100 * Millisecond 33 } 34 35 var errs []string 36 logErrs := func() { 37 for _, e := range errs { 38 t.Log(e) 39 } 40 } 41 42 for _, test := range []struct { 43 count int 44 delta Duration 45 }{{ 46 count: baseCount, 47 delta: baseDelta, 48 }, { 49 count: 8, 50 delta: 1 * Second, 51 }} { 52 count, delta := test.count, test.delta 53 ticker := NewTicker(delta) 54 t0 := Now() 55 for i := 0; i < count/2; i++ { 56 <-ticker.C 57 } 58 ticker.Reset(delta * 2) 59 for i := count / 2; i < count; i++ { 60 <-ticker.C 61 } 62 ticker.Stop() 63 t1 := Now() 64 dt := t1.Sub(t0) 65 target := 3 * delta * Duration(count/2) 66 slop := target * 3 / 10 67 if dt < target-slop || dt > target+slop { 68 errs = append(errs, fmt.Sprintf("%d %s ticks then %d %s ticks took %s, expected [%s,%s]", count/2, delta, count/2, delta*2, dt, target-slop, target+slop)) 69 if dt > target+slop { 70 // System may be overloaded; sleep a bit 71 // in the hopes it will recover. 72 Sleep(Second / 2) 73 } 74 continue 75 } 76 // Now test that the ticker stopped. 77 Sleep(2 * delta) 78 select { 79 case <-ticker.C: 80 errs = append(errs, "Ticker did not shut down") 81 continue 82 default: 83 // ok 84 } 85 86 // Test passed, so all done. 87 if len(errs) > 0 { 88 t.Logf("saw %d errors, ignoring to avoid flakiness", len(errs)) 89 logErrs() 90 } 91 92 return 93 } 94 95 t.Errorf("saw %d errors", len(errs)) 96 logErrs() 97 } 98 99 // Issue 21874 100 func TestTickerStopWithDirectInitialization(t *testing.T) { 101 c := make(chan Time) 102 tk := &Ticker{C: c} 103 tk.Stop() 104 } 105 106 // Test that a bug tearing down a ticker has been fixed. This routine should not deadlock. 107 func TestTeardown(t *testing.T) { 108 Delta := 100 * Millisecond 109 if testing.Short() { 110 Delta = 20 * Millisecond 111 } 112 for i := 0; i < 3; i++ { 113 ticker := NewTicker(Delta) 114 <-ticker.C 115 ticker.Stop() 116 } 117 } 118 119 // Test the Tick convenience wrapper. 120 func TestTick(t *testing.T) { 121 // Test that giving a negative duration returns nil. 122 if got := Tick(-1); got != nil { 123 t.Errorf("Tick(-1) = %v; want nil", got) 124 } 125 } 126 127 // Test that NewTicker panics when given a duration less than zero. 128 func TestNewTickerLtZeroDuration(t *testing.T) { 129 defer func() { 130 if err := recover(); err == nil { 131 t.Errorf("NewTicker(-1) should have panicked") 132 } 133 }() 134 NewTicker(-1) 135 } 136 137 // Test that Ticker.Reset panics when given a duration less than zero. 138 func TestTickerResetLtZeroDuration(t *testing.T) { 139 defer func() { 140 if err := recover(); err == nil { 141 t.Errorf("Ticker.Reset(0) should have panicked") 142 } 143 }() 144 tk := NewTicker(Second) 145 tk.Reset(0) 146 } 147 148 func BenchmarkTicker(b *testing.B) { 149 benchmark(b, func(n int) { 150 ticker := NewTicker(Nanosecond) 151 for i := 0; i < n; i++ { 152 <-ticker.C 153 } 154 ticker.Stop() 155 }) 156 } 157 158 func BenchmarkTickerReset(b *testing.B) { 159 benchmark(b, func(n int) { 160 ticker := NewTicker(Nanosecond) 161 for i := 0; i < n; i++ { 162 ticker.Reset(Nanosecond * 2) 163 } 164 ticker.Stop() 165 }) 166 } 167 168 func BenchmarkTickerResetNaive(b *testing.B) { 169 benchmark(b, func(n int) { 170 ticker := NewTicker(Nanosecond) 171 for i := 0; i < n; i++ { 172 ticker.Stop() 173 ticker = NewTicker(Nanosecond * 2) 174 } 175 ticker.Stop() 176 }) 177 }