OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package testclock | 5 package testclock |
6 | 6 |
7 import ( | 7 import ( |
| 8 "fmt" |
| 9 "strings" |
| 10 "sync" |
8 "testing" | 11 "testing" |
9 "time" | 12 "time" |
10 | 13 |
11 "github.com/luci/luci-go/common/clock" | 14 "github.com/luci/luci-go/common/clock" |
12 . "github.com/smartystreets/goconvey/convey" | 15 . "github.com/smartystreets/goconvey/convey" |
| 16 "golang.org/x/net/context" |
13 ) | 17 ) |
14 | 18 |
| 19 // trashTimer is a useless implementation of clock.Timer specifically designed |
| 20 // to exist and not be a test timer type. |
| 21 type trashTimer struct { |
| 22 clock.Timer |
| 23 } |
| 24 |
15 func TestTestClock(t *testing.T) { | 25 func TestTestClock(t *testing.T) { |
16 t.Parallel() | 26 t.Parallel() |
17 | 27 |
18 Convey(`A testing clock instance`, t, func() { | 28 Convey(`A testing clock instance`, t, func() { |
19 now := time.Date(2015, 01, 01, 00, 00, 00, 00, time.UTC) | 29 now := time.Date(2015, 01, 01, 00, 00, 00, 00, time.UTC) |
20 c := New(now) | 30 c := New(now) |
| 31 ctx := context.Background() |
21 | 32 |
22 Convey(`Returns the current time.`, func() { | 33 Convey(`Returns the current time.`, func() { |
23 So(c.Now(), ShouldResemble, now) | 34 So(c.Now(), ShouldResemble, now) |
24 }) | 35 }) |
25 | 36 |
26 Convey(`When sleeping with a time of zero, immediately awakens.`
, func() { | 37 Convey(`When sleeping with a time of zero, immediately awakens.`
, func() { |
27 » » » c.Sleep(0) | 38 » » » c.Sleep(ctx, 0) |
28 So(c.Now(), ShouldResemble, now) | 39 So(c.Now(), ShouldResemble, now) |
29 }) | 40 }) |
30 | 41 |
| 42 Convey(`Will panic if going backwards in time.`, func() { |
| 43 So(func() { c.Add(-1 * time.Second) }, ShouldPanic) |
| 44 }) |
| 45 |
31 Convey(`When sleeping for a period of time, awakens when signall
ed.`, func() { | 46 Convey(`When sleeping for a period of time, awakens when signall
ed.`, func() { |
32 sleepingC := make(chan struct{}) | 47 sleepingC := make(chan struct{}) |
33 c.SetTimerCallback(func(_ time.Duration, _ clock.Timer)
{ | 48 c.SetTimerCallback(func(_ time.Duration, _ clock.Timer)
{ |
34 close(sleepingC) | 49 close(sleepingC) |
35 }) | 50 }) |
36 | 51 |
37 awakeC := make(chan time.Time) | 52 awakeC := make(chan time.Time) |
38 go func() { | 53 go func() { |
39 » » » » c.Sleep(2 * time.Second) | 54 » » » » c.Sleep(ctx, 2*time.Second) |
40 awakeC <- c.Now() | 55 awakeC <- c.Now() |
41 }() | 56 }() |
42 | 57 |
43 <-sleepingC | 58 <-sleepingC |
44 c.Set(now.Add(1 * time.Second)) | 59 c.Set(now.Add(1 * time.Second)) |
45 c.Set(now.Add(2 * time.Second)) | 60 c.Set(now.Add(2 * time.Second)) |
46 So(<-awakeC, ShouldResemble, now.Add(2*time.Second)) | 61 So(<-awakeC, ShouldResemble, now.Add(2*time.Second)) |
47 }) | 62 }) |
48 | 63 |
49 Convey(`Awakens after a period of time.`, func() { | 64 Convey(`Awakens after a period of time.`, func() { |
50 » » » afterC := c.After(2 * time.Second) | 65 » » » afterC := c.After(ctx, 2*time.Second) |
51 | 66 |
52 c.Set(now.Add(1 * time.Second)) | 67 c.Set(now.Add(1 * time.Second)) |
53 c.Set(now.Add(2 * time.Second)) | 68 c.Set(now.Add(2 * time.Second)) |
54 » » » So(<-afterC, ShouldResemble, now.Add(2*time.Second)) | 69 » » » So(<-afterC, ShouldResemble, clock.TimerResult{now.Add(2
* time.Second), nil}) |
| 70 » » }) |
| 71 |
| 72 » » Convey(`When sleeping, awakens if canceled.`, func() { |
| 73 » » » ctx, cancelFunc := context.WithCancel(ctx) |
| 74 |
| 75 » » » c.SetTimerCallback(func(_ time.Duration, _ clock.Timer)
{ |
| 76 » » » » cancelFunc() |
| 77 » » » }) |
| 78 |
| 79 » » » So(c.Sleep(ctx, time.Second), ShouldEqual, context.Cance
led) |
| 80 » » }) |
| 81 |
| 82 » » Convey(`Can set and retrieve timer tags.`, func() { |
| 83 » » » var tagMu sync.Mutex |
| 84 » » » tagMap := map[string]struct{}{} |
| 85 |
| 86 » » » // On the last timer callback, advance time past the tim
er threshold. |
| 87 » » » timers := make([]clock.Timer, 10) |
| 88 » » » count := 0 |
| 89 » » » c.SetTimerCallback(func(_ time.Duration, t clock.Timer)
{ |
| 90 » » » » tagMu.Lock() |
| 91 » » » » defer tagMu.Unlock() |
| 92 |
| 93 » » » » tagMap[strings.Join(GetTags(t), "")] = struct{}{
} |
| 94 » » » » count++ |
| 95 » » » » if count == len(timers) { |
| 96 » » » » » c.Add(time.Second) |
| 97 » » » » } |
| 98 » » » }) |
| 99 |
| 100 » » » for i := range timers { |
| 101 » » » » t := c.NewTimer(clock.Tag(ctx, fmt.Sprintf("%d",
i))) |
| 102 » » » » t.Reset(time.Second) |
| 103 » » » » timers[i] = t |
| 104 » » » } |
| 105 |
| 106 » » » // Wait until all timers have expired. |
| 107 » » » for _, t := range timers { |
| 108 » » » » <-t.GetC() |
| 109 » » » } |
| 110 |
| 111 » » » // Did we see all of their tags? |
| 112 » » » for i := range timers { |
| 113 » » » » _, ok := tagMap[fmt.Sprintf("%d", i)] |
| 114 » » » » So(ok, ShouldBeTrue) |
| 115 » » » } |
| 116 » » }) |
| 117 |
| 118 » » Convey(`A non-test timer has a nil tag.`, func() { |
| 119 » » » t := trashTimer{} |
| 120 » » » So(GetTags(t), ShouldBeNil) |
55 }) | 121 }) |
56 }) | 122 }) |
57 } | 123 } |
OLD | NEW |