invoices/test: add test clock

This commit is contained in:
Joost Jager 2019-12-09 13:28:05 +01:00
parent 499f2b16cf
commit 56958493fe
No known key found for this signature in database
GPG Key ID: A61B9D4C393C59C7

77
invoices/clock_test.go Normal file

@ -0,0 +1,77 @@
package invoices
import (
"sync"
"time"
)
// testClock can be used in tests to mock time.
type testClock struct {
currentTime time.Time
timeChanMap map[time.Time][]chan time.Time
timeLock sync.Mutex
}
// newTestClock returns a new test clock.
func newTestClock(startTime time.Time) *testClock {
return &testClock{
currentTime: startTime,
timeChanMap: make(map[time.Time][]chan time.Time),
}
}
// now returns the current (test) time.
func (c *testClock) now() time.Time {
c.timeLock.Lock()
defer c.timeLock.Unlock()
return c.currentTime
}
// tickAfter returns a channel that will receive a tick at the specified time.
func (c *testClock) tickAfter(duration time.Duration) <-chan time.Time {
c.timeLock.Lock()
defer c.timeLock.Unlock()
triggerTime := c.currentTime.Add(duration)
log.Debugf("tickAfter called: duration=%v, trigger_time=%v",
duration, triggerTime)
ch := make(chan time.Time, 1)
// If already expired, tick immediately.
if !triggerTime.After(c.currentTime) {
ch <- c.currentTime
return ch
}
// Otherwise store the channel until the trigger time is there.
chans := c.timeChanMap[triggerTime]
chans = append(chans, ch)
c.timeChanMap[triggerTime] = chans
return ch
}
// setTime sets the (test) time and triggers tick channels when they expire.
func (c *testClock) setTime(now time.Time) {
c.timeLock.Lock()
defer c.timeLock.Unlock()
c.currentTime = now
remainingChans := make(map[time.Time][]chan time.Time)
for triggerTime, chans := range c.timeChanMap {
// If the trigger time is still in the future, keep this channel
// in the channel map for later.
if triggerTime.After(now) {
remainingChans[triggerTime] = chans
continue
}
for _, c := range chans {
c <- now
}
}
c.timeChanMap = remainingChans
}