test: e2e/client to system tests (#21981)
This commit is contained in:
parent
e5b22e4cda
commit
91b47cb5e6
@ -1,347 +0,0 @@
|
||||
//go:build e2e
|
||||
// +build e2e
|
||||
|
||||
package cmtservice_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"cosmossdk.io/simapp"
|
||||
_ "cosmossdk.io/x/gov"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/grpc/cmtservice"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
"github.com/cosmos/cosmos-sdk/testutil"
|
||||
"github.com/cosmos/cosmos-sdk/testutil/network"
|
||||
qtypes "github.com/cosmos/cosmos-sdk/types/query"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
)
|
||||
|
||||
type E2ETestSuite struct {
|
||||
suite.Suite
|
||||
|
||||
cfg network.Config
|
||||
network network.NetworkI
|
||||
queryClient cmtservice.ServiceClient
|
||||
}
|
||||
|
||||
func TestE2ETestSuite(t *testing.T) {
|
||||
suite.Run(t, new(E2ETestSuite))
|
||||
}
|
||||
|
||||
func (s *E2ETestSuite) SetupSuite() {
|
||||
s.T().Log("setting up e2e test suite")
|
||||
|
||||
cfg := network.DefaultConfig(simapp.NewTestNetworkFixture)
|
||||
cfg.NumValidators = 1
|
||||
s.cfg = cfg
|
||||
|
||||
var err error
|
||||
s.network, err = network.New(s.T(), s.T().TempDir(), s.cfg)
|
||||
s.Require().NoError(err)
|
||||
|
||||
s.Require().NoError(s.network.WaitForNextBlock())
|
||||
|
||||
s.queryClient = cmtservice.NewServiceClient(s.network.GetValidators()[0].GetClientCtx())
|
||||
}
|
||||
|
||||
func (s *E2ETestSuite) TearDownSuite() {
|
||||
s.T().Log("tearing down e2e test suite")
|
||||
s.network.Cleanup()
|
||||
}
|
||||
|
||||
func (s *E2ETestSuite) TestQueryNodeInfo() {
|
||||
val := s.network.GetValidators()[0]
|
||||
|
||||
res, err := s.queryClient.GetNodeInfo(context.Background(), &cmtservice.GetNodeInfoRequest{})
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(res.ApplicationVersion.AppName, version.NewInfo().AppName)
|
||||
|
||||
restRes, err := testutil.GetRequest(fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/node_info", val.GetAPIAddress()))
|
||||
s.Require().NoError(err)
|
||||
var getInfoRes cmtservice.GetNodeInfoResponse
|
||||
s.Require().NoError(val.GetClientCtx().Codec.UnmarshalJSON(restRes, &getInfoRes))
|
||||
s.Require().Equal(getInfoRes.ApplicationVersion.AppName, version.NewInfo().AppName)
|
||||
}
|
||||
|
||||
func (s *E2ETestSuite) TestQuerySyncing() {
|
||||
val := s.network.GetValidators()[0]
|
||||
|
||||
_, err := s.queryClient.GetSyncing(context.Background(), &cmtservice.GetSyncingRequest{})
|
||||
s.Require().NoError(err)
|
||||
|
||||
restRes, err := testutil.GetRequest(fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/syncing", val.GetAPIAddress()))
|
||||
s.Require().NoError(err)
|
||||
var syncingRes cmtservice.GetSyncingResponse
|
||||
s.Require().NoError(val.GetClientCtx().Codec.UnmarshalJSON(restRes, &syncingRes))
|
||||
}
|
||||
|
||||
func (s *E2ETestSuite) TestQueryLatestBlock() {
|
||||
val := s.network.GetValidators()[0]
|
||||
|
||||
_, err := s.queryClient.GetLatestBlock(context.Background(), &cmtservice.GetLatestBlockRequest{})
|
||||
s.Require().NoError(err)
|
||||
|
||||
restRes, err := testutil.GetRequest(fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/blocks/latest", val.GetAPIAddress()))
|
||||
s.Require().NoError(err)
|
||||
var blockInfoRes cmtservice.GetLatestBlockResponse
|
||||
s.Require().NoError(val.GetClientCtx().Codec.UnmarshalJSON(restRes, &blockInfoRes))
|
||||
s.Require().Contains(blockInfoRes.SdkBlock.Header.ProposerAddress, "cosmosvalcons")
|
||||
}
|
||||
|
||||
func (s *E2ETestSuite) TestQueryBlockByHeight() {
|
||||
val := s.network.GetValidators()[0]
|
||||
_, err := s.queryClient.GetBlockByHeight(context.Background(), &cmtservice.GetBlockByHeightRequest{Height: 1})
|
||||
s.Require().NoError(err)
|
||||
|
||||
restRes, err := testutil.GetRequest(fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/blocks/%d", val.GetAPIAddress(), 1))
|
||||
s.Require().NoError(err)
|
||||
var blockInfoRes cmtservice.GetBlockByHeightResponse
|
||||
s.Require().NoError(val.GetClientCtx().Codec.UnmarshalJSON(restRes, &blockInfoRes))
|
||||
s.Require().Contains(blockInfoRes.SdkBlock.Header.ProposerAddress, "cosmosvalcons")
|
||||
}
|
||||
|
||||
func (s *E2ETestSuite) TestQueryLatestValidatorSet() {
|
||||
val := s.network.GetValidators()[0]
|
||||
|
||||
// nil pagination
|
||||
res, err := s.queryClient.GetLatestValidatorSet(context.Background(), &cmtservice.GetLatestValidatorSetRequest{
|
||||
Pagination: nil,
|
||||
})
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(1, len(res.Validators))
|
||||
content, ok := res.Validators[0].PubKey.GetCachedValue().(cryptotypes.PubKey)
|
||||
s.Require().Equal(true, ok)
|
||||
s.Require().Equal(content, val.GetPubKey())
|
||||
|
||||
// with pagination
|
||||
_, err = s.queryClient.GetLatestValidatorSet(context.Background(), &cmtservice.GetLatestValidatorSetRequest{Pagination: &qtypes.PageRequest{
|
||||
Offset: 0,
|
||||
Limit: 10,
|
||||
}})
|
||||
s.Require().NoError(err)
|
||||
|
||||
// rest request without pagination
|
||||
_, err = testutil.GetRequest(fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/latest", val.GetAPIAddress()))
|
||||
s.Require().NoError(err)
|
||||
|
||||
// rest request with pagination
|
||||
restRes, err := testutil.GetRequest(fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/latest?pagination.offset=%d&pagination.limit=%d", val.GetAPIAddress(), 0, 1))
|
||||
s.Require().NoError(err)
|
||||
var validatorSetRes cmtservice.GetLatestValidatorSetResponse
|
||||
s.Require().NoError(val.GetClientCtx().Codec.UnmarshalJSON(restRes, &validatorSetRes))
|
||||
s.Require().Equal(1, len(validatorSetRes.Validators))
|
||||
anyPub, err := codectypes.NewAnyWithValue(val.GetPubKey())
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(validatorSetRes.Validators[0].PubKey, anyPub)
|
||||
}
|
||||
|
||||
func (s *E2ETestSuite) TestLatestValidatorSet_GRPC() {
|
||||
vals := s.network.GetValidators()
|
||||
testCases := []struct {
|
||||
name string
|
||||
req *cmtservice.GetLatestValidatorSetRequest
|
||||
expErr bool
|
||||
expErrMsg string
|
||||
}{
|
||||
{"nil request", nil, true, "cannot be nil"},
|
||||
{"no pagination", &cmtservice.GetLatestValidatorSetRequest{}, false, ""},
|
||||
{"with pagination", &cmtservice.GetLatestValidatorSetRequest{Pagination: &qtypes.PageRequest{Offset: 0, Limit: uint64(len(vals))}}, false, ""},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
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].GetPubKey())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *E2ETestSuite) TestLatestValidatorSet_GRPCGateway() {
|
||||
vals := s.network.GetValidators()
|
||||
testCases := []struct {
|
||||
name string
|
||||
url string
|
||||
expErr bool
|
||||
expErrMsg string
|
||||
}{
|
||||
{"no pagination", fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/latest", vals[0].GetAPIAddress()), false, ""},
|
||||
{"pagination invalid fields", fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/latest?pagination.offset=-1&pagination.limit=-2", vals[0].GetAPIAddress()), true, "strconv.ParseUint"},
|
||||
{"with pagination", fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/latest?pagination.offset=0&pagination.limit=2", vals[0].GetAPIAddress()), false, ""},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
res, err := testutil.GetRequest(tc.url)
|
||||
s.Require().NoError(err)
|
||||
if tc.expErr {
|
||||
s.Require().Contains(string(res), tc.expErrMsg)
|
||||
} else {
|
||||
var result cmtservice.GetLatestValidatorSetResponse
|
||||
err = vals[0].GetClientCtx().Codec.UnmarshalJSON(res, &result)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(uint64(len(vals)), result.Pagination.Total)
|
||||
anyPub, err := codectypes.NewAnyWithValue(vals[0].GetPubKey())
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(result.Validators[0].PubKey, anyPub)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *E2ETestSuite) TestValidatorSetByHeight_GRPC() {
|
||||
vals := s.network.GetValidators()
|
||||
testCases := []struct {
|
||||
name string
|
||||
req *cmtservice.GetValidatorSetByHeightRequest
|
||||
expErr bool
|
||||
expErrMsg string
|
||||
}{
|
||||
{"nil request", nil, true, "request cannot be nil"},
|
||||
{"empty request", &cmtservice.GetValidatorSetByHeightRequest{}, true, "height must be greater than 0"},
|
||||
{"no pagination", &cmtservice.GetValidatorSetByHeightRequest{Height: 1}, false, ""},
|
||||
{"with pagination", &cmtservice.GetValidatorSetByHeightRequest{Height: 1, Pagination: &qtypes.PageRequest{Offset: 0, Limit: 1}}, false, ""},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
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 *E2ETestSuite) TestValidatorSetByHeight_GRPCGateway() {
|
||||
vals := s.network.GetValidators()
|
||||
testCases := []struct {
|
||||
name string
|
||||
url string
|
||||
expErr bool
|
||||
expErrMsg string
|
||||
}{
|
||||
{"invalid height", fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/%d", vals[0].GetAPIAddress(), -1), true, "height must be greater than 0"},
|
||||
{"no pagination", fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/%d", vals[0].GetAPIAddress(), 1), false, ""},
|
||||
{"pagination invalid fields", fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/%d?pagination.offset=-1&pagination.limit=-2", vals[0].GetAPIAddress(), 1), true, "strconv.ParseUint"},
|
||||
{"with pagination", fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/%d?pagination.offset=0&pagination.limit=2", vals[0].GetAPIAddress(), 1), false, ""},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
res, err := testutil.GetRequest(tc.url)
|
||||
s.Require().NoError(err)
|
||||
if tc.expErr {
|
||||
s.Require().Contains(string(res), tc.expErrMsg)
|
||||
} else {
|
||||
var result cmtservice.GetValidatorSetByHeightResponse
|
||||
err = vals[0].GetClientCtx().Codec.UnmarshalJSON(res, &result)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(uint64(len(vals)), result.Pagination.Total)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (s *E2ETestSuite) TestABCIQuery() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
req *cmtservice.ABCIQueryRequest
|
||||
expectErr bool
|
||||
expectedCode uint32
|
||||
validQuery bool
|
||||
}{
|
||||
{
|
||||
name: "valid request with proof",
|
||||
req: &cmtservice.ABCIQueryRequest{
|
||||
Path: "/store/gov/key",
|
||||
Data: []byte{0x03},
|
||||
Prove: true,
|
||||
},
|
||||
validQuery: true,
|
||||
},
|
||||
{
|
||||
name: "valid request without proof",
|
||||
req: &cmtservice.ABCIQueryRequest{
|
||||
Path: "/store/gov/key",
|
||||
Data: []byte{0x03},
|
||||
Prove: false,
|
||||
},
|
||||
validQuery: true,
|
||||
},
|
||||
{
|
||||
name: "request with invalid path",
|
||||
req: &cmtservice.ABCIQueryRequest{
|
||||
Path: "/foo/bar",
|
||||
Data: []byte{0x03},
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "request with invalid path recursive",
|
||||
req: &cmtservice.ABCIQueryRequest{
|
||||
Path: "/cosmos.base.tendermint.v1beta1.Service/ABCIQuery",
|
||||
Data: s.cfg.Codec.MustMarshal(&cmtservice.ABCIQueryRequest{
|
||||
Path: "/cosmos.base.tendermint.v1beta1.Service/ABCIQuery",
|
||||
}),
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "request with invalid broadcast tx path",
|
||||
req: &cmtservice.ABCIQueryRequest{
|
||||
Path: "/cosmos.tx.v1beta1.Service/BroadcastTx",
|
||||
Data: []byte{0x00},
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "request with invalid data",
|
||||
req: &cmtservice.ABCIQueryRequest{
|
||||
Path: "/store/gov/key",
|
||||
Data: []byte{0x0044, 0x00},
|
||||
},
|
||||
validQuery: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
s.Run(tc.name, func() {
|
||||
res, err := s.queryClient.ABCIQuery(context.Background(), tc.req)
|
||||
if tc.expectErr {
|
||||
s.Require().Error(err)
|
||||
s.Require().Nil(res)
|
||||
} else {
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(res)
|
||||
s.Require().Equal(res.Code, tc.expectedCode)
|
||||
}
|
||||
|
||||
if tc.validQuery {
|
||||
s.Require().Greater(res.Height, int64(0))
|
||||
s.Require().Greater(len(res.Key), 0, "expected non-empty key")
|
||||
s.Require().Greater(len(res.Value), 0, "expected non-empty value")
|
||||
}
|
||||
|
||||
if tc.req.Prove {
|
||||
s.Require().Greater(len(res.ProofOps.Ops), 0, "expected proofs")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
330
tests/systemtests/cometbft_client_test.go
Normal file
330
tests/systemtests/cometbft_client_test.go
Normal file
@ -0,0 +1,330 @@
|
||||
//go:build system_test
|
||||
|
||||
package systemtests
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tidwall/gjson"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/grpc/cmtservice"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
"github.com/cosmos/cosmos-sdk/testutil"
|
||||
qtypes "github.com/cosmos/cosmos-sdk/types/query"
|
||||
)
|
||||
|
||||
func TestQueryNodeInfo(t *testing.T) {
|
||||
baseurl := fmt.Sprintf("http://localhost:%d", apiPortStart)
|
||||
sut.ResetChain(t)
|
||||
sut.StartChain(t)
|
||||
|
||||
qc := cmtservice.NewServiceClient(sut.RPCClient(t))
|
||||
res, err := qc.GetNodeInfo(context.Background(), &cmtservice.GetNodeInfoRequest{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
v := NewCLIWrapper(t, sut, true).Version()
|
||||
assert.Equal(t, res.ApplicationVersion.Version, v)
|
||||
|
||||
// TODO: we should be adding a way to distinguish a v2. Eventually we should skip some v2 system depending on the consensus engine we want to test
|
||||
restRes, err := testutil.GetRequest(fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/node_info", baseurl))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, gjson.GetBytes(restRes, "application_version.version").String(), res.ApplicationVersion.Version)
|
||||
}
|
||||
|
||||
func TestQuerySyncing(t *testing.T) {
|
||||
baseurl := fmt.Sprintf("http://localhost:%d", apiPortStart)
|
||||
sut.ResetChain(t)
|
||||
sut.StartChain(t)
|
||||
|
||||
qc := cmtservice.NewServiceClient(sut.RPCClient(t))
|
||||
res, err := qc.GetSyncing(context.Background(), &cmtservice.GetSyncingRequest{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
restRes, err := testutil.GetRequest(fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/syncing", baseurl))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, gjson.GetBytes(restRes, "syncing").Bool(), res.Syncing)
|
||||
}
|
||||
|
||||
func TestQueryLatestBlock(t *testing.T) {
|
||||
baseurl := fmt.Sprintf("http://localhost:%d", apiPortStart)
|
||||
sut.ResetChain(t)
|
||||
sut.StartChain(t)
|
||||
|
||||
qc := cmtservice.NewServiceClient(sut.RPCClient(t))
|
||||
res, err := qc.GetLatestBlock(context.Background(), &cmtservice.GetLatestBlockRequest{})
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, res.SdkBlock.Header.ProposerAddress, "cosmosvalcons")
|
||||
|
||||
_, err = testutil.GetRequest(fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/blocks/latest", baseurl))
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestQueryBlockByHeight(t *testing.T) {
|
||||
baseurl := fmt.Sprintf("http://localhost:%d", apiPortStart)
|
||||
sut.ResetChain(t)
|
||||
sut.StartChain(t)
|
||||
|
||||
sut.AwaitNBlocks(t, 2, time.Second*25)
|
||||
|
||||
qc := cmtservice.NewServiceClient(sut.RPCClient(t))
|
||||
res, err := qc.GetBlockByHeight(context.Background(), &cmtservice.GetBlockByHeightRequest{Height: 2})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, res.SdkBlock.Header.Height, int64(2))
|
||||
assert.Contains(t, res.SdkBlock.Header.ProposerAddress, "cosmosvalcons")
|
||||
|
||||
restRes, err := testutil.GetRequest(fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/blocks/%d", baseurl, 2))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, gjson.GetBytes(restRes, "sdk_block.header.height").Int(), int64(2))
|
||||
assert.Contains(t, gjson.GetBytes(restRes, "sdk_block.header.proposer_address").String(), "cosmosvalcons")
|
||||
}
|
||||
|
||||
func TestQueryLatestValidatorSet(t *testing.T) {
|
||||
baseurl := fmt.Sprintf("http://localhost:%d", apiPortStart)
|
||||
sut.ResetChain(t)
|
||||
sut.StartChain(t)
|
||||
|
||||
vals := sut.RPCClient(t).Validators()
|
||||
|
||||
qc := cmtservice.NewServiceClient(sut.RPCClient(t))
|
||||
res, err := qc.GetLatestValidatorSet(context.Background(), &cmtservice.GetLatestValidatorSetRequest{
|
||||
Pagination: nil,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, len(res.Validators), len(vals))
|
||||
|
||||
// with pagination
|
||||
res, err = qc.GetLatestValidatorSet(context.Background(), &cmtservice.GetLatestValidatorSetRequest{Pagination: &qtypes.PageRequest{
|
||||
Offset: 0,
|
||||
Limit: 2,
|
||||
}})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, len(res.Validators), 2)
|
||||
|
||||
restRes, err := testutil.GetRequest(fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/latest?pagination.offset=%d&pagination.limit=%d", baseurl, 0, 2))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, len(gjson.GetBytes(restRes, "validators").Array()), 2)
|
||||
}
|
||||
|
||||
func TestLatestValidatorSet(t *testing.T) {
|
||||
sut.ResetChain(t)
|
||||
sut.StartChain(t)
|
||||
|
||||
vals := sut.RPCClient(t).Validators()
|
||||
|
||||
qc := cmtservice.NewServiceClient(sut.RPCClient(t))
|
||||
testCases := []struct {
|
||||
name string
|
||||
req *cmtservice.GetLatestValidatorSetRequest
|
||||
expErr bool
|
||||
expErrMsg string
|
||||
}{
|
||||
{"nil request", nil, true, "cannot be nil"},
|
||||
{"no pagination", &cmtservice.GetLatestValidatorSetRequest{}, false, ""},
|
||||
{"with pagination", &cmtservice.GetLatestValidatorSetRequest{Pagination: &qtypes.PageRequest{Offset: 0, Limit: uint64(len(vals))}}, false, ""},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
res, err := qc.GetLatestValidatorSet(context.Background(), tc.req)
|
||||
if tc.expErr {
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), tc.expErrMsg)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, len(res.Validators), len(vals))
|
||||
content, ok := res.Validators[0].PubKey.GetCachedValue().(cryptotypes.PubKey)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, content.Address(), vals[0].PubKey.Address())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
func TestLatestValidatorSet_GRPCGateway(t *testing.T) {
|
||||
sut.ResetChain(t)
|
||||
sut.StartChain(t)
|
||||
|
||||
baseurl := fmt.Sprintf("http://localhost:%d", apiPortStart)
|
||||
|
||||
vals := sut.RPCClient(t).Validators()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
url string
|
||||
expErr bool
|
||||
expErrMsg string
|
||||
}{
|
||||
{"no pagination", "/cosmos/base/tendermint/v1beta1/validatorsets/latest", false, ""},
|
||||
{"pagination invalid fields", "/cosmos/base/tendermint/v1beta1/validatorsets/latest?pagination.offset=-1&pagination.limit=-2", true, "strconv.ParseUint"},
|
||||
{"with pagination", "/cosmos/base/tendermint/v1beta1/validatorsets/latest?pagination.offset=0&pagination.limit=2", false, ""},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
rsp, err := testutil.GetRequest(fmt.Sprintf("%s%s", baseurl, tc.url))
|
||||
assert.NoError(t, err)
|
||||
if tc.expErr {
|
||||
errMsg := gjson.GetBytes(rsp, "message").String()
|
||||
assert.Contains(t, errMsg, tc.expErrMsg)
|
||||
} else {
|
||||
assert.Equal(t, len(vals), int(gjson.GetBytes(rsp, "pagination.total").Int()))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidatorSetByHeight(t *testing.T) {
|
||||
sut.ResetChain(t)
|
||||
sut.StartChain(t)
|
||||
|
||||
qc := cmtservice.NewServiceClient(sut.RPCClient(t))
|
||||
vals := sut.RPCClient(t).Validators()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
req *cmtservice.GetValidatorSetByHeightRequest
|
||||
expErr bool
|
||||
expErrMsg string
|
||||
}{
|
||||
{"nil request", nil, true, "request cannot be nil"},
|
||||
{"empty request", &cmtservice.GetValidatorSetByHeightRequest{}, true, "height must be greater than 0"},
|
||||
{"no pagination", &cmtservice.GetValidatorSetByHeightRequest{Height: 1}, false, ""},
|
||||
{"with pagination", &cmtservice.GetValidatorSetByHeightRequest{Height: 1, Pagination: &qtypes.PageRequest{Offset: 0, Limit: uint64(len(vals))}}, false, ""},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
res, err := qc.GetValidatorSetByHeight(context.Background(), tc.req)
|
||||
if tc.expErr {
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), tc.expErrMsg)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, len(res.Validators), len(vals))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidatorSetByHeight_GRPCGateway(t *testing.T) {
|
||||
sut.ResetChain(t)
|
||||
sut.StartChain(t)
|
||||
|
||||
vals := sut.RPCClient(t).Validators()
|
||||
|
||||
baseurl := fmt.Sprintf("http://localhost:%d", apiPortStart)
|
||||
|
||||
block := sut.AwaitNextBlock(t, time.Second*3)
|
||||
testCases := []struct {
|
||||
name string
|
||||
url string
|
||||
expErr bool
|
||||
expErrMsg string
|
||||
}{
|
||||
{"invalid height", fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/%d", baseurl, -1), true, "height must be greater than 0"},
|
||||
{"no pagination", fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/%d", baseurl, block), false, ""},
|
||||
{"pagination invalid fields", fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/%d?pagination.offset=-1&pagination.limit=-2", baseurl, block), true, "strconv.ParseUint"},
|
||||
{"with pagination", fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/validatorsets/%d?pagination.limit=2", baseurl, 1), false, ""},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
rsp, err := testutil.GetRequest(tc.url)
|
||||
assert.NoError(t, err)
|
||||
if tc.expErr {
|
||||
errMsg := gjson.GetBytes(rsp, "message").String()
|
||||
assert.Contains(t, errMsg, tc.expErrMsg)
|
||||
} else {
|
||||
assert.Equal(t, len(vals), int(gjson.GetBytes(rsp, "pagination.total").Int()))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestABCIQuery(t *testing.T) {
|
||||
sut.ResetChain(t)
|
||||
sut.StartChain(t)
|
||||
|
||||
qc := cmtservice.NewServiceClient(sut.RPCClient(t))
|
||||
cdc := codec.NewProtoCodec(codectypes.NewInterfaceRegistry())
|
||||
testCases := []struct {
|
||||
name string
|
||||
req *cmtservice.ABCIQueryRequest
|
||||
expectErr bool
|
||||
expectedCode uint32
|
||||
validQuery bool
|
||||
}{
|
||||
{
|
||||
name: "valid request with proof",
|
||||
req: &cmtservice.ABCIQueryRequest{
|
||||
Path: "/store/gov/key",
|
||||
Data: []byte{0x03},
|
||||
Prove: true,
|
||||
},
|
||||
validQuery: true,
|
||||
},
|
||||
{
|
||||
name: "valid request without proof",
|
||||
req: &cmtservice.ABCIQueryRequest{
|
||||
Path: "/store/gov/key",
|
||||
Data: []byte{0x03},
|
||||
Prove: false,
|
||||
},
|
||||
validQuery: true,
|
||||
},
|
||||
{
|
||||
name: "request with invalid path",
|
||||
req: &cmtservice.ABCIQueryRequest{
|
||||
Path: "/foo/bar",
|
||||
Data: []byte{0x03},
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "request with invalid path recursive",
|
||||
req: &cmtservice.ABCIQueryRequest{
|
||||
Path: "/cosmos.base.tendermint.v1beta1.Service/ABCIQuery",
|
||||
Data: cdc.MustMarshal(&cmtservice.ABCIQueryRequest{
|
||||
Path: "/cosmos.base.tendermint.v1beta1.Service/ABCIQuery",
|
||||
}),
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "request with invalid broadcast tx path",
|
||||
req: &cmtservice.ABCIQueryRequest{
|
||||
Path: "/cosmos.tx.v1beta1.Service/BroadcastTx",
|
||||
Data: []byte{0x00},
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "request with invalid data",
|
||||
req: &cmtservice.ABCIQueryRequest{
|
||||
Path: "/store/gov/key",
|
||||
Data: []byte{0x0044, 0x00},
|
||||
},
|
||||
validQuery: false,
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
res, err := qc.ABCIQuery(context.Background(), tc.req)
|
||||
if tc.expectErr {
|
||||
assert.Error(t, err)
|
||||
assert.Nil(t, res)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, res)
|
||||
assert.Equal(t, res.Code, tc.expectedCode)
|
||||
}
|
||||
|
||||
if tc.validQuery {
|
||||
assert.Greater(t, res.Height, int64(0))
|
||||
assert.Greater(t, len(res.Key), 0)
|
||||
assert.Greater(t, len(res.Value), 0)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -20,12 +20,13 @@ require (
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
|
||||
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect
|
||||
google.golang.org/grpc v1.67.0 // indirect
|
||||
google.golang.org/grpc v1.67.0
|
||||
)
|
||||
|
||||
require (
|
||||
cosmossdk.io/math v1.3.0
|
||||
github.com/cometbft/cometbft v0.38.8
|
||||
github.com/cometbft/cometbft/api v1.0.0-rc.1
|
||||
github.com/creachadair/tomledit v0.0.26
|
||||
github.com/tidwall/gjson v1.14.2
|
||||
github.com/tidwall/sjson v1.2.5
|
||||
|
||||
@ -129,6 +129,8 @@ github.com/cometbft/cometbft v0.38.8 h1:XyJ9Cu3xqap6xtNxiemrO8roXZ+KS2Zlu7qQ0w1t
|
||||
github.com/cometbft/cometbft v0.38.8/go.mod h1:xOoGZrtUT+A5izWfHSJgl0gYZUE7lu7Z2XIS1vWG/QQ=
|
||||
github.com/cometbft/cometbft-db v0.9.1 h1:MIhVX5ja5bXNHF8EYrThkG9F7r9kSfv8BX4LWaxWJ4M=
|
||||
github.com/cometbft/cometbft-db v0.9.1/go.mod h1:iliyWaoV0mRwBJoizElCwwRA9Tf7jZJOURcRZF9m60U=
|
||||
github.com/cometbft/cometbft/api v1.0.0-rc.1 h1:GtdXwDGlqwHYs16A4egjwylfYOMYyEacLBrs3Zvpt7g=
|
||||
github.com/cometbft/cometbft/api v1.0.0-rc.1/go.mod h1:NDFKiBBD8HJC6QQLAoUI99YhsiRZtg2+FJWfk6A6m6o=
|
||||
github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg=
|
||||
github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
|
||||
@ -2,11 +2,23 @@ package systemtests
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
abci "github.com/cometbft/cometbft/api/cometbft/abci/v1"
|
||||
rpcclient "github.com/cometbft/cometbft/rpc/client"
|
||||
client "github.com/cometbft/cometbft/rpc/client/http"
|
||||
cmtypes "github.com/cometbft/cometbft/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/metadata"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/codec/types"
|
||||
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
|
||||
grpctypes "github.com/cosmos/cosmos-sdk/types/grpc"
|
||||
)
|
||||
|
||||
// RPCClient is a test helper to interact with a node via the RPC endpoint.
|
||||
@ -31,3 +43,71 @@ func (r RPCClient) Validators() []*cmtypes.Validator {
|
||||
require.NoError(r.t, err)
|
||||
return v.Validators
|
||||
}
|
||||
|
||||
func (r RPCClient) Invoke(ctx context.Context, method string, req, reply interface{}, opts ...grpc.CallOption) error {
|
||||
if reflect.ValueOf(req).IsNil() {
|
||||
return errors.New("request cannot be nil")
|
||||
}
|
||||
|
||||
ir := types.NewInterfaceRegistry()
|
||||
cryptocodec.RegisterInterfaces(ir)
|
||||
cdc := codec.NewProtoCodec(ir).GRPCCodec()
|
||||
|
||||
reqBz, err := cdc.Marshal(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var height int64
|
||||
md, _ := metadata.FromOutgoingContext(ctx)
|
||||
if heights := md.Get(grpctypes.GRPCBlockHeightHeader); len(heights) > 0 {
|
||||
height, err := strconv.ParseInt(heights[0], 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if height < 0 {
|
||||
return errors.New("height must be greater than or equal to 0")
|
||||
}
|
||||
}
|
||||
|
||||
abciReq := abci.QueryRequest{
|
||||
Path: method,
|
||||
Data: reqBz,
|
||||
Height: height,
|
||||
}
|
||||
|
||||
abciOpts := rpcclient.ABCIQueryOptions{
|
||||
Height: height,
|
||||
Prove: abciReq.Prove,
|
||||
}
|
||||
|
||||
result, err := r.client.ABCIQueryWithOptions(ctx, abciReq.Path, abciReq.Data, abciOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !result.Response.IsOK() {
|
||||
return errors.New(result.Response.String())
|
||||
}
|
||||
|
||||
err = cdc.Unmarshal(result.Response.Value, reply)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
md = metadata.Pairs(grpctypes.GRPCBlockHeightHeader, strconv.FormatInt(result.Response.Height, 10))
|
||||
for _, callOpt := range opts {
|
||||
header, ok := callOpt.(grpc.HeaderCallOption)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
*header.HeaderAddr = md
|
||||
}
|
||||
|
||||
return types.UnpackInterfaces(reply, ir)
|
||||
}
|
||||
|
||||
func (r RPCClient) NewStream(ctx context.Context, desc *grpc.StreamDesc, method string, opts ...grpc.CallOption) (grpc.ClientStream, error) {
|
||||
return nil, errors.New("not implemented")
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user