ticker: rename mock.go -> force.go
This commit is contained in:
1 file changed
+105
@@ -0,0 +1,105 @@
|
||||
package ticker
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Force implements the Ticker interface, and provides a method of force-feeding
|
||||
// ticks, even while paused.
|
||||
type Force struct {
|
||||
isActive uint32 // used atomically
|
||||
|
||||
// Force is used to force-feed a ticks into the ticker. Useful for
|
||||
// debugging when trying to wake an event.
|
||||
Force chan time.Time
|
||||
|
||||
ticker <-chan time.Time
|
||||
skip chan struct{}
|
||||
|
||||
wg sync.WaitGroup
|
||||
quit chan struct{}
|
||||
}
|
||||
|
||||
// A compile-time constraint to ensure Force satisfies the Ticker interface.
|
||||
var _ Ticker = (*Force)(nil)
|
||||
|
||||
// NewForce returns a Force ticker, used for testing and debugging. It supports
|
||||
// the ability to force-feed events that get output by the
|
||||
func NewForce(interval time.Duration) *Force {
|
||||
m := &Force{
|
||||
ticker: time.NewTicker(interval).C,
|
||||
Force: make(chan time.Time),
|
||||
skip: make(chan struct{}),
|
||||
quit: make(chan struct{}),
|
||||
}
|
||||
|
||||
// Proxy the real ticks to our Force channel if we are active.
|
||||
m.wg.Add(1)
|
||||
go func() {
|
||||
defer m.wg.Done()
|
||||
for {
|
||||
select {
|
||||
case t := <-m.ticker:
|
||||
if atomic.LoadUint32(&m.isActive) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
select {
|
||||
case m.Force <- t:
|
||||
case <-m.skip:
|
||||
case <-m.quit:
|
||||
return
|
||||
}
|
||||
|
||||
case <-m.quit:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// Ticks returns a receive-only channel that delivers times at the ticker's
|
||||
// prescribed interval when active. Force-fed ticks can be delivered at any
|
||||
// time.
|
||||
//
|
||||
// NOTE: Part of the Ticker interface.
|
||||
func (m *Force) Ticks() <-chan time.Time {
|
||||
return m.Force
|
||||
}
|
||||
|
||||
// Resume starts underlying time.Ticker and causes the ticker to begin
|
||||
// delivering scheduled events.
|
||||
//
|
||||
// NOTE: Part of the Ticker interface.
|
||||
func (m *Force) Resume() {
|
||||
atomic.StoreUint32(&m.isActive, 1)
|
||||
}
|
||||
|
||||
// Pause suspends the underlying ticker, such that Ticks() stops signaling at
|
||||
// regular intervals.
|
||||
//
|
||||
// NOTE: Part of the Ticker interface.
|
||||
func (m *Force) Pause() {
|
||||
atomic.StoreUint32(&m.isActive, 0)
|
||||
|
||||
// If the ticker fired and read isActive as true, it may still send the
|
||||
// tick. We'll try to send on the skip channel to drop it.
|
||||
select {
|
||||
case m.skip <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
// Stop suspends the underlying ticker, such that Ticks() stops signaling at
|
||||
// regular intervals, and permanently frees up any resources.
|
||||
//
|
||||
// NOTE: Part of the Ticker interface.
|
||||
func (m *Force) Stop() {
|
||||
m.Pause()
|
||||
close(m.quit)
|
||||
m.wg.Wait()
|
||||
}
|
||||
Reference in new issue
Block a user