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.

303 lines
8.9 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) New() Pendinger { return &testExitsResponse{} }
  42. func (t *testExitsResponse) Len() int {
  43. return len(t.Exits)
  44. }
  45. func genTestExits(
  46. commonExits []common.ExitInfo,
  47. tokens []historydb.TokenWithUSD,
  48. accs []common.Account,
  49. ) []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. return allExits
  78. }
  79. func TestGetExits(t *testing.T) {
  80. endpoint := apiURL + "exits"
  81. fetchedExits := []testExit{}
  82. appendIter := func(intr interface{}) {
  83. for i := 0; i < len(intr.(*testExitsResponse).Exits); i++ {
  84. tmp, err := copystructure.Copy(intr.(*testExitsResponse).Exits[i])
  85. if err != nil {
  86. panic(err)
  87. }
  88. fetchedExits = append(fetchedExits, tmp.(testExit))
  89. }
  90. }
  91. // Get all (no filters)
  92. limit := 8
  93. path := fmt.Sprintf("%s?limit=%d", endpoint, limit)
  94. err := doGoodReqPaginated(path, historydb.OrderAsc, &testExitsResponse{}, appendIter)
  95. assert.NoError(t, err)
  96. assertExitAPIs(t, tc.exits, fetchedExits)
  97. // Get by ethAddr
  98. fetchedExits = []testExit{}
  99. limit = 7
  100. var account testAccount
  101. for _, tx := range tc.txs {
  102. found := false
  103. if tx.Type == common.TxTypeExit {
  104. for i := 0; i < len(tc.accounts); i++ {
  105. if tx.FromIdx != nil && string(tc.accounts[i].Idx) == *tx.FromIdx {
  106. account = tc.accounts[i]
  107. break
  108. }
  109. }
  110. }
  111. if found {
  112. break
  113. }
  114. }
  115. path = fmt.Sprintf(
  116. "%s?hezEthereumAddress=%s&limit=%d",
  117. endpoint, account.EthAddr, limit,
  118. )
  119. err = doGoodReqPaginated(path, historydb.OrderAsc, &testExitsResponse{}, appendIter)
  120. assert.NoError(t, err)
  121. var accountExits []testExit
  122. for i := range tc.exits {
  123. for _, acc := range tc.accounts {
  124. if string(acc.Idx) == tc.exits[i].AccountIdx {
  125. if acc.EthAddr == account.EthAddr {
  126. accountExits = append(accountExits, tc.exits[i])
  127. }
  128. }
  129. }
  130. }
  131. assertExitAPIs(t, accountExits, fetchedExits)
  132. // Get by bjj
  133. fetchedExits = []testExit{}
  134. limit = 6
  135. path = fmt.Sprintf(
  136. "%s?BJJ=%s&limit=%d",
  137. endpoint, account.PublicKey, limit,
  138. )
  139. err = doGoodReqPaginated(path, historydb.OrderAsc, &testExitsResponse{}, appendIter)
  140. assert.NoError(t, err)
  141. assertExitAPIs(t, accountExits, fetchedExits)
  142. // Get by tokenID
  143. fetchedExits = []testExit{}
  144. limit = 5
  145. tokenID := tc.exits[0].Token.TokenID
  146. path = fmt.Sprintf(
  147. "%s?tokenId=%d&limit=%d",
  148. endpoint, tokenID, limit,
  149. )
  150. err = doGoodReqPaginated(path, historydb.OrderAsc, &testExitsResponse{}, appendIter)
  151. assert.NoError(t, err)
  152. tokenIDExits := []testExit{}
  153. for i := 0; i < len(tc.exits); i++ {
  154. if tc.exits[i].Token.TokenID == tokenID {
  155. tokenIDExits = append(tokenIDExits, tc.exits[i])
  156. }
  157. }
  158. assertExitAPIs(t, tokenIDExits, fetchedExits)
  159. // idx
  160. fetchedExits = []testExit{}
  161. limit = 4
  162. idx := tc.exits[0].AccountIdx
  163. path = fmt.Sprintf(
  164. "%s?accountIndex=%s&limit=%d",
  165. endpoint, idx, limit,
  166. )
  167. err = doGoodReqPaginated(path, historydb.OrderAsc, &testExitsResponse{}, appendIter)
  168. assert.NoError(t, err)
  169. idxExits := []testExit{}
  170. for i := 0; i < len(tc.exits); i++ {
  171. if tc.exits[i].AccountIdx[6:] == idx[6:] {
  172. idxExits = append(idxExits, tc.exits[i])
  173. }
  174. }
  175. assertExitAPIs(t, idxExits, fetchedExits)
  176. // batchNum
  177. fetchedExits = []testExit{}
  178. limit = 3
  179. batchNum := tc.exits[0].BatchNum
  180. path = fmt.Sprintf(
  181. "%s?batchNum=%d&limit=%d",
  182. endpoint, batchNum, limit,
  183. )
  184. err = doGoodReqPaginated(path, historydb.OrderAsc, &testExitsResponse{}, appendIter)
  185. assert.NoError(t, err)
  186. batchNumExits := []testExit{}
  187. for i := 0; i < len(tc.exits); i++ {
  188. if tc.exits[i].BatchNum == batchNum {
  189. batchNumExits = append(batchNumExits, tc.exits[i])
  190. }
  191. }
  192. assertExitAPIs(t, batchNumExits, fetchedExits)
  193. // OnlyPendingWithdraws
  194. fetchedExits = []testExit{}
  195. limit = 7
  196. path = fmt.Sprintf(
  197. "%s?&onlyPendingWithdraws=%t&limit=%d",
  198. endpoint, true, limit,
  199. )
  200. err = doGoodReqPaginated(path, historydb.OrderAsc, &testExitsResponse{}, appendIter)
  201. assert.NoError(t, err)
  202. pendingExits := []testExit{}
  203. for i := 0; i < len(tc.exits); i++ {
  204. if tc.exits[i].InstantWithdrawn == nil && tc.exits[i].DelayedWithdrawn == nil {
  205. pendingExits = append(pendingExits, tc.exits[i])
  206. }
  207. }
  208. assertExitAPIs(t, pendingExits, fetchedExits)
  209. // Multiple filters
  210. fetchedExits = []testExit{}
  211. limit = 1
  212. path = fmt.Sprintf(
  213. "%s?batchNum=%d&tokeId=%d&limit=%d",
  214. endpoint, batchNum, tokenID, limit,
  215. )
  216. err = doGoodReqPaginated(path, historydb.OrderAsc, &testExitsResponse{}, appendIter)
  217. assert.NoError(t, err)
  218. mixedExits := []testExit{}
  219. flipedExits := []testExit{}
  220. for i := 0; i < len(tc.exits); i++ {
  221. if tc.exits[i].BatchNum == batchNum && tc.exits[i].Token.TokenID == tokenID {
  222. mixedExits = append(mixedExits, tc.exits[i])
  223. }
  224. flipedExits = append(flipedExits, tc.exits[len(tc.exits)-1-i])
  225. }
  226. assertExitAPIs(t, mixedExits, fetchedExits)
  227. // All, in reverse order
  228. fetchedExits = []testExit{}
  229. limit = 5
  230. path = fmt.Sprintf("%s?limit=%d", endpoint, limit)
  231. err = doGoodReqPaginated(path, historydb.OrderDesc, &testExitsResponse{}, appendIter)
  232. assert.NoError(t, err)
  233. assertExitAPIs(t, flipedExits, fetchedExits)
  234. // 400
  235. path = fmt.Sprintf(
  236. "%s?accountIndex=%s&hezEthereumAddress=%s",
  237. endpoint, idx, account.EthAddr,
  238. )
  239. err = doBadReq("GET", path, nil, 400)
  240. assert.NoError(t, err)
  241. path = fmt.Sprintf("%s?tokenId=X", endpoint)
  242. err = doBadReq("GET", path, nil, 400)
  243. assert.NoError(t, err)
  244. // 404
  245. path = fmt.Sprintf("%s?batchNum=999999", endpoint)
  246. err = doBadReq("GET", path, nil, 404)
  247. assert.NoError(t, err)
  248. path = fmt.Sprintf("%s?fromItem=1000999999", endpoint)
  249. err = doBadReq("GET", path, nil, 404)
  250. assert.NoError(t, err)
  251. }
  252. func TestGetExit(t *testing.T) {
  253. // Get all txs by their ID
  254. endpoint := apiURL + "exits/"
  255. fetchedExits := []testExit{}
  256. for _, exit := range tc.exits {
  257. fetchedExit := testExit{}
  258. assert.NoError(
  259. t, doGoodReq(
  260. "GET",
  261. fmt.Sprintf("%s%d/%s", endpoint, exit.BatchNum, exit.AccountIdx),
  262. nil, &fetchedExit,
  263. ),
  264. )
  265. fetchedExits = append(fetchedExits, fetchedExit)
  266. }
  267. assertExitAPIs(t, tc.exits, fetchedExits)
  268. // 400
  269. err := doBadReq("GET", endpoint+"1/haz:BOOM:1", nil, 400)
  270. assert.NoError(t, err)
  271. err = doBadReq("GET", endpoint+"-1/hez:BOOM:1", nil, 400)
  272. assert.NoError(t, err)
  273. // 404
  274. err = doBadReq("GET", endpoint+"494/hez:XXX:1", nil, 404)
  275. assert.NoError(t, err)
  276. }
  277. func assertExitAPIs(t *testing.T, expected, actual []testExit) {
  278. require.Equal(t, len(expected), len(actual))
  279. for i := 0; i < len(actual); i++ { //nolint len(actual) won't change within the loop
  280. actual[i].ItemID = 0
  281. actual[i].Token.ItemID = 0
  282. if expected[i].Token.USDUpdate == nil {
  283. assert.Equal(t, expected[i].Token.USDUpdate, actual[i].Token.USDUpdate)
  284. } else {
  285. assert.Equal(t, expected[i].Token.USDUpdate.Unix(), actual[i].Token.USDUpdate.Unix())
  286. expected[i].Token.USDUpdate = actual[i].Token.USDUpdate
  287. }
  288. assert.Equal(t, expected[i], actual[i])
  289. }
  290. }