mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-09-09 18:52:09 +02:00
Merge pull request #4317 from bhandras/testclock_improvement
clock: optionally wait until tickers are registered in TestClock
This commit is contained in:
@@ -10,6 +10,7 @@ type TestClock struct {
|
|||||||
currentTime time.Time
|
currentTime time.Time
|
||||||
timeChanMap map[time.Time][]chan time.Time
|
timeChanMap map[time.Time][]chan time.Time
|
||||||
timeLock sync.Mutex
|
timeLock sync.Mutex
|
||||||
|
tickSignal chan time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTestClock returns a new test clock.
|
// NewTestClock returns a new test clock.
|
||||||
@@ -20,6 +21,19 @@ func NewTestClock(startTime time.Time) *TestClock {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewTestClockWithTickSignal will create a new test clock with an added
|
||||||
|
// channel which will be used to signal when a new ticker is registered.
|
||||||
|
// This is useful when creating a ticker on a separate goroutine and we'd
|
||||||
|
// like to wait for that to happen before advancing the test case.
|
||||||
|
func NewTestClockWithTickSignal(startTime time.Time,
|
||||||
|
tickSignal chan time.Duration) *TestClock {
|
||||||
|
|
||||||
|
testClock := NewTestClock(startTime)
|
||||||
|
testClock.tickSignal = tickSignal
|
||||||
|
|
||||||
|
return testClock
|
||||||
|
}
|
||||||
|
|
||||||
// Now returns the current (test) time.
|
// Now returns the current (test) time.
|
||||||
func (c *TestClock) Now() time.Time {
|
func (c *TestClock) Now() time.Time {
|
||||||
c.timeLock.Lock()
|
c.timeLock.Lock()
|
||||||
@@ -32,7 +46,14 @@ func (c *TestClock) Now() time.Time {
|
|||||||
// duration has passed passed by the user set test time.
|
// duration has passed passed by the user set test time.
|
||||||
func (c *TestClock) TickAfter(duration time.Duration) <-chan time.Time {
|
func (c *TestClock) TickAfter(duration time.Duration) <-chan time.Time {
|
||||||
c.timeLock.Lock()
|
c.timeLock.Lock()
|
||||||
defer c.timeLock.Unlock()
|
defer func() {
|
||||||
|
c.timeLock.Unlock()
|
||||||
|
|
||||||
|
// Signal that the ticker has been added.
|
||||||
|
if c.tickSignal != nil {
|
||||||
|
c.tickSignal <- duration
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
triggerTime := c.currentTime.Add(duration)
|
triggerTime := c.currentTime.Add(duration)
|
||||||
ch := make(chan time.Time, 1)
|
ch := make(chan time.Time, 1)
|
||||||
|
@@ -1,8 +1,11 @@
|
|||||||
package clock
|
package clock
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -12,16 +15,11 @@ var (
|
|||||||
func TestNow(t *testing.T) {
|
func TestNow(t *testing.T) {
|
||||||
c := NewTestClock(testTime)
|
c := NewTestClock(testTime)
|
||||||
now := c.Now()
|
now := c.Now()
|
||||||
|
assert.Equal(t, testTime, now)
|
||||||
if now != testTime {
|
|
||||||
t.Fatalf("expected: %v, got: %v", testTime, now)
|
|
||||||
}
|
|
||||||
|
|
||||||
now = now.Add(time.Hour)
|
now = now.Add(time.Hour)
|
||||||
c.SetTime(now)
|
c.SetTime(now)
|
||||||
if c.Now() != now {
|
assert.Equal(t, now, c.Now())
|
||||||
t.Fatalf("epected: %v, got: %v", now, c.Now())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTickAfter(t *testing.T) {
|
func TestTickAfter(t *testing.T) {
|
||||||
@@ -42,12 +40,11 @@ func TestTickAfter(t *testing.T) {
|
|||||||
select {
|
select {
|
||||||
case <-ticker:
|
case <-ticker:
|
||||||
tick = true
|
tick = true
|
||||||
|
|
||||||
case <-time.After(time.Millisecond):
|
case <-time.After(time.Millisecond):
|
||||||
}
|
}
|
||||||
|
|
||||||
if tick != expectTick {
|
assert.Equal(t, expectTick, tick)
|
||||||
t.Fatalf("expected tick: %v, ticked: %v", expectTick, tick)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tickOrTimeOut(ticker0, true)
|
tickOrTimeOut(ticker0, true)
|
||||||
@@ -61,3 +58,34 @@ func TestTickAfter(t *testing.T) {
|
|||||||
tickOrTimeOut(ticker2, true)
|
tickOrTimeOut(ticker2, true)
|
||||||
tickOrTimeOut(ticker3, false)
|
tickOrTimeOut(ticker3, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestTickSignal tests that TickAfter signals registration allowing
|
||||||
|
// safe time advancement.
|
||||||
|
func TestTickSignal(t *testing.T) {
|
||||||
|
const interval = time.Second
|
||||||
|
|
||||||
|
ch := make(chan time.Duration)
|
||||||
|
c := NewTestClockWithTickSignal(testTime, ch)
|
||||||
|
err := make(chan error, 1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
select {
|
||||||
|
// TickAfter will signal registration but will not
|
||||||
|
// tick, unless we read the signal and set the time.
|
||||||
|
case <-c.TickAfter(interval):
|
||||||
|
err <- nil
|
||||||
|
|
||||||
|
// Signal timeout if tick didn't happen.
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
err <- fmt.Errorf("timeout")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
tick := <-ch
|
||||||
|
// Expect that the interval is correctly passed over the channel.
|
||||||
|
assert.Equal(t, interval, tick)
|
||||||
|
|
||||||
|
// Once the ticker is registered, set the time to make it fire.
|
||||||
|
c.SetTime(testTime.Add(time.Second))
|
||||||
|
assert.NoError(t, <-err)
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user