Index: common/clock/testclock/testclock_test.go |
diff --git a/common/clock/testclock/testclock_test.go b/common/clock/testclock/testclock_test.go |
index f063c02f3d3e33b9f2e245fb4228f0f4a5037443..6bfc090d2b8ac94b67d97c9f23f8480944e71e7a 100644 |
--- a/common/clock/testclock/testclock_test.go |
+++ b/common/clock/testclock/testclock_test.go |
@@ -5,29 +5,44 @@ |
package testclock |
import ( |
+ "fmt" |
+ "strings" |
+ "sync" |
"testing" |
"time" |
"github.com/luci/luci-go/common/clock" |
. "github.com/smartystreets/goconvey/convey" |
+ "golang.org/x/net/context" |
) |
+// trashTimer is a useless implementation of clock.Timer specifically designed |
+// to exist and not be a test timer type. |
+type trashTimer struct { |
+ clock.Timer |
+} |
+ |
func TestTestClock(t *testing.T) { |
t.Parallel() |
Convey(`A testing clock instance`, t, func() { |
now := time.Date(2015, 01, 01, 00, 00, 00, 00, time.UTC) |
c := New(now) |
+ ctx := context.Background() |
Convey(`Returns the current time.`, func() { |
So(c.Now(), ShouldResemble, now) |
}) |
Convey(`When sleeping with a time of zero, immediately awakens.`, func() { |
- c.Sleep(0) |
+ c.Sleep(ctx, 0) |
So(c.Now(), ShouldResemble, now) |
}) |
+ Convey(`Will panic if going backwards in time.`, func() { |
+ So(func() { c.Add(-1 * time.Second) }, ShouldPanic) |
+ }) |
+ |
Convey(`When sleeping for a period of time, awakens when signalled.`, func() { |
sleepingC := make(chan struct{}) |
c.SetTimerCallback(func(_ time.Duration, _ clock.Timer) { |
@@ -36,7 +51,7 @@ func TestTestClock(t *testing.T) { |
awakeC := make(chan time.Time) |
go func() { |
- c.Sleep(2 * time.Second) |
+ c.Sleep(ctx, 2*time.Second) |
awakeC <- c.Now() |
}() |
@@ -47,11 +62,62 @@ func TestTestClock(t *testing.T) { |
}) |
Convey(`Awakens after a period of time.`, func() { |
- afterC := c.After(2 * time.Second) |
+ afterC := c.After(ctx, 2*time.Second) |
c.Set(now.Add(1 * time.Second)) |
c.Set(now.Add(2 * time.Second)) |
- So(<-afterC, ShouldResemble, now.Add(2*time.Second)) |
+ So(<-afterC, ShouldResemble, clock.TimerResult{now.Add(2 * time.Second), nil}) |
+ }) |
+ |
+ Convey(`When sleeping, awakens if canceled.`, func() { |
+ ctx, cancelFunc := context.WithCancel(ctx) |
+ |
+ c.SetTimerCallback(func(_ time.Duration, _ clock.Timer) { |
+ cancelFunc() |
+ }) |
+ |
+ So(c.Sleep(ctx, time.Second), ShouldEqual, context.Canceled) |
+ }) |
+ |
+ Convey(`Can set and retrieve timer tags.`, func() { |
+ var tagMu sync.Mutex |
+ tagMap := map[string]struct{}{} |
+ |
+ // On the last timer callback, advance time past the timer threshold. |
+ timers := make([]clock.Timer, 10) |
+ count := 0 |
+ c.SetTimerCallback(func(_ time.Duration, t clock.Timer) { |
+ tagMu.Lock() |
+ defer tagMu.Unlock() |
+ |
+ tagMap[strings.Join(GetTags(t), "")] = struct{}{} |
+ count++ |
+ if count == len(timers) { |
+ c.Add(time.Second) |
+ } |
+ }) |
+ |
+ for i := range timers { |
+ t := c.NewTimer(clock.Tag(ctx, fmt.Sprintf("%d", i))) |
+ t.Reset(time.Second) |
+ timers[i] = t |
+ } |
+ |
+ // Wait until all timers have expired. |
+ for _, t := range timers { |
+ <-t.GetC() |
+ } |
+ |
+ // Did we see all of their tags? |
+ for i := range timers { |
+ _, ok := tagMap[fmt.Sprintf("%d", i)] |
+ So(ok, ShouldBeTrue) |
+ } |
+ }) |
+ |
+ Convey(`A non-test timer has a nil tag.`, func() { |
+ t := trashTimer{} |
+ So(GetTags(t), ShouldBeNil) |
}) |
}) |
} |