From 44c4b5e7760a083e074c16ef2dfa18a5b633cc88 Mon Sep 17 00:00:00 2001 From: akhilkumarpilli Date: Wed, 18 Dec 2024 17:19:03 +0530 Subject: [PATCH 1/4] WIP: migrate types integration tests --- .../v2/types/filtered_pagination_test.go | 247 ++++++++++++ tests/integration/v2/types/fuzz_test.go | 90 +++++ tests/integration/v2/types/pagination_test.go | 374 ++++++++++++++++++ 3 files changed, 711 insertions(+) create mode 100644 tests/integration/v2/types/filtered_pagination_test.go create mode 100644 tests/integration/v2/types/fuzz_test.go create mode 100644 tests/integration/v2/types/pagination_test.go diff --git a/tests/integration/v2/types/filtered_pagination_test.go b/tests/integration/v2/types/filtered_pagination_test.go new file mode 100644 index 000000000000..9961f8fb3b35 --- /dev/null +++ b/tests/integration/v2/types/filtered_pagination_test.go @@ -0,0 +1,247 @@ +package types + +import ( + "context" + "fmt" + + "cosmossdk.io/collections" + "cosmossdk.io/math" + bankkeeper "cosmossdk.io/x/bank/keeper" + "cosmossdk.io/x/bank/testutil" + "cosmossdk.io/x/bank/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/query" +) + +var addr1 = sdk.AccAddress([]byte("addr1")) + +func (s *paginationTestSuite) TestFilteredPaginations() { + var balances sdk.Coins + for i := 0; i < numBalances; i++ { + denom := fmt.Sprintf("foo%ddenom", i) + balances = append(balances, sdk.NewInt64Coin(denom, 100)) + } + + for i := 0; i < 4; i++ { + denom := fmt.Sprintf("test%ddenom", i) + balances = append(balances, sdk.NewInt64Coin(denom, 250)) + } + + balances = balances.Sort() + addr1 := sdk.AccAddress([]byte("addr1")) + acc1 := s.accountKeeper.NewAccountWithAddress(s.ctx, addr1) + s.accountKeeper.SetAccount(s.ctx, acc1) + s.Require().NoError(testutil.FundAccount(s.ctx, s.bankKeeper, addr1, balances)) + + // verify pagination with limit > total values + pageReq := &query.PageRequest{Key: nil, Limit: 5, CountTotal: true} + balances, res, err := execFilterPaginate(s.ctx, s.bankKeeper, pageReq) + s.Require().NoError(err) + s.Require().NotNil(res) + s.Require().Equal(4, len(balances)) + + s.T().Log("verify empty request") + balances, res, err = execFilterPaginate(s.ctx, s.bankKeeper, pageReq) + s.Require().NoError(err) + s.Require().NotNil(res) + s.Require().Equal(4, len(balances)) + s.Require().Equal(uint64(4), res.Total) + s.Require().Nil(res.NextKey) + + s.T().Log("verify nextKey is returned if there are more results") + pageReq = &query.PageRequest{Key: nil, Limit: 2, CountTotal: true} + balances, res, err = execFilterPaginate(s.ctx, s.bankKeeper, pageReq) + s.Require().NoError(err) + s.Require().NotNil(res) + s.Require().Equal(2, len(balances)) + s.Require().NotNil(res.NextKey) + s.Require().Equal(string(res.NextKey), "test2denom") + s.Require().Equal(uint64(4), res.Total) + + s.T().Log("verify both key and offset can't be given") + pageReq = &query.PageRequest{Key: res.NextKey, Limit: 1, Offset: 2, CountTotal: true} + _, _, err = execFilterPaginate(s.ctx, s.bankKeeper, pageReq) + s.Require().Error(err) + + s.T().Log("use nextKey for query") + pageReq = &query.PageRequest{Key: res.NextKey, Limit: 2, CountTotal: true} + balances, res, err = execFilterPaginate(s.ctx, s.bankKeeper, pageReq) + s.Require().NoError(err) + s.Require().NotNil(res) + s.Require().Equal(2, len(balances)) + s.Require().Nil(res.NextKey) + + s.T().Log("verify default limit") + pageReq = &query.PageRequest{Key: nil, Limit: 0} + balances, res, err = execFilterPaginate(s.ctx, s.bankKeeper, pageReq) + s.Require().NoError(err) + s.Require().NotNil(res) + s.Require().Equal(4, len(balances)) + s.Require().Equal(uint64(4), res.Total) + + s.T().Log("verify with offset") + pageReq = &query.PageRequest{Offset: 2, Limit: 2} + balances, res, err = execFilterPaginate(s.ctx, s.bankKeeper, pageReq) + s.Require().NoError(err) + s.Require().NotNil(res) + s.Require().LessOrEqual(len(balances), 2) +} + +func (s *paginationTestSuite) TestReverseFilteredPaginations() { + var balances sdk.Coins + for i := 0; i < numBalances; i++ { + denom := fmt.Sprintf("foo%ddenom", i) + balances = append(balances, sdk.NewInt64Coin(denom, 100)) + } + + for i := 0; i < 10; i++ { + denom := fmt.Sprintf("test%ddenom", i) + balances = append(balances, sdk.NewInt64Coin(denom, 250)) + } + + balances = balances.Sort() + addr1 := sdk.AccAddress([]byte("addr1")) + acc1 := s.accountKeeper.NewAccountWithAddress(s.ctx, addr1) + s.accountKeeper.SetAccount(s.ctx, acc1) + s.Require().NoError(testutil.FundAccount(s.ctx, s.bankKeeper, addr1, balances)) + + // verify pagination with limit > total values + pageReq := &query.PageRequest{Key: nil, Limit: 5, CountTotal: true, Reverse: true} + balns, res, err := execFilterPaginate(s.ctx, s.bankKeeper, pageReq) + s.Require().NoError(err) + s.Require().NotNil(res) + s.Require().Equal(5, len(balns)) + + s.T().Log("verify empty request") + balns, res, err = execFilterPaginate(s.ctx, s.bankKeeper, nil) + s.Require().NoError(err) + s.Require().NotNil(res) + s.Require().Equal(10, len(balns)) + s.Require().Equal(uint64(10), res.Total) + s.Require().Nil(res.NextKey) + + s.T().Log("verify default limit") + pageReq = &query.PageRequest{Reverse: true} + balns, res, err = execFilterPaginate(s.ctx, s.bankKeeper, pageReq) + s.Require().NoError(err) + s.Require().NotNil(res) + s.Require().Equal(10, len(balns)) + s.Require().Equal(uint64(10), res.Total) + + s.T().Log("verify nextKey is returned if there are more results") + pageReq = &query.PageRequest{Limit: 2, CountTotal: true, Reverse: true} + balns, res, err = execFilterPaginate(s.ctx, s.bankKeeper, pageReq) + s.Require().NoError(err) + s.Require().NotNil(res) + s.Require().Equal(2, len(balns)) + s.Require().NotNil(res.NextKey) + s.Require().Equal(string(res.NextKey), "test7denom") + s.Require().Equal(uint64(10), res.Total) + + s.T().Log("verify both key and offset can't be given") + pageReq = &query.PageRequest{Key: res.NextKey, Limit: 1, Offset: 2, Reverse: true} + _, _, err = execFilterPaginate(s.ctx, s.bankKeeper, pageReq) + s.Require().Error(err) + + s.T().Log("use nextKey for query and reverse true") + pageReq = &query.PageRequest{Key: res.NextKey, Limit: 2, Reverse: true} + balns, res, err = execFilterPaginate(s.ctx, s.bankKeeper, pageReq) + s.Require().NoError(err) + s.Require().NotNil(res) + s.Require().Equal(2, len(balns)) + s.Require().NotNil(res.NextKey) + s.Require().Equal(string(res.NextKey), "test5denom") + + s.T().Log("verify last page records, nextKey for query and reverse true") + pageReq = &query.PageRequest{Key: res.NextKey, Reverse: true} + balns, res, err = execFilterPaginate(s.ctx, s.bankKeeper, pageReq) + s.Require().NoError(err) + s.Require().NotNil(res) + s.Require().Equal(6, len(balns)) + s.Require().Nil(res.NextKey) + + s.T().Log("verify Reverse pagination returns valid result") + s.Require().Equal(balances[235:241].String(), balns.Sort().String()) +} + +func (s *paginationTestSuite) TestFilteredPaginate() { + var balances sdk.Coins + for i := 0; i < numBalances; i++ { + denom := fmt.Sprintf("foo%ddenom", i) + balances = append(balances, sdk.NewInt64Coin(denom, 100)) + } + + for i := 0; i < 5; i++ { + denom := fmt.Sprintf("test%ddenom", i) + balances = append(balances, sdk.NewInt64Coin(denom, 250)) + } + + balances = balances.Sort() + addr1 := sdk.AccAddress([]byte("addr1")) + acc1 := s.accountKeeper.NewAccountWithAddress(s.ctx, addr1) + s.accountKeeper.SetAccount(s.ctx, acc1) + err := testutil.FundAccount(s.ctx, s.bankKeeper, addr1, balances) + if err != nil { // should return no error + fmt.Println(err) + } + + pageReq := &query.PageRequest{Key: nil, Limit: 1, CountTotal: true} + + var balResult sdk.Coins + balResult, pageRes, err := execFilterPaginate(s.ctx, s.bankKeeper, pageReq) + s.Require().NoError(err) + fmt.Println(&types.QueryAllBalancesResponse{Balances: balResult, Pagination: pageRes}) + // Output: + // balances: pagination: +} + +func execFilterPaginate(ctx context.Context, bk bankkeeper.BaseKeeper, pageReq *query.PageRequest) (balances sdk.Coins, res *query.PageResponse, err error) { + return query.CollectionFilteredPaginate(ctx, bk.Balances, pageReq, func(key collections.Pair[sdk.AccAddress, string], amount math.Int) (bool, error) { + return amount.Int64() > int64(100), nil + }, func(key collections.Pair[sdk.AccAddress, string], amount math.Int) (sdk.Coin, error) { + balance := sdk.NewCoin(key.K2(), amount) + return balance, nil + }, query.WithCollectionPaginationPairPrefix[sdk.AccAddress, string](addr1)) +} + +func (s *paginationTestSuite) TestFilteredPaginationsNextKey() { + var balances sdk.Coins + + for i := 1; i <= 10; i++ { + denom := fmt.Sprintf("test%ddenom", i) + balances = append(balances, sdk.NewInt64Coin(denom, int64(i))) + } + + balances = balances.Sort() + addr1 := sdk.AccAddress([]byte("addr1")) + acc1 := s.accountKeeper.NewAccountWithAddress(s.ctx, addr1) + s.accountKeeper.SetAccount(s.ctx, acc1) + s.Require().NoError(testutil.FundAccount(s.ctx, s.bankKeeper, addr1, balances)) + execFilterPaginate := func(ctx context.Context, bk bankkeeper.BaseKeeper, pageReq *query.PageRequest) (balances sdk.Coins, res *query.PageResponse, err error) { + return query.CollectionFilteredPaginate(ctx, bk.Balances, pageReq, func(key collections.Pair[sdk.AccAddress, string], amount math.Int) (bool, error) { + return amount.Int64()%2 == 1, nil + }, func(key collections.Pair[sdk.AccAddress, string], amount math.Int) (sdk.Coin, error) { + balance := sdk.NewCoin(key.K2(), amount) + return balance, nil + }, query.WithCollectionPaginationPairPrefix[sdk.AccAddress, string](addr1)) + } + + s.T().Log("verify next key of offset query") + pageReq := &query.PageRequest{Key: nil, Limit: 1, CountTotal: true} + balances, res, err := execFilterPaginate(s.ctx, s.bankKeeper, pageReq) + s.Require().NoError(err) + s.Require().NotNil(res) + s.Require().Equal(1, len(balances)) + s.Require().Equal(balances[0].Amount.Int64(), int64(1)) + s.Require().Equal(uint64(5), res.Total) + s.Require().NotNil(res.NextKey) + + pageReq = &query.PageRequest{Key: res.NextKey, Limit: 1} + balances, res, err = execFilterPaginate(s.ctx, s.bankKeeper, pageReq) + s.Require().NoError(err) + s.Require().NotNil(res) + s.Require().Equal(1, len(balances)) + s.Require().Equal(balances[0].Amount.Int64(), int64(3)) + s.Require().NotNil(res.NextKey) +} diff --git a/tests/integration/v2/types/fuzz_test.go b/tests/integration/v2/types/fuzz_test.go new file mode 100644 index 000000000000..973408439c25 --- /dev/null +++ b/tests/integration/v2/types/fuzz_test.go @@ -0,0 +1,90 @@ +package types + +import ( + "fmt" + "testing" + + fuzz "github.com/google/gofuzz" + + "cosmossdk.io/collections" + "cosmossdk.io/math" + "cosmossdk.io/x/bank/testutil" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/query" +) + +const ( + balancesPrefix = 0x2 +) + +type fuzzTestSuite struct { + paginationTestSuite +} + +func FuzzPagination(f *testing.F) { + if testing.Short() { + f.Skip("In -short mode") + } + + suite := new(fuzzTestSuite) + suite.SetT(new(testing.T)) + suite.SetupTest() + + gf := fuzz.New() + // 1. Set up some seeds. + seeds := []*query.PageRequest{ + new(query.PageRequest), + { + Offset: 0, + Limit: 10, + }, + } + + // 1.5. Use the inprocess fuzzer to mutate variables. + for i := 0; i < 1000; i++ { + qr := new(query.PageRequest) + gf.Fuzz(qr) + seeds = append(seeds, qr) + } + + // 2. Now serialize the fuzzers to bytes so that future mutations + // can occur. + for _, seed := range seeds { + seedBlob, err := suite.cdc.Marshal(seed) + if err == nil { // Some seeds could have been invalid so only add those that marshal. + f.Add(seedBlob) + } + } + + // 3. Setup the keystore. + var balances sdk.Coins + for i := 0; i < 5; i++ { + denom := fmt.Sprintf("foo%ddenom", i) + balances = append(balances, sdk.NewInt64Coin(denom, int64(100+i))) + } + + balances = balances.Sort() + addr1 := sdk.AccAddress([]byte("addr1")) + acc1 := suite.accountKeeper.NewAccountWithAddress(suite.ctx, addr1) + suite.accountKeeper.SetAccount(suite.ctx, acc1) + err := testutil.FundAccount(suite.ctx, suite.bankKeeper, addr1, balances) + if err != nil { // should return no error + f.Fatal(err) + } + + // 4. Now run that fuzzer! + f.Fuzz(func(t *testing.T, pagBz []byte) { + qr := new(query.PageRequest) + if err := suite.cdc.Unmarshal(pagBz, qr); err != nil { + // Some pagination requests won't unmarshal and that's okay. + return + } + + // Now try to paginate it. + _, _, _ = query.CollectionPaginate(suite.ctx, suite.bankKeeper.Balances, qr, func(key collections.Pair[sdk.AccAddress, string], amount math.Int) (sdk.Coin, error) { + balance := sdk.NewCoin(key.K2(), amount) + return balance, nil + }, query.WithCollectionPaginationPairPrefix[sdk.AccAddress, string](addr1)) + }) +} diff --git a/tests/integration/v2/types/pagination_test.go b/tests/integration/v2/types/pagination_test.go new file mode 100644 index 000000000000..f33f5bec981a --- /dev/null +++ b/tests/integration/v2/types/pagination_test.go @@ -0,0 +1,374 @@ +package types + +import ( + "context" + "fmt" + "testing" + + "github.com/stretchr/testify/suite" + + "cosmossdk.io/collections" + "cosmossdk.io/depinject" + "cosmossdk.io/log" + "cosmossdk.io/math" + _ "cosmossdk.io/x/accounts" + _ "cosmossdk.io/x/bank" + bankkeeper "cosmossdk.io/x/bank/keeper" + "cosmossdk.io/x/bank/testutil" + "cosmossdk.io/x/bank/types" + _ "cosmossdk.io/x/consensus" + + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + "github.com/cosmos/cosmos-sdk/tests/integration/v2" + "github.com/cosmos/cosmos-sdk/testutil/configurator" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/query" + _ "github.com/cosmos/cosmos-sdk/x/auth" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" +) + +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 + ctx context.Context + bankKeeper bankkeeper.BaseKeeper + accountKeeper authkeeper.AccountKeeper + cdc codec.Codec + interfaceReg codectypes.InterfaceRegistry + app *integration.App + + queryClient bankkeeper.Querier +} + +func TestPaginationTestSuite(t *testing.T) { + suite.Run(t, new(paginationTestSuite)) +} + +func (s *paginationTestSuite) SetupTest() { + moduleConfigs := []configurator.ModuleOption{ + configurator.AccountsModule(), + configurator.AuthModule(), + configurator.BankModule(), + configurator.ConsensusModule(), + configurator.OmitInitGenesis(), + } + + var err error + startupCfg := integration.DefaultStartUpConfig(s.T()) + + startupCfg.BranchService = &integration.BranchService{} + startupCfg.HeaderService = &integration.HeaderService{} + + s.app, err = integration.NewApp( + depinject.Configs( + configurator.NewAppV2Config(moduleConfigs...), + depinject.Supply(log.NewNopLogger()), + ), + startupCfg, + &s.bankKeeper, &s.accountKeeper, &s.cdc, &s.interfaceReg, + ) + s.Assert().NoError(err) + + s.ctx = s.app.StateLatestContext(s.T()) + + s.queryClient = bankkeeper.NewQuerier(&s.bankKeeper) + + s.Require().NoError(s.bankKeeper.SetParams(s.ctx, types.DefaultParams())) +} + +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() { + queryClient := s.queryClient + + 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 := s.accountKeeper.NewAccountWithAddress(s.ctx, addr1) + s.accountKeeper.SetAccount(s.ctx, acc1) + s.Require().NoError(testutil.FundAccount(s.ctx, s.bankKeeper, addr1, balances)) + + addr1Str, err := s.accountKeeper.AddressCodec().BytesToString(addr1) + s.Require().NoError(err) + + s.T().Log("verify empty page request results a max of defaultLimit records and counts total records") + pageReq := &query.PageRequest{} + request := types.NewQueryAllBalancesRequest(addr1Str, pageReq, false) + res, err := queryClient.AllBalances(s.ctx, 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(addr1Str, pageReq, false) + res, err = queryClient.AllBalances(s.ctx, 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(addr1Str, pageReq, false) + res, err = queryClient.AllBalances(s.ctx, 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(addr1Str, pageReq, false) + res, err = queryClient.AllBalances(s.ctx, 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(addr1Str, pageReq, false) + res, err = queryClient.AllBalances(s.ctx, 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(addr1Str, pageReq, false) + res, err = queryClient.AllBalances(s.ctx, 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(addr1Str, pageReq, false) + res, err = queryClient.AllBalances(s.ctx, 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(addr1Str, pageReq, false) + res, err = queryClient.AllBalances(s.ctx, 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(addr1Str, pageReq, false) + _, err = queryClient.AllBalances(s.ctx, 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(addr1Str, pageReq, false) + res, err = queryClient.AllBalances(s.ctx, request) + s.Require().NoError(err) + s.Require().LessOrEqual(res.Balances.Len(), 0) + s.Require().Nil(res.Pagination.NextKey) +} + +func (s *paginationTestSuite) TestReversePagination() { + queryClient := s.queryClient + + 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 := s.accountKeeper.NewAccountWithAddress(s.ctx, addr1) + s.accountKeeper.SetAccount(s.ctx, acc1) + s.Require().NoError(testutil.FundAccount(s.ctx, s.bankKeeper, addr1, balances)) + + addr1Str, err := s.accountKeeper.AddressCodec().BytesToString(addr1) + s.Require().NoError(err) + + s.T().Log("verify paginate with custom limit and countTotal, Reverse false") + pageReq := &query.PageRequest{Limit: 2, CountTotal: true, Reverse: true, Key: nil} + request := types.NewQueryAllBalancesRequest(addr1Str, pageReq, false) + res1, err := queryClient.AllBalances(s.ctx, request) + s.Require().NoError(err) + s.Require().Equal(2, res1.Balances.Len()) + s.Require().NotNil(res1.Pagination.NextKey) + + s.T().Log("verify paginate with custom limit and countTotal, Reverse false") + pageReq = &query.PageRequest{Limit: 150} + request = types.NewQueryAllBalancesRequest(addr1Str, pageReq, false) + res1, err = queryClient.AllBalances(s.ctx, request) + s.Require().NoError(err) + s.Require().Equal(res1.Balances.Len(), 150) + s.Require().NotNil(res1.Pagination.NextKey) + s.Require().Equal(res1.Pagination.Total, uint64(0)) + + s.T().Log("verify paginate with custom limit, key and Reverse true") + pageReq = &query.PageRequest{Limit: defaultLimit, Reverse: true} + request = types.NewQueryAllBalancesRequest(addr1Str, pageReq, false) + res, err := queryClient.AllBalances(s.ctx, 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 Reverse true") + pageReq = &query.PageRequest{Offset: 100, Limit: defaultLimit, Reverse: true} + request = types.NewQueryAllBalancesRequest(addr1Str, pageReq, false) + res, err = queryClient.AllBalances(s.ctx, 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, Reverse true") + pageReq = &query.PageRequest{Offset: 200, Limit: defaultLimit, Reverse: true} + request = types.NewQueryAllBalancesRequest(addr1Str, pageReq, false) + res, err = queryClient.AllBalances(s.ctx, request) + s.Require().NoError(err) + 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 page request with limit > defaultLimit, returns less or equal to `limit` records") + pageReq = &query.PageRequest{Limit: overLimit, Reverse: true} + request = types.NewQueryAllBalancesRequest(addr1Str, pageReq, false) + res, err = queryClient.AllBalances(s.ctx, 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, key, countTotal false and Reverse true") + pageReq = &query.PageRequest{Key: res1.Pagination.NextKey, Limit: 50, Reverse: true} + request = types.NewQueryAllBalancesRequest(addr1Str, pageReq, false) + res, err = queryClient.AllBalances(s.ctx, request) + s.Require().NoError(err) + s.Require().Equal(res.Balances.Len(), 50) + s.Require().NotNil(res.Pagination.NextKey) + s.Require().Equal(res.Pagination.Total, uint64(0)) + + s.T().Log("verify Reverse pagination returns valid result") + s.Require().Equal(balances[101:151].String(), res.Balances.Sort().String()) + + s.T().Log("verify paginate with custom limit, key, countTotal false and Reverse true") + pageReq = &query.PageRequest{Key: res.Pagination.NextKey, Limit: 50, Reverse: true} + request = types.NewQueryAllBalancesRequest(addr1Str, pageReq, false) + res, err = queryClient.AllBalances(s.ctx, request) + s.Require().NoError(err) + s.Require().Equal(res.Balances.Len(), 50) + s.Require().NotNil(res.Pagination.NextKey) + s.Require().Equal(res.Pagination.Total, uint64(0)) + + s.T().Log("verify Reverse pagination returns valid result") + s.Require().Equal(balances[51:101].String(), res.Balances.Sort().String()) + + s.T().Log("verify paginate for last page Reverse true") + pageReq = &query.PageRequest{Key: res.Pagination.NextKey, Limit: defaultLimit, Reverse: true} + request = types.NewQueryAllBalancesRequest(addr1Str, pageReq, false) + res, err = queryClient.AllBalances(s.ctx, request) + s.Require().NoError(err) + s.Require().Equal(res.Balances.Len(), 51) + s.Require().Nil(res.Pagination.NextKey) + s.Require().Equal(res.Pagination.Total, uint64(0)) + + s.T().Log("verify Reverse pagination returns valid result") + s.Require().Equal(balances[0:51].String(), res.Balances.Sort().String()) + + s.T().Log("verify paginate with offset and key - error") + pageReq = &query.PageRequest{Key: res1.Pagination.NextKey, Offset: 100, Limit: defaultLimit, CountTotal: false} + request = types.NewQueryAllBalancesRequest(addr1Str, pageReq, false) + _, err = queryClient.AllBalances(s.ctx, 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, Reverse: true} + request = types.NewQueryAllBalancesRequest(addr1Str, pageReq, false) + res, err = queryClient.AllBalances(s.ctx, request) + s.Require().NoError(err) + s.Require().LessOrEqual(res.Balances.Len(), 0) + s.Require().Nil(res.Pagination.NextKey) +} + +func (s *paginationTestSuite) TestPaginate() { + 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 := s.accountKeeper.NewAccountWithAddress(s.ctx, addr1) + s.accountKeeper.SetAccount(s.ctx, acc1) + err := testutil.FundAccount(s.ctx, s.bankKeeper, addr1, balances) + if err != nil { // should return no error + fmt.Println(err) + } + + addr1Str, err := s.accountKeeper.AddressCodec().BytesToString(addr1) + s.Require().NoError(err) + + // Paginate example + pageReq := &query.PageRequest{Key: nil, Limit: 1, CountTotal: true} + request := types.NewQueryAllBalancesRequest(addr1Str, pageReq, false) + balResult, pageRes, err := query.CollectionPaginate(s.ctx, s.bankKeeper.Balances, request.Pagination, func(key collections.Pair[sdk.AccAddress, string], amount math.Int) (sdk.Coin, error) { + balance := sdk.NewCoin(key.K2(), amount) + return balance, nil + }, query.WithCollectionPaginationPairPrefix[sdk.AccAddress, string](addr1)) + s.Require().NoError(err) + fmt.Println(&types.QueryAllBalancesResponse{Balances: balResult, Pagination: pageRes}) + // Output: + // balances: pagination: +} From 034ef9733c4b81748dbaddfbbdf8a73786183cdf Mon Sep 17 00:00:00 2001 From: akhilkumarpilli Date: Wed, 18 Dec 2024 18:03:00 +0530 Subject: [PATCH 2/4] fix few tests --- tests/integration/v2/types/pagination_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/integration/v2/types/pagination_test.go b/tests/integration/v2/types/pagination_test.go index f33f5bec981a..e223018330c3 100644 --- a/tests/integration/v2/types/pagination_test.go +++ b/tests/integration/v2/types/pagination_test.go @@ -27,6 +27,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/query" _ "github.com/cosmos/cosmos-sdk/x/auth" authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + _ "github.com/cosmos/cosmos-sdk/x/auth/tx/config" ) const ( @@ -61,6 +62,8 @@ func (s *paginationTestSuite) SetupTest() { configurator.AccountsModule(), configurator.AuthModule(), configurator.BankModule(), + configurator.TxModule(), + configurator.ValidateModule(), configurator.ConsensusModule(), configurator.OmitInitGenesis(), } From f0348ec87bdaef89e0ca13eefc8f18bf2026cc9b Mon Sep 17 00:00:00 2001 From: akhilkumarpilli Date: Wed, 18 Dec 2024 18:03:27 +0530 Subject: [PATCH 3/4] delete v1 files --- .../types/filtered_pagination_test.go | 310 -------------- tests/integration/types/fuzz_test.go | 101 ----- tests/integration/types/pagination_test.go | 389 ------------------ 3 files changed, 800 deletions(-) delete mode 100644 tests/integration/types/filtered_pagination_test.go delete mode 100644 tests/integration/types/fuzz_test.go delete mode 100644 tests/integration/types/pagination_test.go diff --git a/tests/integration/types/filtered_pagination_test.go b/tests/integration/types/filtered_pagination_test.go deleted file mode 100644 index 042aa224495c..000000000000 --- a/tests/integration/types/filtered_pagination_test.go +++ /dev/null @@ -1,310 +0,0 @@ -package query_test - -import ( - "fmt" - - "cosmossdk.io/math" - "cosmossdk.io/store/prefix" - storetypes "cosmossdk.io/store/types" - "cosmossdk.io/x/bank/testutil" - "cosmossdk.io/x/bank/types" - - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/address" - "github.com/cosmos/cosmos-sdk/types/query" -) - -var addr1 = sdk.AccAddress([]byte("addr1")) - -func (s *paginationTestSuite) TestFilteredPaginations() { - var balances sdk.Coins - for i := 0; i < numBalances; i++ { - denom := fmt.Sprintf("foo%ddenom", i) - balances = append(balances, sdk.NewInt64Coin(denom, 100)) - } - - for i := 0; i < 4; i++ { - denom := fmt.Sprintf("test%ddenom", i) - balances = append(balances, sdk.NewInt64Coin(denom, 250)) - } - - balances = balances.Sort() - addr1 := sdk.AccAddress([]byte("addr1")) - acc1 := s.accountKeeper.NewAccountWithAddress(s.ctx, addr1) - s.accountKeeper.SetAccount(s.ctx, acc1) - s.Require().NoError(testutil.FundAccount(s.ctx, s.bankKeeper, addr1, balances)) - store := s.ctx.KVStore(s.app.UnsafeFindStoreKey(types.StoreKey)) - - // verify pagination with limit > total values - pageReq := &query.PageRequest{Key: nil, Limit: 5, CountTotal: true} - balances, res, err := execFilterPaginate(store, pageReq, s.cdc) - s.Require().NoError(err) - s.Require().NotNil(res) - s.Require().Equal(4, len(balances)) - - s.T().Log("verify empty request") - balances, res, err = execFilterPaginate(store, nil, s.cdc) - s.Require().NoError(err) - s.Require().NotNil(res) - s.Require().Equal(4, len(balances)) - s.Require().Equal(uint64(4), res.Total) - s.Require().Nil(res.NextKey) - - s.T().Log("verify nextKey is returned if there are more results") - pageReq = &query.PageRequest{Key: nil, Limit: 2, CountTotal: true} - balances, res, err = execFilterPaginate(store, pageReq, s.cdc) - s.Require().NoError(err) - s.Require().NotNil(res) - s.Require().Equal(2, len(balances)) - s.Require().NotNil(res.NextKey) - s.Require().Equal(string(res.NextKey), "test2denom") - s.Require().Equal(uint64(4), res.Total) - - s.T().Log("verify both key and offset can't be given") - pageReq = &query.PageRequest{Key: res.NextKey, Limit: 1, Offset: 2, CountTotal: true} - _, _, err = execFilterPaginate(store, pageReq, s.cdc) - s.Require().Error(err) - - s.T().Log("use nextKey for query") - pageReq = &query.PageRequest{Key: res.NextKey, Limit: 2, CountTotal: true} - balances, res, err = execFilterPaginate(store, pageReq, s.cdc) - s.Require().NoError(err) - s.Require().NotNil(res) - s.Require().Equal(2, len(balances)) - s.Require().Nil(res.NextKey) - - s.T().Log("verify default limit") - pageReq = &query.PageRequest{Key: nil, Limit: 0} - balances, res, err = execFilterPaginate(store, pageReq, s.cdc) - s.Require().NoError(err) - s.Require().NotNil(res) - s.Require().Equal(4, len(balances)) - s.Require().Equal(uint64(4), res.Total) - - s.T().Log("verify with offset") - pageReq = &query.PageRequest{Offset: 2, Limit: 2} - balances, res, err = execFilterPaginate(store, pageReq, s.cdc) - s.Require().NoError(err) - s.Require().NotNil(res) - s.Require().LessOrEqual(len(balances), 2) -} - -func (s *paginationTestSuite) TestReverseFilteredPaginations() { - var balances sdk.Coins - for i := 0; i < numBalances; i++ { - denom := fmt.Sprintf("foo%ddenom", i) - balances = append(balances, sdk.NewInt64Coin(denom, 100)) - } - - for i := 0; i < 10; i++ { - denom := fmt.Sprintf("test%ddenom", i) - balances = append(balances, sdk.NewInt64Coin(denom, 250)) - } - - balances = balances.Sort() - addr1 := sdk.AccAddress([]byte("addr1")) - acc1 := s.accountKeeper.NewAccountWithAddress(s.ctx, addr1) - s.accountKeeper.SetAccount(s.ctx, acc1) - s.Require().NoError(testutil.FundAccount(s.ctx, s.bankKeeper, addr1, balances)) - store := s.ctx.KVStore(s.app.UnsafeFindStoreKey(types.StoreKey)) - - // verify pagination with limit > total values - pageReq := &query.PageRequest{Key: nil, Limit: 5, CountTotal: true, Reverse: true} - balns, res, err := execFilterPaginate(store, pageReq, s.cdc) - s.Require().NoError(err) - s.Require().NotNil(res) - s.Require().Equal(5, len(balns)) - - s.T().Log("verify empty request") - balns, res, err = execFilterPaginate(store, nil, s.cdc) - s.Require().NoError(err) - s.Require().NotNil(res) - s.Require().Equal(10, len(balns)) - s.Require().Equal(uint64(10), res.Total) - s.Require().Nil(res.NextKey) - - s.T().Log("verify default limit") - pageReq = &query.PageRequest{Reverse: true} - balns, res, err = execFilterPaginate(store, pageReq, s.cdc) - s.Require().NoError(err) - s.Require().NotNil(res) - s.Require().Equal(10, len(balns)) - s.Require().Equal(uint64(10), res.Total) - - s.T().Log("verify nextKey is returned if there are more results") - pageReq = &query.PageRequest{Limit: 2, CountTotal: true, Reverse: true} - balns, res, err = execFilterPaginate(store, pageReq, s.cdc) - s.Require().NoError(err) - s.Require().NotNil(res) - s.Require().Equal(2, len(balns)) - s.Require().NotNil(res.NextKey) - s.Require().Equal(string(res.NextKey), "test7denom") - s.Require().Equal(uint64(10), res.Total) - - s.T().Log("verify both key and offset can't be given") - pageReq = &query.PageRequest{Key: res.NextKey, Limit: 1, Offset: 2, Reverse: true} - _, _, err = execFilterPaginate(store, pageReq, s.cdc) - s.Require().Error(err) - - s.T().Log("use nextKey for query and reverse true") - pageReq = &query.PageRequest{Key: res.NextKey, Limit: 2, Reverse: true} - balns, res, err = execFilterPaginate(store, pageReq, s.cdc) - s.Require().NoError(err) - s.Require().NotNil(res) - s.Require().Equal(2, len(balns)) - s.Require().NotNil(res.NextKey) - s.Require().Equal(string(res.NextKey), "test5denom") - - s.T().Log("verify last page records, nextKey for query and reverse true") - pageReq = &query.PageRequest{Key: res.NextKey, Reverse: true} - balns, res, err = execFilterPaginate(store, pageReq, s.cdc) - s.Require().NoError(err) - s.Require().NotNil(res) - s.Require().Equal(6, len(balns)) - s.Require().Nil(res.NextKey) - - s.T().Log("verify Reverse pagination returns valid result") - s.Require().Equal(balances[235:241].String(), balns.Sort().String()) -} - -func (s *paginationTestSuite) TestFilteredPaginate() { - var balances sdk.Coins - for i := 0; i < numBalances; i++ { - denom := fmt.Sprintf("foo%ddenom", i) - balances = append(balances, sdk.NewInt64Coin(denom, 100)) - } - - for i := 0; i < 5; i++ { - denom := fmt.Sprintf("test%ddenom", i) - balances = append(balances, sdk.NewInt64Coin(denom, 250)) - } - - balances = balances.Sort() - addr1 := sdk.AccAddress([]byte("addr1")) - acc1 := s.accountKeeper.NewAccountWithAddress(s.ctx, addr1) - s.accountKeeper.SetAccount(s.ctx, acc1) - err := testutil.FundAccount(s.ctx, s.bankKeeper, addr1, balances) - if err != nil { // should return no error - fmt.Println(err) - } - - pageReq := &query.PageRequest{Key: nil, Limit: 1, CountTotal: true} - store := s.ctx.KVStore(s.app.UnsafeFindStoreKey(types.StoreKey)) - balancesStore := prefix.NewStore(store, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, address.MustLengthPrefix(addr1)) - - var balResult sdk.Coins - pageRes, err := query.FilteredPaginate(accountStore, pageReq, func(key, value []byte, accumulate bool) (bool, error) { - var amount math.Int - err := amount.Unmarshal(value) - if err != nil { - return false, err - } - - // filter amount greater than 100 - if amount.Int64() > int64(100) { - if accumulate { - balResult = append(balResult, sdk.NewCoin(string(key), amount)) - } - - return true, nil - } - - return false, nil - }) - if err != nil { // should return no error - fmt.Println(err) - } - fmt.Println(&types.QueryAllBalancesResponse{Balances: balResult, Pagination: pageRes}) - // Output: - // balances: pagination: -} - -func execFilterPaginate(store storetypes.KVStore, pageReq *query.PageRequest, _ codec.Codec) (balances sdk.Coins, res *query.PageResponse, err error) { - balancesStore := prefix.NewStore(store, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, address.MustLengthPrefix(addr1)) - - var balResult sdk.Coins - res, err = query.FilteredPaginate(accountStore, pageReq, func(key, value []byte, accumulate bool) (bool, error) { - var amount math.Int - err := amount.Unmarshal(value) - if err != nil { - return false, err - } - - // filter amount greater than 100 - if amount.Int64() > int64(100) { - if accumulate { - balResult = append(balResult, sdk.NewCoin(string(key), amount)) - } - - return true, nil - } - - return false, nil - }) - - return balResult, res, err -} - -func (s *paginationTestSuite) TestFilteredPaginationsNextKey() { - var balances sdk.Coins - - for i := 1; i <= 10; i++ { - denom := fmt.Sprintf("test%ddenom", i) - balances = append(balances, sdk.NewInt64Coin(denom, int64(i))) - } - - balances = balances.Sort() - addr1 := sdk.AccAddress([]byte("addr1")) - acc1 := s.accountKeeper.NewAccountWithAddress(s.ctx, addr1) - s.accountKeeper.SetAccount(s.ctx, acc1) - s.Require().NoError(testutil.FundAccount(s.ctx, s.bankKeeper, addr1, balances)) - store := s.ctx.KVStore(s.app.UnsafeFindStoreKey(types.StoreKey)) - - execFilterPaginate := func(store storetypes.KVStore, pageReq *query.PageRequest, _ codec.Codec) (balances sdk.Coins, res *query.PageResponse, err error) { - balancesStore := prefix.NewStore(store, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, address.MustLengthPrefix(addr1)) - - var balResult sdk.Coins - res, err = query.FilteredPaginate(accountStore, pageReq, func(key, value []byte, accumulate bool) (bool, error) { - var amount math.Int - err := amount.Unmarshal(value) - if err != nil { - return false, err - } - - // filter odd amounts - if amount.Int64()%2 == 1 { - if accumulate { - balResult = append(balResult, sdk.NewCoin(string(key), amount)) - } - - return true, nil - } - - return false, nil - }) - - return balResult, res, err - } - - s.T().Log("verify next key of offset query") - pageReq := &query.PageRequest{Key: nil, Limit: 1, CountTotal: true} - balances, res, err := execFilterPaginate(store, pageReq, s.cdc) - s.Require().NoError(err) - s.Require().NotNil(res) - s.Require().Equal(1, len(balances)) - s.Require().Equal(balances[0].Amount.Int64(), int64(1)) - s.Require().Equal(uint64(5), res.Total) - s.Require().NotNil(res.NextKey) - - pageReq = &query.PageRequest{Key: res.NextKey, Limit: 1} - balances, res, err = execFilterPaginate(store, pageReq, s.cdc) - s.Require().NoError(err) - s.Require().NotNil(res) - s.Require().Equal(1, len(balances)) - s.Require().Equal(balances[0].Amount.Int64(), int64(3)) - s.Require().NotNil(res.NextKey) -} diff --git a/tests/integration/types/fuzz_test.go b/tests/integration/types/fuzz_test.go deleted file mode 100644 index e3f47d38f83a..000000000000 --- a/tests/integration/types/fuzz_test.go +++ /dev/null @@ -1,101 +0,0 @@ -package query_test - -import ( - "fmt" - "testing" - - fuzz "github.com/google/gofuzz" - - "cosmossdk.io/math" - "cosmossdk.io/store/prefix" - "cosmossdk.io/x/bank/testutil" - - sdktestutil "github.com/cosmos/cosmos-sdk/testutil" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/address" - "github.com/cosmos/cosmos-sdk/types/query" -) - -const ( - balancesPrefix = 0x2 -) - -type fuzzTestSuite struct { - paginationTestSuite -} - -func FuzzPagination(f *testing.F) { - if testing.Short() { - f.Skip("In -short mode") - } - - suite := new(fuzzTestSuite) - suite.SetT(new(testing.T)) - suite.SetupTest() - - gf := fuzz.New() - // 1. Set up some seeds. - seeds := []*query.PageRequest{ - new(query.PageRequest), - { - Offset: 0, - Limit: 10, - }, - } - - // 1.5. Use the inprocess fuzzer to mutate variables. - for i := 0; i < 1000; i++ { - qr := new(query.PageRequest) - gf.Fuzz(qr) - seeds = append(seeds, qr) - } - - // 2. Now serialize the fuzzers to bytes so that future mutations - // can occur. - for _, seed := range seeds { - seedBlob, err := suite.cdc.Marshal(seed) - if err == nil { // Some seeds could have been invalid so only add those that marshal. - f.Add(seedBlob) - } - } - - // 3. Setup the keystore. - var balances sdk.Coins - for i := 0; i < 5; i++ { - denom := fmt.Sprintf("foo%ddenom", i) - balances = append(balances, sdk.NewInt64Coin(denom, int64(100+i))) - } - - balances = balances.Sort() - addr1 := sdk.AccAddress([]byte("addr1")) - acc1 := suite.accountKeeper.NewAccountWithAddress(suite.ctx, addr1) - suite.accountKeeper.SetAccount(suite.ctx, acc1) - err := testutil.FundAccount(suite.ctx, suite.bankKeeper, addr1, balances) - if err != nil { // should return no error - f.Fatal(err) - } - - // 4. Now run that fuzzer! - f.Fuzz(func(t *testing.T, pagBz []byte) { - qr := new(query.PageRequest) - if err := suite.cdc.Unmarshal(pagBz, qr); err != nil { - // Some pagination requests won't unmarshal and that's okay. - return - } - - // Now try to paginate it. - balResult := sdk.NewCoins() - authStore := suite.ctx.KVStore(suite.app.UnsafeFindStoreKey(sdktestutil.BankModuleName)) - balancesStore := prefix.NewStore(authStore, []byte{balancesPrefix}) - accountStore := prefix.NewStore(balancesStore, address.MustLengthPrefix(addr1)) - _, _ = query.Paginate(accountStore, qr, func(key, value []byte) error { - var amount math.Int - err := amount.Unmarshal(value) - if err != nil { - return err - } - balResult = append(balResult, sdk.NewCoin(string(key), amount)) - return nil - }) - }) -} diff --git a/tests/integration/types/pagination_test.go b/tests/integration/types/pagination_test.go deleted file mode 100644 index 2ab998fd1170..000000000000 --- a/tests/integration/types/pagination_test.go +++ /dev/null @@ -1,389 +0,0 @@ -package query_test - -import ( - gocontext "context" - "fmt" - "testing" - - cmtproto "github.com/cometbft/cometbft/api/cometbft/types/v1" - "github.com/stretchr/testify/suite" - - "cosmossdk.io/depinject" - "cosmossdk.io/log" - "cosmossdk.io/math" - "cosmossdk.io/store/prefix" - _ "cosmossdk.io/x/accounts" - _ "cosmossdk.io/x/bank" - bankkeeper "cosmossdk.io/x/bank/keeper" - "cosmossdk.io/x/bank/testutil" - "cosmossdk.io/x/bank/types" - _ "cosmossdk.io/x/consensus" - - "github.com/cosmos/cosmos-sdk/baseapp" - "github.com/cosmos/cosmos-sdk/codec" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" - "github.com/cosmos/cosmos-sdk/runtime" - "github.com/cosmos/cosmos-sdk/testutil/configurator" - testutilsims "github.com/cosmos/cosmos-sdk/testutil/sims" - 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/auth" - authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" -) - -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 - ctx sdk.Context - bankKeeper bankkeeper.Keeper - accountKeeper authkeeper.AccountKeeper - cdc codec.Codec - interfaceReg codectypes.InterfaceRegistry - app *runtime.App -} - -func TestPaginationTestSuite(t *testing.T) { - suite.Run(t, new(paginationTestSuite)) -} - -func (s *paginationTestSuite) SetupTest() { - var ( - bankKeeper bankkeeper.Keeper - accountKeeper authkeeper.AccountKeeper - reg codectypes.InterfaceRegistry - cdc codec.Codec - ) - - app, err := testutilsims.Setup( - depinject.Configs( - configurator.NewAppConfig( - configurator.AccountsModule(), - configurator.AuthModule(), - configurator.BankModule(), - configurator.ConsensusModule(), - configurator.OmitInitGenesis(), - ), - depinject.Supply(log.NewNopLogger()), - ), - &bankKeeper, &accountKeeper, ®, &cdc) - - s.NoError(err) - - ctx := app.BaseApp.NewContextLegacy(false, cmtproto.Header{Height: 1}) - - s.ctx, s.bankKeeper, s.accountKeeper, s.cdc, s.app, s.interfaceReg = ctx, bankKeeper, accountKeeper, cdc, app, reg - - s.Require().NoError(s.bankKeeper.SetParams(s.ctx, types.DefaultParams())) -} - -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() { - queryHelper := baseapp.NewQueryServerTestHelper(s.ctx, s.interfaceReg) - types.RegisterQueryServer(queryHelper, s.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 := s.accountKeeper.NewAccountWithAddress(s.ctx, addr1) - s.accountKeeper.SetAccount(s.ctx, acc1) - s.Require().NoError(testutil.FundAccount(s.ctx, s.bankKeeper, addr1, balances)) - - addr1Str, err := s.accountKeeper.AddressCodec().BytesToString(addr1) - s.Require().NoError(err) - - s.T().Log("verify empty page request results a max of defaultLimit records and counts total records") - pageReq := &query.PageRequest{} - request := types.NewQueryAllBalancesRequest(addr1Str, pageReq, false) - 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(addr1Str, pageReq, false) - 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(addr1Str, pageReq, false) - 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(addr1Str, pageReq, false) - 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(addr1Str, pageReq, false) - 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(addr1Str, pageReq, false) - 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(addr1Str, pageReq, false) - 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(addr1Str, pageReq, false) - 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(addr1Str, pageReq, false) - _, 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(addr1Str, pageReq, false) - 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 (s *paginationTestSuite) TestReversePagination() { - queryHelper := baseapp.NewQueryServerTestHelper(s.ctx, s.interfaceReg) - types.RegisterQueryServer(queryHelper, s.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 := s.accountKeeper.NewAccountWithAddress(s.ctx, addr1) - s.accountKeeper.SetAccount(s.ctx, acc1) - s.Require().NoError(testutil.FundAccount(s.ctx, s.bankKeeper, addr1, balances)) - - addr1Str, err := s.accountKeeper.AddressCodec().BytesToString(addr1) - s.Require().NoError(err) - - s.T().Log("verify paginate with custom limit and countTotal, Reverse false") - pageReq := &query.PageRequest{Limit: 2, CountTotal: true, Reverse: true, Key: nil} - request := types.NewQueryAllBalancesRequest(addr1Str, pageReq, false) - res1, err := queryClient.AllBalances(gocontext.Background(), request) - s.Require().NoError(err) - s.Require().Equal(2, res1.Balances.Len()) - s.Require().NotNil(res1.Pagination.NextKey) - - s.T().Log("verify paginate with custom limit and countTotal, Reverse false") - pageReq = &query.PageRequest{Limit: 150} - request = types.NewQueryAllBalancesRequest(addr1Str, pageReq, false) - res1, err = queryClient.AllBalances(gocontext.Background(), request) - s.Require().NoError(err) - s.Require().Equal(res1.Balances.Len(), 150) - s.Require().NotNil(res1.Pagination.NextKey) - s.Require().Equal(res1.Pagination.Total, uint64(0)) - - s.T().Log("verify paginate with custom limit, key and Reverse true") - pageReq = &query.PageRequest{Limit: defaultLimit, Reverse: true} - request = types.NewQueryAllBalancesRequest(addr1Str, pageReq, false) - 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 Reverse true") - pageReq = &query.PageRequest{Offset: 100, Limit: defaultLimit, Reverse: true} - request = types.NewQueryAllBalancesRequest(addr1Str, pageReq, false) - 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, Reverse true") - pageReq = &query.PageRequest{Offset: 200, Limit: defaultLimit, Reverse: true} - request = types.NewQueryAllBalancesRequest(addr1Str, pageReq, false) - res, err = queryClient.AllBalances(gocontext.Background(), request) - s.Require().NoError(err) - 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 page request with limit > defaultLimit, returns less or equal to `limit` records") - pageReq = &query.PageRequest{Limit: overLimit, Reverse: true} - request = types.NewQueryAllBalancesRequest(addr1Str, pageReq, false) - 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, key, countTotal false and Reverse true") - pageReq = &query.PageRequest{Key: res1.Pagination.NextKey, Limit: 50, Reverse: true} - request = types.NewQueryAllBalancesRequest(addr1Str, pageReq, false) - res, err = queryClient.AllBalances(gocontext.Background(), request) - s.Require().NoError(err) - s.Require().Equal(res.Balances.Len(), 50) - s.Require().NotNil(res.Pagination.NextKey) - s.Require().Equal(res.Pagination.Total, uint64(0)) - - s.T().Log("verify Reverse pagination returns valid result") - s.Require().Equal(balances[101:151].String(), res.Balances.Sort().String()) - - s.T().Log("verify paginate with custom limit, key, countTotal false and Reverse true") - pageReq = &query.PageRequest{Key: res.Pagination.NextKey, Limit: 50, Reverse: true} - request = types.NewQueryAllBalancesRequest(addr1Str, pageReq, false) - res, err = queryClient.AllBalances(gocontext.Background(), request) - s.Require().NoError(err) - s.Require().Equal(res.Balances.Len(), 50) - s.Require().NotNil(res.Pagination.NextKey) - s.Require().Equal(res.Pagination.Total, uint64(0)) - - s.T().Log("verify Reverse pagination returns valid result") - s.Require().Equal(balances[51:101].String(), res.Balances.Sort().String()) - - s.T().Log("verify paginate for last page Reverse true") - pageReq = &query.PageRequest{Key: res.Pagination.NextKey, Limit: defaultLimit, Reverse: true} - request = types.NewQueryAllBalancesRequest(addr1Str, pageReq, false) - res, err = queryClient.AllBalances(gocontext.Background(), request) - s.Require().NoError(err) - s.Require().Equal(res.Balances.Len(), 51) - s.Require().Nil(res.Pagination.NextKey) - s.Require().Equal(res.Pagination.Total, uint64(0)) - - s.T().Log("verify Reverse pagination returns valid result") - s.Require().Equal(balances[0:51].String(), res.Balances.Sort().String()) - - s.T().Log("verify paginate with offset and key - error") - pageReq = &query.PageRequest{Key: res1.Pagination.NextKey, Offset: 100, Limit: defaultLimit, CountTotal: false} - request = types.NewQueryAllBalancesRequest(addr1Str, pageReq, false) - _, 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, Reverse: true} - request = types.NewQueryAllBalancesRequest(addr1Str, pageReq, false) - 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 (s *paginationTestSuite) TestPaginate() { - 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 := s.accountKeeper.NewAccountWithAddress(s.ctx, addr1) - s.accountKeeper.SetAccount(s.ctx, acc1) - err := testutil.FundAccount(s.ctx, s.bankKeeper, addr1, balances) - if err != nil { // should return no error - fmt.Println(err) - } - - addr1Str, err := s.accountKeeper.AddressCodec().BytesToString(addr1) - s.Require().NoError(err) - - // Paginate example - pageReq := &query.PageRequest{Key: nil, Limit: 1, CountTotal: true} - request := types.NewQueryAllBalancesRequest(addr1Str, pageReq, false) - balResult := sdk.NewCoins() - authStore := s.ctx.KVStore(s.app.UnsafeFindStoreKey(types.StoreKey)) - balancesStore := prefix.NewStore(authStore, types.BalancesPrefix) - accountStore := prefix.NewStore(balancesStore, address.MustLengthPrefix(addr1)) - pageRes, err := query.Paginate(accountStore, request.Pagination, func(key, value []byte) error { - var amount math.Int - err := amount.Unmarshal(value) - if err != nil { - return err - } - balResult = append(balResult, sdk.NewCoin(string(key), amount)) - return nil - }) - if err != nil { // should return no error - fmt.Println(err) - } - fmt.Println(&types.QueryAllBalancesResponse{Balances: balResult, Pagination: pageRes}) - // Output: - // balances: pagination: -} From 1ad66ec0ac91f481f82917dcd8e45b1397e08e8b Mon Sep 17 00:00:00 2001 From: akhilkumarpilli Date: Thu, 19 Dec 2024 12:34:49 +0530 Subject: [PATCH 4/4] add comment --- tests/integration/v2/types/filtered_pagination_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/integration/v2/types/filtered_pagination_test.go b/tests/integration/v2/types/filtered_pagination_test.go index 9961f8fb3b35..b61afd623638 100644 --- a/tests/integration/v2/types/filtered_pagination_test.go +++ b/tests/integration/v2/types/filtered_pagination_test.go @@ -198,6 +198,7 @@ func (s *paginationTestSuite) TestFilteredPaginate() { func execFilterPaginate(ctx context.Context, bk bankkeeper.BaseKeeper, pageReq *query.PageRequest) (balances sdk.Coins, res *query.PageResponse, err error) { return query.CollectionFilteredPaginate(ctx, bk.Balances, pageReq, func(key collections.Pair[sdk.AccAddress, string], amount math.Int) (bool, error) { + // filter amount greater than 100 return amount.Int64() > int64(100), nil }, func(key collections.Pair[sdk.AccAddress, string], amount math.Int) (sdk.Coin, error) { balance := sdk.NewCoin(key.K2(), amount)