package common
|
|
|
|
import (
|
|
"math/rand"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/fortytw2/leaktest"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestDefaultTicker(t *testing.T) {
|
|
ticker := defaultTickerMaker(time.Millisecond * 10)
|
|
<-ticker.Chan()
|
|
ticker.Stop()
|
|
}
|
|
|
|
func TestRepeatTimer(t *testing.T) {
|
|
|
|
ch := make(chan time.Time, 100)
|
|
mtx := new(sync.Mutex)
|
|
|
|
// tick() fires from start to end
|
|
// (exclusive) in milliseconds with incr.
|
|
// It locks on mtx, so subsequent calls
|
|
// run in series.
|
|
tick := func(startMs, endMs, incrMs time.Duration) {
|
|
mtx.Lock()
|
|
go func() {
|
|
for tMs := startMs; tMs < endMs; tMs += incrMs {
|
|
lt := time.Time{}
|
|
lt = lt.Add(tMs * time.Millisecond)
|
|
ch <- lt
|
|
}
|
|
mtx.Unlock()
|
|
}()
|
|
}
|
|
|
|
// tock consumes Ticker.Chan() events and checks them against the ms in "timesMs".
|
|
tock := func(t *testing.T, rt *RepeatTimer, timesMs []int64) {
|
|
|
|
// Check against timesMs.
|
|
for _, timeMs := range timesMs {
|
|
tyme := <-rt.Chan()
|
|
sinceMs := tyme.Sub(time.Time{}) / time.Millisecond
|
|
assert.Equal(t, timeMs, int64(sinceMs))
|
|
}
|
|
|
|
// TODO detect number of running
|
|
// goroutines to ensure that
|
|
// no other times will fire.
|
|
// See https://github.com/tendermint/tendermint/libs/issues/120.
|
|
time.Sleep(time.Millisecond * 100)
|
|
done := true
|
|
select {
|
|
case <-rt.Chan():
|
|
done = false
|
|
default:
|
|
}
|
|
assert.True(t, done)
|
|
}
|
|
|
|
tm := NewLogicalTickerMaker(ch)
|
|
rt := NewRepeatTimerWithTickerMaker("bar", time.Second, tm)
|
|
|
|
/* NOTE: Useful for debugging deadlocks...
|
|
go func() {
|
|
time.Sleep(time.Second * 3)
|
|
trace := make([]byte, 102400)
|
|
count := runtime.Stack(trace, true)
|
|
fmt.Printf("Stack of %d bytes: %s\n", count, trace)
|
|
}()
|
|
*/
|
|
|
|
tick(0, 1000, 10)
|
|
tock(t, rt, []int64{})
|
|
tick(1000, 2000, 10)
|
|
tock(t, rt, []int64{1000})
|
|
tick(2005, 5000, 10)
|
|
tock(t, rt, []int64{2005, 3005, 4005})
|
|
tick(5001, 5999, 1)
|
|
// Read 5005 instead of 5001 because
|
|
// it's 1 second greater than 4005.
|
|
tock(t, rt, []int64{5005})
|
|
tick(6000, 7005, 1)
|
|
tock(t, rt, []int64{6005})
|
|
tick(7033, 8032, 1)
|
|
tock(t, rt, []int64{7033})
|
|
|
|
// After a reset, nothing happens
|
|
// until two ticks are received.
|
|
rt.Reset()
|
|
tock(t, rt, []int64{})
|
|
tick(8040, 8041, 1)
|
|
tock(t, rt, []int64{})
|
|
tick(9555, 9556, 1)
|
|
tock(t, rt, []int64{9555})
|
|
|
|
// After a stop, nothing more is sent.
|
|
rt.Stop()
|
|
tock(t, rt, []int64{})
|
|
|
|
// Another stop panics.
|
|
assert.Panics(t, func() { rt.Stop() })
|
|
}
|
|
|
|
func TestRepeatTimerReset(t *testing.T) {
|
|
// check that we are not leaking any go-routines
|
|
defer leaktest.Check(t)()
|
|
|
|
timer := NewRepeatTimer("test", 20*time.Millisecond)
|
|
defer timer.Stop()
|
|
|
|
// test we don't receive tick before duration ms.
|
|
select {
|
|
case <-timer.Chan():
|
|
t.Fatal("did not expect to receive tick")
|
|
default:
|
|
}
|
|
|
|
timer.Reset()
|
|
|
|
// test we receive tick after Reset is called
|
|
select {
|
|
case <-timer.Chan():
|
|
// all good
|
|
case <-time.After(40 * time.Millisecond):
|
|
t.Fatal("expected to receive tick after reset")
|
|
}
|
|
|
|
// just random calls
|
|
for i := 0; i < 100; i++ {
|
|
time.Sleep(time.Duration(rand.Intn(40)) * time.Millisecond)
|
|
timer.Reset()
|
|
}
|
|
}
|