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.

292 lines
8.8 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. // OnlyPendingWithdraws
  184. fetchedExits = []testExit{}
  185. limit = 7
  186. path = fmt.Sprintf(
  187. "%s?&onlyPendingWithdraws=%t&limit=%d&fromItem=",
  188. endpoint, true, limit,
  189. )
  190. err = doGoodReqPaginated(path, historydb.OrderAsc, &testExitsResponse{}, appendIter)
  191. assert.NoError(t, err)
  192. pendingExits := []testExit{}
  193. for i := 0; i < len(tc.exits); i++ {
  194. if tc.exits[i].InstantWithdrawn == nil && tc.exits[i].DelayedWithdrawn == nil {
  195. pendingExits = append(pendingExits, tc.exits[i])
  196. }
  197. }
  198. assertExitAPIs(t, pendingExits, fetchedExits)
  199. // Multiple filters
  200. fetchedExits = []testExit{}
  201. limit = 1
  202. path = fmt.Sprintf(
  203. "%s?batchNum=%d&tokeId=%d&limit=%d&fromItem=",
  204. endpoint, batchNum, tokenID, limit,
  205. )
  206. err = doGoodReqPaginated(path, historydb.OrderAsc, &testExitsResponse{}, appendIter)
  207. assert.NoError(t, err)
  208. mixedExits := []testExit{}
  209. flipedExits := []testExit{}
  210. for i := 0; i < len(tc.exits); i++ {
  211. if tc.exits[i].BatchNum == batchNum && tc.exits[i].Token.TokenID == tokenID {
  212. mixedExits = append(mixedExits, tc.exits[i])
  213. }
  214. flipedExits = append(flipedExits, tc.exits[len(tc.exits)-1-i])
  215. }
  216. assertExitAPIs(t, mixedExits, fetchedExits)
  217. // All, in reverse order
  218. fetchedExits = []testExit{}
  219. limit = 5
  220. path = fmt.Sprintf("%s?limit=%d&fromItem=", endpoint, limit)
  221. err = doGoodReqPaginated(path, historydb.OrderDesc, &testExitsResponse{}, appendIter)
  222. assert.NoError(t, err)
  223. assertExitAPIs(t, flipedExits, fetchedExits)
  224. // 400
  225. path = fmt.Sprintf(
  226. "%s?accountIndex=%s&hermezEthereumAddress=%s",
  227. endpoint, idx, tc.usrAddr,
  228. )
  229. err = doBadReq("GET", path, nil, 400)
  230. assert.NoError(t, err)
  231. path = fmt.Sprintf("%s?tokenId=X", endpoint)
  232. err = doBadReq("GET", path, nil, 400)
  233. assert.NoError(t, err)
  234. // 404
  235. path = fmt.Sprintf("%s?batchNum=999999", endpoint)
  236. err = doBadReq("GET", path, nil, 404)
  237. assert.NoError(t, err)
  238. path = fmt.Sprintf("%s?limit=1000&fromItem=999999", endpoint)
  239. err = doBadReq("GET", path, nil, 404)
  240. assert.NoError(t, err)
  241. }
  242. func TestGetExit(t *testing.T) {
  243. // Get all txs by their ID
  244. endpoint := apiURL + "exits/"
  245. fetchedExits := []testExit{}
  246. for _, exit := range tc.exits {
  247. fetchedExit := testExit{}
  248. assert.NoError(
  249. t, doGoodReq(
  250. "GET",
  251. fmt.Sprintf("%s%d/%s", endpoint, exit.BatchNum, exit.AccountIdx),
  252. nil, &fetchedExit,
  253. ),
  254. )
  255. fetchedExits = append(fetchedExits, fetchedExit)
  256. }
  257. assertExitAPIs(t, tc.exits, fetchedExits)
  258. // 400
  259. err := doBadReq("GET", endpoint+"1/haz:BOOM:1", nil, 400)
  260. assert.NoError(t, err)
  261. err = doBadReq("GET", endpoint+"-1/hez:BOOM:1", nil, 400)
  262. assert.NoError(t, err)
  263. // 404
  264. err = doBadReq("GET", endpoint+"494/hez:XXX:1", nil, 404)
  265. assert.NoError(t, err)
  266. }
  267. func assertExitAPIs(t *testing.T, expected, actual []testExit) {
  268. require.Equal(t, len(expected), len(actual))
  269. for i := 0; i < len(actual); i++ { //nolint len(actual) won't change within the loop
  270. actual[i].ItemID = 0
  271. actual[i].Token.ItemID = 0
  272. if expected[i].Token.USDUpdate == nil {
  273. assert.Equal(t, expected[i].Token.USDUpdate, actual[i].Token.USDUpdate)
  274. } else {
  275. assert.Equal(t, expected[i].Token.USDUpdate.Unix(), actual[i].Token.USDUpdate.Unix())
  276. expected[i].Token.USDUpdate = actual[i].Token.USDUpdate
  277. }
  278. assert.Equal(t, expected[i], actual[i])
  279. }
  280. }