mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-03-04 09:48:19 +01:00
Merge pull request #7314 from yyforyongyu/fix-unit-test-mailbox
htlcswitch: fix test flake in `TestMailBoxAddExpiry`
This commit is contained in:
commit
143eba82ea
6 changed files with 102 additions and 19 deletions
|
@ -238,3 +238,10 @@ issues:
|
||||||
- govet
|
- govet
|
||||||
# itest case can be very long so we disable long function check.
|
# itest case can be very long so we disable long function check.
|
||||||
- funlen
|
- funlen
|
||||||
|
|
||||||
|
- path: lnmock/*
|
||||||
|
linters:
|
||||||
|
# forcetypeassert is skipped for the mock because the test would fail
|
||||||
|
# if the returned value doesn't match the type, so there's no need to
|
||||||
|
# check the convert.
|
||||||
|
- forcetypeassert
|
||||||
|
|
|
@ -205,6 +205,9 @@ certain large transactions](https://github.com/lightningnetwork/lnd/pull/7100).
|
||||||
* [Code style cleanup](https://github.com/lightningnetwork/lnd/pull/7308) in the
|
* [Code style cleanup](https://github.com/lightningnetwork/lnd/pull/7308) in the
|
||||||
funding package.
|
funding package.
|
||||||
|
|
||||||
|
* [Fixed a flake in the TestMailBoxAddExpiry unit
|
||||||
|
test](https://github.com/lightningnetwork/lnd/pull/7314).
|
||||||
|
|
||||||
## `lncli`
|
## `lncli`
|
||||||
|
|
||||||
* [Add an `insecure` flag to skip tls auth as well as a `metadata` string slice
|
* [Add an `insecure` flag to skip tls auth as well as a `metadata` string slice
|
||||||
|
|
|
@ -935,7 +935,7 @@ type Keystone struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns a human readable description of the Keystone.
|
// String returns a human readable description of the Keystone.
|
||||||
func (k *Keystone) String() string {
|
func (k Keystone) String() string {
|
||||||
return fmt.Sprintf("%s --> %s", k.InKey, k.OutKey)
|
return fmt.Sprintf("%s --> %s", k.InKey, k.OutKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -548,6 +548,8 @@ func (m *memoryMailBox) mailCourier(cType courierType) {
|
||||||
m.pktCond.L.Unlock()
|
m.pktCond.L.Unlock()
|
||||||
|
|
||||||
case <-deadline:
|
case <-deadline:
|
||||||
|
log.Debugf("Expiring add htlc with "+
|
||||||
|
"keystone=%v", add.keystone())
|
||||||
m.FailAdd(add)
|
m.FailAdd(add)
|
||||||
|
|
||||||
case pktDone := <-m.pktReset:
|
case pktDone := <-m.pktReset:
|
||||||
|
|
|
@ -10,8 +10,10 @@ import (
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
"github.com/lightningnetwork/lnd/clock"
|
"github.com/lightningnetwork/lnd/clock"
|
||||||
|
"github.com/lightningnetwork/lnd/lnmock"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
|
"github.com/stretchr/testify/mock"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -192,6 +194,35 @@ type mailboxContext struct {
|
||||||
forwards chan *htlcPacket
|
forwards chan *htlcPacket
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// newMailboxContextWithClock creates a new mailbox context with the given
|
||||||
|
// mocked clock.
|
||||||
|
//
|
||||||
|
// TODO(yy): replace all usage of `newMailboxContext` with this method.
|
||||||
|
func newMailboxContextWithClock(t *testing.T,
|
||||||
|
clock clock.Clock) *mailboxContext {
|
||||||
|
|
||||||
|
ctx := &mailboxContext{
|
||||||
|
t: t,
|
||||||
|
forwards: make(chan *htlcPacket, 1),
|
||||||
|
}
|
||||||
|
|
||||||
|
failMailboxUpdate := func(outScid,
|
||||||
|
mboxScid lnwire.ShortChannelID) lnwire.FailureMessage {
|
||||||
|
|
||||||
|
return &lnwire.FailTemporaryNodeFailure{}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.mailbox = newMemoryMailBox(&mailBoxConfig{
|
||||||
|
failMailboxUpdate: failMailboxUpdate,
|
||||||
|
forwardPackets: ctx.forward,
|
||||||
|
clock: clock,
|
||||||
|
})
|
||||||
|
ctx.mailbox.Start()
|
||||||
|
t.Cleanup(ctx.mailbox.Stop)
|
||||||
|
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
func newMailboxContext(t *testing.T, startTime time.Time,
|
func newMailboxContext(t *testing.T, startTime time.Time,
|
||||||
expiry time.Duration) *mailboxContext {
|
expiry time.Duration) *mailboxContext {
|
||||||
|
|
||||||
|
@ -294,7 +325,7 @@ func (c *mailboxContext) checkFails(adds []*htlcPacket) {
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case pkt := <-c.forwards:
|
case pkt := <-c.forwards:
|
||||||
c.t.Fatalf("unexpected forward: %v", pkt)
|
c.t.Fatalf("unexpected forward: %v", pkt.keystone())
|
||||||
case <-time.After(50 * time.Millisecond):
|
case <-time.After(50 * time.Millisecond):
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -461,34 +492,44 @@ func TestMailBoxPacketPrioritization(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestMailBoxAddExpiry asserts that the mailbox will cancel back Adds that have
|
// TestMailBoxAddExpiry asserts that the mailbox will cancel back Adds that
|
||||||
// reached their expiry time.
|
// have reached their expiry time.
|
||||||
func TestMailBoxAddExpiry(t *testing.T) {
|
func TestMailBoxAddExpiry(t *testing.T) {
|
||||||
var (
|
|
||||||
expiry = time.Minute
|
|
||||||
batchDelay = time.Second
|
|
||||||
firstBatchStart = time.Now()
|
|
||||||
firstBatchExpiry = firstBatchStart.Add(expiry)
|
|
||||||
secondBatchStart = firstBatchStart.Add(batchDelay)
|
|
||||||
secondBatchExpiry = secondBatchStart.Add(expiry)
|
|
||||||
)
|
|
||||||
|
|
||||||
ctx := newMailboxContext(t, firstBatchStart, expiry)
|
|
||||||
|
|
||||||
// Each batch will consist of 10 messages.
|
// Each batch will consist of 10 messages.
|
||||||
const numBatchPackets = 10
|
const numBatchPackets = 10
|
||||||
|
|
||||||
firstBatch := ctx.sendAdds(0, numBatchPackets)
|
// deadline is the returned value from the `pktWithExpiry.deadline`.
|
||||||
|
deadline := make(chan time.Time, numBatchPackets*2)
|
||||||
|
|
||||||
ctx.clock.SetTime(secondBatchStart)
|
// Create a mock clock and mock the methods.
|
||||||
|
mockClock := &lnmock.MockClock{}
|
||||||
|
mockClock.On("Now").Return(time.Now())
|
||||||
|
|
||||||
|
// Mock TickAfter, which mounts the above `deadline` channel to the
|
||||||
|
// returned value from `pktWithExpiry.deadline`.
|
||||||
|
mockClock.On("TickAfter", mock.Anything).Return(deadline)
|
||||||
|
|
||||||
|
// Create a test mailbox context.
|
||||||
|
ctx := newMailboxContextWithClock(t, mockClock)
|
||||||
|
|
||||||
|
// Send 10 packets and assert no failures are sent back.
|
||||||
|
firstBatch := ctx.sendAdds(0, numBatchPackets)
|
||||||
ctx.checkFails(nil)
|
ctx.checkFails(nil)
|
||||||
|
|
||||||
|
// Send another 10 packets and assert no failures are sent back.
|
||||||
secondBatch := ctx.sendAdds(numBatchPackets, numBatchPackets)
|
secondBatch := ctx.sendAdds(numBatchPackets, numBatchPackets)
|
||||||
|
ctx.checkFails(nil)
|
||||||
|
|
||||||
ctx.clock.SetTime(firstBatchExpiry)
|
// Tick 10 times and we should see the first batch expired.
|
||||||
|
for i := 0; i < numBatchPackets; i++ {
|
||||||
|
deadline <- time.Now()
|
||||||
|
}
|
||||||
ctx.checkFails(firstBatch)
|
ctx.checkFails(firstBatch)
|
||||||
|
|
||||||
ctx.clock.SetTime(secondBatchExpiry)
|
// Tick another 10 times and we should see the second batch expired.
|
||||||
|
for i := 0; i < numBatchPackets; i++ {
|
||||||
|
deadline <- time.Now()
|
||||||
|
}
|
||||||
ctx.checkFails(secondBatch)
|
ctx.checkFails(secondBatch)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
30
lnmock/clock.go
Normal file
30
lnmock/clock.go
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// NOTE: forcetypeassert is skipped for the mock because the test would fail if
|
||||||
|
// the returned value doesn't match the type.
|
||||||
|
package lnmock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/lightningnetwork/lnd/clock"
|
||||||
|
"github.com/stretchr/testify/mock"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MockClock implements the `clock.Clock` interface.
|
||||||
|
type MockClock struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile time assertion that MockClock implements clock.Clock.
|
||||||
|
var _ clock.Clock = (*MockClock)(nil)
|
||||||
|
|
||||||
|
func (m *MockClock) Now() time.Time {
|
||||||
|
args := m.Called()
|
||||||
|
|
||||||
|
return args.Get(0).(time.Time)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockClock) TickAfter(d time.Duration) <-chan time.Time {
|
||||||
|
args := m.Called(d)
|
||||||
|
|
||||||
|
return args.Get(0).(chan time.Time)
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue