OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 package testclock |
| 6 |
| 7 import ( |
| 8 "sync" |
| 9 "time" |
| 10 |
| 11 "golang.org/x/net/context" |
| 12 "infra/libs/clock" |
| 13 ) |
| 14 |
| 15 // TestClock is a Clock interface with additional methods to help instrument it. |
| 16 type TestClock interface { |
| 17 clock.Clock |
| 18 SetNow(time.Time) |
| 19 SetTimerCallback(TimerCallback) |
| 20 } |
| 21 |
| 22 // TimerCallback that can be invoked when a timer has been set. This is useful f
or |
| 23 // sychronizing state when testing. |
| 24 type TimerCallback func(clock.Timer) |
| 25 |
| 26 // testClock is a test-oriented implementation of the 'Clock' interface. |
| 27 // |
| 28 // This implementation's Clock responses are configurable by modifying its membe
r |
| 29 // variables. Time-based events are explicitly triggered by sending on a Timer |
| 30 // instance's channel. |
| 31 type testClock struct { |
| 32 sync.RWMutex |
| 33 |
| 34 now time.Time // The current clock time. |
| 35 timerCond *sync.Cond // Condition used to manage timer blocking. |
| 36 |
| 37 timerCallback TimerCallback // Optional callback when a timer has been s
et. |
| 38 } |
| 39 |
| 40 var _ TestClock = (*testClock)(nil) |
| 41 |
| 42 // New returns a TestClock instance set at the specified time. |
| 43 func New(now time.Time) TestClock { |
| 44 c := testClock{ |
| 45 now: now, |
| 46 } |
| 47 c.timerCond = sync.NewCond(&c) |
| 48 return &c |
| 49 } |
| 50 |
| 51 func (c *testClock) Now() time.Time { |
| 52 c.RLock() |
| 53 defer c.RUnlock() |
| 54 |
| 55 return c.now |
| 56 } |
| 57 |
| 58 func (c *testClock) Sleep(d time.Duration) { |
| 59 <-c.After(d) |
| 60 } |
| 61 |
| 62 func (c *testClock) NewTimer() clock.Timer { |
| 63 return newTimer(c) |
| 64 } |
| 65 |
| 66 func (c *testClock) After(d time.Duration) <-chan time.Time { |
| 67 t := c.NewTimer() |
| 68 t.Reset(d) |
| 69 return t.GetC() |
| 70 } |
| 71 |
| 72 func (c *testClock) SetNow(t time.Time) { |
| 73 c.Lock() |
| 74 defer c.Unlock() |
| 75 |
| 76 c.now = t |
| 77 |
| 78 // Unblock any blocking timers that are waiting on our lock. |
| 79 go c.pokeTimers() |
| 80 } |
| 81 |
| 82 func (c *testClock) SetTimerCallback(callback TimerCallback) { |
| 83 c.Lock() |
| 84 defer c.Unlock() |
| 85 |
| 86 c.timerCallback = callback |
| 87 } |
| 88 |
| 89 func (c *testClock) getTimerCallback() TimerCallback { |
| 90 c.Lock() |
| 91 defer c.Unlock() |
| 92 |
| 93 return c.timerCallback |
| 94 } |
| 95 |
| 96 func (c *testClock) signalTimerSet(t clock.Timer) { |
| 97 callback := c.getTimerCallback() |
| 98 if callback != nil { |
| 99 callback(t) |
| 100 } |
| 101 } |
| 102 |
| 103 func (c *testClock) pokeTimers() { |
| 104 c.Lock() |
| 105 defer c.Unlock() |
| 106 |
| 107 c.timerCond.Broadcast() |
| 108 } |
| 109 |
| 110 // Set creates a new Context using the supplied clock instance. |
| 111 func Set(ctx context.Context, now time.Time) context.Context { |
| 112 return clock.SetClock(ctx, New(now)) |
| 113 } |
OLD | NEW |