From 4599aaf192d57ab324aa7110294a2421a2deaad0 Mon Sep 17 00:00:00 2001 From: akhilkumarpilli Date: Mon, 9 Sep 2024 16:40:03 +0530 Subject: [PATCH 1/8] test: migrate e2e/bank to system tests --- tests/e2e/bank/grpc.go | 79 +++++++ tests/e2e/bank/suite.go | 397 --------------------------------- tests/systemtests/bank_test.go | 216 ++++++++++++++++++ 3 files changed, 295 insertions(+), 397 deletions(-) delete mode 100644 tests/e2e/bank/suite.go create mode 100644 tests/systemtests/bank_test.go diff --git a/tests/e2e/bank/grpc.go b/tests/e2e/bank/grpc.go index 29f57bc4ae84..2c8198c5c4dc 100644 --- a/tests/e2e/bank/grpc.go +++ b/tests/e2e/bank/grpc.go @@ -4,16 +4,95 @@ import ( "fmt" "github.com/cosmos/gogoproto/proto" + "github.com/stretchr/testify/suite" + "cosmossdk.io/core/address" "cosmossdk.io/math" "cosmossdk.io/x/bank/types" + addresscodec "github.com/cosmos/cosmos-sdk/codec/address" "github.com/cosmos/cosmos-sdk/testutil" + "github.com/cosmos/cosmos-sdk/testutil/network" sdk "github.com/cosmos/cosmos-sdk/types" grpctypes "github.com/cosmos/cosmos-sdk/types/grpc" "github.com/cosmos/cosmos-sdk/types/query" ) +type E2ETestSuite struct { + suite.Suite + + cfg network.Config + ac address.Codec + network network.NetworkI +} + +func NewE2ETestSuite(cfg network.Config) *E2ETestSuite { + return &E2ETestSuite{cfg: cfg} +} + +func (s *E2ETestSuite) SetupSuite() { + s.T().Log("setting up e2e test suite") + + genesisState := s.cfg.GenesisState + var bankGenesis types.GenesisState + s.Require().NoError(s.cfg.Codec.UnmarshalJSON(genesisState[types.ModuleName], &bankGenesis)) + + bankGenesis.DenomMetadata = []types.Metadata{ + { + Name: "Cosmos Hub Atom", + Symbol: "ATOM", + Description: "The native staking token of the Cosmos Hub.", + DenomUnits: []*types.DenomUnit{ + { + Denom: "uatom", + Exponent: 0, + Aliases: []string{"microatom"}, + }, + { + Denom: "atom", + Exponent: 6, + Aliases: []string{"ATOM"}, + }, + }, + Base: "uatom", + Display: "atom", + }, + { + Name: "Ethereum", + Symbol: "ETH", + Description: "Ethereum mainnet token", + DenomUnits: []*types.DenomUnit{ + { + Denom: "wei", + Exponent: 0, + }, + { + Denom: "eth", + Exponent: 6, + Aliases: []string{"ETH"}, + }, + }, + Base: "wei", + Display: "eth", + }, + } + + bankGenesisBz, err := s.cfg.Codec.MarshalJSON(&bankGenesis) + s.Require().NoError(err) + genesisState[types.ModuleName] = bankGenesisBz + s.cfg.GenesisState = genesisState + + s.network, err = network.New(s.T(), s.T().TempDir(), s.cfg) + s.Require().NoError(err) + s.Require().NoError(s.network.WaitForNextBlock()) + s.ac = addresscodec.NewBech32Codec("cosmos") +} + +func (s *E2ETestSuite) TearDownSuite() { + s.T().Log("tearing down e2e test suite") + s.network.Cleanup() +} + func (s *E2ETestSuite) TestTotalSupplyGRPCHandler() { val := s.network.GetValidators()[0] baseURL := val.GetAPIAddress() diff --git a/tests/e2e/bank/suite.go b/tests/e2e/bank/suite.go deleted file mode 100644 index e717bd1f6a4b..000000000000 --- a/tests/e2e/bank/suite.go +++ /dev/null @@ -1,397 +0,0 @@ -package client - -import ( - "fmt" - - "github.com/cosmos/gogoproto/proto" - "github.com/stretchr/testify/suite" - - "cosmossdk.io/core/address" - "cosmossdk.io/math" - "cosmossdk.io/x/bank/client/cli" - "cosmossdk.io/x/bank/types" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - addresscodec "github.com/cosmos/cosmos-sdk/codec/address" - "github.com/cosmos/cosmos-sdk/testutil" - clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" - "github.com/cosmos/cosmos-sdk/testutil/network" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -type E2ETestSuite struct { - suite.Suite - - cfg network.Config - ac address.Codec - network network.NetworkI -} - -func NewE2ETestSuite(cfg network.Config) *E2ETestSuite { - return &E2ETestSuite{cfg: cfg} -} - -func (s *E2ETestSuite) SetupSuite() { - s.T().Log("setting up e2e test suite") - - genesisState := s.cfg.GenesisState - var bankGenesis types.GenesisState - s.Require().NoError(s.cfg.Codec.UnmarshalJSON(genesisState[types.ModuleName], &bankGenesis)) - - bankGenesis.DenomMetadata = []types.Metadata{ - { - Name: "Cosmos Hub Atom", - Symbol: "ATOM", - Description: "The native staking token of the Cosmos Hub.", - DenomUnits: []*types.DenomUnit{ - { - Denom: "uatom", - Exponent: 0, - Aliases: []string{"microatom"}, - }, - { - Denom: "atom", - Exponent: 6, - Aliases: []string{"ATOM"}, - }, - }, - Base: "uatom", - Display: "atom", - }, - { - Name: "Ethereum", - Symbol: "ETH", - Description: "Ethereum mainnet token", - DenomUnits: []*types.DenomUnit{ - { - Denom: "wei", - Exponent: 0, - }, - { - Denom: "eth", - Exponent: 6, - Aliases: []string{"ETH"}, - }, - }, - Base: "wei", - Display: "eth", - }, - } - - bankGenesisBz, err := s.cfg.Codec.MarshalJSON(&bankGenesis) - s.Require().NoError(err) - genesisState[types.ModuleName] = bankGenesisBz - s.cfg.GenesisState = genesisState - - s.network, err = network.New(s.T(), s.T().TempDir(), s.cfg) - s.Require().NoError(err) - s.Require().NoError(s.network.WaitForNextBlock()) - s.ac = addresscodec.NewBech32Codec("cosmos") -} - -func (s *E2ETestSuite) TearDownSuite() { - s.T().Log("tearing down e2e test suite") - s.network.Cleanup() -} - -func (s *E2ETestSuite) TestNewSendTxCmdGenOnly() { - val := s.network.GetValidators()[0] - - from := val.GetAddress() - to := val.GetAddress() - amount := sdk.NewCoins( - sdk.NewCoin(fmt.Sprintf("%stoken", val.GetMoniker()), math.NewInt(10)), - sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10)), - ) - fromStr, err := s.ac.BytesToString(from) - s.Require().NoError(err) - toStr, err := s.ac.BytesToString(to) - s.Require().NoError(err) - msgSend := &types.MsgSend{ - FromAddress: fromStr, - ToAddress: toStr, - Amount: amount, - } - - bz, err := clitestutil.SubmitTestTx( - val.GetClientCtx(), - msgSend, - from, - clitestutil.TestTxConfig{ - GenOnly: true, - }, - ) - s.Require().NoError(err) - - tx, err := s.cfg.TxConfig.TxJSONDecoder()(bz.Bytes()) - s.Require().NoError(err) - s.Require().Equal([]sdk.Msg{types.NewMsgSend(fromStr, toStr, amount)}, tx.GetMsgs()) -} - -func (s *E2ETestSuite) TestNewSendTxCmdDryRun() { - val := s.network.GetValidators()[0] - - from := val.GetAddress() - to := val.GetAddress() - amount := sdk.NewCoins( - sdk.NewCoin(fmt.Sprintf("%stoken", val.GetMoniker()), math.NewInt(10)), - sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10)), - ) - - msgSend := &types.MsgSend{ - FromAddress: from.String(), - ToAddress: to.String(), - Amount: amount, - } - - out, err := clitestutil.SubmitTestTx( - val.GetClientCtx(), - msgSend, - from, - clitestutil.TestTxConfig{ - Simulate: true, - }, - ) - s.Require().NoError(err) - s.Require().Regexp("\"gas_info\"", out.String()) - s.Require().Regexp("\"gas_used\":\"[0-9]+\"", out.String()) -} - -func (s *E2ETestSuite) TestNewSendTxCmd() { - val := s.network.GetValidators()[0] - - testCases := []struct { - name string - from, to sdk.AccAddress - amount sdk.Coins - config clitestutil.TestTxConfig - expectErr bool - expectedCode uint32 - respType proto.Message - }{ - { - "valid transaction", - val.GetAddress(), - val.GetAddress(), - sdk.NewCoins( - sdk.NewCoin(fmt.Sprintf("%stoken", val.GetMoniker()), math.NewInt(10)), - sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10)), - ), - clitestutil.TestTxConfig{ - Fee: sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))), - }, - false, 0, &sdk.TxResponse{}, - }, - { - "not enough fees", - val.GetAddress(), - val.GetAddress(), - sdk.NewCoins( - sdk.NewCoin(fmt.Sprintf("%stoken", val.GetMoniker()), math.NewInt(10)), - sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10)), - ), - clitestutil.TestTxConfig{ - Fee: sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(1))), - }, - - false, - sdkerrors.ErrInsufficientFee.ABCICode(), - &sdk.TxResponse{}, - }, - { - "not enough gas", - val.GetAddress(), - val.GetAddress(), - sdk.NewCoins( - sdk.NewCoin(fmt.Sprintf("%stoken", val.GetMoniker()), math.NewInt(10)), - sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10)), - ), - clitestutil.TestTxConfig{ - Gas: 10, - Fee: sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))), - }, - false, - sdkerrors.ErrOutOfGas.ABCICode(), - &sdk.TxResponse{}, - }, - } - - for _, tc := range testCases { - tc := tc - - s.Require().NoError(s.network.WaitForNextBlock()) - s.Run(tc.name, func() { - clientCtx := val.GetClientCtx() - - msgSend := types.MsgSend{ - FromAddress: tc.from.String(), - ToAddress: tc.to.String(), - Amount: tc.amount, - } - bz, err := clitestutil.SubmitTestTx(val.GetClientCtx(), &msgSend, tc.from, tc.config) - if tc.expectErr { - s.Require().Error(err) - } else { - s.Require().NoError(err) - - s.Require().NoError(clientCtx.Codec.UnmarshalJSON(bz.Bytes(), tc.respType), bz.String()) - txResp := tc.respType.(*sdk.TxResponse) - s.Require().Equal(tc.expectedCode, txResp.Code) - } - }) - } -} - -func (s *E2ETestSuite) TestNewMultiSendTxCmd() { - val := s.network.GetValidators()[0] - testAddr := sdk.AccAddress("cosmos139f7kncmglres2nf3h4hc4tade85ekfr8sulz5") - - testCases := []struct { - name string - from sdk.AccAddress - to []sdk.AccAddress - amount sdk.Coins - args []string - expectErr bool - expectedCode uint32 - respType proto.Message - }{ - { - "valid transaction", - val.GetAddress(), - []sdk.AccAddress{val.GetAddress(), testAddr}, - sdk.NewCoins( - sdk.NewCoin(fmt.Sprintf("%stoken", val.GetMoniker()), math.NewInt(10)), - sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10)), - ), - []string{ - fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), - fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()), - }, - false, 0, &sdk.TxResponse{}, - }, - { - "valid split transaction", - val.GetAddress(), - []sdk.AccAddress{val.GetAddress(), testAddr}, - sdk.NewCoins( - sdk.NewCoin(fmt.Sprintf("%stoken", val.GetMoniker()), math.NewInt(10)), - sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10)), - ), - []string{ - fmt.Sprintf("--%s=true", cli.FlagSplit), - fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), - fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()), - }, - false, 0, &sdk.TxResponse{}, - }, - { - "not enough arguments", - val.GetAddress(), - []sdk.AccAddress{val.GetAddress()}, - sdk.NewCoins( - sdk.NewCoin(fmt.Sprintf("%stoken", val.GetMoniker()), math.NewInt(10)), - sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10)), - ), - []string{ - fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), - fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()), - }, - true, 0, &sdk.TxResponse{}, - }, - { - "chain-id shouldn't be used with offline and generate-only flags", - val.GetAddress(), - []sdk.AccAddress{val.GetAddress(), testAddr}, - sdk.NewCoins( - sdk.NewCoin(fmt.Sprintf("%stoken", val.GetMoniker()), math.NewInt(10)), - sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10)), - ), - []string{ - fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), - fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()), - fmt.Sprintf("--%s=true", flags.FlagOffline), - fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), - }, - true, 0, &sdk.TxResponse{}, - }, - { - "not enough fees", - val.GetAddress(), - []sdk.AccAddress{val.GetAddress(), testAddr}, - sdk.NewCoins( - sdk.NewCoin(fmt.Sprintf("%stoken", val.GetMoniker()), math.NewInt(10)), - sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10)), - ), - []string{ - fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), - fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(1))).String()), - }, - false, - sdkerrors.ErrInsufficientFee.ABCICode(), - &sdk.TxResponse{}, - }, - { - "not enough gas", - val.GetAddress(), - []sdk.AccAddress{val.GetAddress(), testAddr}, - sdk.NewCoins( - sdk.NewCoin(fmt.Sprintf("%stoken", val.GetMoniker()), math.NewInt(10)), - sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10)), - ), - []string{ - fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), - fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, math.NewInt(10))).String()), - "--gas=10", - }, - false, - sdkerrors.ErrOutOfGas.ABCICode(), - &sdk.TxResponse{}, - }, - } - - for _, tc := range testCases { - tc := tc - - s.Require().NoError(s.network.WaitForNextBlock()) - s.Run(tc.name, func() { - clientCtx := val.GetClientCtx() - - bz, err := MsgMultiSendExec(clientCtx, tc.from, tc.to, tc.amount, tc.args...) - if tc.expectErr { - s.Require().Error(err) - } else { - s.Require().NoError(err) - - s.Require().NoError(clientCtx.Codec.UnmarshalJSON(bz.Bytes(), tc.respType), bz.String()) - txResp := tc.respType.(*sdk.TxResponse) - s.Require().Equal(tc.expectedCode, txResp.Code) - } - }) - } -} - -func NewCoin(denom string, amount math.Int) *sdk.Coin { - coin := sdk.NewCoin(denom, amount) - return &coin -} - -func MsgMultiSendExec(clientCtx client.Context, from sdk.AccAddress, to []sdk.AccAddress, amount fmt.Stringer, extraArgs ...string) (testutil.BufferWriter, error) { - args := []string{from.String()} - for _, addr := range to { - args = append(args, addr.String()) - } - - args = append(args, amount.String()) - args = append(args, extraArgs...) - - return clitestutil.ExecTestCLICmd(clientCtx, cli.NewMultiSendTxCmd(), args) -} diff --git a/tests/systemtests/bank_test.go b/tests/systemtests/bank_test.go new file mode 100644 index 000000000000..fbba062cd01e --- /dev/null +++ b/tests/systemtests/bank_test.go @@ -0,0 +1,216 @@ +//go:build system_test + +package systemtests + +import ( + "fmt" + "testing" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tidwall/gjson" +) + +func TestBankSendTxCmd(t *testing.T) { + // scenario: test bank send command + // given a running chain + + sut.ResetChain(t) + cli := NewCLIWrapper(t, sut, verbose) + // add genesis account with some tokens + account1Addr := cli.AddKey("account1") + account2Addr := cli.AddKey("account2") + require.NotEqual(t, account1Addr, account2Addr) + denom := "stake" + initialAmount := 10000000 + initialBalance := fmt.Sprintf("%d%s", initialAmount, denom) + sut.ModifyGenesisCLI(t, + []string{"genesis", "add-genesis-account", account1Addr, initialBalance}, + []string{"genesis", "add-genesis-account", account2Addr, initialBalance}, + ) + sut.StartChain(t) + + // query accounts balances + balance := cli.QueryBalance(account1Addr, "stake") + assert.Equal(t, int64(initialAmount), balance) + balance = cli.QueryBalance(account2Addr, "stake") + assert.Equal(t, int64(initialAmount), balance) + + bankSendCmdArgs := []string{"tx", "bank", "send", account1Addr, account2Addr, "1000stake", "--from=" + account1Addr} + + testCases := []struct { + name string + extraArgs []string + expectErr bool + expectedCode uint32 + }{ + { + "valid transaction", + []string{"--fees=1stake"}, + false, + 0, + }, + { + "not enough fees", + []string{"--fees=2stake"}, + true, + sdkerrors.ErrInsufficientFee.ABCICode(), + }, + { + "not enough gas", + []string{"--fees=1stake", "--gas=10"}, + true, + sdkerrors.ErrOutOfGas.ABCICode(), + }, + } + + for _, tc := range testCases { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + cmdArgs := append(bankSendCmdArgs, tc.extraArgs...) + + if tc.expectErr { + assertErr := func(xt assert.TestingT, gotErr error, gotOutputs ...interface{}) bool { + assert.Len(t, gotOutputs, 1) + code := gjson.Get(gotOutputs[0].(string), "code") + assert.True(t, code.Exists()) + assert.Equal(t, int64(tc.expectedCode), code.Int()) + return false // always abort + } + rsp := cli.WithRunErrorMatcher(assertErr).Run(cmdArgs...) + RequireTxFailure(t, rsp) + } else { + rsp := cli.Run(cmdArgs...) + txResult, found := cli.AwaitTxCommitted(rsp) + assert.True(t, found) + RequireTxSuccess(t, txResult) + } + }) + } + + // test tx bank send generate only + assertGenOnlyOutput := func(t assert.TestingT, gotErr error, gotOutputs ...interface{}) bool { + assert.Len(t, gotOutputs, 1) + rsp := gotOutputs[0].(string) + // get msg from output + msgs := gjson.Get(rsp, "body.messages").Array() + assert.Len(t, msgs, 1) + // check from address is equal to account1 address + fromAddr := gjson.Get(msgs[0].String(), "from_address").String() + assert.Equal(t, account1Addr, fromAddr) + // check to address is equal to account2 address + toAddr := gjson.Get(msgs[0].String(), "to_address").String() + assert.Equal(t, account2Addr, toAddr) + return false + } + genCmdArgs := append(bankSendCmdArgs, "--generate-only") + _ = cli.WithRunErrorMatcher(assertGenOnlyOutput).Run(genCmdArgs...) + + // test tx bank send with dry-run flag + assertDryRunOutput := func(t assert.TestingT, gotErr error, gotOutputs ...interface{}) bool { + assert.Len(t, gotOutputs, 1) + rsp := gotOutputs[0].(string) + // check gas estimate value found in output + assert.Contains(t, rsp, "gas estimate") + return false + } + dryRunCmdArgs := append(bankSendCmdArgs, "--dry-run") + _ = cli.WithRunErrorMatcher(assertDryRunOutput).Run(dryRunCmdArgs...) +} + +func TestBankMultiSendTxCmd(t *testing.T) { + // scenario: test bank multi-send command + // given a running chain + + sut.ResetChain(t) + cli := NewCLIWrapper(t, sut, verbose) + // add genesis account with some tokens + account1Addr := cli.AddKey("account1") + account2Addr := cli.AddKey("account2") + account3Addr := cli.AddKey("account3") + require.NotEqual(t, account1Addr, account2Addr, account3Addr) + denom := "stake" + initialAmount := 10000000 + initialBalance := fmt.Sprintf("%d%s", initialAmount, denom) + sut.ModifyGenesisCLI(t, + []string{"genesis", "add-genesis-account", account1Addr, initialBalance}, + []string{"genesis", "add-genesis-account", account2Addr, initialBalance}, + []string{"genesis", "add-genesis-account", account3Addr, initialBalance}, + ) + sut.StartChain(t) + + multiSendCmdArgs := []string{"tx", "bank", "multi-send", account1Addr, account2Addr, account3Addr, "1000stake", "--from=" + account1Addr} + + testCases := []struct { + name string + cmdArgs []string + expectErr bool + expectedCode uint32 + expErrMsg string + }{ + { + "valid transaction", + append(multiSendCmdArgs, "--fees=1stake"), + false, + 0, + "", + }, + { + "not enough arguments", + []string{"tx", "bank", "multi-send", account1Addr, account2Addr, "1000stake", "--from=" + account1Addr}, + true, + 0, + "only received 3", + }, + { + "not enough fees", + append(multiSendCmdArgs, "--fees=0stake"), + true, + sdkerrors.ErrInsufficientFee.ABCICode(), + "insufficient fee", + }, + { + "not enough gas", + append(multiSendCmdArgs, "--fees=1stake", "--gas=10"), + true, + sdkerrors.ErrOutOfGas.ABCICode(), + "out of gas", + }, + { + "chain-id shouldn't be used with offline and generate-only flags", + append(multiSendCmdArgs, "--generate-only", "--offline", "-a=0", "-s=4"), + true, + 0, + "chain ID cannot be used", + }, + } + + for _, tc := range testCases { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + + if tc.expectErr { + assertErr := func(xt assert.TestingT, gotErr error, gotOutputs ...interface{}) bool { + assert.Len(t, gotOutputs, 1) + output := gotOutputs[0].(string) + assert.Contains(t, output, tc.expErrMsg) + if tc.expectedCode != 0 { + code := gjson.Get(output, "code") + assert.True(t, code.Exists()) + assert.Equal(t, int64(tc.expectedCode), code.Int()) + } + return false // always abort + } + _ = cli.WithRunErrorMatcher(assertErr).Run(tc.cmdArgs...) + } else { + rsp := cli.Run(tc.cmdArgs...) + txResult, found := cli.AwaitTxCommitted(rsp) + assert.True(t, found) + RequireTxSuccess(t, txResult) + } + }) + } +} From f2b5903ccc0dc0a27628a66ab63ccdb2aedc8d28 Mon Sep 17 00:00:00 2001 From: akhilkumarpilli Date: Mon, 9 Sep 2024 17:00:44 +0530 Subject: [PATCH 2/8] fix test --- tests/systemtests/bank_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/systemtests/bank_test.go b/tests/systemtests/bank_test.go index fbba062cd01e..15b94ba48021 100644 --- a/tests/systemtests/bank_test.go +++ b/tests/systemtests/bank_test.go @@ -53,7 +53,7 @@ func TestBankSendTxCmd(t *testing.T) { }, { "not enough fees", - []string{"--fees=2stake"}, + []string{"--fees=0stake"}, true, sdkerrors.ErrInsufficientFee.ABCICode(), }, From 7c9611cca5de89f72c7f7a0075009512bf981d33 Mon Sep 17 00:00:00 2001 From: akhilkumarpilli Date: Tue, 10 Sep 2024 16:52:06 +0530 Subject: [PATCH 3/8] WIP: add few more testcases and start tests on grpc queries --- tests/systemtests/bank_test.go | 50 +++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/tests/systemtests/bank_test.go b/tests/systemtests/bank_test.go index 15b94ba48021..42668b23a018 100644 --- a/tests/systemtests/bank_test.go +++ b/tests/systemtests/bank_test.go @@ -1,5 +1,3 @@ -//go:build system_test - package systemtests import ( @@ -32,12 +30,12 @@ func TestBankSendTxCmd(t *testing.T) { sut.StartChain(t) // query accounts balances - balance := cli.QueryBalance(account1Addr, "stake") - assert.Equal(t, int64(initialAmount), balance) - balance = cli.QueryBalance(account2Addr, "stake") - assert.Equal(t, int64(initialAmount), balance) + balance1 := cli.QueryBalance(account1Addr, "stake") + assert.Equal(t, int64(initialAmount), balance1) + balance2 := cli.QueryBalance(account2Addr, "stake") + assert.Equal(t, int64(initialAmount), balance2) - bankSendCmdArgs := []string{"tx", "bank", "send", account1Addr, account2Addr, "1000stake", "--from=" + account1Addr} + bankSendCmdArgs := []string{"tx", "bank", "send", account1Addr, account2Addr, "1000stake"} testCases := []struct { name string @@ -90,6 +88,26 @@ func TestBankSendTxCmd(t *testing.T) { }) } + // test tx bank send with insufficient funds + insufficientCmdArgs := bankSendCmdArgs[0 : len(bankSendCmdArgs)-1] + insufficientCmdArgs = append(insufficientCmdArgs, initialBalance, "--fees=10stake") + rsp := cli.Run(insufficientCmdArgs...) + RequireTxFailure(t, rsp) + assert.Contains(t, rsp, sdkerrors.ErrInsufficientFunds.Error()) + + // test tx bank send with unauthorized signature + assertUnauthorizedErr := func(t assert.TestingT, gotErr error, gotOutputs ...interface{}) bool { + assert.Len(t, gotOutputs, 1) + code := gjson.Get(gotOutputs[0].(string), "code") + assert.True(t, code.Exists()) + assert.Equal(t, int64(sdkerrors.ErrUnauthorized.ABCICode()), code.Int()) + return false + } + invalidCli := cli + invalidCli.chainID = cli.chainID + "a" // set invalid chain-id + rsp = invalidCli.WithRunErrorMatcher(assertUnauthorizedErr).Run(bankSendCmdArgs...) + RequireTxFailure(t, rsp) + // test tx bank send generate only assertGenOnlyOutput := func(t assert.TestingT, gotErr error, gotOutputs ...interface{}) bool { assert.Len(t, gotOutputs, 1) @@ -214,3 +232,21 @@ func TestBankMultiSendTxCmd(t *testing.T) { }) } } + +func TestBankGRPCQueries(t *testing.T) { + // scenario: test bank grpc gateway queries + // given a running chain + + sut.ResetChain(t) + cli := NewCLIWrapper(t, sut, verbose) + // add genesis account with some tokens + account1Addr := cli.AddKey("account1") + account2Addr := cli.AddKey("account2") + require.NotEqual(t, account1Addr, account2Addr) + sut.ModifyGenesisCLI(t, + []string{"genesis", "add-genesis-account", account1Addr, "10000000stake"}, + ) + + sut.StartChain(t) + +} From 9edd09b4b79855269f56f915d2cf191a4d5c1589 Mon Sep 17 00:00:00 2001 From: akhilkumarpilli Date: Wed, 11 Sep 2024 12:38:13 +0530 Subject: [PATCH 4/8] add bank grpc query tests --- tests/e2e/bank/cli_test.go | 20 -- tests/e2e/bank/grpc.go | 365 --------------------------------- tests/systemtests/bank_test.go | 156 +++++++++++++- 3 files changed, 149 insertions(+), 392 deletions(-) delete mode 100644 tests/e2e/bank/cli_test.go delete mode 100644 tests/e2e/bank/grpc.go diff --git a/tests/e2e/bank/cli_test.go b/tests/e2e/bank/cli_test.go deleted file mode 100644 index 4560aea6bf62..000000000000 --- a/tests/e2e/bank/cli_test.go +++ /dev/null @@ -1,20 +0,0 @@ -//go:build e2e -// +build e2e - -package client - -import ( - "testing" - - "github.com/stretchr/testify/suite" - - "cosmossdk.io/simapp" - - "github.com/cosmos/cosmos-sdk/testutil/network" -) - -func TestE2ETestSuite(t *testing.T) { - cfg := network.DefaultConfig(simapp.NewTestNetworkFixture) - cfg.NumValidators = 1 - suite.Run(t, NewE2ETestSuite(cfg)) -} diff --git a/tests/e2e/bank/grpc.go b/tests/e2e/bank/grpc.go deleted file mode 100644 index 2c8198c5c4dc..000000000000 --- a/tests/e2e/bank/grpc.go +++ /dev/null @@ -1,365 +0,0 @@ -package client - -import ( - "fmt" - - "github.com/cosmos/gogoproto/proto" - "github.com/stretchr/testify/suite" - - "cosmossdk.io/core/address" - "cosmossdk.io/math" - "cosmossdk.io/x/bank/types" - - addresscodec "github.com/cosmos/cosmos-sdk/codec/address" - "github.com/cosmos/cosmos-sdk/testutil" - "github.com/cosmos/cosmos-sdk/testutil/network" - sdk "github.com/cosmos/cosmos-sdk/types" - grpctypes "github.com/cosmos/cosmos-sdk/types/grpc" - "github.com/cosmos/cosmos-sdk/types/query" -) - -type E2ETestSuite struct { - suite.Suite - - cfg network.Config - ac address.Codec - network network.NetworkI -} - -func NewE2ETestSuite(cfg network.Config) *E2ETestSuite { - return &E2ETestSuite{cfg: cfg} -} - -func (s *E2ETestSuite) SetupSuite() { - s.T().Log("setting up e2e test suite") - - genesisState := s.cfg.GenesisState - var bankGenesis types.GenesisState - s.Require().NoError(s.cfg.Codec.UnmarshalJSON(genesisState[types.ModuleName], &bankGenesis)) - - bankGenesis.DenomMetadata = []types.Metadata{ - { - Name: "Cosmos Hub Atom", - Symbol: "ATOM", - Description: "The native staking token of the Cosmos Hub.", - DenomUnits: []*types.DenomUnit{ - { - Denom: "uatom", - Exponent: 0, - Aliases: []string{"microatom"}, - }, - { - Denom: "atom", - Exponent: 6, - Aliases: []string{"ATOM"}, - }, - }, - Base: "uatom", - Display: "atom", - }, - { - Name: "Ethereum", - Symbol: "ETH", - Description: "Ethereum mainnet token", - DenomUnits: []*types.DenomUnit{ - { - Denom: "wei", - Exponent: 0, - }, - { - Denom: "eth", - Exponent: 6, - Aliases: []string{"ETH"}, - }, - }, - Base: "wei", - Display: "eth", - }, - } - - bankGenesisBz, err := s.cfg.Codec.MarshalJSON(&bankGenesis) - s.Require().NoError(err) - genesisState[types.ModuleName] = bankGenesisBz - s.cfg.GenesisState = genesisState - - s.network, err = network.New(s.T(), s.T().TempDir(), s.cfg) - s.Require().NoError(err) - s.Require().NoError(s.network.WaitForNextBlock()) - s.ac = addresscodec.NewBech32Codec("cosmos") -} - -func (s *E2ETestSuite) TearDownSuite() { - s.T().Log("tearing down e2e test suite") - s.network.Cleanup() -} - -func (s *E2ETestSuite) TestTotalSupplyGRPCHandler() { - val := s.network.GetValidators()[0] - baseURL := val.GetAPIAddress() - - testCases := []struct { - name string - url string - headers map[string]string - respType proto.Message - expected proto.Message - }{ - { - "test GRPC total supply", - fmt.Sprintf("%s/cosmos/bank/v1beta1/supply", baseURL), - map[string]string{ - grpctypes.GRPCBlockHeightHeader: "1", - }, - &types.QueryTotalSupplyResponse{}, - &types.QueryTotalSupplyResponse{ - Supply: sdk.NewCoins( - sdk.NewCoin(fmt.Sprintf("%stoken", val.GetMoniker()), s.cfg.AccountTokens), - sdk.NewCoin(s.cfg.BondDenom, s.cfg.StakingTokens.Add(math.NewInt(47))), - ), - Pagination: &query.PageResponse{ - Total: 2, - }, - }, - }, - { - "GRPC total supply of a specific denom", - fmt.Sprintf("%s/cosmos/bank/v1beta1/supply/by_denom?denom=%s", baseURL, s.cfg.BondDenom), - map[string]string{ - grpctypes.GRPCBlockHeightHeader: "1", - }, - &types.QuerySupplyOfResponse{}, - &types.QuerySupplyOfResponse{ - Amount: sdk.NewCoin(s.cfg.BondDenom, s.cfg.StakingTokens.Add(math.NewInt(47))), - }, - }, - { - "Query for `height` > 1", - fmt.Sprintf("%s/cosmos/bank/v1beta1/supply/by_denom?denom=%s", baseURL, s.cfg.BondDenom), - map[string]string{ - grpctypes.GRPCBlockHeightHeader: "2", - }, - &types.QuerySupplyOfResponse{}, - &types.QuerySupplyOfResponse{ - Amount: sdk.NewCoin(s.cfg.BondDenom, s.cfg.StakingTokens.Add(math.NewInt(47))), - }, - }, - { - "Query params shouldn't be considered as height", - fmt.Sprintf("%s/cosmos/bank/v1beta1/supply/by_denom?denom=%s&height=2", baseURL, s.cfg.BondDenom), - map[string]string{ - grpctypes.GRPCBlockHeightHeader: "1", - }, - &types.QuerySupplyOfResponse{}, - &types.QuerySupplyOfResponse{ - Amount: sdk.NewCoin(s.cfg.BondDenom, s.cfg.StakingTokens.Add(math.NewInt(47))), - }, - }, - { - "GRPC total supply of a bogus denom", - fmt.Sprintf("%s/cosmos/bank/v1beta1/supply/by_denom?denom=foobar", baseURL), - map[string]string{ - grpctypes.GRPCBlockHeightHeader: "1", - }, - &types.QuerySupplyOfResponse{}, - &types.QuerySupplyOfResponse{ - Amount: sdk.NewCoin("foobar", math.ZeroInt()), - }, - }, - } - - for _, tc := range testCases { - tc := tc - s.Run(tc.name, func() { - resp, err := testutil.GetRequestWithHeaders(tc.url, tc.headers) - s.Require().NoError(err) - - s.Require().NoError(val.GetClientCtx().Codec.UnmarshalJSON(resp, tc.respType)) - s.Require().Equal(tc.expected.String(), tc.respType.String()) - }) - } -} - -func (s *E2ETestSuite) TestDenomMetadataGRPCHandler() { - val := s.network.GetValidators()[0] - baseURL := val.GetAPIAddress() - - testCases := []struct { - name string - url string - headers map[string]string - expErr bool - respType proto.Message - expected proto.Message - }{ - { - "test GRPC client metadata", - fmt.Sprintf("%s/cosmos/bank/v1beta1/denoms_metadata", baseURL), - map[string]string{ - grpctypes.GRPCBlockHeightHeader: "1", - }, - false, - &types.QueryDenomsMetadataResponse{}, - &types.QueryDenomsMetadataResponse{ - Metadatas: []types.Metadata{ - { - Name: "Cosmos Hub Atom", - Symbol: "ATOM", - Description: "The native staking token of the Cosmos Hub.", - DenomUnits: []*types.DenomUnit{ - { - Denom: "uatom", - Exponent: 0, - Aliases: []string{"microatom"}, - }, - { - Denom: "atom", - Exponent: 6, - Aliases: []string{"ATOM"}, - }, - }, - Base: "uatom", - Display: "atom", - }, - { - Name: "Ethereum", - Symbol: "ETH", - Description: "Ethereum mainnet token", - DenomUnits: []*types.DenomUnit{ - { - Denom: "wei", - Exponent: 0, - }, - { - Denom: "eth", - Exponent: 6, - Aliases: []string{"ETH"}, - }, - }, - Base: "wei", - Display: "eth", - }, - }, - Pagination: &query.PageResponse{Total: 2}, - }, - }, - { - "GRPC client metadata of a specific denom", - fmt.Sprintf("%s/cosmos/bank/v1beta1/denoms_metadata/uatom", baseURL), - map[string]string{ - grpctypes.GRPCBlockHeightHeader: "1", - }, - false, - &types.QueryDenomMetadataResponse{}, - &types.QueryDenomMetadataResponse{ - Metadata: types.Metadata{ - Name: "Cosmos Hub Atom", - Symbol: "ATOM", - Description: "The native staking token of the Cosmos Hub.", - DenomUnits: []*types.DenomUnit{ - { - Denom: "uatom", - Exponent: 0, - Aliases: []string{"microatom"}, - }, - { - Denom: "atom", - Exponent: 6, - Aliases: []string{"ATOM"}, - }, - }, - Base: "uatom", - Display: "atom", - }, - }, - }, - { - "GRPC client metadata of a bogus denom", - fmt.Sprintf("%s/cosmos/bank/v1beta1/denoms_metadata/foobar", baseURL), - map[string]string{ - grpctypes.GRPCBlockHeightHeader: "1", - }, - true, - &types.QueryDenomMetadataResponse{}, - &types.QueryDenomMetadataResponse{ - Metadata: types.Metadata{ - DenomUnits: []*types.DenomUnit{}, - }, - }, - }, - } - - for _, tc := range testCases { - tc := tc - s.Run(tc.name, func() { - resp, err := testutil.GetRequestWithHeaders(tc.url, tc.headers) - s.Require().NoError(err) - - if tc.expErr { - s.Require().Error(val.GetClientCtx().Codec.UnmarshalJSON(resp, tc.respType)) - } else { - s.Require().NoError(val.GetClientCtx().Codec.UnmarshalJSON(resp, tc.respType)) - s.Require().Equal(tc.expected.String(), tc.respType.String()) - } - }) - } -} - -func (s *E2ETestSuite) TestBalancesGRPCHandler() { - val := s.network.GetValidators()[0] - baseURL := val.GetAPIAddress() - - testCases := []struct { - name string - url string - respType proto.Message - expected proto.Message - }{ - { - "gRPC total account balance", - fmt.Sprintf("%s/cosmos/bank/v1beta1/balances/%s", baseURL, val.GetAddress().String()), - &types.QueryAllBalancesResponse{}, - &types.QueryAllBalancesResponse{ - Balances: sdk.NewCoins( - sdk.NewCoin(fmt.Sprintf("%stoken", val.GetMoniker()), s.cfg.AccountTokens), - sdk.NewCoin(s.cfg.BondDenom, s.cfg.StakingTokens.Sub(s.cfg.BondedTokens)), - ), - Pagination: &query.PageResponse{ - Total: 2, - }, - }, - }, - { - "gPRC account balance of a denom", - fmt.Sprintf("%s/cosmos/bank/v1beta1/balances/%s/by_denom?denom=%s", baseURL, val.GetAddress().String(), s.cfg.BondDenom), - &types.QueryBalanceResponse{}, - &types.QueryBalanceResponse{ - Balance: &sdk.Coin{ - Denom: s.cfg.BondDenom, - Amount: s.cfg.StakingTokens.Sub(s.cfg.BondedTokens), - }, - }, - }, - { - "gPRC account balance of a bogus denom", - fmt.Sprintf("%s/cosmos/bank/v1beta1/balances/%s/by_denom?denom=foobar", baseURL, val.GetAddress().String()), - &types.QueryBalanceResponse{}, - &types.QueryBalanceResponse{ - Balance: &sdk.Coin{ - Denom: "foobar", - Amount: math.NewInt(0), - }, - }, - }, - } - - for _, tc := range testCases { - tc := tc - s.Run(tc.name, func() { - resp, err := testutil.GetRequest(tc.url) - s.Require().NoError(err) - - s.Require().NoError(val.GetClientCtx().Codec.UnmarshalJSON(resp, tc.respType)) - s.Require().Equal(tc.expected.String(), tc.respType.String()) - }) - } -} diff --git a/tests/systemtests/bank_test.go b/tests/systemtests/bank_test.go index 42668b23a018..aae2693f8166 100644 --- a/tests/systemtests/bank_test.go +++ b/tests/systemtests/bank_test.go @@ -4,10 +4,13 @@ import ( "fmt" "testing" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/tidwall/gjson" + "github.com/tidwall/sjson" + + "github.com/cosmos/cosmos-sdk/testutil" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) func TestBankSendTxCmd(t *testing.T) { @@ -30,9 +33,9 @@ func TestBankSendTxCmd(t *testing.T) { sut.StartChain(t) // query accounts balances - balance1 := cli.QueryBalance(account1Addr, "stake") + balance1 := cli.QueryBalance(account1Addr, denom) assert.Equal(t, int64(initialAmount), balance1) - balance2 := cli.QueryBalance(account2Addr, "stake") + balance2 := cli.QueryBalance(account2Addr, denom) assert.Equal(t, int64(initialAmount), balance2) bankSendCmdArgs := []string{"tx", "bank", "send", account1Addr, account2Addr, "1000stake"} @@ -209,7 +212,6 @@ func TestBankMultiSendTxCmd(t *testing.T) { tc := tc t.Run(tc.name, func(t *testing.T) { - if tc.expectErr { assertErr := func(xt assert.TestingT, gotErr error, gotOutputs ...interface{}) bool { assert.Len(t, gotOutputs, 1) @@ -239,14 +241,154 @@ func TestBankGRPCQueries(t *testing.T) { sut.ResetChain(t) cli := NewCLIWrapper(t, sut, verbose) + + // update denom metadata in bank genesis + atomDenomMetadata := `{"description":"The native staking token of the Cosmos Hub.","denom_units":[{"denom":"uatom","exponent":0,"aliases":["microatom"]},{"denom":"atom","exponent":6,"aliases":["ATOM"]}],"base":"uatom","display":"atom","name":"Cosmos Hub Atom","symbol":"ATOM","uri":"","uri_hash":""}` + ethDenomMetadata := `{"description":"Ethereum mainnet token","denom_units":[{"denom":"wei","exponent":0,"aliases":[]},{"denom":"eth","exponent":6,"aliases":["ETH"]}],"base":"wei","display":"eth","name":"Ethereum","symbol":"ETH","uri":"","uri_hash":""}` + + bankDenomMetadata := fmt.Sprintf("[%s,%s]", atomDenomMetadata, ethDenomMetadata) + + sut.ModifyGenesisJSON(t, func(genesis []byte) []byte { + state, err := sjson.SetRawBytes(genesis, "app_state.bank.denom_metadata", []byte(bankDenomMetadata)) + assert.NoError(t, err) + return state + }) + // add genesis account with some tokens account1Addr := cli.AddKey("account1") - account2Addr := cli.AddKey("account2") - require.NotEqual(t, account1Addr, account2Addr) + newDenom := "newdenom" + initialAmount := "10000000" sut.ModifyGenesisCLI(t, - []string{"genesis", "add-genesis-account", account1Addr, "10000000stake"}, + []string{"genesis", "add-genesis-account", account1Addr, "10000000stake," + initialAmount + newDenom}, ) + // start chain sut.StartChain(t) + baseurl := fmt.Sprintf("http://localhost:%d", apiPortStart) + + // test supply grpc endpoint + supplyUrl := baseurl + "/cosmos/bank/v1beta1/supply" + + defaultExpSupplyOutput := `{"supply":[{"denom":"newdenom","amount":"10000000"},{"denom":"stake","amount":"2010000191"},{"denom":"testtoken","amount":"4000000000"}],"pagination":{"next_key":null,"total":"3"}}` + specificDenomOutput := fmt.Sprintf(`{"denom":"%s","amount":"%s"}`, newDenom, initialAmount) + bogusDenomOutput := `{"denom":"foobar","amount":"0"}` + + blockHeightHeader := "x-cosmos-block-height" + blockHeight := sut.CurrentHeight() + + supplyTestCases := []struct { + name string + url string + headers map[string]string + expOut string + }{ + { + "test GRPC total supply", + supplyUrl, + map[string]string{ + blockHeightHeader: fmt.Sprintf("%d", blockHeight), + }, + defaultExpSupplyOutput, + }, + { + "test GRPC total supply of a specific denom", + supplyUrl + "/by_denom?denom=" + newDenom, + map[string]string{}, + specificDenomOutput, + }, + { + "error when querying supply with height greater than block height", + supplyUrl, + map[string]string{ + blockHeightHeader: fmt.Sprintf("%d", blockHeight+5), + }, + "invalid height", + }, + { + "test GRPC total supply of a bogus denom", + supplyUrl + "/by_denom?denom=foobar", + map[string]string{}, + bogusDenomOutput, + }, + } + + for _, tc := range supplyTestCases { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + resp, err := testutil.GetRequestWithHeaders(tc.url, tc.headers) + assert.NoError(t, err) + assert.Contains(t, string(resp), tc.expOut) + }) + } + // test denom metadata endpoint + denomMetadataUrl := baseurl + "/cosmos/bank/v1beta1/denoms_metadata" + dmTestCases := []struct { + name string + url string + expOut string + }{ + { + "test GRPC client metadata", + denomMetadataUrl, + bankDenomMetadata, + }, + { + "test GRPC client metadata of a specific denom", + denomMetadataUrl + "/uatom", + atomDenomMetadata, + }, + { + "test GRPC client metadata of a bogus denom", + denomMetadataUrl + "/foobar", + `{"code":5,"message":"client metadata for denom foobar","details":[]}`, + }, + } + + for _, tc := range dmTestCases { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + resp, err := testutil.GetRequest(tc.url) + assert.NoError(t, err) + assert.Contains(t, string(resp), tc.expOut) + }) + } + + // test bank balances endpoint + balanceUrl := baseurl + "/cosmos/bank/v1beta1/balances/" + allBalancesOutput := `{"balances":[` + specificDenomOutput + `,{"denom":"stake","amount":"10000000"}],"pagination":{"next_key":null,"total":"2"}}` + + balanceTestCases := []struct { + name string + url string + expOut string + }{ + { + "test GRPC total account balance", + balanceUrl + account1Addr, + allBalancesOutput, + }, + { + "test GRPC account balance of a specific denom", + fmt.Sprintf("%s%s/by_denom?denom=%s", balanceUrl, account1Addr, newDenom), + specificDenomOutput, + }, + { + "test GRPC account balance of a bogus denom", + fmt.Sprintf("%s%s/by_denom?denom=foobar", balanceUrl, account1Addr), + bogusDenomOutput, + }, + } + + for _, tc := range balanceTestCases { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + resp, err := testutil.GetRequest(tc.url) + assert.NoError(t, err) + assert.Contains(t, string(resp), tc.expOut) + }) + } } From 75af4f9f75a282ad4c27eea5c1d05467acc6d366 Mon Sep 17 00:00:00 2001 From: akhilkumarpilli Date: Wed, 11 Sep 2024 12:58:33 +0530 Subject: [PATCH 5/8] fix test --- tests/systemtests/bank_test.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/systemtests/bank_test.go b/tests/systemtests/bank_test.go index aae2693f8166..6f0582fc407d 100644 --- a/tests/systemtests/bank_test.go +++ b/tests/systemtests/bank_test.go @@ -242,7 +242,7 @@ func TestBankGRPCQueries(t *testing.T) { sut.ResetChain(t) cli := NewCLIWrapper(t, sut, verbose) - // update denom metadata in bank genesis + // update bank denom metadata in genesis atomDenomMetadata := `{"description":"The native staking token of the Cosmos Hub.","denom_units":[{"denom":"uatom","exponent":0,"aliases":["microatom"]},{"denom":"atom","exponent":6,"aliases":["ATOM"]}],"base":"uatom","display":"atom","name":"Cosmos Hub Atom","symbol":"ATOM","uri":"","uri_hash":""}` ethDenomMetadata := `{"description":"Ethereum mainnet token","denom_units":[{"denom":"wei","exponent":0,"aliases":[]},{"denom":"eth","exponent":6,"aliases":["ETH"]}],"base":"wei","display":"eth","name":"Ethereum","symbol":"ETH","uri":"","uri_hash":""}` @@ -269,7 +269,8 @@ func TestBankGRPCQueries(t *testing.T) { // test supply grpc endpoint supplyUrl := baseurl + "/cosmos/bank/v1beta1/supply" - defaultExpSupplyOutput := `{"supply":[{"denom":"newdenom","amount":"10000000"},{"denom":"stake","amount":"2010000191"},{"denom":"testtoken","amount":"4000000000"}],"pagination":{"next_key":null,"total":"3"}}` + // as supply might change for each block, can't set complete expected output + expTotalSupplyOutput := `{"supply":[{"denom":"newdenom","amount":"10000000"},{"denom":"stake","amount"` specificDenomOutput := fmt.Sprintf(`{"denom":"%s","amount":"%s"}`, newDenom, initialAmount) bogusDenomOutput := `{"denom":"foobar","amount":"0"}` @@ -288,7 +289,7 @@ func TestBankGRPCQueries(t *testing.T) { map[string]string{ blockHeightHeader: fmt.Sprintf("%d", blockHeight), }, - defaultExpSupplyOutput, + expTotalSupplyOutput, }, { "test GRPC total supply of a specific denom", From 2f8c32f56d73d8dcb8640d48a52ebaa7b3598ea3 Mon Sep 17 00:00:00 2001 From: akhilkumarpilli Date: Wed, 11 Sep 2024 15:50:06 +0530 Subject: [PATCH 6/8] address comments --- tests/systemtests/bank_test.go | 187 ++++++++++++--------------------- 1 file changed, 69 insertions(+), 118 deletions(-) diff --git a/tests/systemtests/bank_test.go b/tests/systemtests/bank_test.go index 6f0582fc407d..f7722562bf5d 100644 --- a/tests/systemtests/bank_test.go +++ b/tests/systemtests/bank_test.go @@ -19,91 +19,46 @@ func TestBankSendTxCmd(t *testing.T) { sut.ResetChain(t) cli := NewCLIWrapper(t, sut, verbose) - // add genesis account with some tokens - account1Addr := cli.AddKey("account1") - account2Addr := cli.AddKey("account2") - require.NotEqual(t, account1Addr, account2Addr) - denom := "stake" - initialAmount := 10000000 - initialBalance := fmt.Sprintf("%d%s", initialAmount, denom) - sut.ModifyGenesisCLI(t, - []string{"genesis", "add-genesis-account", account1Addr, initialBalance}, - []string{"genesis", "add-genesis-account", account2Addr, initialBalance}, - ) - sut.StartChain(t) - // query accounts balances - balance1 := cli.QueryBalance(account1Addr, denom) - assert.Equal(t, int64(initialAmount), balance1) - balance2 := cli.QueryBalance(account2Addr, denom) - assert.Equal(t, int64(initialAmount), balance2) - - bankSendCmdArgs := []string{"tx", "bank", "send", account1Addr, account2Addr, "1000stake"} + // get validator address + valAddr := gjson.Get(cli.Keys("keys", "list"), "1.address").String() + require.NotEmpty(t, valAddr) - testCases := []struct { - name string - extraArgs []string - expectErr bool - expectedCode uint32 - }{ - { - "valid transaction", - []string{"--fees=1stake"}, - false, - 0, - }, - { - "not enough fees", - []string{"--fees=0stake"}, - true, - sdkerrors.ErrInsufficientFee.ABCICode(), - }, - { - "not enough gas", - []string{"--fees=1stake", "--gas=10"}, - true, - sdkerrors.ErrOutOfGas.ABCICode(), - }, - } + // add new key + receiverAddr := cli.AddKey("account1") + denom := "stake" + sut.StartChain(t) - for _, tc := range testCases { - tc := tc + // query validator balance and make sure it has enough balance + var transferAmount int64 = 1000 + valBalance := cli.QueryBalance(valAddr, denom) + require.Greater(t, valBalance, transferAmount, "not enough balance found with validator") - t.Run(tc.name, func(t *testing.T) { - cmdArgs := append(bankSendCmdArgs, tc.extraArgs...) + bankSendCmdArgs := []string{"tx", "bank", "send", valAddr, receiverAddr, fmt.Sprintf("%d%s", transferAmount, denom)} - if tc.expectErr { - assertErr := func(xt assert.TestingT, gotErr error, gotOutputs ...interface{}) bool { - assert.Len(t, gotOutputs, 1) - code := gjson.Get(gotOutputs[0].(string), "code") - assert.True(t, code.Exists()) - assert.Equal(t, int64(tc.expectedCode), code.Int()) - return false // always abort - } - rsp := cli.WithRunErrorMatcher(assertErr).Run(cmdArgs...) - RequireTxFailure(t, rsp) - } else { - rsp := cli.Run(cmdArgs...) - txResult, found := cli.AwaitTxCommitted(rsp) - assert.True(t, found) - RequireTxSuccess(t, txResult) - } - }) - } + // test valid transaction + rsp := cli.Run(append(bankSendCmdArgs, "--fees=1stake")...) + txResult, found := cli.AwaitTxCommitted(rsp) + require.True(t, found) + RequireTxSuccess(t, txResult) + // check valaddr balance equals to valBalance-(transferedAmount+feeAmount) + require.Equal(t, valBalance-(transferAmount+1), cli.QueryBalance(valAddr, denom)) + // check receiver balance equals to transferAmount + require.Equal(t, transferAmount, cli.QueryBalance(receiverAddr, denom)) // test tx bank send with insufficient funds insufficientCmdArgs := bankSendCmdArgs[0 : len(bankSendCmdArgs)-1] - insufficientCmdArgs = append(insufficientCmdArgs, initialBalance, "--fees=10stake") - rsp := cli.Run(insufficientCmdArgs...) + insufficientCmdArgs = append(insufficientCmdArgs, fmt.Sprintf("%d%s", valBalance, denom), "--fees=10stake") + rsp = cli.Run(insufficientCmdArgs...) RequireTxFailure(t, rsp) - assert.Contains(t, rsp, sdkerrors.ErrInsufficientFunds.Error()) + require.Contains(t, rsp, sdkerrors.ErrInsufficientFunds.Error()) // test tx bank send with unauthorized signature - assertUnauthorizedErr := func(t assert.TestingT, gotErr error, gotOutputs ...interface{}) bool { - assert.Len(t, gotOutputs, 1) + assertUnauthorizedErr := func(_ assert.TestingT, gotErr error, gotOutputs ...interface{}) bool { + require.Len(t, gotOutputs, 1) code := gjson.Get(gotOutputs[0].(string), "code") - assert.True(t, code.Exists()) - assert.Equal(t, int64(sdkerrors.ErrUnauthorized.ABCICode()), code.Int()) + require.True(t, code.Exists()) + require.Equal(t, int64(sdkerrors.ErrUnauthorized.ABCICode()), code.Int()) return false } invalidCli := cli @@ -112,29 +67,29 @@ func TestBankSendTxCmd(t *testing.T) { RequireTxFailure(t, rsp) // test tx bank send generate only - assertGenOnlyOutput := func(t assert.TestingT, gotErr error, gotOutputs ...interface{}) bool { - assert.Len(t, gotOutputs, 1) + assertGenOnlyOutput := func(_ assert.TestingT, gotErr error, gotOutputs ...interface{}) bool { + require.Len(t, gotOutputs, 1) rsp := gotOutputs[0].(string) // get msg from output msgs := gjson.Get(rsp, "body.messages").Array() - assert.Len(t, msgs, 1) + require.Len(t, msgs, 1) // check from address is equal to account1 address fromAddr := gjson.Get(msgs[0].String(), "from_address").String() - assert.Equal(t, account1Addr, fromAddr) + require.Equal(t, valAddr, fromAddr) // check to address is equal to account2 address toAddr := gjson.Get(msgs[0].String(), "to_address").String() - assert.Equal(t, account2Addr, toAddr) + require.Equal(t, receiverAddr, toAddr) return false } genCmdArgs := append(bankSendCmdArgs, "--generate-only") _ = cli.WithRunErrorMatcher(assertGenOnlyOutput).Run(genCmdArgs...) // test tx bank send with dry-run flag - assertDryRunOutput := func(t assert.TestingT, gotErr error, gotOutputs ...interface{}) bool { - assert.Len(t, gotOutputs, 1) + assertDryRunOutput := func(_ assert.TestingT, gotErr error, gotOutputs ...interface{}) bool { + require.Len(t, gotOutputs, 1) rsp := gotOutputs[0].(string) // check gas estimate value found in output - assert.Contains(t, rsp, "gas estimate") + require.Contains(t, rsp, "gas estimate") return false } dryRunCmdArgs := append(bankSendCmdArgs, "--dry-run") @@ -158,10 +113,16 @@ func TestBankMultiSendTxCmd(t *testing.T) { sut.ModifyGenesisCLI(t, []string{"genesis", "add-genesis-account", account1Addr, initialBalance}, []string{"genesis", "add-genesis-account", account2Addr, initialBalance}, - []string{"genesis", "add-genesis-account", account3Addr, initialBalance}, ) sut.StartChain(t) + // query accounts balances + account1Bal := cli.QueryBalance(account1Addr, denom) + require.Equal(t, int64(initialAmount), account1Bal) + account2Bal := cli.QueryBalance(account2Addr, denom) + require.Equal(t, int64(initialAmount), account2Bal) + var account3Bal int64 = 0 + multiSendCmdArgs := []string{"tx", "bank", "multi-send", account1Addr, account2Addr, account3Addr, "1000stake", "--from=" + account1Addr} testCases := []struct { @@ -185,20 +146,6 @@ func TestBankMultiSendTxCmd(t *testing.T) { 0, "only received 3", }, - { - "not enough fees", - append(multiSendCmdArgs, "--fees=0stake"), - true, - sdkerrors.ErrInsufficientFee.ABCICode(), - "insufficient fee", - }, - { - "not enough gas", - append(multiSendCmdArgs, "--fees=1stake", "--gas=10"), - true, - sdkerrors.ErrOutOfGas.ABCICode(), - "out of gas", - }, { "chain-id shouldn't be used with offline and generate-only flags", append(multiSendCmdArgs, "--generate-only", "--offline", "-a=0", "-s=4"), @@ -209,18 +156,16 @@ func TestBankMultiSendTxCmd(t *testing.T) { } for _, tc := range testCases { - tc := tc - t.Run(tc.name, func(t *testing.T) { if tc.expectErr { - assertErr := func(xt assert.TestingT, gotErr error, gotOutputs ...interface{}) bool { - assert.Len(t, gotOutputs, 1) + assertErr := func(_ assert.TestingT, gotErr error, gotOutputs ...interface{}) bool { + require.Len(t, gotOutputs, 1) output := gotOutputs[0].(string) - assert.Contains(t, output, tc.expErrMsg) + require.Contains(t, output, tc.expErrMsg) if tc.expectedCode != 0 { code := gjson.Get(output, "code") - assert.True(t, code.Exists()) - assert.Equal(t, int64(tc.expectedCode), code.Int()) + require.True(t, code.Exists()) + require.Equal(t, int64(tc.expectedCode), code.Int()) } return false // always abort } @@ -228,8 +173,20 @@ func TestBankMultiSendTxCmd(t *testing.T) { } else { rsp := cli.Run(tc.cmdArgs...) txResult, found := cli.AwaitTxCommitted(rsp) - assert.True(t, found) + require.True(t, found) RequireTxSuccess(t, txResult) + // check account1 balance equals to account1Bal - transferredAmount*no_of_accounts - fees + expAcc1Balance := account1Bal - (1000 * 2) - 1 + require.Equal(t, expAcc1Balance, cli.QueryBalance(account1Addr, denom)) + account1Bal = expAcc1Balance + // check account2 balance equals to account2Bal + transferredAmount + expAcc2Balance := account2Bal + 1000 + require.Equal(t, expAcc2Balance, cli.QueryBalance(account2Addr, denom)) + account2Bal = expAcc2Balance + // check account3 balance equals to account3Bal + transferredAmount + expAcc3Balance := account3Bal + 1000 + require.Equal(t, expAcc3Balance, cli.QueryBalance(account3Addr, denom)) + account3Bal = expAcc3Balance } }) } @@ -250,7 +207,7 @@ func TestBankGRPCQueries(t *testing.T) { sut.ModifyGenesisJSON(t, func(genesis []byte) []byte { state, err := sjson.SetRawBytes(genesis, "app_state.bank.denom_metadata", []byte(bankDenomMetadata)) - assert.NoError(t, err) + require.NoError(t, err) return state }) @@ -314,12 +271,10 @@ func TestBankGRPCQueries(t *testing.T) { } for _, tc := range supplyTestCases { - tc := tc - t.Run(tc.name, func(t *testing.T) { resp, err := testutil.GetRequestWithHeaders(tc.url, tc.headers) - assert.NoError(t, err) - assert.Contains(t, string(resp), tc.expOut) + require.NoError(t, err) + require.Contains(t, string(resp), tc.expOut) }) } @@ -343,17 +298,15 @@ func TestBankGRPCQueries(t *testing.T) { { "test GRPC client metadata of a bogus denom", denomMetadataUrl + "/foobar", - `{"code":5,"message":"client metadata for denom foobar","details":[]}`, + `"details":[]`, }, } for _, tc := range dmTestCases { - tc := tc - t.Run(tc.name, func(t *testing.T) { resp, err := testutil.GetRequest(tc.url) - assert.NoError(t, err) - assert.Contains(t, string(resp), tc.expOut) + require.NoError(t, err) + require.Contains(t, string(resp), tc.expOut) }) } @@ -384,12 +337,10 @@ func TestBankGRPCQueries(t *testing.T) { } for _, tc := range balanceTestCases { - tc := tc - t.Run(tc.name, func(t *testing.T) { resp, err := testutil.GetRequest(tc.url) - assert.NoError(t, err) - assert.Contains(t, string(resp), tc.expOut) + require.NoError(t, err) + require.Contains(t, string(resp), tc.expOut) }) } } From 08ccb0d56fe9eb4170156af1d2792f8ada8d6116 Mon Sep 17 00:00:00 2001 From: akhilkumarpilli Date: Wed, 11 Sep 2024 17:14:32 +0530 Subject: [PATCH 7/8] add build flag --- tests/systemtests/bank_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/systemtests/bank_test.go b/tests/systemtests/bank_test.go index f7722562bf5d..7082cf444fe3 100644 --- a/tests/systemtests/bank_test.go +++ b/tests/systemtests/bank_test.go @@ -1,3 +1,5 @@ +//go:build system_test + package systemtests import ( From fa336bf2bad030d0c9516398a27ed27b640d1e63 Mon Sep 17 00:00:00 2001 From: akhilkumarpilli Date: Thu, 12 Sep 2024 16:23:17 +0530 Subject: [PATCH 8/8] typo --- tests/systemtests/bank_test.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/systemtests/bank_test.go b/tests/systemtests/bank_test.go index 7082cf444fe3..ae654fcba457 100644 --- a/tests/systemtests/bank_test.go +++ b/tests/systemtests/bank_test.go @@ -108,9 +108,10 @@ func TestBankMultiSendTxCmd(t *testing.T) { account1Addr := cli.AddKey("account1") account2Addr := cli.AddKey("account2") account3Addr := cli.AddKey("account3") - require.NotEqual(t, account1Addr, account2Addr, account3Addr) + require.NotEqual(t, account1Addr, account2Addr) + require.NotEqual(t, account1Addr, account3Addr) denom := "stake" - initialAmount := 10000000 + var initialAmount int64 = 10000000 initialBalance := fmt.Sprintf("%d%s", initialAmount, denom) sut.ModifyGenesisCLI(t, []string{"genesis", "add-genesis-account", account1Addr, initialBalance}, @@ -120,9 +121,9 @@ func TestBankMultiSendTxCmd(t *testing.T) { // query accounts balances account1Bal := cli.QueryBalance(account1Addr, denom) - require.Equal(t, int64(initialAmount), account1Bal) + require.Equal(t, initialAmount, account1Bal) account2Bal := cli.QueryBalance(account2Addr, denom) - require.Equal(t, int64(initialAmount), account2Bal) + require.Equal(t, initialAmount, account2Bal) var account3Bal int64 = 0 multiSendCmdArgs := []string{"tx", "bank", "multi-send", account1Addr, account2Addr, account3Addr, "1000stake", "--from=" + account1Addr}