payment_status_test.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. package channeldb
  2. import (
  3. "fmt"
  4. "testing"
  5. "github.com/lightningnetwork/lnd/lntypes"
  6. "github.com/stretchr/testify/require"
  7. )
  8. // TestDecidePaymentStatus checks that given a set of HTLC and a failure
  9. // reason, the payment's current status is returned as expected.
  10. func TestDecidePaymentStatus(t *testing.T) {
  11. t.Parallel()
  12. // Create two attempts used for testing.
  13. inflight := HTLCAttempt{}
  14. settled := HTLCAttempt{
  15. Settle: &HTLCSettleInfo{Preimage: lntypes.Preimage{}},
  16. }
  17. failed := HTLCAttempt{
  18. Failure: &HTLCFailInfo{FailureSourceIndex: 1},
  19. }
  20. // Create a test failure reason and get the pointer.
  21. reason := FailureReasonNoRoute
  22. failure := &reason
  23. testCases := []struct {
  24. name string
  25. htlcs []HTLCAttempt
  26. reason *FailureReason
  27. expectedStatus PaymentStatus
  28. expectedErr error
  29. }{
  30. {
  31. // Test when inflight=true, settled=true, failed=true,
  32. // reason=yes.
  33. name: "state 1111",
  34. htlcs: []HTLCAttempt{
  35. inflight, settled, failed,
  36. },
  37. reason: failure,
  38. expectedStatus: StatusInFlight,
  39. },
  40. {
  41. // Test when inflight=true, settled=true, failed=true,
  42. // reason=no.
  43. name: "state 1110",
  44. htlcs: []HTLCAttempt{
  45. inflight, settled, failed,
  46. },
  47. reason: nil,
  48. expectedStatus: StatusInFlight,
  49. },
  50. {
  51. // Test when inflight=true, settled=true, failed=false,
  52. // reason=yes.
  53. name: "state 1101",
  54. htlcs: []HTLCAttempt{inflight, settled},
  55. reason: failure,
  56. expectedStatus: StatusInFlight,
  57. },
  58. {
  59. // Test when inflight=true, settled=true, failed=false,
  60. // reason=no.
  61. name: "state 1100",
  62. htlcs: []HTLCAttempt{inflight, settled},
  63. reason: nil,
  64. expectedStatus: StatusInFlight,
  65. },
  66. {
  67. // Test when inflight=true, settled=false, failed=true,
  68. // reason=yes.
  69. name: "state 1011",
  70. htlcs: []HTLCAttempt{inflight, failed},
  71. reason: failure,
  72. expectedStatus: StatusInFlight,
  73. },
  74. {
  75. // Test when inflight=true, settled=false, failed=true,
  76. // reason=no.
  77. name: "state 1010",
  78. htlcs: []HTLCAttempt{inflight, failed},
  79. reason: nil,
  80. expectedStatus: StatusInFlight,
  81. },
  82. {
  83. // Test when inflight=true, settled=false, failed=false,
  84. // reason=yes.
  85. name: "state 1001",
  86. htlcs: []HTLCAttempt{inflight},
  87. reason: failure,
  88. expectedStatus: StatusInFlight,
  89. },
  90. {
  91. // Test when inflight=true, settled=false, failed=false,
  92. // reason=no.
  93. name: "state 1000",
  94. htlcs: []HTLCAttempt{inflight},
  95. reason: nil,
  96. expectedStatus: StatusInFlight,
  97. },
  98. {
  99. // Test when inflight=false, settled=true, failed=true,
  100. // reason=yes.
  101. name: "state 0111",
  102. htlcs: []HTLCAttempt{settled, failed},
  103. reason: failure,
  104. expectedStatus: StatusSucceeded,
  105. },
  106. {
  107. // Test when inflight=false, settled=true, failed=true,
  108. // reason=no.
  109. name: "state 0110",
  110. htlcs: []HTLCAttempt{settled, failed},
  111. reason: nil,
  112. expectedStatus: StatusSucceeded,
  113. },
  114. {
  115. // Test when inflight=false, settled=true,
  116. // failed=false, reason=yes.
  117. name: "state 0101",
  118. htlcs: []HTLCAttempt{settled},
  119. reason: failure,
  120. expectedStatus: StatusSucceeded,
  121. },
  122. {
  123. // Test when inflight=false, settled=true,
  124. // failed=false, reason=no.
  125. name: "state 0100",
  126. htlcs: []HTLCAttempt{settled},
  127. reason: nil,
  128. expectedStatus: StatusSucceeded,
  129. },
  130. {
  131. // Test when inflight=false, settled=false,
  132. // failed=true, reason=yes.
  133. name: "state 0011",
  134. htlcs: []HTLCAttempt{failed},
  135. reason: failure,
  136. expectedStatus: StatusFailed,
  137. },
  138. {
  139. // Test when inflight=false, settled=false,
  140. // failed=true, reason=no.
  141. name: "state 0010",
  142. htlcs: []HTLCAttempt{failed},
  143. reason: nil,
  144. expectedStatus: StatusInFlight,
  145. },
  146. {
  147. // Test when inflight=false, settled=false,
  148. // failed=false, reason=yes.
  149. name: "state 0001",
  150. htlcs: []HTLCAttempt{},
  151. reason: failure,
  152. expectedStatus: StatusFailed,
  153. },
  154. {
  155. // Test when inflight=false, settled=false,
  156. // failed=false, reason=no.
  157. name: "state 0000",
  158. htlcs: []HTLCAttempt{},
  159. reason: nil,
  160. expectedStatus: StatusInitiated,
  161. },
  162. }
  163. for _, tc := range testCases {
  164. tc := tc
  165. t.Run(tc.name, func(t *testing.T) {
  166. t.Parallel()
  167. status, err := decidePaymentStatus(tc.htlcs, tc.reason)
  168. require.Equalf(t, tc.expectedStatus, status,
  169. "got %s, want %s", status, tc.expectedStatus)
  170. require.ErrorIs(t, err, tc.expectedErr)
  171. })
  172. }
  173. }
  174. // TestPaymentStatusActions checks whether a list of actions can be applied
  175. // against ALL possible payment statuses. Unlike normal unit tests where we
  176. // check against a single function, all the actions including `removable`,
  177. // `initable`, and `updatable` are tested together so this test can be used as
  178. // a reference of state transition.
  179. func TestPaymentStatusActions(t *testing.T) {
  180. t.Parallel()
  181. testCases := []struct {
  182. status PaymentStatus
  183. initErr error
  184. updateErr error
  185. removeErr error
  186. }{
  187. {
  188. status: StatusInitiated,
  189. initErr: ErrPaymentExists,
  190. updateErr: nil,
  191. removeErr: nil,
  192. },
  193. {
  194. status: StatusInFlight,
  195. initErr: ErrPaymentInFlight,
  196. updateErr: nil,
  197. removeErr: ErrPaymentInFlight,
  198. },
  199. {
  200. status: StatusSucceeded,
  201. initErr: ErrAlreadyPaid,
  202. updateErr: ErrPaymentAlreadySucceeded,
  203. removeErr: nil,
  204. },
  205. {
  206. status: StatusFailed,
  207. initErr: nil,
  208. updateErr: ErrPaymentAlreadyFailed,
  209. removeErr: nil,
  210. },
  211. {
  212. status: 0,
  213. initErr: ErrUnknownPaymentStatus,
  214. updateErr: ErrUnknownPaymentStatus,
  215. removeErr: ErrUnknownPaymentStatus,
  216. },
  217. }
  218. for i, tc := range testCases {
  219. i, tc := i, tc
  220. ps := tc.status
  221. name := fmt.Sprintf("test_%d_%s", i, ps.String())
  222. t.Run(name, func(t *testing.T) {
  223. t.Parallel()
  224. require.ErrorIs(t, ps.initializable(), tc.initErr,
  225. "initable under state %v", tc.status)
  226. require.ErrorIs(t, ps.updatable(), tc.updateErr,
  227. "updatable under state %v", tc.status)
  228. require.ErrorIs(t, ps.removable(), tc.removeErr,
  229. "removable under state %v", tc.status)
  230. })
  231. }
  232. }