Skip to content
This repository has been archived by the owner on May 18, 2023. It is now read-only.

Commit

Permalink
Merge pull request #46 from cptpcrd/master
Browse files Browse the repository at this point in the history
Allow resetting previously stopped tickers
  • Loading branch information
djmitche committed Apr 23, 2023
2 parents 4dacbdc + 38e21b7 commit 023ccf9
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 6 deletions.
19 changes: 13 additions & 6 deletions clock.go
Original file line number Diff line number Diff line change
Expand Up @@ -332,12 +332,13 @@ func (t *internalTimer) Tick(now time.Time) {

// Ticker holds a channel that receives "ticks" at regular intervals.
type Ticker struct {
C <-chan time.Time
c chan time.Time
ticker *time.Ticker // realtime impl, if set
next time.Time // next tick time
mock *Mock // mock clock, if set
d time.Duration // time between ticks
C <-chan time.Time
c chan time.Time
ticker *time.Ticker // realtime impl, if set
next time.Time // next tick time
mock *Mock // mock clock, if set
d time.Duration // time between ticks
stopped bool // True if stopped, false if running
}

// Stop turns off the ticker.
Expand All @@ -347,6 +348,7 @@ func (t *Ticker) Stop() {
} else {
t.mock.mu.Lock()
t.mock.removeClockTimer((*internalTicker)(t))
t.stopped = true
t.mock.mu.Unlock()
}
}
Expand All @@ -361,6 +363,11 @@ func (t *Ticker) Reset(dur time.Duration) {
t.mock.mu.Lock()
defer t.mock.mu.Unlock()

if t.stopped {
t.mock.timers = append(t.mock.timers, (*internalTicker)(t))
t.stopped = false
}

t.d = dur
t.next = t.mock.now.Add(dur)
}
Expand Down
66 changes: 66 additions & 0 deletions clock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,26 @@ func TestClock_Ticker_Rst(t *testing.T) {
ticker.Stop()
}

// Ensure that the clock's ticker can stop and then be reset correctly.
func TestClock_Ticker_Stop_Rst(t *testing.T) {
start := time.Now()
ticker := New().Ticker(20 * time.Millisecond)
<-ticker.C
ticker.Stop()
select {
case <-ticker.C:
t.Fatal("unexpected send")
case <-time.After(30 * time.Millisecond):
}
ticker.Reset(5 * time.Millisecond)
<-ticker.C
dur := time.Since(start)
if dur >= 60*time.Millisecond {
t.Fatal("took more than 60ms")
}
ticker.Stop()
}

// Ensure that the clock's timer waits correctly.
func TestClock_Timer(t *testing.T) {
start := time.Now()
Expand Down Expand Up @@ -475,6 +495,52 @@ func TestMock_Ticker_Reset(t *testing.T) {
}
}

func TestMock_Ticker_Stop_Reset(t *testing.T) {
var n int32
clock := NewMock()

ticker := clock.Ticker(5 * time.Second)
defer ticker.Stop()

go func() {
for {
<-ticker.C
atomic.AddInt32(&n, 1)
}
}()
gosched()

// Move clock forward.
clock.Add(10 * time.Second)
if atomic.LoadInt32(&n) != 2 {
t.Fatalf("expected 2, got: %d", n)
}

ticker.Stop()

// Move clock forward again.
clock.Add(5 * time.Second)
if atomic.LoadInt32(&n) != 2 {
t.Fatalf("still expected 2, got: %d", n)
}

ticker.Reset(2 * time.Second)

// Advance the remaining 2 seconds
clock.Add(2 * time.Second)

if atomic.LoadInt32(&n) != 3 {
t.Fatalf("expected 3, got: %d", n)
}

// Advance another 2 seconds
clock.Add(2 * time.Second)

if atomic.LoadInt32(&n) != 4 {
t.Fatalf("expected 4, got: %d", n)
}
}

// Ensure that multiple tickers can be used together.
func TestMock_Ticker_Multi(t *testing.T) {
var n int32
Expand Down

0 comments on commit 023ccf9

Please sign in to comment.