Skip to content

feat: add Peek() method to mock Clock #13657

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions clock/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,22 @@ w.MustWait(ctx)
// d contains the duration we advanced
```

`d, ok := Peek()` returns the duration until the next event, if any (`ok` is `true`). You can use
this to advance a specific time, regardless of the tickers and timer events:

```go
desired := time.Minute // time to advance
for desired > 0 {
p, ok := mClock.Peek()
if !ok || p > desired {
mClock.Advance(desired).MustWait(ctx)
break
}
mClock.Advance(p).MustWait(ctx)
desired -= p
}
```

### Traps

A trap allows you to match specific calls into the library while mocking, block their return,
Expand Down
12 changes: 12 additions & 0 deletions clock/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,18 @@ func (m *Mock) AdvanceNext() (time.Duration, AdvanceWaiter) {
return d, w
}

// Peek returns the duration until the next ticker or timer event and the value
// true, or, if there are no running tickers or timers, it returns zero and
// false.
func (m *Mock) Peek() (d time.Duration, ok bool) {
m.mu.Lock()
defer m.mu.Unlock()
if m.nextTime.IsZero() {
return 0, false
}
return m.nextTime.Sub(m.cur), true
}

// Trapper allows the creation of Traps
type Trapper struct {
// mock is the underlying Mock. This is a thin wrapper around Mock so that
Expand Down
49 changes: 48 additions & 1 deletion clock/mock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func TestAfterFunc_NegativeDuration(t *testing.T) {
func TestNewTicker(t *testing.T) {
t.Parallel()
// nolint:gocritic // trying to avoid Coder-specific stuff with an eye toward spinning this out
ctx, cancel := context.WithTimeout(context.Background(), 1000*time.Second)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

mClock := clock.NewMock(t)
Expand Down Expand Up @@ -167,3 +167,50 @@ func TestNewTicker(t *testing.T) {
}
}
}

func TestPeek(t *testing.T) {
t.Parallel()
// nolint:gocritic // trying to avoid Coder-specific stuff with an eye toward spinning this out
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

mClock := clock.NewMock(t)
d, ok := mClock.Peek()
if d != 0 {
t.Fatal("expected Peek() to return 0")
}
if ok {
t.Fatal("expected Peek() to return false")
}

tmr := mClock.NewTimer(time.Second)
d, ok = mClock.Peek()
if d != time.Second {
t.Fatal("expected Peek() to return 1s")
}
if !ok {
t.Fatal("expected Peek() to return true")
}

mClock.Advance(999 * time.Millisecond).MustWait(ctx)
d, ok = mClock.Peek()
if d != time.Millisecond {
t.Fatal("expected Peek() to return 1ms")
}
if !ok {
t.Fatal("expected Peek() to return true")
}

stopped := tmr.Stop()
if !stopped {
t.Fatal("expected Stop() to return true")
}

d, ok = mClock.Peek()
if d != 0 {
t.Fatal("expected Peek() to return 0")
}
if ok {
t.Fatal("expected Peek() to return false")
}
}
Loading