diff --git a/routing/mock_test.go b/routing/mock_test.go index 2caf9336..30d5dedc 100644 --- a/routing/mock_test.go +++ b/routing/mock_test.go @@ -83,7 +83,8 @@ func (m *mockPaymentAttemptDispatcher) setPaymentResult( } type mockPaymentSessionSource struct { - routes []*route.Route + routes []*route.Route + routeRelease chan struct{} } var _ PaymentSessionSource = (*mockPaymentSessionSource)(nil) @@ -91,7 +92,10 @@ var _ PaymentSessionSource = (*mockPaymentSessionSource)(nil) func (m *mockPaymentSessionSource) NewPaymentSession( _ *LightningPayment) (PaymentSession, error) { - return &mockPaymentSession{m.routes}, nil + return &mockPaymentSession{ + routes: m.routes, + release: m.routeRelease, + }, nil } func (m *mockPaymentSessionSource) NewPaymentSessionForRoute( @@ -137,6 +141,11 @@ func (m *mockMissionControl) GetProbability(fromNode, toNode route.Vertex, type mockPaymentSession struct { 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) @@ -144,6 +153,10 @@ var _ PaymentSession = (*mockPaymentSession)(nil) func (m *mockPaymentSession) RequestRoute(_, _ lnwire.MilliSatoshi, _, height uint32) (*route.Route, error) { + if m.release != nil { + m.release <- struct{}{} + } + if len(m.routes) == 0 { return nil, errNoPathFound } diff --git a/routing/payment_lifecycle_test.go b/routing/payment_lifecycle_test.go index 4fc5a015..036dc8ff 100644 --- a/routing/payment_lifecycle_test.go +++ b/routing/payment_lifecycle_test.go @@ -89,6 +89,10 @@ const ( // to call the Fail method on the control tower. 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 // call send the payment attempt to the switch, and we will // respond with a non-error, indicating that the payment @@ -205,6 +209,7 @@ func TestRouterPaymentStateMachine(t *testing.T) { steps: []string{ routerInitPayment, + routeRelease, routerRegisterAttempt, sendToSwitchSuccess, getPaymentResultSuccess, @@ -220,6 +225,7 @@ func TestRouterPaymentStateMachine(t *testing.T) { steps: []string{ routerInitPayment, + routeRelease, routerRegisterAttempt, sendToSwitchSuccess, @@ -228,6 +234,7 @@ func TestRouterPaymentStateMachine(t *testing.T) { routerFailAttempt, // The router should retry. + routeRelease, routerRegisterAttempt, sendToSwitchSuccess, @@ -246,6 +253,7 @@ func TestRouterPaymentStateMachine(t *testing.T) { steps: []string{ routerInitPayment, + routeRelease, routerRegisterAttempt, // Make the first sent attempt fail. @@ -253,6 +261,7 @@ func TestRouterPaymentStateMachine(t *testing.T) { routerFailAttempt, // The router should retry. + routeRelease, routerRegisterAttempt, sendToSwitchSuccess, @@ -271,6 +280,7 @@ func TestRouterPaymentStateMachine(t *testing.T) { steps: []string{ routerInitPayment, + routeRelease, routerRegisterAttempt, sendToSwitchSuccess, @@ -278,6 +288,8 @@ func TestRouterPaymentStateMachine(t *testing.T) { getPaymentResultTempFailure, routerFailAttempt, + routeRelease, + // Since there are no more routes to try, the // payment should fail. routerFailPayment, @@ -293,6 +305,7 @@ func TestRouterPaymentStateMachine(t *testing.T) { steps: []string{ routerInitPayment, + routeRelease, routerFailPayment, paymentError, }, @@ -308,6 +321,7 @@ func TestRouterPaymentStateMachine(t *testing.T) { steps: []string{ routerInitPayment, + routeRelease, routerRegisterAttempt, // Manually resend the payment, the router @@ -350,6 +364,7 @@ func TestRouterPaymentStateMachine(t *testing.T) { steps: []string{ routerInitPayment, + routeRelease, routerRegisterAttempt, sendToSwitchSuccess, @@ -375,6 +390,7 @@ func TestRouterPaymentStateMachine(t *testing.T) { steps: []string{ routerInitPayment, + routeRelease, routerRegisterAttempt, sendToSwitchSuccess, @@ -390,6 +406,7 @@ func TestRouterPaymentStateMachine(t *testing.T) { // Since we have no more routes to try, the // original payment should fail. + routeRelease, routerFailPayment, paymentError, @@ -397,6 +414,7 @@ func TestRouterPaymentStateMachine(t *testing.T) { // allowed, since the payment has failed. resendPayment, routerInitPayment, + routeRelease, routerRegisterAttempt, sendToSwitchSuccess, getPaymentResultSuccess, @@ -418,18 +436,22 @@ func TestRouterPaymentStateMachine(t *testing.T) { routerInitPayment, // shard 0 + routeRelease, routerRegisterAttempt, sendToSwitchSuccess, // shard 1 + routeRelease, routerRegisterAttempt, sendToSwitchSuccess, // shard 2 + routeRelease, routerRegisterAttempt, sendToSwitchSuccess, // shard 3 + routeRelease, routerRegisterAttempt, sendToSwitchSuccess, @@ -460,18 +482,22 @@ func TestRouterPaymentStateMachine(t *testing.T) { routerInitPayment, // shard 0 + routeRelease, routerRegisterAttempt, sendToSwitchSuccess, // shard 1 + routeRelease, routerRegisterAttempt, sendToSwitchSuccess, // shard 2 + routeRelease, routerRegisterAttempt, sendToSwitchSuccess, // shard 3 + routeRelease, routerRegisterAttempt, sendToSwitchSuccess, @@ -481,8 +507,10 @@ func TestRouterPaymentStateMachine(t *testing.T) { routerFailAttempt, routerFailAttempt, + routeRelease, routerRegisterAttempt, sendToSwitchSuccess, + routeRelease, routerRegisterAttempt, sendToSwitchSuccess, @@ -512,10 +540,12 @@ func TestRouterPaymentStateMachine(t *testing.T) { routerInitPayment, // shard 0 + routeRelease, routerRegisterAttempt, sendToSwitchSuccess, // shard 1 + routeRelease, routerRegisterAttempt, sendToSwitchSuccess, @@ -524,6 +554,10 @@ func TestRouterPaymentStateMachine(t *testing.T) { getPaymentResultTempFailure, routerFailAttempt, + // We will try one more shard because we haven't + // sent the full payment amount. + routeRelease, + // The second shard succeed against all odds, // making the overall payment succeed. getPaymentResultSuccess, @@ -541,18 +575,22 @@ func TestRouterPaymentStateMachine(t *testing.T) { routerInitPayment, // shard 0 + routeRelease, routerRegisterAttempt, sendToSwitchSuccess, // shard 1 + routeRelease, routerRegisterAttempt, sendToSwitchSuccess, // shard 2 + routeRelease, routerRegisterAttempt, sendToSwitchSuccess, // shard 3 + routeRelease, routerRegisterAttempt, sendToSwitchSuccess, @@ -697,8 +735,12 @@ func testPaymentLifecycle(t *testing.T, test paymentLifecycleTestCase, PaymentHash: payHash, } + // Setup our payment session source to block on release of + // routes. + routeChan := make(chan struct{}) router.cfg.SessionSource = &mockPaymentSessionSource{ - routes: test.routes, + routes: test.routes, + routeRelease: routeChan, } router.cfg.MissionControl = &mockMissionControl{} @@ -729,6 +771,14 @@ func testPaymentLifecycle(t *testing.T, test paymentLifecycleTestCase, 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 // register a new attempt with the ControlTower. case routerRegisterAttempt: