Skip to content

Commit e00c320

Browse files
committed
paymentsdb: make delete payments test db agnostic
We make the TestDeleteNonInFlight and separate all the logic out for the duplicate payment test case. The deletion of duplicate payments is now tested in isolation only for the kv backend.
1 parent 3bcb356 commit e00c320

File tree

2 files changed

+220
-199
lines changed

2 files changed

+220
-199
lines changed

payments/db/kv_store_test.go

Lines changed: 66 additions & 199 deletions
Original file line numberDiff line numberDiff line change
@@ -23,225 +23,92 @@ import (
2323
"github.com/stretchr/testify/require"
2424
)
2525

26-
// TestKVStoreDeleteNonInFlight checks that calling DeletePayments only
27-
// deletes payments from the database that are not in-flight.
28-
//
29-
// TODO(ziggie): Make this test db agnostic.
30-
func TestKVStoreDeleteNonInFlight(t *testing.T) {
26+
// TestKVStoreDeleteDuplicatePayments tests that when a payment with duplicate
27+
// payments is deleted, both the parent payment and its duplicates are properly
28+
// removed from the payment index. This is specific to the KV store's legacy
29+
// duplicate payment handling.
30+
func TestKVStoreDeleteDuplicatePayments(t *testing.T) {
3131
t.Parallel()
3232

3333
ctx := t.Context()
3434

3535
paymentDB := NewKVTestDB(t)
3636

37-
// Create a sequence number for duplicate payments that will not collide
38-
// with the sequence numbers for the payments we create. These values
39-
// start at 1, so 9999 is a safe bet for this test.
40-
var duplicateSeqNr = 9999
41-
42-
payments := []struct {
43-
failed bool
44-
success bool
45-
hasDuplicate bool
46-
}{
47-
{
48-
failed: true,
49-
success: false,
50-
hasDuplicate: false,
51-
},
52-
{
53-
failed: false,
54-
success: true,
55-
hasDuplicate: false,
56-
},
57-
{
58-
failed: false,
59-
success: false,
60-
hasDuplicate: false,
61-
},
62-
{
63-
failed: false,
64-
success: true,
65-
hasDuplicate: true,
66-
},
67-
}
68-
69-
var numSuccess, numInflight int
70-
71-
for _, p := range payments {
72-
preimg, err := genPreimage(t)
73-
require.NoError(t, err)
74-
75-
rhash := sha256.Sum256(preimg[:])
76-
info := genPaymentCreationInfo(t, rhash)
77-
attempt, err := genAttemptWithHash(
78-
t, 0, genSessionKey(t), rhash,
79-
)
80-
require.NoError(t, err)
81-
82-
// Sends base htlc message which initiate StatusInFlight.
83-
err = paymentDB.InitPayment(ctx, info.PaymentIdentifier, info)
84-
if err != nil {
85-
t.Fatalf("unable to send htlc message: %v", err)
86-
}
87-
_, err = paymentDB.RegisterAttempt(
88-
ctx, info.PaymentIdentifier, attempt,
89-
)
90-
if err != nil {
91-
t.Fatalf("unable to send htlc message: %v", err)
92-
}
93-
94-
htlc := &htlcStatus{
95-
HTLCAttemptInfo: attempt,
96-
}
97-
98-
switch {
99-
case p.failed:
100-
// Fail the payment attempt.
101-
htlcFailure := HTLCFailUnreadable
102-
_, err := paymentDB.FailAttempt(
103-
ctx, info.PaymentIdentifier, attempt.AttemptID,
104-
&HTLCFailInfo{
105-
Reason: htlcFailure,
106-
},
107-
)
108-
if err != nil {
109-
t.Fatalf("unable to fail htlc: %v", err)
110-
}
37+
// Create a successful payment.
38+
preimg, err := genPreimage(t)
39+
require.NoError(t, err)
11140

112-
// Fail the payment, which should moved it to Failed.
113-
failReason := FailureReasonNoRoute
114-
_, err = paymentDB.Fail(
115-
ctx, info.PaymentIdentifier, failReason,
116-
)
117-
if err != nil {
118-
t.Fatalf("unable to fail payment hash: %v", err)
119-
}
41+
rhash := sha256.Sum256(preimg[:])
42+
info := genPaymentCreationInfo(t, rhash)
43+
attempt, err := genAttemptWithHash(t, 0, genSessionKey(t), rhash)
44+
require.NoError(t, err)
12045

121-
// Verify the status is indeed Failed.
122-
assertDBPaymentstatus(
123-
t, paymentDB, info.PaymentIdentifier,
124-
StatusFailed,
125-
)
46+
// Init and settle the payment.
47+
err = paymentDB.InitPayment(ctx, info.PaymentIdentifier, info)
48+
require.NoError(t, err, "unable to init payment")
12649

127-
htlc.failure = &htlcFailure
128-
assertPaymentInfo(
129-
t, paymentDB, info.PaymentIdentifier, info,
130-
&failReason, htlc,
131-
)
50+
_, err = paymentDB.RegisterAttempt(
51+
ctx, info.PaymentIdentifier, attempt,
52+
)
53+
require.NoError(t, err, "unable to register attempt")
13254

133-
case p.success:
134-
// Verifies that status was changed to StatusSucceeded.
135-
_, err := paymentDB.SettleAttempt(
136-
ctx, info.PaymentIdentifier, attempt.AttemptID,
137-
&HTLCSettleInfo{
138-
Preimage: preimg,
139-
},
140-
)
141-
if err != nil {
142-
t.Fatalf("error shouldn't have been received,"+
143-
" got: %v", err)
144-
}
55+
_, err = paymentDB.SettleAttempt(
56+
ctx, info.PaymentIdentifier, attempt.AttemptID,
57+
&HTLCSettleInfo{
58+
Preimage: preimg,
59+
},
60+
)
61+
require.NoError(t, err, "unable to settle attempt")
14562

146-
assertDBPaymentstatus(
147-
t, paymentDB, info.PaymentIdentifier,
148-
StatusSucceeded,
149-
)
63+
assertDBPaymentstatus(
64+
t, paymentDB, info.PaymentIdentifier, StatusSucceeded,
65+
)
15066

151-
htlc.settle = &preimg
152-
assertPaymentInfo(
153-
t, paymentDB, info.PaymentIdentifier, info, nil,
154-
htlc,
155-
)
67+
// Fetch the payment to get its sequence number.
68+
payment, err := paymentDB.FetchPayment(ctx, info.PaymentIdentifier)
69+
require.NoError(t, err)
15670

157-
numSuccess++
71+
// Add two duplicate payments. Use high sequence numbers that won't
72+
// collide with the original payment.
73+
duplicateSeqNr1 := payment.SequenceNum + 1000
74+
duplicateSeqNr2 := payment.SequenceNum + 1001
15875

159-
default:
160-
assertDBPaymentstatus(
161-
t, paymentDB, info.PaymentIdentifier,
162-
StatusInFlight,
163-
)
164-
assertPaymentInfo(
165-
t, paymentDB, info.PaymentIdentifier, info, nil,
166-
htlc,
167-
)
76+
appendDuplicatePayment(
77+
t, paymentDB.db, info.PaymentIdentifier, duplicateSeqNr1,
78+
preimg,
79+
)
80+
appendDuplicatePayment(
81+
t, paymentDB.db, info.PaymentIdentifier, duplicateSeqNr2,
82+
preimg,
83+
)
16884

169-
numInflight++
170-
}
85+
// Verify we now have 3 index entries: original + 2 duplicates.
86+
var indexCount int
87+
err = kvdb.View(paymentDB.db, func(tx walletdb.ReadTx) error {
88+
index := tx.ReadBucket(paymentsIndexBucket)
17189

172-
// If the payment is intended to have a duplicate payment, we
173-
// add one.
174-
if p.hasDuplicate {
175-
appendDuplicatePayment(
176-
t, paymentDB.db, info.PaymentIdentifier,
177-
uint64(duplicateSeqNr), preimg,
178-
)
179-
duplicateSeqNr++
180-
numSuccess++
181-
}
182-
}
90+
return index.ForEach(func(k, v []byte) error {
91+
indexCount++
92+
return nil
93+
})
94+
}, func() { indexCount = 0 })
95+
require.NoError(t, err)
96+
require.Equal(t, 3, indexCount, "expected 3 index entries "+
97+
"(parent + 2 duplicates)")
18398

184-
// Delete all failed payments.
185-
numPayments, err := paymentDB.DeletePayments(ctx, true, false)
99+
// Delete all successful payments.
100+
numPayments, err := paymentDB.DeletePayments(ctx, false, false)
186101
require.NoError(t, err)
187-
require.EqualValues(t, 1, numPayments)
102+
require.EqualValues(t, 1, numPayments, "should delete 1 payment")
188103

189-
// This should leave the succeeded and in-flight payments.
104+
// Verify all payments are deleted.
190105
dbPayments, err := paymentDB.FetchPayments()
191-
if err != nil {
192-
t.Fatal(err)
193-
}
194-
195-
if len(dbPayments) != numSuccess+numInflight {
196-
t.Fatalf("expected %d payments, got %d",
197-
numSuccess+numInflight, len(dbPayments))
198-
}
199-
200-
var s, i int
201-
for _, p := range dbPayments {
202-
t.Log("fetch payment has status", p.Status)
203-
switch p.Status {
204-
case StatusSucceeded:
205-
s++
206-
case StatusInFlight:
207-
i++
208-
}
209-
}
210-
211-
if s != numSuccess {
212-
t.Fatalf("expected %d succeeded payments , got %d",
213-
numSuccess, s)
214-
}
215-
if i != numInflight {
216-
t.Fatalf("expected %d in-flight payments, got %d",
217-
numInflight, i)
218-
}
219-
220-
// Now delete all payments except in-flight.
221-
numPayments, err = paymentDB.DeletePayments(ctx, false, false)
222106
require.NoError(t, err)
223-
require.EqualValues(t, 2, numPayments)
107+
require.Empty(t, dbPayments, "all payments should be deleted")
224108

225-
// This should leave the in-flight payment.
226-
dbPayments, err = paymentDB.FetchPayments()
227-
if err != nil {
228-
t.Fatal(err)
229-
}
230-
231-
if len(dbPayments) != numInflight {
232-
t.Fatalf("expected %d payments, got %d", numInflight,
233-
len(dbPayments))
234-
}
235-
236-
for _, p := range dbPayments {
237-
if p.Status != StatusInFlight {
238-
t.Fatalf("expected in-fligth status, got %v", p.Status)
239-
}
240-
}
241-
242-
// Finally, check that we only have a single index left in the payment
243-
// index bucket.
244-
var indexCount int
109+
// Verify the payment index is now empty - all 3 entries (parent +
110+
// duplicates) should be removed.
111+
indexCount = 0
245112
err = kvdb.View(paymentDB.db, func(tx walletdb.ReadTx) error {
246113
index := tx.ReadBucket(paymentsIndexBucket)
247114

@@ -251,8 +118,8 @@ func TestKVStoreDeleteNonInFlight(t *testing.T) {
251118
})
252119
}, func() { indexCount = 0 })
253120
require.NoError(t, err)
254-
255-
require.Equal(t, 1, indexCount)
121+
require.Equal(t, 0, indexCount, "payment index should be empty "+
122+
"after deleting payment with duplicates")
256123
}
257124

258125
func makeFakeInfo(t *testing.T) (*PaymentCreationInfo,

0 commit comments

Comments
 (0)