Skip to content

Commit 4696c47

Browse files
accounts: add service disabled unit tests
1 parent a49422f commit 4696c47

File tree

1 file changed

+225
-16
lines changed

1 file changed

+225
-16
lines changed

accounts/service_test.go

Lines changed: 225 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,12 @@ type mockLnd struct {
3232
invoiceReq chan lndclient.InvoiceSubscriptionRequest
3333
paymentReq chan lntypes.Hash
3434

35-
callErr error
36-
errChan chan error
37-
invoiceChan chan *lndclient.Invoice
38-
paymentChans map[lntypes.Hash]chan lndclient.PaymentStatus
35+
invoiceSubscriptionErr error
36+
trackPaymentErr error
37+
invoiceErrChan chan error
38+
paymentErrChan chan error
39+
invoiceChan chan *lndclient.Invoice
40+
paymentChans map[lntypes.Hash]chan lndclient.PaymentStatus
3941
}
4042

4143
func newMockLnd() *mockLnd {
@@ -44,9 +46,10 @@ func newMockLnd() *mockLnd {
4446
invoiceReq: make(
4547
chan lndclient.InvoiceSubscriptionRequest, 10,
4648
),
47-
paymentReq: make(chan lntypes.Hash, 10),
48-
errChan: make(chan error, 10),
49-
invoiceChan: make(chan *lndclient.Invoice),
49+
paymentReq: make(chan lntypes.Hash, 10),
50+
invoiceErrChan: make(chan error, 10),
51+
paymentErrChan: make(chan error, 10),
52+
invoiceChan: make(chan *lndclient.Invoice),
5053
paymentChans: make(
5154
map[lntypes.Hash]chan lndclient.PaymentStatus,
5255
),
@@ -144,28 +147,28 @@ func (m *mockLnd) SubscribeInvoices(_ context.Context,
144147
req lndclient.InvoiceSubscriptionRequest) (<-chan *lndclient.Invoice,
145148
<-chan error, error) {
146149

147-
if m.callErr != nil {
148-
return nil, nil, m.callErr
150+
if m.invoiceSubscriptionErr != nil {
151+
return nil, nil, m.invoiceSubscriptionErr
149152
}
150153

151154
m.invoiceReq <- req
152155

153-
return m.invoiceChan, m.errChan, nil
156+
return m.invoiceChan, m.invoiceErrChan, nil
154157
}
155158

156159
// TrackPayment picks up a previously started payment and returns a payment
157160
// update stream and an error stream.
158161
func (m *mockLnd) TrackPayment(_ context.Context,
159162
hash lntypes.Hash) (chan lndclient.PaymentStatus, chan error, error) {
160163

161-
if m.callErr != nil {
162-
return nil, nil, m.callErr
164+
if m.trackPaymentErr != nil {
165+
return nil, nil, m.trackPaymentErr
163166
}
164167

165168
m.paymentReq <- hash
166169
m.paymentChans[hash] = make(chan lndclient.PaymentStatus, 1)
167170

168-
return m.paymentChans[hash], m.errChan, nil
171+
return m.paymentChans[hash], m.paymentErrChan, nil
169172
}
170173

171174
// TestAccountService tests that the account service can track payments and
@@ -181,15 +184,92 @@ func TestAccountService(t *testing.T) {
181184
validate func(t *testing.T, lnd *mockLnd,
182185
s *InterceptorService)
183186
}{{
184-
name: "startup err on tracking payment",
187+
name: "startup err on invoice subscription",
185188
setup: func(t *testing.T, lnd *mockLnd, s *InterceptorService) {
186-
lnd.callErr = testErr
189+
lnd.invoiceSubscriptionErr = testErr
187190
},
188191
startupErr: testErr.Error(),
189192
validate: func(t *testing.T, lnd *mockLnd,
190193
s *InterceptorService) {
191194

192195
lnd.assertNoInvoiceRequest(t)
196+
require.False(t, s.IsRunning())
197+
},
198+
}, {
199+
name: "err on invoice update",
200+
setup: func(t *testing.T, lnd *mockLnd, s *InterceptorService) {
201+
acct := &OffChainBalanceAccount{
202+
ID: testID,
203+
Type: TypeInitialBalance,
204+
CurrentBalance: 1234,
205+
Invoices: AccountInvoices{
206+
testHash: {},
207+
},
208+
}
209+
210+
err := s.store.UpdateAccount(acct)
211+
require.NoError(t, err)
212+
},
213+
validate: func(t *testing.T, lnd *mockLnd,
214+
s *InterceptorService) {
215+
216+
// Start by closing the store. This should cause an
217+
// error once we make an invoice update, as the service
218+
// will fail when persisting the invoice update.
219+
s.store.Close()
220+
221+
// Ensure that the service was started successfully and
222+
// still running though, despite the closing of the
223+
// db store.
224+
require.True(t, s.IsRunning())
225+
226+
// Now let's send the invoice update, which should fail.
227+
lnd.invoiceChan <- &lndclient.Invoice{
228+
AddIndex: 12,
229+
SettleIndex: 12,
230+
Hash: testHash,
231+
AmountPaid: 777,
232+
State: invpkg.ContractSettled,
233+
}
234+
235+
// Ensure that the service was eventually disabled.
236+
assertEventually(t, func() bool {
237+
isRunning := s.IsRunning()
238+
return isRunning == false
239+
})
240+
lnd.assertMainErrContains(t, "database not open")
241+
},
242+
}, {
243+
name: "err in invoice err channel",
244+
setup: func(t *testing.T, lnd *mockLnd, s *InterceptorService) {
245+
acct := &OffChainBalanceAccount{
246+
ID: testID,
247+
Type: TypeInitialBalance,
248+
CurrentBalance: 1234,
249+
Invoices: AccountInvoices{
250+
testHash: {},
251+
},
252+
}
253+
254+
err := s.store.UpdateAccount(acct)
255+
require.NoError(t, err)
256+
},
257+
validate: func(t *testing.T, lnd *mockLnd,
258+
s *InterceptorService) {
259+
// Ensure that the service was started successfully.
260+
require.True(t, s.IsRunning())
261+
262+
// Now let's send an error over the invoice error
263+
// channel. This should disable the service.
264+
lnd.invoiceErrChan <- testErr
265+
266+
// Ensure that the service was eventually disabled.
267+
assertEventually(t, func() bool {
268+
isRunning := s.IsRunning()
269+
return isRunning == false
270+
})
271+
272+
lnd.assertMainErrContains(t, testErr.Error())
193273
},
194274
}, {
195275
name: "goroutine err sent on main err chan",
@@ -207,7 +287,7 @@ func TestAccountService(t *testing.T) {
207287
err := s.store.UpdateAccount(acct)
208288
require.NoError(t, err)
209289

210-
lnd.errChan <- testErr
290+
lnd.mainErrChan <- testErr
211291
},
212292
validate: func(t *testing.T, lnd *mockLnd,
213293
s *InterceptorService) {
@@ -239,6 +319,135 @@ func TestAccountService(t *testing.T) {
239319
lnd.assertNoPaymentRequest(t)
240320
lnd.assertInvoiceRequest(t, 0, 0)
241321
lnd.assertNoMainErr(t)
322+
require.True(t, s.IsRunning())
323+
},
324+
}, {
325+
name: "startup err on payment tracking",
326+
setup: func(t *testing.T, lnd *mockLnd, s *InterceptorService) {
327+
acct := &OffChainBalanceAccount{
328+
ID: testID,
329+
Type: TypeInitialBalance,
330+
CurrentBalance: 1234,
331+
Invoices: AccountInvoices{
332+
testHash: {},
333+
},
334+
Payments: AccountPayments{
335+
testHash: {
336+
Status: lnrpc.Payment_IN_FLIGHT,
337+
FullAmount: 1234,
338+
},
339+
},
340+
}
341+
342+
err := s.store.UpdateAccount(acct)
343+
require.NoError(t, err)
344+
345+
lnd.trackPaymentErr = testErr
346+
},
347+
validate: func(t *testing.T, lnd *mockLnd,
348+
s *InterceptorService) {
349+
350+
// Assert that the invoice subscription succeeded.
351+
require.Contains(t, s.invoiceToAccount, testHash)
352+
353+
// But setting up the payment tracking should have failed.
354+
require.False(t, s.IsRunning())
355+
356+
// Finally let's assert that we didn't successfully add the
357+
// payment to pending payment, and that lnd isn't awaiting
358+
// the payment request.
359+
require.NotContains(t, s.pendingPayments, testHash)
360+
lnd.assertNoPaymentRequest(t)
361+
},
362+
}, {
363+
name: "err on payment update",
364+
setup: func(t *testing.T, lnd *mockLnd, s *InterceptorService) {
365+
acct := &OffChainBalanceAccount{
366+
ID: testID,
367+
Type: TypeInitialBalance,
368+
CurrentBalance: 1234,
369+
Payments: AccountPayments{
370+
testHash: {
371+
Status: lnrpc.Payment_IN_FLIGHT,
372+
FullAmount: 1234,
373+
},
374+
},
375+
}
376+
377+
err := s.store.UpdateAccount(acct)
378+
require.NoError(t, err)
379+
},
380+
validate: func(t *testing.T, lnd *mockLnd,
381+
s *InterceptorService) {
382+
// Ensure that the service was started successfully,
383+
// and lnd contains the payment request.
384+
require.True(t, s.IsRunning())
385+
lnd.assertPaymentRequests(t, map[lntypes.Hash]struct{}{
386+
testHash: {},
387+
})
388+
389+
// Now let's wipe the service's pending payments.
390+
// This will cause an error send an update over
391+
// the payment channel, which should disable the
392+
// service.
393+
s.pendingPayments = make(map[lntypes.Hash]*trackedPayment)
394+
395+
// Send an invalid payment over the payment chan
396+
// which should error and disable the service
397+
lnd.paymentChans[testHash] <- lndclient.PaymentStatus{
398+
State: lnrpc.Payment_SUCCEEDED,
399+
Fee: 234,
400+
Value: 1000,
401+
}
402+
403+
// Ensure that the service was eventually disabled.
404+
assertEventually(t, func() bool {
405+
isRunning := s.IsRunning()
406+
return isRunning == false
407+
})
408+
lnd.assertMainErrContains(
409+
t, "not mapped to any account",
410+
)
411+
412+
},
413+
}, {
414+
name: "err in payment update chan",
415+
setup: func(t *testing.T, lnd *mockLnd, s *InterceptorService) {
416+
acct := &OffChainBalanceAccount{
417+
ID: testID,
418+
Type: TypeInitialBalance,
419+
CurrentBalance: 1234,
420+
Payments: AccountPayments{
421+
testHash: {
422+
Status: lnrpc.Payment_IN_FLIGHT,
423+
FullAmount: 1234,
424+
},
425+
},
426+
}
427+
428+
err := s.store.UpdateAccount(acct)
429+
require.NoError(t, err)
430+
},
431+
validate: func(t *testing.T, lnd *mockLnd,
432+
s *InterceptorService) {
433+
// Ensure that the service was started successfully,
434+
// and lnd contains the payment request.
435+
require.True(t, s.IsRunning())
436+
lnd.assertPaymentRequests(t, map[lntypes.Hash]struct{}{
437+
testHash: {},
438+
})
439+
440+
// Now let's send an error over the payment error
441+
// channel. This should disable the service.
442+
lnd.paymentErrChan <- testErr
443+
444+
// Ensure that the service was eventually disabled.
445+
assertEventually(t, func() bool {
446+
isRunning := s.IsRunning()
447+
return isRunning == false
448+
})
449+
450+
lnd.assertMainErrContains(t, testErr.Error())
242451
},
243452
}, {
244453
name: "startup track in-flight payments",

0 commit comments

Comments
 (0)