226 lines
8.4 KiB
Go
226 lines
8.4 KiB
Go
package query_test
|
|
|
|
import (
|
|
gocontext "context"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/suite"
|
|
|
|
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
|
dbm "github.com/tendermint/tm-db"
|
|
|
|
"github.com/cosmos/cosmos-sdk/baseapp"
|
|
"github.com/cosmos/cosmos-sdk/codec"
|
|
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
|
"github.com/cosmos/cosmos-sdk/simapp"
|
|
"github.com/cosmos/cosmos-sdk/store"
|
|
"github.com/cosmos/cosmos-sdk/store/prefix"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
"github.com/cosmos/cosmos-sdk/types/address"
|
|
"github.com/cosmos/cosmos-sdk/types/query"
|
|
"github.com/cosmos/cosmos-sdk/x/bank/types"
|
|
)
|
|
|
|
const (
|
|
holder = "holder"
|
|
multiPerm = "multiple permissions account"
|
|
randomPerm = "random permission"
|
|
numBalances = 235
|
|
defaultLimit = 100
|
|
overLimit = 101
|
|
underLimit = 10
|
|
lastPageRecords = 35
|
|
)
|
|
|
|
type paginationTestSuite struct {
|
|
suite.Suite
|
|
}
|
|
|
|
func TestPaginationTestSuite(t *testing.T) {
|
|
suite.Run(t, new(paginationTestSuite))
|
|
}
|
|
|
|
func (s *paginationTestSuite) TestParsePagination() {
|
|
s.T().Log("verify default values for empty page request")
|
|
pageReq := &query.PageRequest{}
|
|
page, limit, err := query.ParsePagination(pageReq)
|
|
s.Require().NoError(err)
|
|
s.Require().Equal(limit, query.DefaultLimit)
|
|
s.Require().Equal(page, 1)
|
|
|
|
s.T().Log("verify with custom values")
|
|
pageReq = &query.PageRequest{
|
|
Offset: 0,
|
|
Limit: 10,
|
|
}
|
|
page, limit, err = query.ParsePagination(pageReq)
|
|
s.Require().NoError(err)
|
|
s.Require().Equal(page, 1)
|
|
s.Require().Equal(limit, 10)
|
|
}
|
|
|
|
func (s *paginationTestSuite) TestPagination() {
|
|
app, ctx, _ := setupTest()
|
|
queryHelper := baseapp.NewQueryServerTestHelper(ctx, app.InterfaceRegistry())
|
|
types.RegisterQueryServer(queryHelper, app.BankKeeper)
|
|
queryClient := types.NewQueryClient(queryHelper)
|
|
|
|
var balances sdk.Coins
|
|
|
|
for i := 0; i < numBalances; i++ {
|
|
denom := fmt.Sprintf("foo%ddenom", i)
|
|
balances = append(balances, sdk.NewInt64Coin(denom, 100))
|
|
}
|
|
|
|
balances = balances.Sort()
|
|
addr1 := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address())
|
|
acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1)
|
|
app.AccountKeeper.SetAccount(ctx, acc1)
|
|
s.Require().NoError(simapp.FundAccount(app, ctx, addr1, balances))
|
|
|
|
s.T().Log("verify empty page request results a max of defaultLimit records and counts total records")
|
|
pageReq := &query.PageRequest{}
|
|
request := types.NewQueryAllBalancesRequest(addr1, pageReq)
|
|
res, err := queryClient.AllBalances(gocontext.Background(), request)
|
|
s.Require().NoError(err)
|
|
s.Require().Equal(res.Pagination.Total, uint64(numBalances))
|
|
s.Require().NotNil(res.Pagination.NextKey)
|
|
s.Require().LessOrEqual(res.Balances.Len(), defaultLimit)
|
|
|
|
s.T().Log("verify page request with limit > defaultLimit, returns less or equal to `limit` records")
|
|
pageReq = &query.PageRequest{Limit: overLimit}
|
|
request = types.NewQueryAllBalancesRequest(addr1, pageReq)
|
|
res, err = queryClient.AllBalances(gocontext.Background(), request)
|
|
s.Require().NoError(err)
|
|
s.Require().Equal(res.Pagination.Total, uint64(0))
|
|
s.Require().NotNil(res.Pagination.NextKey)
|
|
s.Require().LessOrEqual(res.Balances.Len(), overLimit)
|
|
|
|
s.T().Log("verify paginate with custom limit and countTotal true")
|
|
pageReq = &query.PageRequest{Limit: underLimit, CountTotal: true}
|
|
request = types.NewQueryAllBalancesRequest(addr1, pageReq)
|
|
res, err = queryClient.AllBalances(gocontext.Background(), request)
|
|
s.Require().NoError(err)
|
|
s.Require().Equal(res.Balances.Len(), underLimit)
|
|
s.Require().NotNil(res.Pagination.NextKey)
|
|
s.Require().Equal(res.Pagination.Total, uint64(numBalances))
|
|
|
|
s.T().Log("verify paginate with custom limit and countTotal false")
|
|
pageReq = &query.PageRequest{Limit: defaultLimit, CountTotal: false}
|
|
request = types.NewQueryAllBalancesRequest(addr1, pageReq)
|
|
res, err = queryClient.AllBalances(gocontext.Background(), request)
|
|
s.Require().NoError(err)
|
|
s.Require().Equal(res.Balances.Len(), defaultLimit)
|
|
s.Require().NotNil(res.Pagination.NextKey)
|
|
s.Require().Equal(res.Pagination.Total, uint64(0))
|
|
|
|
s.T().Log("verify paginate with custom limit, key and countTotal false")
|
|
pageReq = &query.PageRequest{Key: res.Pagination.NextKey, Limit: defaultLimit, CountTotal: false}
|
|
request = types.NewQueryAllBalancesRequest(addr1, pageReq)
|
|
res, err = queryClient.AllBalances(gocontext.Background(), request)
|
|
s.Require().NoError(err)
|
|
s.Require().Equal(res.Balances.Len(), defaultLimit)
|
|
s.Require().NotNil(res.Pagination.NextKey)
|
|
s.Require().Equal(res.Pagination.Total, uint64(0))
|
|
|
|
s.T().Log("verify paginate for last page, results in records less than max limit")
|
|
pageReq = &query.PageRequest{Key: res.Pagination.NextKey, Limit: defaultLimit, CountTotal: false}
|
|
request = types.NewQueryAllBalancesRequest(addr1, pageReq)
|
|
res, err = queryClient.AllBalances(gocontext.Background(), request)
|
|
s.Require().NoError(err)
|
|
s.Require().LessOrEqual(res.Balances.Len(), defaultLimit)
|
|
s.Require().Equal(res.Balances.Len(), lastPageRecords)
|
|
s.Require().Nil(res.Pagination.NextKey)
|
|
s.Require().Equal(res.Pagination.Total, uint64(0))
|
|
|
|
s.T().Log("verify paginate with offset and limit")
|
|
pageReq = &query.PageRequest{Offset: 200, Limit: defaultLimit, CountTotal: false}
|
|
request = types.NewQueryAllBalancesRequest(addr1, pageReq)
|
|
res, err = queryClient.AllBalances(gocontext.Background(), request)
|
|
s.Require().NoError(err)
|
|
s.Require().LessOrEqual(res.Balances.Len(), defaultLimit)
|
|
s.Require().Equal(res.Balances.Len(), lastPageRecords)
|
|
s.Require().Nil(res.Pagination.NextKey)
|
|
s.Require().Equal(res.Pagination.Total, uint64(0))
|
|
|
|
s.T().Log("verify paginate with offset and limit")
|
|
pageReq = &query.PageRequest{Offset: 100, Limit: defaultLimit, CountTotal: false}
|
|
request = types.NewQueryAllBalancesRequest(addr1, pageReq)
|
|
res, err = queryClient.AllBalances(gocontext.Background(), request)
|
|
s.Require().NoError(err)
|
|
s.Require().LessOrEqual(res.Balances.Len(), defaultLimit)
|
|
s.Require().NotNil(res.Pagination.NextKey)
|
|
s.Require().Equal(res.Pagination.Total, uint64(0))
|
|
|
|
s.T().Log("verify paginate with offset and key - error")
|
|
pageReq = &query.PageRequest{Key: res.Pagination.NextKey, Offset: 100, Limit: defaultLimit, CountTotal: false}
|
|
request = types.NewQueryAllBalancesRequest(addr1, pageReq)
|
|
res, err = queryClient.AllBalances(gocontext.Background(), request)
|
|
s.Require().Error(err)
|
|
s.Require().Equal("rpc error: code = InvalidArgument desc = paginate: invalid request, either offset or key is expected, got both", err.Error())
|
|
|
|
s.T().Log("verify paginate with offset greater than total results")
|
|
pageReq = &query.PageRequest{Offset: 300, Limit: defaultLimit, CountTotal: false}
|
|
request = types.NewQueryAllBalancesRequest(addr1, pageReq)
|
|
res, err = queryClient.AllBalances(gocontext.Background(), request)
|
|
s.Require().NoError(err)
|
|
s.Require().LessOrEqual(res.Balances.Len(), 0)
|
|
s.Require().Nil(res.Pagination.NextKey)
|
|
}
|
|
|
|
func ExamplePaginate() {
|
|
app, ctx, _ := setupTest()
|
|
|
|
var balances sdk.Coins
|
|
|
|
for i := 0; i < 2; i++ {
|
|
denom := fmt.Sprintf("foo%ddenom", i)
|
|
balances = append(balances, sdk.NewInt64Coin(denom, 100))
|
|
}
|
|
|
|
balances = balances.Sort()
|
|
addr1 := sdk.AccAddress([]byte("addr1"))
|
|
acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1)
|
|
app.AccountKeeper.SetAccount(ctx, acc1)
|
|
err := simapp.FundAccount(app, ctx, addr1, balances)
|
|
if err != nil { // should return no error
|
|
fmt.Println(err)
|
|
}
|
|
// Paginate example
|
|
pageReq := &query.PageRequest{Key: nil, Limit: 1, CountTotal: true}
|
|
request := types.NewQueryAllBalancesRequest(addr1, pageReq)
|
|
balResult := sdk.NewCoins()
|
|
authStore := ctx.KVStore(app.GetKey(types.StoreKey))
|
|
balancesStore := prefix.NewStore(authStore, types.BalancesPrefix)
|
|
accountStore := prefix.NewStore(balancesStore, address.MustLengthPrefix(addr1))
|
|
pageRes, err := query.Paginate(accountStore, request.Pagination, func(key []byte, value []byte) error {
|
|
var tempRes sdk.Coin
|
|
err := app.AppCodec().UnmarshalBinaryBare(value, &tempRes)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
balResult = append(balResult, tempRes)
|
|
return nil
|
|
})
|
|
if err != nil { // should return no error
|
|
fmt.Println(err)
|
|
}
|
|
fmt.Println(&types.QueryAllBalancesResponse{Balances: balResult, Pagination: pageRes})
|
|
// Output:
|
|
// balances:<denom:"foo0denom" amount:"100" > pagination:<next_key:"foo1denom" total:2 >
|
|
}
|
|
|
|
func setupTest() (*simapp.SimApp, sdk.Context, codec.Marshaler) {
|
|
app := simapp.Setup(false)
|
|
ctx := app.BaseApp.NewContext(false, tmproto.Header{Height: 1})
|
|
appCodec := app.AppCodec()
|
|
|
|
db := dbm.NewMemDB()
|
|
ms := store.NewCommitMultiStore(db)
|
|
|
|
ms.LoadLatestVersion()
|
|
|
|
return app, ctx, appCodec
|
|
}
|