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 |
} |