11
11
"github.com/juju/utils/clock"
14
// timerClock exposes the underlying Clock's capabilities to a Timer.
15
type timerClock interface {
16
reset(id int, d time.Duration) bool
20
// Timer implements a mock clock.Timer for testing purposes.
26
// Reset is part of the clock.Timer interface.
27
func (t *Timer) Reset(d time.Duration) bool {
28
return t.clock.reset(t.ID, d)
31
// Stop is part of the clock.Timer interface.
32
func (t *Timer) Stop() bool {
33
return t.clock.stop(t.ID)
36
// stoppedTimer is a no-op implementation of clock.Timer.
37
type stoppedTimer struct{}
39
// Reset is part of the clock.Timer interface.
40
func (stoppedTimer) Reset(time.Duration) bool { return false }
42
// Stop is part of the clock.Timer interface.
43
func (stoppedTimer) Stop() bool { return false }
14
// timer implements a mock clock.Timer for testing purposes.
19
// trigger is called when the timer expires. It is
20
// called with the clock mutex held and will not block.
24
// Reset is part of the clock.Timer interface.
25
func (t *timer) Reset(d time.Duration) bool {
26
return t.clock.reset(t, d)
29
// Stop is part of the clock.Timer interface.
30
func (t *timer) Stop() bool {
31
return t.clock.stop(t)
34
// Chan is part of the clock.Timer interface.
35
func (t *timer) Chan() <-chan time.Time {
45
39
// Clock implements a mock clock.Clock for testing purposes.
46
40
type Clock struct {
51
notifyAlarms chan struct{}
43
waiting []*timer // timers waiting to fire, sorted by deadline.
44
notifyAlarms chan struct{}
54
47
// NewClock returns a new clock set to the supplied time. If your SUT needs to
55
// call After, AfterFunc, or Timer.Reset more than 1024 times: (1) you have
48
// call After, AfterFunc, NewTimer or Timer.Reset more than 10000 times: (1) you have
56
49
// probably written a bad test; and (2) you'll need to read from the Alarms
57
50
// chan to keep the buffer clear.
58
51
func NewClock(now time.Time) *Clock {
61
notifyAlarms: make(chan struct{}, 1024),
54
notifyAlarms: make(chan struct{}, 10000),
72
65
// After is part of the clock.Clock interface.
73
66
func (clock *Clock) After(d time.Duration) <-chan time.Time {
74
defer clock.notifyAlarm()
76
defer clock.mu.Unlock()
77
notify := make(chan time.Time, 1)
81
clock.setAlarm(clock.now.Add(d), func() { notify <- clock.now })
67
return clock.NewTimer(d).Chan()
70
func (clock *Clock) NewTimer(d time.Duration) clock.Timer {
71
c := make(chan time.Time, 1)
72
return clock.addAlarm(d, c, func() {
86
77
// AfterFunc is part of the clock.Clock interface.
87
78
func (clock *Clock) AfterFunc(d time.Duration, f func()) clock.Timer {
79
return clock.addAlarm(d, nil, func() {
84
func (clock *Clock) addAlarm(d time.Duration, c chan time.Time, trigger func()) *timer {
88
85
defer clock.notifyAlarm()
90
87
defer clock.mu.Unlock()
93
return &stoppedTimer{}
90
deadline: clock.now.Add(d),
95
id := clock.setAlarm(clock.now.Add(d), f)
96
return &Timer{id, clock}
99
99
// Advance advances the result of Now by the supplied duration, and sends
121
113
return clock.notifyAlarms
116
// triggerAll triggers any alarms that are currently due and removes them
117
// from clock.waiting.
118
func (clock *Clock) triggerAll() {
120
for _, t := range clock.waiting {
121
if clock.now.Before(t.deadline) {
127
clock.waiting = clock.waiting[triggered:]
124
130
// reset is the underlying implementation of clock.Timer.Reset, which may be
125
131
// called by any Timer backed by this Clock.
126
func (clock *Clock) reset(id int, d time.Duration) bool {
132
func (clock *Clock) reset(t *timer, d time.Duration) bool {
133
defer clock.notifyAlarm()
128
135
defer clock.mu.Unlock()
130
for i, alarm := range clock.alarms {
132
defer clock.notifyAlarm()
133
clock.alarms[i].time = clock.now.Add(d)
134
sort.Sort(byTime(clock.alarms))
138
for _, wt := range clock.waiting {
144
clock.waiting = append(clock.waiting, t)
146
t.deadline = clock.now.Add(d)
147
sort.Sort(byDeadline(clock.waiting))
141
151
// stop is the underlying implementation of clock.Timer.Reset, which may be
142
152
// called by any Timer backed by this Clock.
143
func (clock *Clock) stop(id int) bool {
153
func (clock *Clock) stop(t *timer) bool {
145
155
defer clock.mu.Unlock()
147
for i, alarm := range clock.alarms {
149
clock.alarms = removeFromSlice(clock.alarms, i)
157
for i, wt := range clock.waiting {
159
clock.waiting = removeFromSlice(clock.waiting, i)
156
// setAlarm adds an alarm at time t.
157
// It also sorts the alarms and increments the current ID by 1.
158
func (clock *Clock) setAlarm(t time.Time, trigger func()) int {
162
ID: clock.currentAlarmID,
164
clock.alarms = append(clock.alarms, alarm)
165
sort.Sort(byTime(clock.alarms))
166
clock.currentAlarmID = clock.currentAlarmID + 1
166
// addTimer adds an alarm at time t.
167
func (clock *Clock) addTimer(t *timer) {
168
clock.waiting = append(clock.waiting, t)
169
sort.Sort(byDeadline(clock.waiting))
170
172
// notifyAlarm sends a value on the channel exposed by Alarms().
179
// alarm records the time at which we're expected to execute trigger.
186
// byTime is used to sort alarms by time.
189
func (a byTime) Len() int { return len(a) }
190
func (a byTime) Less(i, j int) bool { return a[i].time.Before(a[j].time) }
191
func (a byTime) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
181
// byDeadline is used to sort alarms by time.
182
type byDeadline []*timer
184
func (a byDeadline) Len() int { return len(a) }
185
func (a byDeadline) Less(i, j int) bool { return a[i].deadline.Before(a[j].deadline) }
186
func (a byDeadline) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
193
188
// removeFromSlice removes item at the specified index from the slice.
194
func removeFromSlice(sl []alarm, index int) []alarm {
189
func removeFromSlice(sl []*timer, index int) []*timer {
195
190
return append(sl[:index], sl[index+1:]...)