123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- package clockwork
- import (
- "sync"
- "time"
- )
- // Clock provides an interface that packages can use instead of directly
- // using the time module, so that chronology-related behavior can be tested
- type Clock interface {
- After(d time.Duration) <-chan time.Time
- Sleep(d time.Duration)
- Now() time.Time
- }
- // FakeClock provides an interface for a clock which can be
- // manually advanced through time
- type FakeClock interface {
- Clock
- // Advance advances the FakeClock to a new point in time, ensuring any existing
- // sleepers are notified appropriately before returning
- Advance(d time.Duration)
- // BlockUntil will block until the FakeClock has the given number of
- // sleepers (callers of Sleep or After)
- BlockUntil(n int)
- }
- // NewRealClock returns a Clock which simply delegates calls to the actual time
- // package; it should be used by packages in production.
- func NewRealClock() Clock {
- return &realClock{}
- }
- // NewFakeClock returns a FakeClock implementation which can be
- // manually advanced through time for testing.
- func NewFakeClock() FakeClock {
- return &fakeClock{
- l: sync.RWMutex{},
- }
- }
- type realClock struct{}
- func (rc *realClock) After(d time.Duration) <-chan time.Time {
- return time.After(d)
- }
- func (rc *realClock) Sleep(d time.Duration) {
- time.Sleep(d)
- }
- func (rc *realClock) Now() time.Time {
- return time.Now()
- }
- type fakeClock struct {
- sleepers []*sleeper
- blockers []*blocker
- time time.Time
- l sync.RWMutex
- }
- // sleeper represents a caller of After or Sleep
- type sleeper struct {
- until time.Time
- done chan time.Time
- }
- // blocker represents a caller of BlockUntil
- type blocker struct {
- count int
- ch chan struct{}
- }
- // After mimics time.After; it waits for the given duration to elapse on the
- // fakeClock, then sends the current time on the returned channel.
- func (fc *fakeClock) After(d time.Duration) <-chan time.Time {
- fc.l.Lock()
- defer fc.l.Unlock()
- now := fc.time
- done := make(chan time.Time, 1)
- if d.Nanoseconds() == 0 {
- // special case - trigger immediately
- done <- now
- } else {
- // otherwise, add to the set of sleepers
- s := &sleeper{
- until: now.Add(d),
- done: done,
- }
- fc.sleepers = append(fc.sleepers, s)
- // and notify any blockers
- fc.blockers = notifyBlockers(fc.blockers, len(fc.sleepers))
- }
- return done
- }
- // notifyBlockers notifies all the blockers waiting until the
- // given number of sleepers are waiting on the fakeClock. It
- // returns an updated slice of blockers (i.e. those still waiting)
- func notifyBlockers(blockers []*blocker, count int) (newBlockers []*blocker) {
- for _, b := range blockers {
- if b.count == count {
- close(b.ch)
- } else {
- newBlockers = append(newBlockers, b)
- }
- }
- return
- }
- // Sleep blocks until the given duration has passed on the fakeClock
- func (fc *fakeClock) Sleep(d time.Duration) {
- <-fc.After(d)
- }
- // Time returns the current time of the fakeClock
- func (fc *fakeClock) Now() time.Time {
- fc.l.Lock()
- defer fc.l.Unlock()
- return fc.time
- }
- // Advance advances fakeClock to a new point in time, ensuring channels from any
- // previous invocations of After are notified appropriately before returning
- func (fc *fakeClock) Advance(d time.Duration) {
- fc.l.Lock()
- defer fc.l.Unlock()
- end := fc.time.Add(d)
- var newSleepers []*sleeper
- for _, s := range fc.sleepers {
- if end.Sub(s.until) >= 0 {
- s.done <- end
- } else {
- newSleepers = append(newSleepers, s)
- }
- }
- fc.sleepers = newSleepers
- fc.blockers = notifyBlockers(fc.blockers, len(fc.sleepers))
- fc.time = end
- }
- // BlockUntil will block until the fakeClock has the given number of sleepers
- // (callers of Sleep or After)
- func (fc *fakeClock) BlockUntil(n int) {
- fc.l.Lock()
- // Fast path: current number of sleepers is what we're looking for
- if len(fc.sleepers) == n {
- fc.l.Unlock()
- return
- }
- // Otherwise, set up a new blocker
- b := &blocker{
- count: n,
- ch: make(chan struct{}),
- }
- fc.blockers = append(fc.blockers, b)
- fc.l.Unlock()
- <-b.ch
- }
|