You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

259 lines
6.1 KiB

  1. package loop
  2. import (
  3. "errors"
  4. "testing"
  5. "time"
  6. "github.com/lightninglabs/loop/loopdb"
  7. "github.com/lightninglabs/loop/test"
  8. "github.com/lightningnetwork/lnd/lntypes"
  9. )
  10. // storeMock implements a mock client swap store.
  11. type storeMock struct {
  12. loopOutSwaps map[lntypes.Hash]*loopdb.LoopOutContract
  13. loopOutUpdates map[lntypes.Hash][]loopdb.SwapStateData
  14. loopOutStoreChan chan loopdb.LoopOutContract
  15. loopOutUpdateChan chan loopdb.SwapStateData
  16. loopInSwaps map[lntypes.Hash]*loopdb.LoopInContract
  17. loopInUpdates map[lntypes.Hash][]loopdb.SwapStateData
  18. loopInStoreChan chan loopdb.LoopInContract
  19. loopInUpdateChan chan loopdb.SwapStateData
  20. t *testing.T
  21. }
  22. // NewStoreMock instantiates a new mock store.
  23. func newStoreMock(t *testing.T) *storeMock {
  24. return &storeMock{
  25. loopOutStoreChan: make(chan loopdb.LoopOutContract, 1),
  26. loopOutUpdateChan: make(chan loopdb.SwapStateData, 1),
  27. loopOutSwaps: make(map[lntypes.Hash]*loopdb.LoopOutContract),
  28. loopOutUpdates: make(map[lntypes.Hash][]loopdb.SwapStateData),
  29. loopInStoreChan: make(chan loopdb.LoopInContract, 1),
  30. loopInUpdateChan: make(chan loopdb.SwapStateData, 1),
  31. loopInSwaps: make(map[lntypes.Hash]*loopdb.LoopInContract),
  32. loopInUpdates: make(map[lntypes.Hash][]loopdb.SwapStateData),
  33. t: t,
  34. }
  35. }
  36. // FetchLoopOutSwaps returns all swaps currently in the store.
  37. //
  38. // NOTE: Part of the loopdb.SwapStore interface.
  39. func (s *storeMock) FetchLoopOutSwaps() ([]*loopdb.LoopOut, error) {
  40. result := []*loopdb.LoopOut{}
  41. for hash, contract := range s.loopOutSwaps {
  42. updates := s.loopOutUpdates[hash]
  43. events := make([]*loopdb.LoopEvent, len(updates))
  44. for i, u := range updates {
  45. events[i] = &loopdb.LoopEvent{
  46. SwapStateData: u,
  47. }
  48. }
  49. swap := &loopdb.LoopOut{
  50. Loop: loopdb.Loop{
  51. Hash: hash,
  52. Events: events,
  53. },
  54. Contract: contract,
  55. }
  56. result = append(result, swap)
  57. }
  58. return result, nil
  59. }
  60. // CreateLoopOut adds an initiated swap to the store.
  61. //
  62. // NOTE: Part of the loopdb.SwapStore interface.
  63. func (s *storeMock) CreateLoopOut(hash lntypes.Hash,
  64. swap *loopdb.LoopOutContract) error {
  65. _, ok := s.loopOutSwaps[hash]
  66. if ok {
  67. return errors.New("swap already exists")
  68. }
  69. s.loopOutSwaps[hash] = swap
  70. s.loopOutUpdates[hash] = []loopdb.SwapStateData{}
  71. s.loopOutStoreChan <- *swap
  72. return nil
  73. }
  74. // FetchLoopInSwaps returns all in swaps currently in the store.
  75. func (s *storeMock) FetchLoopInSwaps() ([]*loopdb.LoopIn, error) {
  76. result := []*loopdb.LoopIn{}
  77. for hash, contract := range s.loopInSwaps {
  78. updates := s.loopInUpdates[hash]
  79. events := make([]*loopdb.LoopEvent, len(updates))
  80. for i, u := range updates {
  81. events[i] = &loopdb.LoopEvent{
  82. SwapStateData: u,
  83. }
  84. }
  85. swap := &loopdb.LoopIn{
  86. Loop: loopdb.Loop{
  87. Hash: hash,
  88. Events: events,
  89. },
  90. Contract: contract,
  91. }
  92. result = append(result, swap)
  93. }
  94. return result, nil
  95. }
  96. // CreateLoopIn adds an initiated loop in swap to the store.
  97. //
  98. // NOTE: Part of the loopdb.SwapStore interface.
  99. func (s *storeMock) CreateLoopIn(hash lntypes.Hash,
  100. swap *loopdb.LoopInContract) error {
  101. _, ok := s.loopInSwaps[hash]
  102. if ok {
  103. return errors.New("swap already exists")
  104. }
  105. s.loopInSwaps[hash] = swap
  106. s.loopInUpdates[hash] = []loopdb.SwapStateData{}
  107. s.loopInStoreChan <- *swap
  108. return nil
  109. }
  110. // UpdateLoopOut stores a new event for a target loop out swap. This appends to
  111. // the event log for a particular swap as it goes through the various stages in
  112. // its lifetime.
  113. //
  114. // NOTE: Part of the loopdb.SwapStore interface.
  115. func (s *storeMock) UpdateLoopOut(hash lntypes.Hash, time time.Time,
  116. state loopdb.SwapStateData) error {
  117. updates, ok := s.loopOutUpdates[hash]
  118. if !ok {
  119. return errors.New("swap does not exists")
  120. }
  121. updates = append(updates, state)
  122. s.loopOutUpdates[hash] = updates
  123. s.loopOutUpdateChan <- state
  124. return nil
  125. }
  126. // UpdateLoopIn stores a new event for a target loop in swap. This appends to
  127. // the event log for a particular swap as it goes through the various stages in
  128. // its lifetime.
  129. //
  130. // NOTE: Part of the loopdb.SwapStore interface.
  131. func (s *storeMock) UpdateLoopIn(hash lntypes.Hash, time time.Time,
  132. state loopdb.SwapStateData) error {
  133. updates, ok := s.loopInUpdates[hash]
  134. if !ok {
  135. return errors.New("swap does not exists")
  136. }
  137. updates = append(updates, state)
  138. s.loopInUpdates[hash] = updates
  139. s.loopInUpdateChan <- state
  140. return nil
  141. }
  142. func (s *storeMock) Close() error {
  143. return nil
  144. }
  145. func (s *storeMock) isDone() error {
  146. select {
  147. case <-s.loopOutStoreChan:
  148. return errors.New("storeChan not empty")
  149. default:
  150. }
  151. select {
  152. case <-s.loopOutUpdateChan:
  153. return errors.New("updateChan not empty")
  154. default:
  155. }
  156. return nil
  157. }
  158. func (s *storeMock) assertLoopOutStored() {
  159. s.t.Helper()
  160. select {
  161. case <-s.loopOutStoreChan:
  162. case <-time.After(test.Timeout):
  163. s.t.Fatalf("expected swap to be stored")
  164. }
  165. }
  166. func (s *storeMock) assertLoopOutState(expectedState loopdb.SwapState) {
  167. s.t.Helper()
  168. state := <-s.loopOutUpdateChan
  169. if state.State != expectedState {
  170. s.t.Fatalf("expected state %v, got %v", expectedState, state)
  171. }
  172. }
  173. func (s *storeMock) assertLoopInStored() {
  174. s.t.Helper()
  175. <-s.loopInStoreChan
  176. }
  177. // assertLoopInState asserts that a specified state transition is persisted to
  178. // disk.
  179. func (s *storeMock) assertLoopInState(
  180. expectedState loopdb.SwapState) loopdb.SwapStateData {
  181. s.t.Helper()
  182. state := <-s.loopInUpdateChan
  183. if state.State != expectedState {
  184. s.t.Fatalf("expected state %v, got %v", expectedState, state)
  185. }
  186. return state
  187. }
  188. func (s *storeMock) assertStorePreimageReveal() {
  189. s.t.Helper()
  190. select {
  191. case state := <-s.loopOutUpdateChan:
  192. if state.State != loopdb.StatePreimageRevealed {
  193. s.t.Fatalf("unexpected state")
  194. }
  195. case <-time.After(test.Timeout):
  196. s.t.Fatalf("expected swap to be marked as preimage revealed")
  197. }
  198. }
  199. func (s *storeMock) assertStoreFinished(expectedResult loopdb.SwapState) {
  200. s.t.Helper()
  201. select {
  202. case state := <-s.loopOutUpdateChan:
  203. if state.State != expectedResult {
  204. s.t.Fatalf("expected result %v, but got %v",
  205. expectedResult, state)
  206. }
  207. case <-time.After(test.Timeout):
  208. s.t.Fatalf("expected swap to be finished")
  209. }
  210. }