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.

276 lines
8.3 KiB

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