| Index: common/clock/testclock/testtimer.go
|
| diff --git a/common/clock/testclock/testtimer.go b/common/clock/testclock/testtimer.go
|
| index 92c6bd83c9f3467d9ab6993d9d9c4cff7d3bac56..e899c6fcf9d81e99b7f13bceb88acdd3a0ae0ffc 100644
|
| --- a/common/clock/testclock/testtimer.go
|
| +++ b/common/clock/testclock/testtimer.go
|
| @@ -8,6 +8,7 @@ import (
|
| "time"
|
|
|
| "github.com/luci/luci-go/common/clock"
|
| + "golang.org/x/net/context"
|
| )
|
|
|
| // timer is an implementation of clock.TestTimer that uses a channel
|
| @@ -16,28 +17,35 @@ import (
|
| // The channel is buffered so it can be used without requiring a separate
|
| // signalling goroutine.
|
| type timer struct {
|
| - clock *testClock
|
| - signalC chan time.Time
|
| + ctx context.Context
|
| + clock *testClock
|
|
|
| - // Cancels callback from clock.invokeAt. Being not nil implies that the timer
|
| + // tags is the set of tags in the Context when this timer was created.
|
| + tags []string
|
| +
|
| + // afterC will have the TimerResult of the timer's expiration written to it
|
| + // when this timer triggers or is canceled.
|
| + afterC chan clock.TimerResult
|
| +
|
| + // Cancels callback from clock.invokeAt. Being non-nil implies that the timer
|
| // is active.
|
| - cancelFunc cancelFunc
|
| + cancelFunc context.CancelFunc
|
| }
|
|
|
| var _ clock.Timer = (*timer)(nil)
|
|
|
| // NewTimer returns a new, instantiated timer.
|
| -func newTimer(clock *testClock) clock.Timer {
|
| +func newTimer(ctx context.Context, clk *testClock) *timer {
|
| return &timer{
|
| - clock: clock,
|
| + ctx: ctx,
|
| + clock: clk,
|
| + tags: clock.Tags(ctx),
|
| + afterC: make(chan clock.TimerResult, 1),
|
| }
|
| }
|
|
|
| -func (t *timer) GetC() (c <-chan time.Time) {
|
| - if t.cancelFunc != nil {
|
| - c = t.signalC
|
| - }
|
| - return
|
| +func (t *timer) GetC() <-chan clock.TimerResult {
|
| + return t.afterC
|
| }
|
|
|
| func (t *timer) Reset(d time.Duration) (active bool) {
|
| @@ -51,26 +59,65 @@ func (t *timer) Reset(d time.Duration) (active bool) {
|
| active = t.Stop()
|
|
|
| // Set timer properties.
|
| - t.signalC = make(chan time.Time, 1)
|
| - t.cancelFunc = t.clock.invokeAt(triggerTime, t.signal)
|
| + var ctx context.Context
|
| + ctx, t.cancelFunc = context.WithCancel(t.ctx)
|
| + t.clock.invokeAt(ctx, triggerTime, func(tr clock.TimerResult) {
|
| + // If our cancelFunc is nil, then we were stopped and should NOT signal our
|
| + // timer channel.
|
| + if t.cancelFunc != nil {
|
| + t.afterC <- tr
|
| + t.cancelFunc = nil
|
| + }
|
| + })
|
| return
|
| }
|
|
|
| func (t *timer) Stop() bool {
|
| // If the timer is not running, we're done.
|
| - if t.cancelFunc == nil {
|
| + cf := t.cancelFunc
|
| + if cf == nil {
|
| return false
|
| }
|
|
|
| - // Clear our state.
|
| - t.cancelFunc()
|
| + // Clear our state. Set our cancelFunc to nil so our callback knows that we
|
| + // were stopped.
|
| t.cancelFunc = nil
|
| + cf()
|
| return true
|
| }
|
|
|
| -// Sends a single time signal.
|
| -func (t *timer) signal(now time.Time) {
|
| - if t.signalC != nil {
|
| - t.signalC <- now
|
| +// GetTags returns the tags associated with the specified timer. If the timer
|
| +// has no tags, an empty slice (nil) will be returned.
|
| +func GetTags(t clock.Timer) []string {
|
| + if tt, ok := t.(*timer); ok {
|
| + return clock.Tags(tt.ctx)
|
| + }
|
| + return nil
|
| +}
|
| +
|
| +// HasTags tests if a given timer has the same tags.
|
| +func HasTags(t clock.Timer, first string, tags ...string) bool {
|
| + timerTags := GetTags(t)
|
| + if len(timerTags) == 0 {
|
| + return false
|
| }
|
| +
|
| + if first != timerTags[0] {
|
| + return false
|
| + }
|
| +
|
| + if len(timerTags) > 1 {
|
| + // Compare the remainder.
|
| + timerTags = timerTags[1:]
|
| + if len(timerTags) != len(tags) {
|
| + return false
|
| + }
|
| +
|
| + for i, tag := range timerTags {
|
| + if tags[i] != tag {
|
| + return false
|
| + }
|
| + }
|
| + }
|
| + return true
|
| }
|
|
|