routing/test: run each test case individually, add names
Update our payment lifecycle test to run each test case with a fresh router. This prevents test cases from interacting with each other. Names are also added for easy debugging.
This commit is contained in:
parent
cb927e89b0
commit
806c4cbd57
@ -48,56 +48,11 @@ func createTestRoute(amt lnwire.MilliSatoshi,
|
||||
)
|
||||
}
|
||||
|
||||
// TestRouterPaymentStateMachine tests that the router interacts as expected
|
||||
// with the ControlTower during a payment lifecycle, such that it payment
|
||||
// attempts are not sent twice to the switch, and results are handled after a
|
||||
// restart.
|
||||
func TestRouterPaymentStateMachine(t *testing.T) {
|
||||
t.Parallel()
|
||||
// paymentLifecycleTestCase contains the steps that we expect for a payment
|
||||
// lifecycle test, and the routes that pathfinding should deliver.
|
||||
type paymentLifecycleTestCase struct {
|
||||
name string
|
||||
|
||||
const startingBlockHeight = 101
|
||||
|
||||
// Setup two simple channels such that we can mock sending along this
|
||||
// route.
|
||||
chanCapSat := btcutil.Amount(100000)
|
||||
testChannels := []*testChannel{
|
||||
symmetricTestChannel("a", "b", chanCapSat, &testChannelPolicy{
|
||||
Expiry: 144,
|
||||
FeeRate: 400,
|
||||
MinHTLC: 1,
|
||||
MaxHTLC: lnwire.NewMSatFromSatoshis(chanCapSat),
|
||||
}, 1),
|
||||
symmetricTestChannel("b", "c", chanCapSat, &testChannelPolicy{
|
||||
Expiry: 144,
|
||||
FeeRate: 400,
|
||||
MinHTLC: 1,
|
||||
MaxHTLC: lnwire.NewMSatFromSatoshis(chanCapSat),
|
||||
}, 2),
|
||||
}
|
||||
|
||||
testGraph, err := createTestGraphFromChannels(testChannels, "a")
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create graph: %v", err)
|
||||
}
|
||||
defer testGraph.cleanUp()
|
||||
|
||||
paymentAmt := lnwire.NewMSatFromSatoshis(1000)
|
||||
|
||||
// We create a simple route that we will supply every time the router
|
||||
// requests one.
|
||||
rt, err := createTestRoute(paymentAmt, testGraph.aliasMap)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create route: %v", err)
|
||||
}
|
||||
|
||||
shard, err := createTestRoute(paymentAmt/4, testGraph.aliasMap)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create route: %v", err)
|
||||
}
|
||||
|
||||
// A payment state machine test case consists of several ordered steps,
|
||||
// that we use for driving the scenario.
|
||||
type testCase struct {
|
||||
// steps is a list of steps to perform during the testcase.
|
||||
steps []string
|
||||
|
||||
@ -188,9 +143,58 @@ func TestRouterPaymentStateMachine(t *testing.T) {
|
||||
resentPaymentError = "ResentPaymentError"
|
||||
)
|
||||
|
||||
tests := []testCase{
|
||||
// TestRouterPaymentStateMachine tests that the router interacts as expected
|
||||
// with the ControlTower during a payment lifecycle, such that it payment
|
||||
// attempts are not sent twice to the switch, and results are handled after a
|
||||
// restart.
|
||||
func TestRouterPaymentStateMachine(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const startingBlockHeight = 101
|
||||
|
||||
// Setup two simple channels such that we can mock sending along this
|
||||
// route.
|
||||
chanCapSat := btcutil.Amount(100000)
|
||||
testChannels := []*testChannel{
|
||||
symmetricTestChannel("a", "b", chanCapSat, &testChannelPolicy{
|
||||
Expiry: 144,
|
||||
FeeRate: 400,
|
||||
MinHTLC: 1,
|
||||
MaxHTLC: lnwire.NewMSatFromSatoshis(chanCapSat),
|
||||
}, 1),
|
||||
symmetricTestChannel("b", "c", chanCapSat, &testChannelPolicy{
|
||||
Expiry: 144,
|
||||
FeeRate: 400,
|
||||
MinHTLC: 1,
|
||||
MaxHTLC: lnwire.NewMSatFromSatoshis(chanCapSat),
|
||||
}, 2),
|
||||
}
|
||||
|
||||
testGraph, err := createTestGraphFromChannels(testChannels, "a")
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create graph: %v", err)
|
||||
}
|
||||
defer testGraph.cleanUp()
|
||||
|
||||
paymentAmt := lnwire.NewMSatFromSatoshis(1000)
|
||||
|
||||
// We create a simple route that we will supply every time the router
|
||||
// requests one.
|
||||
rt, err := createTestRoute(paymentAmt, testGraph.aliasMap)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create route: %v", err)
|
||||
}
|
||||
|
||||
shard, err := createTestRoute(paymentAmt/4, testGraph.aliasMap)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create route: %v", err)
|
||||
}
|
||||
|
||||
tests := []paymentLifecycleTestCase{
|
||||
{
|
||||
// Tests a normal payment flow that succeeds.
|
||||
name: "single shot success",
|
||||
|
||||
steps: []string{
|
||||
routerInitPayment,
|
||||
routerRegisterAttempt,
|
||||
@ -204,6 +208,8 @@ func TestRouterPaymentStateMachine(t *testing.T) {
|
||||
{
|
||||
// A payment flow with a failure on the first attempt,
|
||||
// but that succeeds on the second attempt.
|
||||
name: "single shot retry",
|
||||
|
||||
steps: []string{
|
||||
routerInitPayment,
|
||||
routerRegisterAttempt,
|
||||
@ -228,6 +234,8 @@ func TestRouterPaymentStateMachine(t *testing.T) {
|
||||
// A payment flow with a forwarding failure first time
|
||||
// sending to the switch, but that succeeds on the
|
||||
// second attempt.
|
||||
name: "single shot switch failure",
|
||||
|
||||
steps: []string{
|
||||
routerInitPayment,
|
||||
routerRegisterAttempt,
|
||||
@ -251,6 +259,8 @@ func TestRouterPaymentStateMachine(t *testing.T) {
|
||||
// A payment that fails on the first attempt, and has
|
||||
// only one route available to try. It will therefore
|
||||
// fail permanently.
|
||||
name: "single shot route fails",
|
||||
|
||||
steps: []string{
|
||||
routerInitPayment,
|
||||
routerRegisterAttempt,
|
||||
@ -270,6 +280,8 @@ func TestRouterPaymentStateMachine(t *testing.T) {
|
||||
{
|
||||
// We expect the payment to fail immediately if we have
|
||||
// no routes to try.
|
||||
name: "single shot no route",
|
||||
|
||||
steps: []string{
|
||||
routerInitPayment,
|
||||
routerFailPayment,
|
||||
@ -282,6 +294,8 @@ func TestRouterPaymentStateMachine(t *testing.T) {
|
||||
// the same payment after each step. This ensures that
|
||||
// the router don't attempt to resend a payment already
|
||||
// in flight.
|
||||
name: "single shot resend",
|
||||
|
||||
steps: []string{
|
||||
routerInitPayment,
|
||||
routerRegisterAttempt,
|
||||
@ -322,6 +336,8 @@ func TestRouterPaymentStateMachine(t *testing.T) {
|
||||
{
|
||||
// Tests that the router is able to handle the
|
||||
// receieved payment result after a restart.
|
||||
name: "single shot restart",
|
||||
|
||||
steps: []string{
|
||||
routerInitPayment,
|
||||
routerRegisterAttempt,
|
||||
@ -344,6 +360,8 @@ func TestRouterPaymentStateMachine(t *testing.T) {
|
||||
{
|
||||
// Tests that we are allowed to resend a payment after
|
||||
// it has permanently failed.
|
||||
name: "single shot resend fail",
|
||||
|
||||
steps: []string{
|
||||
routerInitPayment,
|
||||
routerRegisterAttempt,
|
||||
@ -382,6 +400,8 @@ func TestRouterPaymentStateMachine(t *testing.T) {
|
||||
// =====================================
|
||||
{
|
||||
// Tests a simple successful MP payment of 4 shards.
|
||||
name: "MP success",
|
||||
|
||||
steps: []string{
|
||||
routerInitPayment,
|
||||
|
||||
@ -422,6 +442,8 @@ func TestRouterPaymentStateMachine(t *testing.T) {
|
||||
{
|
||||
// An MP payment scenario where we need several extra
|
||||
// attempts before the payment finally settle.
|
||||
name: "MP failed shards",
|
||||
|
||||
steps: []string{
|
||||
routerInitPayment,
|
||||
|
||||
@ -474,6 +496,8 @@ func TestRouterPaymentStateMachine(t *testing.T) {
|
||||
// However the last shard settle, which means we get
|
||||
// the preimage and should consider the overall payment
|
||||
// a success.
|
||||
name: "MP one shard success",
|
||||
|
||||
steps: []string{
|
||||
routerInitPayment,
|
||||
|
||||
@ -513,6 +537,8 @@ func TestRouterPaymentStateMachine(t *testing.T) {
|
||||
{
|
||||
// An MP payment scenario a shard fail with a terminal
|
||||
// error, causing the router to stop attempting.
|
||||
name: "MP terminal",
|
||||
|
||||
steps: []string{
|
||||
routerInitPayment,
|
||||
|
||||
@ -554,6 +580,21 @@ func TestRouterPaymentStateMachine(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
testPaymentLifecycle(
|
||||
t, test, paymentAmt, startingBlockHeight,
|
||||
testGraph,
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testPaymentLifecycle(t *testing.T, test paymentLifecycleTestCase,
|
||||
paymentAmt lnwire.MilliSatoshi, startingBlockHeight uint32,
|
||||
testGraph *testGraphInstance) {
|
||||
|
||||
// Create a mock control tower with channels set up, that we use to
|
||||
// synchronize and listen for events.
|
||||
control := makeMockControlTower()
|
||||
@ -644,7 +685,6 @@ func TestRouterPaymentStateMachine(t *testing.T) {
|
||||
}
|
||||
}()
|
||||
|
||||
for _, test := range tests {
|
||||
// Craft a LightningPayment struct.
|
||||
var preImage lntypes.Preimage
|
||||
if _, err := rand.Read(preImage[:]); err != nil {
|
||||
@ -900,4 +940,3 @@ func TestRouterPaymentStateMachine(t *testing.T) {
|
||||
t.Fatalf("SendPayment didn't exit")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user