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.
 
 
 

311 lines
9.3 KiB

package api
import (
"fmt"
"testing"
"github.com/hermeznetwork/hermez-node/api/apitypes"
"github.com/hermeznetwork/hermez-node/common"
"github.com/hermeznetwork/hermez-node/db/historydb"
"github.com/mitchellh/copystructure"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type testCVP struct {
Root string
Siblings []string
OldKey string
OldValue string
IsOld0 bool
Key string
Value string
Fnc int
}
type testExit struct {
ItemID uint64 `json:"itemId"`
BatchNum common.BatchNum `json:"batchNum"`
AccountIdx string `json:"accountIndex"`
BJJ apitypes.HezBJJ `json:"bjj"`
EthAddr apitypes.HezEthAddr `json:"hezEthereumAddress"`
MerkleProof testCVP `json:"merkleProof"`
Balance string `json:"balance"`
InstantWithdrawn *int64 `json:"instantWithdraw"`
DelayedWithdrawRequest *int64 `json:"delayedWithdrawRequest"`
DelayedWithdrawn *int64 `json:"delayedWithdraw"`
Token historydb.TokenWithUSD `json:"token"`
}
type testExitsResponse struct {
Exits []testExit `json:"exits"`
PendingItems uint64 `json:"pendingItems"`
}
func (t testExitsResponse) GetPending() (pendingItems, lastItemID uint64) {
if len(t.Exits) == 0 {
return 0, 0
}
pendingItems = t.PendingItems
lastItemID = t.Exits[len(t.Exits)-1].ItemID
return pendingItems, lastItemID
}
func (t testExitsResponse) New() Pendinger { return &testExitsResponse{} }
func (t *testExitsResponse) Len() int {
return len(t.Exits)
}
func genTestExits(
commonExits []common.ExitInfo,
tokens []historydb.TokenWithUSD,
accs []common.Account,
) []testExit {
allExits := []testExit{}
for _, exit := range commonExits {
token := getTokenByIdx(exit.AccountIdx, tokens, accs)
siblings := []string{}
for i := 0; i < len(exit.MerkleProof.Siblings); i++ {
siblings = append(siblings, exit.MerkleProof.Siblings[i].String())
}
acc := getAccountByIdx(exit.AccountIdx, accs)
allExits = append(allExits, testExit{
BatchNum: exit.BatchNum,
AccountIdx: idxToHez(exit.AccountIdx, token.Symbol),
BJJ: apitypes.NewHezBJJ(acc.BJJ),
EthAddr: apitypes.NewHezEthAddr(acc.EthAddr),
MerkleProof: testCVP{
Root: exit.MerkleProof.Root.String(),
Siblings: siblings,
OldKey: exit.MerkleProof.OldKey.String(),
OldValue: exit.MerkleProof.OldValue.String(),
IsOld0: exit.MerkleProof.IsOld0,
Key: exit.MerkleProof.Key.String(),
Value: exit.MerkleProof.Value.String(),
Fnc: exit.MerkleProof.Fnc,
},
Balance: exit.Balance.String(),
InstantWithdrawn: exit.InstantWithdrawn,
DelayedWithdrawRequest: exit.DelayedWithdrawRequest,
DelayedWithdrawn: exit.DelayedWithdrawn,
Token: token,
})
}
return allExits
}
func TestGetExits(t *testing.T) {
endpoint := apiURL + "exits"
fetchedExits := []testExit{}
appendIter := func(intr interface{}) {
for i := 0; i < len(intr.(*testExitsResponse).Exits); i++ {
tmp, err := copystructure.Copy(intr.(*testExitsResponse).Exits[i])
if err != nil {
panic(err)
}
fetchedExits = append(fetchedExits, tmp.(testExit))
}
}
// Get all (no filters)
limit := 8
path := fmt.Sprintf("%s?limit=%d", endpoint, limit)
err := doGoodReqPaginated(path, historydb.OrderAsc, &testExitsResponse{}, appendIter)
assert.NoError(t, err)
assertExitAPIs(t, tc.exits, fetchedExits)
// Get by ethAddr
fetchedExits = []testExit{}
limit = 7
var account testAccount
for _, tx := range tc.txs {
found := false
if tx.Type == common.TxTypeExit {
for i := 0; i < len(tc.accounts); i++ {
if tx.FromIdx != nil && string(tc.accounts[i].Idx) == *tx.FromIdx {
account = tc.accounts[i]
break
}
}
}
if found {
break
}
}
path = fmt.Sprintf(
"%s?hezEthereumAddress=%s&limit=%d",
endpoint, account.EthAddr, limit,
)
err = doGoodReqPaginated(path, historydb.OrderAsc, &testExitsResponse{}, appendIter)
assert.NoError(t, err)
var accountExits []testExit
for i := range tc.exits {
for _, acc := range tc.accounts {
if string(acc.Idx) == tc.exits[i].AccountIdx {
if acc.EthAddr == account.EthAddr {
accountExits = append(accountExits, tc.exits[i])
}
}
}
}
assertExitAPIs(t, accountExits, fetchedExits)
// Get by bjj
fetchedExits = []testExit{}
limit = 6
path = fmt.Sprintf(
"%s?BJJ=%s&limit=%d",
endpoint, account.PublicKey, limit,
)
err = doGoodReqPaginated(path, historydb.OrderAsc, &testExitsResponse{}, appendIter)
assert.NoError(t, err)
assertExitAPIs(t, accountExits, fetchedExits)
// Get by tokenID
fetchedExits = []testExit{}
limit = 5
tokenID := tc.exits[0].Token.TokenID
path = fmt.Sprintf(
"%s?tokenId=%d&limit=%d",
endpoint, tokenID, limit,
)
err = doGoodReqPaginated(path, historydb.OrderAsc, &testExitsResponse{}, appendIter)
assert.NoError(t, err)
tokenIDExits := []testExit{}
for i := 0; i < len(tc.exits); i++ {
if tc.exits[i].Token.TokenID == tokenID {
tokenIDExits = append(tokenIDExits, tc.exits[i])
}
}
assertExitAPIs(t, tokenIDExits, fetchedExits)
// idx
fetchedExits = []testExit{}
limit = 4
idx := tc.exits[0].AccountIdx
path = fmt.Sprintf(
"%s?accountIndex=%s&limit=%d",
endpoint, idx, limit,
)
err = doGoodReqPaginated(path, historydb.OrderAsc, &testExitsResponse{}, appendIter)
assert.NoError(t, err)
idxExits := []testExit{}
for i := 0; i < len(tc.exits); i++ {
if tc.exits[i].AccountIdx[6:] == idx[6:] {
idxExits = append(idxExits, tc.exits[i])
}
}
assertExitAPIs(t, idxExits, fetchedExits)
// batchNum
fetchedExits = []testExit{}
limit = 3
batchNum := tc.exits[0].BatchNum
path = fmt.Sprintf(
"%s?batchNum=%d&limit=%d",
endpoint, batchNum, limit,
)
err = doGoodReqPaginated(path, historydb.OrderAsc, &testExitsResponse{}, appendIter)
assert.NoError(t, err)
batchNumExits := []testExit{}
for i := 0; i < len(tc.exits); i++ {
if tc.exits[i].BatchNum == batchNum {
batchNumExits = append(batchNumExits, tc.exits[i])
}
}
assertExitAPIs(t, batchNumExits, fetchedExits)
// OnlyPendingWithdraws
fetchedExits = []testExit{}
limit = 7
path = fmt.Sprintf(
"%s?&onlyPendingWithdraws=%t&limit=%d",
endpoint, true, limit,
)
err = doGoodReqPaginated(path, historydb.OrderAsc, &testExitsResponse{}, appendIter)
assert.NoError(t, err)
pendingExits := []testExit{}
for i := 0; i < len(tc.exits); i++ {
if tc.exits[i].InstantWithdrawn == nil && tc.exits[i].DelayedWithdrawn == nil {
pendingExits = append(pendingExits, tc.exits[i])
}
}
assertExitAPIs(t, pendingExits, fetchedExits)
// Multiple filters
fetchedExits = []testExit{}
limit = 1
path = fmt.Sprintf(
"%s?batchNum=%d&tokeId=%d&limit=%d",
endpoint, batchNum, tokenID, limit,
)
err = doGoodReqPaginated(path, historydb.OrderAsc, &testExitsResponse{}, appendIter)
assert.NoError(t, err)
mixedExits := []testExit{}
flipedExits := []testExit{}
for i := 0; i < len(tc.exits); i++ {
if tc.exits[i].BatchNum == batchNum && tc.exits[i].Token.TokenID == tokenID {
mixedExits = append(mixedExits, tc.exits[i])
}
flipedExits = append(flipedExits, tc.exits[len(tc.exits)-1-i])
}
assertExitAPIs(t, mixedExits, fetchedExits)
// All, in reverse order
fetchedExits = []testExit{}
limit = 5
path = fmt.Sprintf("%s?limit=%d", endpoint, limit)
err = doGoodReqPaginated(path, historydb.OrderDesc, &testExitsResponse{}, appendIter)
assert.NoError(t, err)
assertExitAPIs(t, flipedExits, fetchedExits)
// Empty array
fetchedExits = []testExit{}
path = fmt.Sprintf("%s?batchNum=999999", endpoint)
err = doGoodReqPaginated(path, historydb.OrderDesc, &testExitsResponse{}, appendIter)
assert.NoError(t, err)
assertExitAPIs(t, []testExit{}, fetchedExits)
// 400
path = fmt.Sprintf(
"%s?accountIndex=%s&hezEthereumAddress=%s",
endpoint, idx, account.EthAddr,
)
err = doBadReq("GET", path, nil, 400)
assert.NoError(t, err)
path = fmt.Sprintf("%s?tokenId=X", endpoint)
err = doBadReq("GET", path, nil, 400)
assert.NoError(t, err)
}
func TestGetExit(t *testing.T) {
// Get all txs by their ID
endpoint := apiURL + "exits/"
fetchedExits := []testExit{}
for _, exit := range tc.exits {
fetchedExit := testExit{}
assert.NoError(
t, doGoodReq(
"GET",
fmt.Sprintf("%s%d/%s", endpoint, exit.BatchNum, exit.AccountIdx),
nil, &fetchedExit,
),
)
fetchedExits = append(fetchedExits, fetchedExit)
}
assertExitAPIs(t, tc.exits, fetchedExits)
// 400
err := doBadReq("GET", endpoint+"1/haz:BOOM:1", nil, 400)
assert.NoError(t, err)
err = doBadReq("GET", endpoint+"-1/hez:BOOM:1", nil, 400)
assert.NoError(t, err)
// 404
err = doBadReq("GET", endpoint+"494/hez:XXX:1", nil, 404)
assert.NoError(t, err)
}
func assertExitAPIs(t *testing.T, expected, actual []testExit) {
require.Equal(t, len(expected), len(actual))
for i := 0; i < len(actual); i++ { //nolint len(actual) won't change within the loop
actual[i].ItemID = 0
actual[i].Token.ItemID = 0
if expected[i].Token.USDUpdate == nil {
assert.Equal(t, expected[i].Token.USDUpdate, actual[i].Token.USDUpdate)
} else {
assert.Equal(t, expected[i].Token.USDUpdate.Unix(), actual[i].Token.USDUpdate.Unix())
expected[i].Token.USDUpdate = actual[i].Token.USDUpdate
}
assert.Equal(t, expected[i], actual[i])
}
}