Add pagination to GetValidatorSetByHeight response (#8567)

* fix pagination

* add test

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
This commit is contained in:
MD Aleem 2021-02-15 16:11:39 +05:30 committed by GitHub
parent e306e5b6f5
commit d162b29cf4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 129 additions and 23 deletions

View File

@ -104,6 +104,9 @@ func (s queryServer) GetLatestValidatorSet(ctx context.Context, req *GetLatestVa
outputValidatorsRes := &GetLatestValidatorSetResponse{ outputValidatorsRes := &GetLatestValidatorSetResponse{
BlockHeight: validatorsRes.BlockHeight, BlockHeight: validatorsRes.BlockHeight,
Validators: make([]*Validator, len(validatorsRes.Validators)), Validators: make([]*Validator, len(validatorsRes.Validators)),
Pagination: &qtypes.PageResponse{
Total: validatorsRes.Total,
},
} }
for i, validator := range validatorsRes.Validators { for i, validator := range validatorsRes.Validators {
@ -156,6 +159,7 @@ func (s queryServer) GetValidatorSetByHeight(ctx context.Context, req *GetValida
outputValidatorsRes := &GetValidatorSetByHeightResponse{ outputValidatorsRes := &GetValidatorSetByHeightResponse{
BlockHeight: validatorsRes.BlockHeight, BlockHeight: validatorsRes.BlockHeight,
Validators: make([]*Validator, len(validatorsRes.Validators)), Validators: make([]*Validator, len(validatorsRes.Validators)),
Pagination: &qtypes.PageResponse{Total: validatorsRes.Total},
} }
for i, validator := range validatorsRes.Validators { for i, validator := range validatorsRes.Validators {

View File

@ -131,32 +131,126 @@ func (s IntegrationTestSuite) TestQueryLatestValidatorSet() {
s.Require().Equal(validatorSetRes.Validators[0].PubKey, anyPub) s.Require().Equal(validatorSetRes.Validators[0].PubKey, anyPub)
} }
func (s IntegrationTestSuite) TestQueryValidatorSetByHeight() { func (s IntegrationTestSuite) TestLatestValidatorSet_GRPC() {
val := s.network.Validators[0] vals := s.network.Validators
testCases := []struct {
// nil pagination name string
_, err := s.queryClient.GetValidatorSetByHeight(context.Background(), &tmservice.GetValidatorSetByHeightRequest{ req *tmservice.GetLatestValidatorSetRequest
Height: 1, expErr bool
Pagination: nil, expErrMsg string
}{
{"nil request", nil, true, "cannot be nil"},
{"no pagination", &tmservice.GetLatestValidatorSetRequest{}, false, ""},
{"with pagination", &tmservice.GetLatestValidatorSetRequest{Pagination: &qtypes.PageRequest{Offset: 0, Limit: uint64(len(vals))}}, false, ""},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
grpcRes, err := s.queryClient.GetLatestValidatorSet(context.Background(), tc.req)
if tc.expErr {
s.Require().Error(err)
s.Require().Contains(err.Error(), tc.expErrMsg)
} else {
s.Require().NoError(err)
s.Require().Len(grpcRes.Validators, len(vals))
s.Require().Equal(grpcRes.Pagination.Total, uint64(len(vals)))
content, ok := grpcRes.Validators[0].PubKey.GetCachedValue().(cryptotypes.PubKey)
s.Require().Equal(true, ok)
s.Require().Equal(content, vals[0].PubKey)
}
}) })
s.Require().NoError(err) }
}
_, err = s.queryClient.GetValidatorSetByHeight(context.Background(), &tmservice.GetValidatorSetByHeightRequest{ func (s IntegrationTestSuite) TestLatestValidatorSet_GRPCGateway() {
Height: 1, vals := s.network.Validators
Pagination: &qtypes.PageRequest{ testCases := []struct {
Offset: 0, name string
Limit: 10, url string
}}) expErr bool
expErrMsg string
}{
{"no pagination", fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/latest", vals[0].APIAddress), false, ""},
{"pagination invalid fields", fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/latest?pagination.offset=-1&pagination.limit=-2", vals[0].APIAddress), true, "strconv.ParseUint"},
{"with pagination", fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/latest?pagination.offset=0&pagination.limit=2", vals[0].APIAddress), false, ""},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
res, err := rest.GetRequest(tc.url)
s.Require().NoError(err) s.Require().NoError(err)
if tc.expErr {
// no pagination rest s.Require().Contains(string(res), tc.expErrMsg)
_, err = rest.GetRequest(fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/%d", val.APIAddress, 1)) } else {
var result tmservice.GetLatestValidatorSetResponse
err = vals[0].ClientCtx.JSONMarshaler.UnmarshalJSON(res, &result)
s.Require().NoError(err) s.Require().NoError(err)
s.Require().Equal(uint64(len(vals)), result.Pagination.Total)
anyPub, err := codectypes.NewAnyWithValue(vals[0].PubKey)
s.Require().NoError(err)
s.Require().Equal(result.Validators[0].PubKey, anyPub)
}
})
}
}
// rest query with pagination func (s IntegrationTestSuite) TestValidatorSetByHeight_GRPC() {
restRes, err := rest.GetRequest(fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/%d?pagination.offset=%d&pagination.limit=%d", val.APIAddress, 1, 0, 1)) vals := s.network.Validators
var validatorSetRes tmservice.GetValidatorSetByHeightResponse testCases := []struct {
s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(restRes, &validatorSetRes)) name string
req *tmservice.GetValidatorSetByHeightRequest
expErr bool
expErrMsg string
}{
{"nil request", nil, true, "request cannot be nil"},
{"empty request", &tmservice.GetValidatorSetByHeightRequest{}, true, "height must be greater than 0"},
{"no pagination", &tmservice.GetValidatorSetByHeightRequest{Height: 1}, false, ""},
{"with pagination", &tmservice.GetValidatorSetByHeightRequest{Height: 1, Pagination: &qtypes.PageRequest{Offset: 0, Limit: 1}}, false, ""},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
grpcRes, err := s.queryClient.GetValidatorSetByHeight(context.Background(), tc.req)
if tc.expErr {
s.Require().Error(err)
s.Require().Contains(err.Error(), tc.expErrMsg)
} else {
s.Require().NoError(err)
s.Require().Len(grpcRes.Validators, len(vals))
s.Require().Equal(grpcRes.Pagination.Total, uint64(len(vals)))
}
})
}
}
func (s IntegrationTestSuite) TestValidatorSetByHeight_GRPCGateway() {
vals := s.network.Validators
testCases := []struct {
name string
url string
expErr bool
expErrMsg string
}{
{"invalid height", fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/%d", vals[0].APIAddress, -1), true, "height must be greater than 0"},
{"no pagination", fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/%d", vals[0].APIAddress, 1), false, ""},
{"pagination invalid fields", fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/%d?pagination.offset=-1&pagination.limit=-2", vals[0].APIAddress, 1), true, "strconv.ParseUint"},
{"with pagination", fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/%d?pagination.offset=0&pagination.limit=2", vals[0].APIAddress, 1), false, ""},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
res, err := rest.GetRequest(tc.url)
s.Require().NoError(err)
if tc.expErr {
s.Require().Contains(string(res), tc.expErrMsg)
} else {
var result tmservice.GetValidatorSetByHeightResponse
err = vals[0].ClientCtx.JSONMarshaler.UnmarshalJSON(res, &result)
s.Require().NoError(err)
s.Require().Equal(uint64(len(vals)), result.Pagination.Total)
}
})
}
} }
func TestIntegrationTestSuite(t *testing.T) { func TestIntegrationTestSuite(t *testing.T) {

View File

@ -79,12 +79,14 @@ type ValidatorOutput struct {
type ResultValidatorsOutput struct { type ResultValidatorsOutput struct {
BlockHeight int64 `json:"block_height"` BlockHeight int64 `json:"block_height"`
Validators []ValidatorOutput `json:"validators"` Validators []ValidatorOutput `json:"validators"`
Total uint64 `json:"total"`
} }
func (rvo ResultValidatorsOutput) String() string { func (rvo ResultValidatorsOutput) String() string {
var b strings.Builder var b strings.Builder
b.WriteString(fmt.Sprintf("block height: %d\n", rvo.BlockHeight)) b.WriteString(fmt.Sprintf("block height: %d\n", rvo.BlockHeight))
b.WriteString(fmt.Sprintf("total count: %d\n", rvo.Total))
for _, val := range rvo.Validators { for _, val := range rvo.Validators {
b.WriteString( b.WriteString(
@ -129,9 +131,15 @@ func GetValidators(ctx context.Context, clientCtx client.Context, height *int64,
return ResultValidatorsOutput{}, err return ResultValidatorsOutput{}, err
} }
total := validatorsRes.Total
if validatorsRes.Total < 0 {
total = 0
}
outputValidatorsRes := ResultValidatorsOutput{ outputValidatorsRes := ResultValidatorsOutput{
BlockHeight: validatorsRes.BlockHeight, BlockHeight: validatorsRes.BlockHeight,
Validators: make([]ValidatorOutput, len(validatorsRes.Validators)), Validators: make([]ValidatorOutput, len(validatorsRes.Validators)),
Total: uint64(total),
} }
for i := 0; i < len(validatorsRes.Validators); i++ { for i := 0; i < len(validatorsRes.Validators); i++ {