func TestAdvanceWithUpdateOffset(t *testing.T) { offset := time.Duration(10) * time.Second last := time.Unix(0, 0) mock := clock.NewMock() mock.Add(time.Duration(1) * time.Hour) desiredLast := mock.Now().Add(-offset) ticker := NewTicker(last, offset, mock) last = assertAdvanceUntil(ticker, last, desiredLast, offset, time.Duration(10)*time.Millisecond, t) assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t) // lowering offset should see a few more ticks offset = time.Duration(5) * time.Second ticker.updateOffset(offset) desiredLast = mock.Now().Add(-offset) last = assertAdvanceUntil(ticker, last, desiredLast, offset, time.Duration(9)*time.Millisecond, t) assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t) // advancing clock should see even more ticks mock.Add(time.Duration(1) * time.Hour) desiredLast = mock.Now().Add(-offset) last = assertAdvanceUntil(ticker, last, desiredLast, offset, time.Duration(8)*time.Millisecond, t) assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t) }
func TestTickerNoAdvance(t *testing.T) { // it's 00:01:00 now. what are some cases where we don't want the ticker to advance? mock := clock.NewMock() mock.Add(time.Duration(60) * time.Second) type Case struct { last int offset int } // note that some cases add up to now, others go into the future cases := []Case{ {50, 10}, {50, 30}, {59, 1}, {59, 10}, {59, 30}, {60, 1}, {60, 10}, {60, 30}, {90, 1}, {90, 10}, {90, 30}, } for _, c := range cases { last, offset := getCase(c.last, c.offset) ticker := NewTicker(last, offset, mock) assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t) } }
// Ensure that multiple tickers can be used together. func TestMock_Ticker_Multi(t *testing.T) { var n int32 clock := clock.NewMock() go func() { a := clock.Ticker(1 * time.Microsecond) b := clock.Ticker(3 * time.Microsecond) for { select { case <-a.C: atomic.AddInt32(&n, 1) case <-b.C: atomic.AddInt32(&n, 100) } } }() gosched() // Move clock forward. clock.Add(10 * time.Microsecond) gosched() if atomic.LoadInt32(&n) != 310 { t.Fatalf("unexpected: %d", n) } }
// Ensure that the mock's Ticker can be stopped. func TestMock_Ticker_Stop(t *testing.T) { var n int32 clock := clock.NewMock() // Create a channel to increment every second. ticker := clock.Ticker(1 * time.Second) go func() { for { <-ticker.C atomic.AddInt32(&n, 1) } }() gosched() // Move clock forward. clock.Add(5 * time.Second) if atomic.LoadInt32(&n) != 5 { t.Fatalf("expected 5, got: %d", n) } ticker.Stop() // Move clock forward again. clock.Add(5 * time.Second) if atomic.LoadInt32(&n) != 5 { t.Fatalf("still expected 5, got: %d", n) } }
func ExampleMock_Ticker() { // Create a new mock clock. clock := clock.NewMock() count := 0 // Increment count every mock second. go func() { ticker := clock.Ticker(1 * time.Second) for { <-ticker.C count++ } }() runtime.Gosched() // Move the clock forward 10 seconds and print the new value. clock.Add(10 * time.Second) fmt.Printf("Count is %d after 10 seconds\n", count) // Move the clock forward 5 more seconds and print the new value. clock.Add(5 * time.Second) fmt.Printf("Count is %d after 15 seconds\n", count) // Output: // Count is 10 after 10 seconds // Count is 15 after 15 seconds }
func ExampleMock_After() { // Create a new mock clock. clock := clock.NewMock() count := 0 // Create a channel to execute after 10 mock seconds. go func() { <-clock.After(10 * time.Second) count = 100 }() runtime.Gosched() // Print the starting value. fmt.Printf("%s: %d\n", clock.Now().UTC(), count) // Move the clock forward 5 seconds and print the value again. clock.Add(5 * time.Second) fmt.Printf("%s: %d\n", clock.Now().UTC(), count) // Move the clock forward 5 seconds to the tick time and check the value. clock.Add(5 * time.Second) fmt.Printf("%s: %d\n", clock.Now().UTC(), count) // Output: // 1970-01-01 00:00:00 +0000 UTC: 0 // 1970-01-01 00:00:05 +0000 UTC: 0 // 1970-01-01 00:00:10 +0000 UTC: 100 }
func TestEtcdKeyMaintainer(t *testing.T) { api := new(testEtcdAPI) clk := clock.NewMock() m := NewKeyMaintainer(api, "/test", "asdf") m.clock = clk api.On("Set", mock.Anything, "/test", "asdf", mock.Anything).Return(nil, nil) go m.Maintain() pause() api.AssertNumberOfCalls(t, "Set", 1) clk.Add(m.Interval - time.Nanosecond) api.AssertNumberOfCalls(t, "Set", 1) clk.Add(time.Nanosecond + 100) api.AssertNumberOfCalls(t, "Set", 2) api.On("Delete", mock.Anything, "/test", mock.Anything).Return(nil, nil) m.Close() pause() clk.Add(m.Interval) api.AssertNumberOfCalls(t, "Set", 2) del := api.Calls[2] assert.Equal(t, "Delete", del.Method) assert.Equal(t, "/test", del.Arguments.String(1)) }
// Ensure we can create a 100 seconds gap in the middle of the time travel func TestSchedCallsGap(t *testing.T) { EnableDebugLogging(testing.Verbose()) Log.Infoln("TestSchedCallsGap starting") const testSecs = 1000 clk := clock.NewMock() schedQueue := NewSchedQueue(clk) schedQueue.Start() defer schedQueue.Stop() c2 := func() time.Time { if schedQueue.Count() == testSecs/2 { return clk.Now().Add(time.Duration(100) * time.Second) } return clk.Now().Add(time.Second) } schedQueue.Add(c2, clk.Now().Add(time.Second)) schedQueue.Flush() for i := 0; i < testSecs; i++ { clk.Add(time.Second) schedQueue.Flush() } t.Logf("Now: %s - calls: %d", clk.Now(), schedQueue.Count()) require.Equal(t, testSecs-100+1, (int)(schedQueue.Count()), "Number of calls") }
func TestSchedCallsStop(t *testing.T) { InitDefaultLogging(testing.Verbose()) Info.Println("TestSchedCallsStop starting") const testSecs = 1000 clk := clock.NewMock() schedQueue := NewSchedQueue(clk) schedQueue.Start() defer schedQueue.Stop() c2 := func() time.Time { if schedQueue.Count() == testSecs/2 { return time.Time{} } return clk.Now().Add(time.Second) } schedQueue.Add(c2, clk.Now().Add(time.Second)) schedQueue.Flush() for i := 0; i < testSecs; i++ { clk.Add(time.Second) schedQueue.Flush() } t.Logf("Now: %s - calls: %d", clk.Now(), schedQueue.Count()) require.Equal(t, testSecs/2, (int)(schedQueue.Count()), "Number of calls") }
// Ensure that the mock's Tick channel sends at the correct time. func TestMock_Tick(t *testing.T) { var n int32 clock := clock.NewMock() // Create a channel to increment every 10 seconds. go func() { tick := clock.Tick(10 * time.Second) for { <-tick atomic.AddInt32(&n, 1) } }() gosched() // Move clock forward to just before the first tick. clock.Add(9 * time.Second) if atomic.LoadInt32(&n) != 0 { t.Fatalf("expected 0, got %d", n) } // Move clock forward to the start of the first tick. clock.Add(1 * time.Second) if atomic.LoadInt32(&n) != 1 { t.Fatalf("expected 1, got %d", n) } // Move clock forward over several ticks. clock.Add(30 * time.Second) if atomic.LoadInt32(&n) != 4 { t.Fatalf("expected 4, got %d", n) } }
func BenchmarkIncomingMetricAmounts(b *testing.B) { daemon := New("test", "rates.", "timers.", "gauges.", "counters.", timers.Percentiles{}, 10, 1000, 1000, nil, false, true, true, false) daemon.Clock = clock.NewMock() daemon.submitFunc = func(c *counters.Counters, g *gauges.Gauges, t *timers.Timers, deadline time.Time) { } go daemon.RunBare() b.ResetTimer() counters := make([]*common.Metric, 10) for i := 0; i < 10; i++ { counters[i] = &common.Metric{ Bucket: "test-counter", Value: float64(1), Modifier: "c", Sampling: float32(1), } } // each operation consists of 100x write (1k * 10 metrics + move clock by 1second) // simulating a fake 10k metrics/s load, 1M metrics in total over 100+10s, so 11 flushes for n := 0; n < b.N; n++ { for j := 0; j < 100; j++ { for i := 0; i < 1000; i++ { daemon.metricAmounts <- counters } daemon.Clock.(*clock.Mock).Add(1 * time.Second) } daemon.Clock.(*clock.Mock).Add(10 * time.Second) } }
func init() { clock := clock.NewMock() backend := memory.NewWithClock(clock) check.Suite(&coordinatetest.Suite{ Coordinate: backend, Clock: clock, }) }
// newChannelNodeWithHostPort creates a testNode with the address specified by // the hostport parameter. func newChannelNodeWithHostPort(t *testing.T, hostport string) *testNode { ch, err := tchannel.NewChannel("test", nil) require.NoError(t, err, "channel must create successfully") node := NewNode("test", hostport, ch.GetSubChannel("test"), &Options{ Clock: clock.NewMock(), }) return &testNode{node, ch} }
func init() { clk := clock.NewMock() c, err := postgres.NewWithClock("", clk) if err != nil { panic(err) } check.Suite(&coordinatetest.Suite{ Coordinate: c, Clock: clk, }) }
// Ensure that the mock's current time can be changed. func TestMock_Now(t *testing.T) { clock := clock.NewMock() if now := clock.Now(); !now.Equal(time.Unix(0, 0)) { t.Fatalf("expected epoch, got: ", now) } // Add 10 seconds and check the time. clock.Add(10 * time.Second) if now := clock.Now(); !now.Equal(time.Unix(10, 0)) { t.Fatalf("expected epoch, got: ", now) } }
func TestProfileSample(t *testing.T) { wantProfile := TimeProfile{ Total: 10 * time.Second, WaitRead: 1 * time.Second, WaitWrite: 9 * time.Second, } clk := clock.NewMock() start := clk.Now() sleepRead := readFunc(func(p []byte) (int, error) { var err error if clk.Now().Sub(start) >= wantProfile.Total { err = io.EOF } clk.Sleep(wantProfile.WaitRead / 1000) return len(p), err }) sleepWrite := writeFunc(func(p []byte) (int, error) { clk.Sleep(wantProfile.WaitWrite / 1000) return len(p), nil }) res := make(chan TimeProfile, 1) go func() { w, r, done := profileSample(clk, sleepWrite, sleepRead, time.Millisecond) io.Copy(w, r) res <- done().TimeProfile }() var gotProfile TimeProfile loop: for { select { case gotProfile = <-res: break loop default: clk.Add(1 * time.Millisecond) } } wantReadRatio := float64(wantProfile.WaitRead) / float64(wantProfile.WaitRead+wantProfile.WaitWrite) gotReadRatio := float64(gotProfile.WaitRead) / float64(gotProfile.WaitRead+gotProfile.WaitWrite) diff := (math.Max(wantReadRatio, gotReadRatio) - math.Min(wantReadRatio, gotReadRatio)) / math.Max(wantReadRatio, gotReadRatio) if diff > 0.05 { t.Logf("want=%#v", wantProfile) t.Logf(" got=%#v", gotProfile) t.Fatalf("profiles are too different: %.2f%% different", 100*diff) } }
func TestTickerRetro1Hour(t *testing.T) { offset := time.Duration(10) * time.Second last := time.Unix(0, 0) mock := clock.NewMock() mock.Add(time.Duration(1) * time.Hour) desiredLast := mock.Now().Add(-offset) ticker := NewTicker(last, offset, mock) last = assertAdvanceUntil(ticker, last, desiredLast, offset, time.Duration(10)*time.Millisecond, t) assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t) }
// Ensure that the mock's AfterFunc doesn't execute if stopped. func TestMock_AfterFunc_Stop(t *testing.T) { // Execute function after duration. clock := clock.NewMock() timer := clock.AfterFunc(10*time.Second, func() { t.Fatal("unexpected function execution") }) gosched() // Stop timer & move clock forward. timer.Stop() clock.Add(10 * time.Second) gosched() }
func (s *RollupTestSuite) SetupTest() { s.node = NewNode("test", "127.0.0.1:3001", nil, &Options{ RollupFlushInterval: 10000 * time.Second, RollupMaxUpdates: 10000, Clock: clock.NewMock(), }) s.r = s.node.rollup s.incarnation = util.TimeNowMS() s.updates = []Change{ Change{Address: "one"}, Change{Address: "two"}, } }
func (s *Suite) SetUpTest(t *testing.T) { s.Clock = clock.NewMock() backend := memory.NewWithClock(s.Clock) var err error s.Namespace, err = backend.Namespace("") if !assert.NoError(t, err) { t.FailNow() } s.Worker = Worker{ Namespace: s.Namespace, } s.Bit = false s.GotWork = make(chan bool) s.Finished = make(chan string) s.Stop = make(chan struct{}) s.Worker.Tasks = map[string]func(context.Context, []coordinate.Attempt){ "sanity": func(ctx context.Context, attempts []coordinate.Attempt) { if assert.Len(t, attempts, 1) { assert.Equal(t, "unit", attempts[0].WorkUnit().Name()) assert.Equal(t, "spec", attempts[0].WorkUnit().WorkSpec().Name()) s.Bit = true err := attempts[0].Finish(nil) assert.NoError(t, err, "finishing attempt in sanity") } }, "timeout": func(ctx context.Context, attempts []coordinate.Attempt) { if !assert.Len(t, attempts, 1) { return } select { case <-ctx.Done(): s.Bit = false status, err := attempts[0].Status() if assert.NoError(t, err) && status == coordinate.Pending { err = attempts[0].Fail(nil) assert.NoError(t, err, "failing attempt in timeout (status=%v)", status) } case <-s.Stop: s.Bit = true status, err := attempts[0].Status() if assert.NoError(t, err) && status == coordinate.Pending { err = attempts[0].Finish(nil) assert.NoError(t, err, "finishing attempt in timeout (status=%v)", status) } } }, } }
func (s *RingpopTestSuite) SetupTest() { s.mockClock = clock.NewMock() ch, err := tchannel.NewChannel("test", nil) s.NoError(err, "channel must create successfully") s.channel = ch s.ringpop, err = New("test", Identity("127.0.0.1:3001"), Channel(ch), Clock(s.mockClock)) s.NoError(err, "Ringpop must create successfully") s.mockRingpop = &mocks.Ringpop{} s.mockSwimNode = &mocks.SwimNode{} s.mockSwimNode.On("Destroy").Return() }
// newChannelNode creates a testNode with a listening channel and associated // SWIM node. The channel listens on a random port assigned by the OS. func newChannelNode(t *testing.T) *testNode { ch, err := tchannel.NewChannel("test", nil) require.NoError(t, err, "channel must create successfully") // Set the channel listening so it binds to the socket and we get a port // allocated by the OS err = ch.ListenAndServe("127.0.0.1:0") require.NoError(t, err, "channel must listen") hostport := ch.PeerInfo().HostPort node := NewNode("test", hostport, ch.GetSubChannel("test"), &Options{ Clock: clock.NewMock(), }) return &testNode{node, ch} }
func TestStat(t *testing.T) { mock := clock.NewMock() app.Clock = mock fixture := Whisper{ graphPrefix: "bing.bang.", } fixture.in = make(chan *points.Points) go func() { output := <-fixture.in expected := points.OnePoint( "bing.bang.persister.foo.bar", 1.5, 0, ) assert.Equal(t, output, expected) }() fixture.Stat("foo.bar", 1.5) }
func BenchmarkIncomingMetrics(b *testing.B) { daemon := New("test", "rates.", "timers.", "gauges.", "counters.", timers.Percentiles{}, 10, 1000, 1000, nil, false, true, true, false) daemon.Clock = clock.NewMock() total := float64(0) totalLock := sync.Mutex{} daemon.submitFunc = func(c *counters.Counters, g *gauges.Gauges, t *timers.Timers, deadline time.Time) { totalLock.Lock() total += c.Values["service_is_statsdaemon.instance_is_test.direction_is_in.statsd_type_is_counter.target_type_is_count.unit_is_Metric"] totalLock.Unlock() } go daemon.RunBare() b.ResetTimer() counters := make([]*common.Metric, 10) for i := 0; i < 10; i++ { counters[i] = &common.Metric{ Bucket: "test-counter", Value: float64(1), Modifier: "c", Sampling: float32(1), } } // each operation consists of 100x write (1k * 10 metrics + move clock by 1second) // simulating a fake 10k metrics/s load, 1M metrics in total over 100+10s, so 11 flushes for n := 0; n < b.N; n++ { totalLock.Lock() total = 0 totalLock.Unlock() for j := 0; j < 100; j++ { for i := 0; i < 1000; i++ { daemon.Metrics <- counters } daemon.Clock.(*clock.Mock).Add(1 * time.Second) } daemon.Clock.(*clock.Mock).Add(10 * time.Second) totalLock.Lock() if total != float64(1000000) { panic(fmt.Sprintf("didn't see 1M counters. only saw %f", total)) } totalLock.Unlock() } }
// Ensure that the mock's Ticker channel sends at the correct time. func TestMock_Ticker(t *testing.T) { var n int32 clock := clock.NewMock() // Create a channel to increment every microsecond. go func() { ticker := clock.Ticker(1 * time.Microsecond) for { <-ticker.C atomic.AddInt32(&n, 1) } }() gosched() // Move clock forward. clock.Add(10 * time.Microsecond) if atomic.LoadInt32(&n) != 10 { t.Fatalf("unexpected: %d", n) } }
// Ensure that the mock's AfterFunc executes at the correct time. func TestMock_AfterFunc(t *testing.T) { var ok int32 clock := clock.NewMock() // Execute function after duration. clock.AfterFunc(10*time.Second, func() { atomic.StoreInt32(&ok, 1) }) // Move clock forward to just before the time. clock.Add(9 * time.Second) if atomic.LoadInt32(&ok) == 1 { t.Fatal("too early") } // Move clock forward to the after channel's time. clock.Add(1 * time.Second) if atomic.LoadInt32(&ok) == 0 { t.Fatal("too late") } }
func ExampleMock_AfterFunc() { // Create a new mock clock. clock := clock.NewMock() count := 0 // Execute a function after 10 mock seconds. clock.AfterFunc(10*time.Second, func() { count = 100 }) runtime.Gosched() // Print the starting value. fmt.Printf("%s: %d\n", clock.Now().UTC(), count) // Move the clock forward 10 seconds and print the new value. clock.Add(10 * time.Second) fmt.Printf("%s: %d\n", clock.Now().UTC(), count) // Output: // 1970-01-01 00:00:00 +0000 UTC: 0 // 1970-01-01 00:00:10 +0000 UTC: 100 }
// Ensure that the mock's After channel sends at the correct time. func TestMock_After(t *testing.T) { var ok int32 clock := clock.NewMock() // Create a channel to execute after 10 mock seconds. ch := clock.After(10 * time.Second) go func(ch <-chan time.Time) { <-ch atomic.StoreInt32(&ok, 1) }(ch) // Move clock forward to just before the time. clock.Add(9 * time.Second) if atomic.LoadInt32(&ok) == 1 { t.Fatal("too early") } // Move clock forward to the after channel's time. clock.Add(1 * time.Second) if atomic.LoadInt32(&ok) == 0 { t.Fatal("too late") } }
// Ensure that the mock can sleep for the correct time. func TestMock_Sleep(t *testing.T) { var ok int32 clock := clock.NewMock() // Create a channel to execute after 10 mock seconds. go func() { clock.Sleep(10 * time.Second) atomic.StoreInt32(&ok, 1) }() gosched() // Move clock forward to just before the sleep duration. clock.Add(9 * time.Second) if atomic.LoadInt32(&ok) == 1 { t.Fatal("too early") } // Move clock forward to the after the sleep duration. clock.Add(1 * time.Second) if atomic.LoadInt32(&ok) == 0 { t.Fatal("too late") } }
func TestEtcdDirMaintainer(t *testing.T) { api := new(testEtcdAPI) clk := clock.NewMock() m := NewDirMaintainer(api, "/test", func(m *Maintainer) error { _, err := m.API.Set(m.Context, m.Key+"/asdf", "42", nil) return err }) m.clock = clk api.On("Set", mock.Anything, "/test", "", &etcd.SetOptions{ TTL: time.Second * 9, Dir: true, PrevExist: etcd.PrevExist, }).Return(nil, nil).Once() go m.Maintain() pause() api.AssertNumberOfCalls(t, "Set", 1) api.On("Set", mock.Anything, "/test", "", &etcd.SetOptions{ TTL: time.Second * 9, Dir: true, PrevExist: etcd.PrevExist, }).Return(nil, etcd.Error{Code: etcd.ErrorCodeKeyNotFound}).Once() api.On("Set", mock.Anything, "/test", "", &etcd.SetOptions{ TTL: time.Second * 9, Dir: true, }).Return(nil, nil).Once() var opts *etcd.SetOptions api.On("Set", mock.Anything, "/test/asdf", "42", opts).Return(nil, nil).Once() clk.Add(m.Interval) api.AssertNumberOfCalls(t, "Set", 4) api.On("Delete", mock.Anything, "/test", mock.Anything).Return(nil, nil) m.Close() }