routing/test: block on pathfinding in tests

This commit adds a step to our payment lifecycle test to add
control over when we find a path for our payment, This is
required for testing race conditions around pathfinding
completing and payment failures being reported.
This commit is contained in:
carla 2021-04-23 08:39:43 +02:00
parent a68155545c
commit 125980afb7
No known key found for this signature in database
GPG Key ID: 4CA7FE54A6213C91
2 changed files with 66 additions and 3 deletions

@ -83,7 +83,8 @@ func (m *mockPaymentAttemptDispatcher) setPaymentResult(
} }
type mockPaymentSessionSource struct { type mockPaymentSessionSource struct {
routes []*route.Route routes []*route.Route
routeRelease chan struct{}
} }
var _ PaymentSessionSource = (*mockPaymentSessionSource)(nil) var _ PaymentSessionSource = (*mockPaymentSessionSource)(nil)
@ -91,7 +92,10 @@ var _ PaymentSessionSource = (*mockPaymentSessionSource)(nil)
func (m *mockPaymentSessionSource) NewPaymentSession( func (m *mockPaymentSessionSource) NewPaymentSession(
_ *LightningPayment) (PaymentSession, error) { _ *LightningPayment) (PaymentSession, error) {
return &mockPaymentSession{m.routes}, nil return &mockPaymentSession{
routes: m.routes,
release: m.routeRelease,
}, nil
} }
func (m *mockPaymentSessionSource) NewPaymentSessionForRoute( func (m *mockPaymentSessionSource) NewPaymentSessionForRoute(
@ -137,6 +141,11 @@ func (m *mockMissionControl) GetProbability(fromNode, toNode route.Vertex,
type mockPaymentSession struct { type mockPaymentSession struct {
routes []*route.Route routes []*route.Route
// release is a channel that optionally blocks requesting a route
// from our mock payment channel. If this value is nil, we will just
// release the route automatically.
release chan struct{}
} }
var _ PaymentSession = (*mockPaymentSession)(nil) var _ PaymentSession = (*mockPaymentSession)(nil)
@ -144,6 +153,10 @@ var _ PaymentSession = (*mockPaymentSession)(nil)
func (m *mockPaymentSession) RequestRoute(_, _ lnwire.MilliSatoshi, func (m *mockPaymentSession) RequestRoute(_, _ lnwire.MilliSatoshi,
_, height uint32) (*route.Route, error) { _, height uint32) (*route.Route, error) {
if m.release != nil {
m.release <- struct{}{}
}
if len(m.routes) == 0 { if len(m.routes) == 0 {
return nil, errNoPathFound return nil, errNoPathFound
} }

@ -89,6 +89,10 @@ const (
// to call the Fail method on the control tower. // to call the Fail method on the control tower.
routerFailPayment = "Router:fail-payment" routerFailPayment = "Router:fail-payment"
// routeRelease is a test step where we unblock pathfinding and
// allow it to respond to our test with a route.
routeRelease = "PaymentSession:release"
// sendToSwitchSuccess is a step where we expect the router to // sendToSwitchSuccess is a step where we expect the router to
// call send the payment attempt to the switch, and we will // call send the payment attempt to the switch, and we will
// respond with a non-error, indicating that the payment // respond with a non-error, indicating that the payment
@ -205,6 +209,7 @@ func TestRouterPaymentStateMachine(t *testing.T) {
steps: []string{ steps: []string{
routerInitPayment, routerInitPayment,
routeRelease,
routerRegisterAttempt, routerRegisterAttempt,
sendToSwitchSuccess, sendToSwitchSuccess,
getPaymentResultSuccess, getPaymentResultSuccess,
@ -220,6 +225,7 @@ func TestRouterPaymentStateMachine(t *testing.T) {
steps: []string{ steps: []string{
routerInitPayment, routerInitPayment,
routeRelease,
routerRegisterAttempt, routerRegisterAttempt,
sendToSwitchSuccess, sendToSwitchSuccess,
@ -228,6 +234,7 @@ func TestRouterPaymentStateMachine(t *testing.T) {
routerFailAttempt, routerFailAttempt,
// The router should retry. // The router should retry.
routeRelease,
routerRegisterAttempt, routerRegisterAttempt,
sendToSwitchSuccess, sendToSwitchSuccess,
@ -246,6 +253,7 @@ func TestRouterPaymentStateMachine(t *testing.T) {
steps: []string{ steps: []string{
routerInitPayment, routerInitPayment,
routeRelease,
routerRegisterAttempt, routerRegisterAttempt,
// Make the first sent attempt fail. // Make the first sent attempt fail.
@ -253,6 +261,7 @@ func TestRouterPaymentStateMachine(t *testing.T) {
routerFailAttempt, routerFailAttempt,
// The router should retry. // The router should retry.
routeRelease,
routerRegisterAttempt, routerRegisterAttempt,
sendToSwitchSuccess, sendToSwitchSuccess,
@ -271,6 +280,7 @@ func TestRouterPaymentStateMachine(t *testing.T) {
steps: []string{ steps: []string{
routerInitPayment, routerInitPayment,
routeRelease,
routerRegisterAttempt, routerRegisterAttempt,
sendToSwitchSuccess, sendToSwitchSuccess,
@ -278,6 +288,8 @@ func TestRouterPaymentStateMachine(t *testing.T) {
getPaymentResultTempFailure, getPaymentResultTempFailure,
routerFailAttempt, routerFailAttempt,
routeRelease,
// Since there are no more routes to try, the // Since there are no more routes to try, the
// payment should fail. // payment should fail.
routerFailPayment, routerFailPayment,
@ -293,6 +305,7 @@ func TestRouterPaymentStateMachine(t *testing.T) {
steps: []string{ steps: []string{
routerInitPayment, routerInitPayment,
routeRelease,
routerFailPayment, routerFailPayment,
paymentError, paymentError,
}, },
@ -308,6 +321,7 @@ func TestRouterPaymentStateMachine(t *testing.T) {
steps: []string{ steps: []string{
routerInitPayment, routerInitPayment,
routeRelease,
routerRegisterAttempt, routerRegisterAttempt,
// Manually resend the payment, the router // Manually resend the payment, the router
@ -350,6 +364,7 @@ func TestRouterPaymentStateMachine(t *testing.T) {
steps: []string{ steps: []string{
routerInitPayment, routerInitPayment,
routeRelease,
routerRegisterAttempt, routerRegisterAttempt,
sendToSwitchSuccess, sendToSwitchSuccess,
@ -375,6 +390,7 @@ func TestRouterPaymentStateMachine(t *testing.T) {
steps: []string{ steps: []string{
routerInitPayment, routerInitPayment,
routeRelease,
routerRegisterAttempt, routerRegisterAttempt,
sendToSwitchSuccess, sendToSwitchSuccess,
@ -390,6 +406,7 @@ func TestRouterPaymentStateMachine(t *testing.T) {
// Since we have no more routes to try, the // Since we have no more routes to try, the
// original payment should fail. // original payment should fail.
routeRelease,
routerFailPayment, routerFailPayment,
paymentError, paymentError,
@ -397,6 +414,7 @@ func TestRouterPaymentStateMachine(t *testing.T) {
// allowed, since the payment has failed. // allowed, since the payment has failed.
resendPayment, resendPayment,
routerInitPayment, routerInitPayment,
routeRelease,
routerRegisterAttempt, routerRegisterAttempt,
sendToSwitchSuccess, sendToSwitchSuccess,
getPaymentResultSuccess, getPaymentResultSuccess,
@ -418,18 +436,22 @@ func TestRouterPaymentStateMachine(t *testing.T) {
routerInitPayment, routerInitPayment,
// shard 0 // shard 0
routeRelease,
routerRegisterAttempt, routerRegisterAttempt,
sendToSwitchSuccess, sendToSwitchSuccess,
// shard 1 // shard 1
routeRelease,
routerRegisterAttempt, routerRegisterAttempt,
sendToSwitchSuccess, sendToSwitchSuccess,
// shard 2 // shard 2
routeRelease,
routerRegisterAttempt, routerRegisterAttempt,
sendToSwitchSuccess, sendToSwitchSuccess,
// shard 3 // shard 3
routeRelease,
routerRegisterAttempt, routerRegisterAttempt,
sendToSwitchSuccess, sendToSwitchSuccess,
@ -460,18 +482,22 @@ func TestRouterPaymentStateMachine(t *testing.T) {
routerInitPayment, routerInitPayment,
// shard 0 // shard 0
routeRelease,
routerRegisterAttempt, routerRegisterAttempt,
sendToSwitchSuccess, sendToSwitchSuccess,
// shard 1 // shard 1
routeRelease,
routerRegisterAttempt, routerRegisterAttempt,
sendToSwitchSuccess, sendToSwitchSuccess,
// shard 2 // shard 2
routeRelease,
routerRegisterAttempt, routerRegisterAttempt,
sendToSwitchSuccess, sendToSwitchSuccess,
// shard 3 // shard 3
routeRelease,
routerRegisterAttempt, routerRegisterAttempt,
sendToSwitchSuccess, sendToSwitchSuccess,
@ -481,8 +507,10 @@ func TestRouterPaymentStateMachine(t *testing.T) {
routerFailAttempt, routerFailAttempt,
routerFailAttempt, routerFailAttempt,
routeRelease,
routerRegisterAttempt, routerRegisterAttempt,
sendToSwitchSuccess, sendToSwitchSuccess,
routeRelease,
routerRegisterAttempt, routerRegisterAttempt,
sendToSwitchSuccess, sendToSwitchSuccess,
@ -512,10 +540,12 @@ func TestRouterPaymentStateMachine(t *testing.T) {
routerInitPayment, routerInitPayment,
// shard 0 // shard 0
routeRelease,
routerRegisterAttempt, routerRegisterAttempt,
sendToSwitchSuccess, sendToSwitchSuccess,
// shard 1 // shard 1
routeRelease,
routerRegisterAttempt, routerRegisterAttempt,
sendToSwitchSuccess, sendToSwitchSuccess,
@ -524,6 +554,10 @@ func TestRouterPaymentStateMachine(t *testing.T) {
getPaymentResultTempFailure, getPaymentResultTempFailure,
routerFailAttempt, routerFailAttempt,
// We will try one more shard because we haven't
// sent the full payment amount.
routeRelease,
// The second shard succeed against all odds, // The second shard succeed against all odds,
// making the overall payment succeed. // making the overall payment succeed.
getPaymentResultSuccess, getPaymentResultSuccess,
@ -541,18 +575,22 @@ func TestRouterPaymentStateMachine(t *testing.T) {
routerInitPayment, routerInitPayment,
// shard 0 // shard 0
routeRelease,
routerRegisterAttempt, routerRegisterAttempt,
sendToSwitchSuccess, sendToSwitchSuccess,
// shard 1 // shard 1
routeRelease,
routerRegisterAttempt, routerRegisterAttempt,
sendToSwitchSuccess, sendToSwitchSuccess,
// shard 2 // shard 2
routeRelease,
routerRegisterAttempt, routerRegisterAttempt,
sendToSwitchSuccess, sendToSwitchSuccess,
// shard 3 // shard 3
routeRelease,
routerRegisterAttempt, routerRegisterAttempt,
sendToSwitchSuccess, sendToSwitchSuccess,
@ -697,8 +735,12 @@ func testPaymentLifecycle(t *testing.T, test paymentLifecycleTestCase,
PaymentHash: payHash, PaymentHash: payHash,
} }
// Setup our payment session source to block on release of
// routes.
routeChan := make(chan struct{})
router.cfg.SessionSource = &mockPaymentSessionSource{ router.cfg.SessionSource = &mockPaymentSessionSource{
routes: test.routes, routes: test.routes,
routeRelease: routeChan,
} }
router.cfg.MissionControl = &mockMissionControl{} router.cfg.MissionControl = &mockMissionControl{}
@ -729,6 +771,14 @@ func testPaymentLifecycle(t *testing.T, test paymentLifecycleTestCase,
t.Fatalf("expected non-nil CreationInfo") t.Fatalf("expected non-nil CreationInfo")
} }
case routeRelease:
select {
case <-routeChan:
case <-time.After(stepTimeout):
t.Fatalf("no route requested")
}
// In this step we expect the router to make a call to // In this step we expect the router to make a call to
// register a new attempt with the ControlTower. // register a new attempt with the ControlTower.
case routerRegisterAttempt: case routerRegisterAttempt: