chanfitness: pass clock in to chaneventstore for testing

This commit is contained in:
carla 2020-09-08 13:47:15 +02:00
parent 7afd113b9f
commit 94accfb69d
No known key found for this signature in database
GPG Key ID: 4CA7FE54A6213C91
6 changed files with 71 additions and 65 deletions

View File

@ -5,6 +5,7 @@ import (
"time" "time"
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/clock"
"github.com/lightningnetwork/lnd/routing/route" "github.com/lightningnetwork/lnd/routing/route"
) )
@ -46,9 +47,8 @@ type chanEventLog struct {
// events is a log of timestamped events observed for the channel. // events is a log of timestamped events observed for the channel.
events []*channelEvent events []*channelEvent
// now is expected to return the current time. It is supplied as an // clock allows creation of deterministic unit tests.
// external function to enable deterministic unit tests. clock clock.Clock
now func() time.Time
// openedAt tracks the first time this channel was seen. This is not // openedAt tracks the first time this channel was seen. This is not
// necessarily the time that it confirmed on chain because channel // necessarily the time that it confirmed on chain because channel
@ -62,13 +62,13 @@ type chanEventLog struct {
// newEventLog creates an event log for a channel with the openedAt time set. // newEventLog creates an event log for a channel with the openedAt time set.
func newEventLog(channelPoint wire.OutPoint, peer route.Vertex, func newEventLog(channelPoint wire.OutPoint, peer route.Vertex,
now func() time.Time) *chanEventLog { clock clock.Clock) *chanEventLog {
eventlog := &chanEventLog{ eventlog := &chanEventLog{
channelPoint: channelPoint, channelPoint: channelPoint,
peer: peer, peer: peer,
now: now, clock: clock,
openedAt: now(), openedAt: clock.Now(),
} }
return eventlog return eventlog
@ -76,7 +76,7 @@ func newEventLog(channelPoint wire.OutPoint, peer route.Vertex,
// close sets the closing time for an event log. // close sets the closing time for an event log.
func (e *chanEventLog) close() { func (e *chanEventLog) close() {
e.closedAt = e.now() e.closedAt = e.clock.Now()
} }
// add appends an event with the given type and current time to the event log. // add appends an event with the given type and current time to the event log.
@ -91,7 +91,7 @@ func (e *chanEventLog) add(eventType eventType) {
// Add the event to the eventLog with the current timestamp. // Add the event to the eventLog with the current timestamp.
event := &channelEvent{ event := &channelEvent{
timestamp: e.now(), timestamp: e.clock.Now(),
eventType: eventType, eventType: eventType,
} }
e.events = append(e.events, event) e.events = append(e.events, event)
@ -165,7 +165,7 @@ func (e *chanEventLog) getOnlinePeriods() []*onlinePeriod {
// closure. It it is still open, we calculate it until the present. // closure. It it is still open, we calculate it until the present.
endTime := e.closedAt endTime := e.closedAt
if endTime.IsZero() { if endTime.IsZero() {
endTime = e.now() endTime = e.clock.Now()
} }
// Add the final online period to the set and return. // Add the final online period to the set and return.

View File

@ -3,6 +3,8 @@ package chanfitness
import ( import (
"testing" "testing"
"time" "time"
"github.com/lightningnetwork/lnd/clock"
) )
// TestAdd tests adding events to an event log. It tests the case where the // TestAdd tests adding events to an event log. It tests the case where the
@ -18,7 +20,7 @@ func TestAdd(t *testing.T) {
{ {
name: "Channel open", name: "Channel open",
eventLog: &chanEventLog{ eventLog: &chanEventLog{
now: time.Now, clock: clock.NewTestClock(testNow),
}, },
event: peerOnlineEvent, event: peerOnlineEvent,
expected: []eventType{peerOnlineEvent}, expected: []eventType{peerOnlineEvent},
@ -26,7 +28,7 @@ func TestAdd(t *testing.T) {
{ {
name: "Channel closed, event not added", name: "Channel closed, event not added",
eventLog: &chanEventLog{ eventLog: &chanEventLog{
now: time.Now, clock: clock.NewTestClock(testNow),
}, },
event: peerOnlineEvent, event: peerOnlineEvent,
expected: []eventType{}, expected: []eventType{},
@ -55,13 +57,10 @@ func TestAdd(t *testing.T) {
// where no events present, and the case where an additional online period // where no events present, and the case where an additional online period
// must be added because the event log ends on an online event. // must be added because the event log ends on an online event.
func TestGetOnlinePeriod(t *testing.T) { func TestGetOnlinePeriod(t *testing.T) {
// Set time for consistent testing. fourHoursAgo := testNow.Add(time.Hour * -4)
now := time.Now() threeHoursAgo := testNow.Add(time.Hour * -3)
twoHoursAgo := testNow.Add(time.Hour * -2)
fourHoursAgo := now.Add(time.Hour * -4) oneHourAgo := testNow.Add(time.Hour * -1)
threeHoursAgo := now.Add(time.Hour * -3)
twoHoursAgo := now.Add(time.Hour * -2)
oneHourAgo := now.Add(time.Hour * -1)
tests := []struct { tests := []struct {
name string name string
@ -112,7 +111,7 @@ func TestGetOnlinePeriod(t *testing.T) {
expectedOnline: []*onlinePeriod{ expectedOnline: []*onlinePeriod{
{ {
start: fourHoursAgo, start: fourHoursAgo,
end: now, end: testNow,
}, },
}, },
}, },
@ -139,10 +138,8 @@ func TestGetOnlinePeriod(t *testing.T) {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
score := &chanEventLog{ score := &chanEventLog{
events: test.events, events: test.events,
now: func() time.Time { clock: clock.NewTestClock(testNow),
return now
},
openedAt: test.openedAt, openedAt: test.openedAt,
closedAt: test.closedAt, closedAt: test.closedAt,
} }
@ -172,13 +169,10 @@ func TestGetOnlinePeriod(t *testing.T) {
// TestUptime tests channel uptime calculation based on its event log. // TestUptime tests channel uptime calculation based on its event log.
func TestUptime(t *testing.T) { func TestUptime(t *testing.T) {
// Set time for consistent testing. fourHoursAgo := testNow.Add(time.Hour * -4)
now := time.Now() threeHoursAgo := testNow.Add(time.Hour * -3)
twoHoursAgo := testNow.Add(time.Hour * -2)
fourHoursAgo := now.Add(time.Hour * -4) oneHourAgo := testNow.Add(time.Hour * -1)
threeHoursAgo := now.Add(time.Hour * -3)
twoHoursAgo := now.Add(time.Hour * -2)
oneHourAgo := now.Add(time.Hour * -1)
tests := []struct { tests := []struct {
name string name string
@ -216,7 +210,7 @@ func TestUptime(t *testing.T) {
{ {
name: "End before start", name: "End before start",
endTime: threeHoursAgo, endTime: threeHoursAgo,
startTime: now, startTime: testNow,
expectErr: true, expectErr: true,
}, },
{ {
@ -234,7 +228,7 @@ func TestUptime(t *testing.T) {
}, },
}, },
startTime: fourHoursAgo, startTime: fourHoursAgo,
endTime: now, endTime: testNow,
expectedUptime: time.Hour * 3, expectedUptime: time.Hour * 3,
}, },
{ {
@ -247,7 +241,7 @@ func TestUptime(t *testing.T) {
}, },
}, },
startTime: fourHoursAgo, startTime: fourHoursAgo,
endTime: now, endTime: testNow,
expectedUptime: time.Hour * 4, expectedUptime: time.Hour * 4,
}, },
{ {
@ -261,7 +255,7 @@ func TestUptime(t *testing.T) {
}, },
}, },
startTime: fourHoursAgo, startTime: fourHoursAgo,
endTime: now, endTime: testNow,
}, },
{ {
name: "Online event before close", name: "Online event before close",
@ -274,7 +268,7 @@ func TestUptime(t *testing.T) {
}, },
}, },
startTime: fourHoursAgo, startTime: fourHoursAgo,
endTime: now, endTime: testNow,
expectedUptime: time.Hour, expectedUptime: time.Hour,
}, },
{ {
@ -292,7 +286,7 @@ func TestUptime(t *testing.T) {
}, },
}, },
startTime: fourHoursAgo, startTime: fourHoursAgo,
endTime: now, endTime: testNow,
expectedUptime: time.Hour, expectedUptime: time.Hour,
}, },
{ {
@ -306,7 +300,7 @@ func TestUptime(t *testing.T) {
}, },
}, },
startTime: twoHoursAgo, startTime: twoHoursAgo,
endTime: now, endTime: testNow,
expectedUptime: time.Hour, expectedUptime: time.Hour,
}, },
{ {
@ -318,12 +312,12 @@ func TestUptime(t *testing.T) {
eventType: peerOnlineEvent, eventType: peerOnlineEvent,
}, },
{ {
timestamp: now.Add(time.Hour), timestamp: testNow.Add(time.Hour),
eventType: peerOfflineEvent, eventType: peerOfflineEvent,
}, },
}, },
startTime: twoHoursAgo, startTime: twoHoursAgo,
endTime: now, endTime: testNow,
expectedUptime: time.Hour * 2, expectedUptime: time.Hour * 2,
}, },
{ {
@ -341,30 +335,30 @@ func TestUptime(t *testing.T) {
}, },
{ {
name: "Multiple online and offline", name: "Multiple online and offline",
openedAt: now.Add(time.Hour * -8), openedAt: testNow.Add(time.Hour * -8),
events: []*channelEvent{ events: []*channelEvent{
{ {
timestamp: now.Add(time.Hour * -7), timestamp: testNow.Add(time.Hour * -7),
eventType: peerOnlineEvent, eventType: peerOnlineEvent,
}, },
{ {
timestamp: now.Add(time.Hour * -6), timestamp: testNow.Add(time.Hour * -6),
eventType: peerOfflineEvent, eventType: peerOfflineEvent,
}, },
{ {
timestamp: now.Add(time.Hour * -5), timestamp: testNow.Add(time.Hour * -5),
eventType: peerOnlineEvent, eventType: peerOnlineEvent,
}, },
{ {
timestamp: now.Add(time.Hour * -4), timestamp: testNow.Add(time.Hour * -4),
eventType: peerOfflineEvent, eventType: peerOfflineEvent,
}, },
{ {
timestamp: now.Add(time.Hour * -3), timestamp: testNow.Add(time.Hour * -3),
eventType: peerOnlineEvent, eventType: peerOnlineEvent,
}, },
}, },
startTime: now.Add(time.Hour * -8), startTime: testNow.Add(time.Hour * -8),
endTime: oneHourAgo, endTime: oneHourAgo,
expectedUptime: time.Hour * 4, expectedUptime: time.Hour * 4,
}, },
@ -375,10 +369,8 @@ func TestUptime(t *testing.T) {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
score := &chanEventLog{ score := &chanEventLog{
events: test.events, events: test.events,
now: func() time.Time { clock: clock.NewTestClock(testNow),
return now
},
openedAt: test.openedAt, openedAt: test.openedAt,
closedAt: test.closedAt, closedAt: test.closedAt,
} }

View File

@ -18,6 +18,7 @@ import (
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/channelnotifier" "github.com/lightningnetwork/lnd/channelnotifier"
"github.com/lightningnetwork/lnd/clock"
"github.com/lightningnetwork/lnd/peernotifier" "github.com/lightningnetwork/lnd/peernotifier"
"github.com/lightningnetwork/lnd/routing/route" "github.com/lightningnetwork/lnd/routing/route"
"github.com/lightningnetwork/lnd/subscribe" "github.com/lightningnetwork/lnd/subscribe"
@ -72,6 +73,10 @@ type Config struct {
// used to populate the ChannelEventStore with a set of channels on // used to populate the ChannelEventStore with a set of channels on
// startup. // startup.
GetOpenChannels func() ([]*channeldb.OpenChannel, error) GetOpenChannels func() ([]*channeldb.OpenChannel, error)
// Clock is the time source that the subsystem uses, provided here
// for ease of testing.
Clock clock.Clock
} }
// lifespanRequest contains the channel ID required to query the store for a // lifespanRequest contains the channel ID required to query the store for a
@ -212,7 +217,7 @@ func (c *ChannelEventStore) addChannel(channelPoint wire.OutPoint,
} }
// Create an event log for the channel. // Create an event log for the channel.
eventLog := newEventLog(channelPoint, peer, time.Now) eventLog := newEventLog(channelPoint, peer, c.cfg.Clock)
// If the peer is already online, add a peer online event to record // If the peer is already online, add a peer online event to record
// the starting state of the peer. // the starting state of the peer.

View File

@ -9,11 +9,15 @@ import (
"github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/clock"
"github.com/lightningnetwork/lnd/routing/route" "github.com/lightningnetwork/lnd/routing/route"
"github.com/lightningnetwork/lnd/subscribe" "github.com/lightningnetwork/lnd/subscribe"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
// testNow is the current time tests will use.
var testNow = time.Unix(1592465134, 0)
// TestStartStoreError tests the starting of the store in cases where the setup // TestStartStoreError tests the starting of the store in cases where the setup
// functions fail. It does not test the mechanics of consuming events because // functions fail. It does not test the mechanics of consuming events because
// these are covered in a separate set of tests. // these are covered in a separate set of tests.
@ -57,10 +61,13 @@ func TestStartStoreError(t *testing.T) {
test := test test := test
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
clock := clock.NewTestClock(testNow)
store := NewChannelEventStore(&Config{ store := NewChannelEventStore(&Config{
SubscribeChannelEvents: test.ChannelEvents, SubscribeChannelEvents: test.ChannelEvents,
SubscribePeerEvents: test.PeerEvents, SubscribePeerEvents: test.PeerEvents,
GetOpenChannels: test.GetChannels, GetOpenChannels: test.GetChannels,
Clock: clock,
}) })
err := store.Start() err := store.Start()
@ -182,8 +189,6 @@ func testEventStore(t *testing.T, generateEvents func(*chanEventStoreTestCtx),
// TestGetLifetime tests the GetLifetime function for the cases where a channel // TestGetLifetime tests the GetLifetime function for the cases where a channel
// is known and unknown to the store. // is known and unknown to the store.
func TestGetLifetime(t *testing.T) { func TestGetLifetime(t *testing.T) {
now := time.Now()
tests := []struct { tests := []struct {
name string name string
channelFound bool channelFound bool
@ -195,8 +200,8 @@ func TestGetLifetime(t *testing.T) {
{ {
name: "Channel found", name: "Channel found",
channelFound: true, channelFound: true,
opened: now, opened: testNow,
closed: now.Add(time.Hour * -1), closed: testNow.Add(time.Hour * -1),
expectedError: nil, expectedError: nil,
}, },
{ {
@ -240,11 +245,8 @@ func TestGetLifetime(t *testing.T) {
// tests the unexpected edge cases where a tracked channel does not have any // tests the unexpected edge cases where a tracked channel does not have any
// events recorded, and when a zero time is specified for the uptime range. // events recorded, and when a zero time is specified for the uptime range.
func TestGetUptime(t *testing.T) { func TestGetUptime(t *testing.T) {
// Set time for deterministic unit tests. twoHoursAgo := testNow.Add(time.Hour * -2)
now := time.Now() fourHoursAgo := testNow.Add(time.Hour * -4)
twoHoursAgo := now.Add(time.Hour * -2)
fourHoursAgo := now.Add(time.Hour * -4)
tests := []struct { tests := []struct {
name string name string
@ -282,7 +284,7 @@ func TestGetUptime(t *testing.T) {
{ {
name: "No events", name: "No events",
startTime: twoHoursAgo, startTime: twoHoursAgo,
endTime: now, endTime: testNow,
channelFound: true, channelFound: true,
expectedError: nil, expectedError: nil,
}, },
@ -301,7 +303,7 @@ func TestGetUptime(t *testing.T) {
openedAt: fourHoursAgo, openedAt: fourHoursAgo,
expectedUptime: time.Hour * 2, expectedUptime: time.Hour * 2,
startTime: fourHoursAgo, startTime: fourHoursAgo,
endTime: now, endTime: testNow,
channelFound: true, channelFound: true,
expectedError: nil, expectedError: nil,
}, },
@ -315,14 +317,14 @@ func TestGetUptime(t *testing.T) {
}, },
openedAt: fourHoursAgo, openedAt: fourHoursAgo,
expectedUptime: time.Hour * 4, expectedUptime: time.Hour * 4,
endTime: now, endTime: testNow,
channelFound: true, channelFound: true,
expectedError: nil, expectedError: nil,
}, },
{ {
name: "Channel not found", name: "Channel not found",
startTime: twoHoursAgo, startTime: twoHoursAgo,
endTime: now, endTime: testNow,
channelFound: false, channelFound: false,
expectedError: ErrChannelNotFound, expectedError: ErrChannelNotFound,
}, },
@ -339,7 +341,7 @@ func TestGetUptime(t *testing.T) {
if test.channelFound { if test.channelFound {
eventLog := &chanEventLog{ eventLog := &chanEventLog{
events: test.events, events: test.events,
now: func() time.Time { return now }, clock: clock.NewTestClock(testNow),
openedAt: test.openedAt, openedAt: test.openedAt,
closedAt: test.closedAt, closedAt: test.closedAt,
} }

View File

@ -10,6 +10,7 @@ import (
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/channelnotifier" "github.com/lightningnetwork/lnd/channelnotifier"
"github.com/lightningnetwork/lnd/clock"
"github.com/lightningnetwork/lnd/peernotifier" "github.com/lightningnetwork/lnd/peernotifier"
"github.com/lightningnetwork/lnd/routing/route" "github.com/lightningnetwork/lnd/routing/route"
"github.com/lightningnetwork/lnd/subscribe" "github.com/lightningnetwork/lnd/subscribe"
@ -34,6 +35,9 @@ type chanEventStoreTestCtx struct {
// for a single pubkey + channel combination because its actual value // for a single pubkey + channel combination because its actual value
// does not matter. // does not matter.
testVarIdx int testVarIdx int
// clock is the clock that our test store will use.
clock *clock.TestClock
} }
// newChanEventStoreTestCtx creates a test context which can be used to test // newChanEventStoreTestCtx creates a test context which can be used to test
@ -43,9 +47,11 @@ func newChanEventStoreTestCtx(t *testing.T) *chanEventStoreTestCtx {
t: t, t: t,
channelSubscription: newMockSubscription(t), channelSubscription: newMockSubscription(t),
peerSubscription: newMockSubscription(t), peerSubscription: newMockSubscription(t),
clock: clock.NewTestClock(testNow),
} }
cfg := &Config{ cfg := &Config{
Clock: testCtx.clock,
SubscribeChannelEvents: func() (subscribe.Subscription, error) { SubscribeChannelEvents: func() (subscribe.Subscription, error) {
return testCtx.channelSubscription, nil return testCtx.channelSubscription, nil
}, },

View File

@ -1211,6 +1211,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
return s.peerNotifier.SubscribePeerEvents() return s.peerNotifier.SubscribePeerEvents()
}, },
GetOpenChannels: s.remoteChanDB.FetchAllOpenChannels, GetOpenChannels: s.remoteChanDB.FetchAllOpenChannels,
Clock: clock.NewDefaultClock(),
}) })
if cfg.WtClient.Active { if cfg.WtClient.Active {