swarm/storage/feed/lookup: Add comments to tests

This commit is contained in:
Javier Peletier 2019-04-02 15:20:36 +02:00
parent daf5126401
commit 34bf9c4993
2 changed files with 255 additions and 192 deletions

File diff suppressed because one or more lines are too long

View file

@ -1,44 +1,54 @@
package lookup_test package lookup_test
// This file contains simple time simulation tools for testing
// and measuring time-aware algorithms
import ( import (
"sync" "sync"
"sync/atomic"
"time" "time"
) )
// Timer tracks information about a simulated timer
type Timer struct { type Timer struct {
deadline time.Time deadline time.Time
signal chan time.Time signal chan time.Time
id int32 id int
} }
// Stopwatch measures simulated execution time and manages simulated timers
type Stopwatch struct { type Stopwatch struct {
t time.Time t time.Time
r time.Duration resolution time.Duration
timers map[int32]*Timer timers map[int]*Timer
timerCounter int32 timerCounter int
stopSignal chan struct{} stopSignal chan struct{}
lock sync.RWMutex lock sync.RWMutex
} }
// NewStopwatch returns a simulated clock that ticks on `resolution` intervals
func NewStopwatch(resolution time.Duration) *Stopwatch { func NewStopwatch(resolution time.Duration) *Stopwatch {
s := &Stopwatch{ s := &Stopwatch{
r: resolution, resolution: resolution,
} }
s.Reset() s.Reset()
return s return s
} }
// Reset clears all timers and sents the stopwatch to zero
func (s *Stopwatch) Reset() { func (s *Stopwatch) Reset() {
s.t = time.Time{} s.t = time.Time{}
s.timers = make(map[int32]*Timer) s.timers = make(map[int]*Timer)
s.Stop() s.Stop()
} }
// Tick advances simulated time by the stopwatch's resolution and triggers
// all due timers
func (s *Stopwatch) Tick() { func (s *Stopwatch) Tick() {
s.t = s.t.Add(s.r) s.t = s.t.Add(s.resolution)
s.lock.Lock() s.lock.Lock()
defer s.lock.Unlock() defer s.lock.Unlock()
for id, timer := range s.timers { for id, timer := range s.timers {
if s.t.After(timer.deadline) || s.t.Equal(timer.deadline) { if s.t.After(timer.deadline) || s.t.Equal(timer.deadline) {
timer.signal <- s.t timer.signal <- s.t
@ -48,33 +58,45 @@ func (s *Stopwatch) Tick() {
} }
} }
// GetTimer returns a new timer that will trigger after `duration` elapses in the
// simulation
func (s *Stopwatch) GetTimer(duration time.Duration) <-chan time.Time { func (s *Stopwatch) GetTimer(duration time.Duration) <-chan time.Time {
s.lock.Lock()
defer s.lock.Unlock()
s.timerCounter++
timer := &Timer{ timer := &Timer{
deadline: s.t.Add(duration), deadline: s.t.Add(duration),
signal: make(chan time.Time, 1), signal: make(chan time.Time, 1),
id: atomic.AddInt32(&s.timerCounter, 1), id: s.timerCounter,
} }
s.lock.Lock()
defer s.lock.Unlock()
s.timers[timer.id] = timer s.timers[timer.id] = timer
return timer.signal return timer.signal
} }
// TimeAfter returns a simulated timer factory that can replace `time.After`
func (s *Stopwatch) TimeAfter() func(d time.Duration) <-chan time.Time { func (s *Stopwatch) TimeAfter() func(d time.Duration) <-chan time.Time {
return func(d time.Duration) <-chan time.Time { return func(d time.Duration) <-chan time.Time {
return s.GetTimer(d) return s.GetTimer(d)
} }
} }
// Elapsed returns the time that has passed in the simulation
func (s *Stopwatch) Elapsed() time.Duration { func (s *Stopwatch) Elapsed() time.Duration {
return s.t.Sub(time.Time{}) return s.t.Sub(time.Time{})
} }
// Run starts the time simulation
func (s *Stopwatch) Run() { func (s *Stopwatch) Run() {
go func() { go func() {
stopSignal := make(chan struct{}) stopSignal := make(chan struct{})
s.lock.Lock()
if s.stopSignal != nil {
close(s.stopSignal)
}
s.stopSignal = stopSignal s.stopSignal = stopSignal
s.lock.Unlock()
for { for {
select { select {
case <-time.After(1 * time.Millisecond): case <-time.After(1 * time.Millisecond):
@ -86,9 +108,21 @@ func (s *Stopwatch) Run() {
}() }()
} }
// Stop stops the time simulation
func (s *Stopwatch) Stop() { func (s *Stopwatch) Stop() {
s.lock.Lock()
defer s.lock.Unlock()
if s.stopSignal != nil { if s.stopSignal != nil {
close(s.stopSignal) close(s.stopSignal)
s.stopSignal = nil s.stopSignal = nil
} }
} }
func (s *Stopwatch) Measure(measuredFunc func()) time.Duration {
s.Reset()
s.Run()
defer s.Stop()
measuredFunc()
return s.Elapsed()
}