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.

286 lines
8.6 KiB

  1. package api
  2. import (
  3. "fmt"
  4. "testing"
  5. "github.com/hermeznetwork/hermez-node/common"
  6. "github.com/hermeznetwork/hermez-node/db/historydb"
  7. "github.com/mitchellh/copystructure"
  8. "github.com/stretchr/testify/assert"
  9. "github.com/stretchr/testify/require"
  10. )
  11. type testCVP struct {
  12. Root string
  13. Siblings []string
  14. OldKey string
  15. OldValue string
  16. IsOld0 bool
  17. Key string
  18. Value string
  19. Fnc int
  20. }
  21. type testExit struct {
  22. ItemID uint64 `json:"itemId"`
  23. BatchNum common.BatchNum `json:"batchNum"`
  24. AccountIdx string `json:"accountIndex"`
  25. MerkleProof testCVP `json:"merkleProof"`
  26. Balance string `json:"balance"`
  27. InstantWithdrawn *int64 `json:"instantWithdrawn"`
  28. DelayedWithdrawRequest *int64 `json:"delayedWithdrawRequest"`
  29. DelayedWithdrawn *int64 `json:"delayedWithdrawn"`
  30. Token historydb.TokenWithUSD `json:"token"`
  31. }
  32. type testExitsResponse struct {
  33. Exits []testExit `json:"exits"`
  34. PendingItems uint64 `json:"pendingItems"`
  35. }
  36. func (t testExitsResponse) GetPending() (pendingItems, lastItemID uint64) {
  37. pendingItems = t.PendingItems
  38. lastItemID = t.Exits[len(t.Exits)-1].ItemID
  39. return pendingItems, lastItemID
  40. }
  41. func (t *testExitsResponse) Len() int {
  42. return len(t.Exits)
  43. }
  44. func genTestExits(
  45. commonExits []common.ExitInfo,
  46. tokens []historydb.TokenWithUSD,
  47. accs []common.Account,
  48. usrIdxs []string,
  49. ) (usrExits, allExits []testExit) {
  50. allExits = []testExit{}
  51. for _, exit := range commonExits {
  52. token := getTokenByIdx(exit.AccountIdx, tokens, accs)
  53. siblings := []string{}
  54. for i := 0; i < len(exit.MerkleProof.Siblings); i++ {
  55. siblings = append(siblings, exit.MerkleProof.Siblings[i].String())
  56. }
  57. allExits = append(allExits, testExit{
  58. BatchNum: exit.BatchNum,
  59. AccountIdx: idxToHez(exit.AccountIdx, token.Symbol),
  60. MerkleProof: testCVP{
  61. Root: exit.MerkleProof.Root.String(),
  62. Siblings: siblings,
  63. OldKey: exit.MerkleProof.OldKey.String(),
  64. OldValue: exit.MerkleProof.OldValue.String(),
  65. IsOld0: exit.MerkleProof.IsOld0,
  66. Key: exit.MerkleProof.Key.String(),
  67. Value: exit.MerkleProof.Value.String(),
  68. Fnc: exit.MerkleProof.Fnc,
  69. },
  70. Balance: exit.Balance.String(),
  71. InstantWithdrawn: exit.InstantWithdrawn,
  72. DelayedWithdrawRequest: exit.DelayedWithdrawRequest,
  73. DelayedWithdrawn: exit.DelayedWithdrawn,
  74. Token: token,
  75. })
  76. }
  77. usrExits = []testExit{}
  78. for _, exit := range allExits {
  79. for _, idx := range usrIdxs {
  80. if idx == exit.AccountIdx {
  81. usrExits = append(usrExits, exit)
  82. break
  83. }
  84. }
  85. }
  86. return usrExits, allExits
  87. }
  88. func TestGetExits(t *testing.T) {
  89. endpoint := apiURL + "exits"
  90. fetchedExits := []testExit{}
  91. appendIter := func(intr interface{}) {
  92. for i := 0; i < len(intr.(*testExitsResponse).Exits); i++ {
  93. tmp, err := copystructure.Copy(intr.(*testExitsResponse).Exits[i])
  94. if err != nil {
  95. panic(err)
  96. }
  97. fetchedExits = append(fetchedExits, tmp.(testExit))
  98. }
  99. }
  100. // Get all (no filters)
  101. limit := 8
  102. path := fmt.Sprintf("%s?limit=%d&fromItem=", endpoint, limit)
  103. err := doGoodReqPaginated(path, historydb.OrderAsc, &testExitsResponse{}, appendIter)
  104. assert.NoError(t, err)
  105. assertExitAPIs(t, tc.exits, fetchedExits)
  106. // Get by ethAddr
  107. fetchedExits = []testExit{}
  108. limit = 7
  109. path = fmt.Sprintf(
  110. "%s?hermezEthereumAddress=%s&limit=%d&fromItem=",
  111. endpoint, tc.usrAddr, limit,
  112. )
  113. err = doGoodReqPaginated(path, historydb.OrderAsc, &testExitsResponse{}, appendIter)
  114. assert.NoError(t, err)
  115. assertExitAPIs(t, tc.usrExits, fetchedExits)
  116. // Get by bjj
  117. fetchedExits = []testExit{}
  118. limit = 6
  119. path = fmt.Sprintf(
  120. "%s?BJJ=%s&limit=%d&fromItem=",
  121. endpoint, tc.usrBjj, limit,
  122. )
  123. err = doGoodReqPaginated(path, historydb.OrderAsc, &testExitsResponse{}, appendIter)
  124. assert.NoError(t, err)
  125. assertExitAPIs(t, tc.usrExits, fetchedExits)
  126. // Get by tokenID
  127. fetchedExits = []testExit{}
  128. limit = 5
  129. tokenID := tc.exits[0].Token.TokenID
  130. path = fmt.Sprintf(
  131. "%s?tokenId=%d&limit=%d&fromItem=",
  132. endpoint, tokenID, limit,
  133. )
  134. err = doGoodReqPaginated(path, historydb.OrderAsc, &testExitsResponse{}, appendIter)
  135. assert.NoError(t, err)
  136. tokenIDExits := []testExit{}
  137. for i := 0; i < len(tc.exits); i++ {
  138. if tc.exits[i].Token.TokenID == tokenID {
  139. tokenIDExits = append(tokenIDExits, tc.exits[i])
  140. }
  141. }
  142. assertExitAPIs(t, tokenIDExits, fetchedExits)
  143. // idx
  144. fetchedExits = []testExit{}
  145. limit = 4
  146. idx := tc.exits[0].AccountIdx
  147. path = fmt.Sprintf(
  148. "%s?accountIndex=%s&limit=%d&fromItem=",
  149. endpoint, idx, limit,
  150. )
  151. err = doGoodReqPaginated(path, historydb.OrderAsc, &testExitsResponse{}, appendIter)
  152. assert.NoError(t, err)
  153. idxExits := []testExit{}
  154. for i := 0; i < len(tc.exits); i++ {
  155. if tc.exits[i].AccountIdx[6:] == idx[6:] {
  156. idxExits = append(idxExits, tc.exits[i])
  157. }
  158. }
  159. assertExitAPIs(t, idxExits, fetchedExits)
  160. // batchNum
  161. fetchedExits = []testExit{}
  162. limit = 3
  163. batchNum := tc.exits[0].BatchNum
  164. path = fmt.Sprintf(
  165. "%s?batchNum=%d&limit=%d&fromItem=",
  166. endpoint, batchNum, limit,
  167. )
  168. err = doGoodReqPaginated(path, historydb.OrderAsc, &testExitsResponse{}, appendIter)
  169. assert.NoError(t, err)
  170. batchNumExits := []testExit{}
  171. for i := 0; i < len(tc.exits); i++ {
  172. if tc.exits[i].BatchNum == batchNum {
  173. batchNumExits = append(batchNumExits, tc.exits[i])
  174. }
  175. }
  176. assertExitAPIs(t, batchNumExits, fetchedExits)
  177. // OnlyPendingWithdraws
  178. fetchedExits = []testExit{}
  179. limit = 7
  180. path = fmt.Sprintf(
  181. "%s?&onlyPendingWithdraws=%t&limit=%d&fromItem=",
  182. endpoint, true, limit,
  183. )
  184. err = doGoodReqPaginated(path, historydb.OrderAsc, &testExitsResponse{}, appendIter)
  185. assert.NoError(t, err)
  186. pendingExits := []testExit{}
  187. for i := 0; i < len(tc.exits); i++ {
  188. if tc.exits[i].InstantWithdrawn == nil && tc.exits[i].DelayedWithdrawn == nil {
  189. pendingExits = append(pendingExits, tc.exits[i])
  190. }
  191. }
  192. assertExitAPIs(t, pendingExits, fetchedExits)
  193. // Multiple filters
  194. fetchedExits = []testExit{}
  195. limit = 1
  196. path = fmt.Sprintf(
  197. "%s?batchNum=%d&tokeId=%d&limit=%d&fromItem=",
  198. endpoint, batchNum, tokenID, limit,
  199. )
  200. err = doGoodReqPaginated(path, historydb.OrderAsc, &testExitsResponse{}, appendIter)
  201. assert.NoError(t, err)
  202. mixedExits := []testExit{}
  203. flipedExits := []testExit{}
  204. for i := 0; i < len(tc.exits); i++ {
  205. if tc.exits[i].BatchNum == batchNum && tc.exits[i].Token.TokenID == tokenID {
  206. mixedExits = append(mixedExits, tc.exits[i])
  207. }
  208. flipedExits = append(flipedExits, tc.exits[len(tc.exits)-1-i])
  209. }
  210. assertExitAPIs(t, mixedExits, fetchedExits)
  211. // All, in reverse order
  212. fetchedExits = []testExit{}
  213. limit = 5
  214. path = fmt.Sprintf("%s?limit=%d&fromItem=", endpoint, limit)
  215. err = doGoodReqPaginated(path, historydb.OrderDesc, &testExitsResponse{}, appendIter)
  216. assert.NoError(t, err)
  217. assertExitAPIs(t, flipedExits, fetchedExits)
  218. // 400
  219. path = fmt.Sprintf(
  220. "%s?accountIndex=%s&hermezEthereumAddress=%s",
  221. endpoint, idx, tc.usrAddr,
  222. )
  223. err = doBadReq("GET", path, nil, 400)
  224. assert.NoError(t, err)
  225. path = fmt.Sprintf("%s?tokenId=X", endpoint)
  226. err = doBadReq("GET", path, nil, 400)
  227. assert.NoError(t, err)
  228. // 404
  229. path = fmt.Sprintf("%s?batchNum=999999", endpoint)
  230. err = doBadReq("GET", path, nil, 404)
  231. assert.NoError(t, err)
  232. path = fmt.Sprintf("%s?limit=1000&fromItem=999999", endpoint)
  233. err = doBadReq("GET", path, nil, 404)
  234. assert.NoError(t, err)
  235. }
  236. func TestGetExit(t *testing.T) {
  237. // Get all txs by their ID
  238. endpoint := apiURL + "exits/"
  239. fetchedExits := []testExit{}
  240. for _, exit := range tc.exits {
  241. fetchedExit := testExit{}
  242. assert.NoError(
  243. t, doGoodReq(
  244. "GET",
  245. fmt.Sprintf("%s%d/%s", endpoint, exit.BatchNum, exit.AccountIdx),
  246. nil, &fetchedExit,
  247. ),
  248. )
  249. fetchedExits = append(fetchedExits, fetchedExit)
  250. }
  251. assertExitAPIs(t, tc.exits, fetchedExits)
  252. // 400
  253. err := doBadReq("GET", endpoint+"1/haz:BOOM:1", nil, 400)
  254. assert.NoError(t, err)
  255. err = doBadReq("GET", endpoint+"-1/hez:BOOM:1", nil, 400)
  256. assert.NoError(t, err)
  257. // 404
  258. err = doBadReq("GET", endpoint+"494/hez:XXX:1", nil, 404)
  259. assert.NoError(t, err)
  260. }
  261. func assertExitAPIs(t *testing.T, expected, actual []testExit) {
  262. require.Equal(t, len(expected), len(actual))
  263. for i := 0; i < len(actual); i++ { //nolint len(actual) won't change within the loop
  264. actual[i].ItemID = 0
  265. actual[i].Token.ItemID = 0
  266. if expected[i].Token.USDUpdate == nil {
  267. assert.Equal(t, expected[i].Token.USDUpdate, actual[i].Token.USDUpdate)
  268. } else {
  269. assert.Equal(t, expected[i].Token.USDUpdate.Unix(), actual[i].Token.USDUpdate.Unix())
  270. expected[i].Token.USDUpdate = actual[i].Token.USDUpdate
  271. }
  272. assert.Equal(t, expected[i], actual[i])
  273. }
  274. }