github.com/cosmos/cosmos-sdk@v0.50.10/x/staking/client/cli/tx_test.go (about)

     1  package cli_test
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"testing"
     7  
     8  	abci "github.com/cometbft/cometbft/abci/types"
     9  	rpcclientmock "github.com/cometbft/cometbft/rpc/client/mock"
    10  	"github.com/spf13/pflag"
    11  	"github.com/stretchr/testify/suite"
    12  
    13  	sdkmath "cosmossdk.io/math"
    14  
    15  	"github.com/cosmos/cosmos-sdk/client"
    16  	"github.com/cosmos/cosmos-sdk/client/flags"
    17  	addresscodec "github.com/cosmos/cosmos-sdk/codec/address"
    18  	"github.com/cosmos/cosmos-sdk/crypto/hd"
    19  	"github.com/cosmos/cosmos-sdk/crypto/keyring"
    20  	"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
    21  	"github.com/cosmos/cosmos-sdk/testutil"
    22  	clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
    23  	simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
    24  	sdk "github.com/cosmos/cosmos-sdk/types"
    25  	testutilmod "github.com/cosmos/cosmos-sdk/types/module/testutil"
    26  	"github.com/cosmos/cosmos-sdk/x/staking"
    27  	"github.com/cosmos/cosmos-sdk/x/staking/client/cli"
    28  )
    29  
    30  var PKs = simtestutil.CreateTestPubKeys(500)
    31  
    32  type CLITestSuite struct {
    33  	suite.Suite
    34  
    35  	kr        keyring.Keyring
    36  	encCfg    testutilmod.TestEncodingConfig
    37  	baseCtx   client.Context
    38  	clientCtx client.Context
    39  	addrs     []sdk.AccAddress
    40  }
    41  
    42  func (s *CLITestSuite) SetupSuite() {
    43  	s.encCfg = testutilmod.MakeTestEncodingConfig(staking.AppModuleBasic{})
    44  	s.kr = keyring.NewInMemory(s.encCfg.Codec)
    45  	s.baseCtx = client.Context{}.
    46  		WithKeyring(s.kr).
    47  		WithTxConfig(s.encCfg.TxConfig).
    48  		WithCodec(s.encCfg.Codec).
    49  		WithClient(clitestutil.MockCometRPC{Client: rpcclientmock.Client{}}).
    50  		WithAccountRetriever(client.MockAccountRetriever{}).
    51  		WithOutput(io.Discard).
    52  		WithChainID("test-chain")
    53  
    54  	ctxGen := func() client.Context {
    55  		bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{})
    56  		c := clitestutil.NewMockCometRPC(abci.ResponseQuery{
    57  			Value: bz,
    58  		})
    59  		return s.baseCtx.WithClient(c)
    60  	}
    61  	s.clientCtx = ctxGen()
    62  
    63  	s.addrs = make([]sdk.AccAddress, 0)
    64  	for i := 0; i < 3; i++ {
    65  		k, _, err := s.clientCtx.Keyring.NewMnemonic("NewValidator", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
    66  		s.Require().NoError(err)
    67  
    68  		pub, err := k.GetPubKey()
    69  		s.Require().NoError(err)
    70  
    71  		newAddr := sdk.AccAddress(pub.Address())
    72  		s.addrs = append(s.addrs, newAddr)
    73  	}
    74  }
    75  
    76  func (s *CLITestSuite) TestPrepareConfigForTxCreateValidator() {
    77  	chainID := "chainID"
    78  	ip := "1.1.1.1"
    79  	nodeID := "nodeID"
    80  	privKey := ed25519.GenPrivKey()
    81  	valPubKey := privKey.PubKey()
    82  	moniker := "DefaultMoniker"
    83  	require := s.Require()
    84  	mkTxValCfg := func(amount, commission, commissionMax, commissionMaxChange, minSelfDelegation string) cli.TxCreateValidatorConfig {
    85  		return cli.TxCreateValidatorConfig{
    86  			IP:                      ip,
    87  			ChainID:                 chainID,
    88  			NodeID:                  nodeID,
    89  			P2PPort:                 26656,
    90  			PubKey:                  valPubKey,
    91  			Moniker:                 moniker,
    92  			Amount:                  amount,
    93  			CommissionRate:          commission,
    94  			CommissionMaxRate:       commissionMax,
    95  			CommissionMaxChangeRate: commissionMaxChange,
    96  			MinSelfDelegation:       minSelfDelegation,
    97  		}
    98  	}
    99  
   100  	tests := []struct {
   101  		name        string
   102  		fsModify    func(fs *pflag.FlagSet)
   103  		expectedCfg cli.TxCreateValidatorConfig
   104  	}{
   105  		{
   106  			name:        "all defaults",
   107  			fsModify:    func(fs *pflag.FlagSet) {},
   108  			expectedCfg: mkTxValCfg(cli.DefaultTokens.String()+sdk.DefaultBondDenom, "0.1", "0.2", "0.01", "1"),
   109  		},
   110  		{
   111  			name: "Custom amount",
   112  			fsModify: func(fs *pflag.FlagSet) {
   113  				require.NoError(fs.Set(cli.FlagAmount, "2000stake"))
   114  			},
   115  			expectedCfg: mkTxValCfg("2000stake", "0.1", "0.2", "0.01", "1"),
   116  		},
   117  		{
   118  			name: "Custom commission rate",
   119  			fsModify: func(fs *pflag.FlagSet) {
   120  				require.NoError(fs.Set(cli.FlagCommissionRate, "0.54"))
   121  			},
   122  			expectedCfg: mkTxValCfg(cli.DefaultTokens.String()+sdk.DefaultBondDenom, "0.54", "0.2", "0.01", "1"),
   123  		},
   124  		{
   125  			name: "Custom commission max rate",
   126  			fsModify: func(fs *pflag.FlagSet) {
   127  				require.NoError(fs.Set(cli.FlagCommissionMaxRate, "0.89"))
   128  			},
   129  			expectedCfg: mkTxValCfg(cli.DefaultTokens.String()+sdk.DefaultBondDenom, "0.1", "0.89", "0.01", "1"),
   130  		},
   131  		{
   132  			name: "Custom commission max change rate",
   133  			fsModify: func(fs *pflag.FlagSet) {
   134  				require.NoError(fs.Set(cli.FlagCommissionMaxChangeRate, "0.55"))
   135  			},
   136  			expectedCfg: mkTxValCfg(cli.DefaultTokens.String()+sdk.DefaultBondDenom, "0.1", "0.2", "0.55", "1"),
   137  		},
   138  		{
   139  			name: "Custom min self delegations",
   140  			fsModify: func(fs *pflag.FlagSet) {
   141  				require.NoError(fs.Set(cli.FlagMinSelfDelegation, "0.33"))
   142  			},
   143  			expectedCfg: mkTxValCfg(cli.DefaultTokens.String()+sdk.DefaultBondDenom, "0.1", "0.2", "0.01", "0.33"),
   144  		},
   145  	}
   146  
   147  	for _, tc := range tests {
   148  		tc := tc
   149  		s.Run(tc.name, func() {
   150  			fs, _ := cli.CreateValidatorMsgFlagSet(ip)
   151  			fs.String(flags.FlagName, "", "name of private key with which to sign the gentx")
   152  
   153  			tc.fsModify(fs)
   154  
   155  			cvCfg, err := cli.PrepareConfigForTxCreateValidator(fs, moniker, nodeID, chainID, valPubKey)
   156  			require.NoError(err)
   157  
   158  			require.Equal(tc.expectedCfg, cvCfg)
   159  		})
   160  	}
   161  }
   162  
   163  func (s *CLITestSuite) TestNewCreateValidatorCmd() {
   164  	require := s.Require()
   165  	cmd := cli.NewCreateValidatorCmd(addresscodec.NewBech32Codec("cosmosvaloper"))
   166  
   167  	validJSON := fmt.Sprintf(`
   168  	{
   169    		"pubkey": {"@type":"/cosmos.crypto.ed25519.PubKey","key":"oWg2ISpLF405Jcm2vXV+2v4fnjodh6aafuIdeoW+rUw="},
   170    		"amount": "%dstake",
   171    		"moniker": "NewValidator",
   172  		"identity": "AFAF00C4",
   173  		"website": "https://newvalidator.io",
   174  		"security": "contact@newvalidator.io",
   175  		"details": "'Hey, I am a new validator. Please delegate!'",
   176    		"commission-rate": "0.5",
   177    		"commission-max-rate": "1.0",
   178    		"commission-max-change-rate": "0.1",
   179    		"min-self-delegation": "1"
   180  	}`, 100)
   181  	validJSONFile := testutil.WriteToNewTempFile(s.T(), validJSON)
   182  	defer validJSONFile.Close()
   183  
   184  	validJSONWithoutOptionalFields := fmt.Sprintf(`
   185  	{
   186    		"pubkey": {"@type":"/cosmos.crypto.ed25519.PubKey","key":"oWg2ISpLF405Jcm2vXV+2v4fnjodh6aafuIdeoW+rUw="},
   187    		"amount": "%dstake",
   188    		"moniker": "NewValidator",
   189    		"commission-rate": "0.5",
   190    		"commission-max-rate": "1.0",
   191    		"commission-max-change-rate": "0.1",
   192    		"min-self-delegation": "1"
   193  	}`, 100)
   194  	validJSONWOOptionalFile := testutil.WriteToNewTempFile(s.T(), validJSONWithoutOptionalFields)
   195  	defer validJSONWOOptionalFile.Close()
   196  
   197  	noAmountJSON := `
   198  	{
   199    		"pubkey": {"@type":"/cosmos.crypto.ed25519.PubKey","key":"oWg2ISpLF405Jcm2vXV+2v4fnjodh6aafuIdeoW+rUw="},
   200    		"moniker": "NewValidator",
   201    		"commission-rate": "0.5",
   202    		"commission-max-rate": "1.0",
   203    		"commission-max-change-rate": "0.1",
   204    		"min-self-delegation": "1"
   205  	}`
   206  	noAmountJSONFile := testutil.WriteToNewTempFile(s.T(), noAmountJSON)
   207  	defer noAmountJSONFile.Close()
   208  
   209  	noPubKeyJSON := fmt.Sprintf(`
   210  	{
   211    		"amount": "%dstake",
   212    		"moniker": "NewValidator",
   213    		"commission-rate": "0.5",
   214    		"commission-max-rate": "1.0",
   215    		"commission-max-change-rate": "0.1",
   216    		"min-self-delegation": "1"
   217  	}`, 100)
   218  	noPubKeyJSONFile := testutil.WriteToNewTempFile(s.T(), noPubKeyJSON)
   219  	defer noPubKeyJSONFile.Close()
   220  
   221  	noMonikerJSON := fmt.Sprintf(`
   222  	{
   223    		"pubkey": {"@type":"/cosmos.crypto.ed25519.PubKey","key":"oWg2ISpLF405Jcm2vXV+2v4fnjodh6aafuIdeoW+rUw="},
   224    		"amount": "%dstake",
   225    		"commission-rate": "0.5",
   226    		"commission-max-rate": "1.0",
   227    		"commission-max-change-rate": "0.1",
   228    		"min-self-delegation": "1"
   229  	}`, 100)
   230  	noMonikerJSONFile := testutil.WriteToNewTempFile(s.T(), noMonikerJSON)
   231  	defer noMonikerJSONFile.Close()
   232  
   233  	testCases := []struct {
   234  		name         string
   235  		args         []string
   236  		expectErrMsg string
   237  	}{
   238  		{
   239  			"invalid transaction (missing amount)",
   240  			[]string{
   241  				noAmountJSONFile.Name(),
   242  				fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
   243  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   244  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
   245  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
   246  			},
   247  			"must specify amount of coins to bond",
   248  		},
   249  		{
   250  			"invalid transaction (missing pubkey)",
   251  			[]string{
   252  				noPubKeyJSONFile.Name(),
   253  				fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
   254  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   255  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
   256  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
   257  			},
   258  			"must specify the JSON encoded pubkey",
   259  		},
   260  		{
   261  			"invalid transaction (missing moniker)",
   262  			[]string{
   263  				noMonikerJSONFile.Name(),
   264  				fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
   265  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   266  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
   267  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
   268  			},
   269  			"must specify the moniker name",
   270  		},
   271  		{
   272  			"valid transaction with all fields",
   273  			[]string{
   274  				validJSONFile.Name(),
   275  				fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
   276  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   277  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
   278  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
   279  			},
   280  			"",
   281  		},
   282  		{
   283  			"valid transaction without optional fields",
   284  			[]string{
   285  				validJSONWOOptionalFile.Name(),
   286  				fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
   287  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   288  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
   289  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
   290  			},
   291  			"",
   292  		},
   293  	}
   294  	for _, tc := range testCases {
   295  		tc := tc
   296  		s.Run(tc.name, func() {
   297  			out, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, tc.args)
   298  			if tc.expectErrMsg != "" {
   299  				require.Error(err)
   300  				require.Contains(err.Error(), tc.expectErrMsg)
   301  			} else {
   302  				require.NoError(err, "test: %s\noutput: %s", tc.name, out.String())
   303  				resp := &sdk.TxResponse{}
   304  				err = s.clientCtx.Codec.UnmarshalJSON(out.Bytes(), resp)
   305  				require.NoError(err, out.String(), "test: %s, output\n:", tc.name, out.String())
   306  			}
   307  		})
   308  	}
   309  }
   310  
   311  func (s *CLITestSuite) TestNewEditValidatorCmd() {
   312  	cmd := cli.NewEditValidatorCmd(addresscodec.NewBech32Codec("cosmos"))
   313  
   314  	moniker := "testing"
   315  	details := "bio"
   316  	identity := "test identity"
   317  	securityContact := "test contact"
   318  	website := "https://test.com"
   319  
   320  	testCases := []struct {
   321  		name         string
   322  		args         []string
   323  		expectErrMsg string
   324  	}{
   325  		{
   326  			"wrong from address",
   327  			[]string{
   328  				fmt.Sprintf("--%s=%s", flags.FlagFrom, "with wrong from address"),
   329  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   330  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
   331  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
   332  			},
   333  			"key not found",
   334  		},
   335  		{
   336  			"valid with no edit flag (since all are optional)",
   337  			[]string{
   338  				fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
   339  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   340  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
   341  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
   342  			},
   343  			"",
   344  		},
   345  		{
   346  			"valid with edit validator details",
   347  			[]string{
   348  				fmt.Sprintf("--details=%s", details),
   349  				fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
   350  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   351  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
   352  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
   353  			},
   354  			"",
   355  		},
   356  		{
   357  			"edit validator identity",
   358  			[]string{
   359  				fmt.Sprintf("--identity=%s", identity),
   360  				fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
   361  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   362  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
   363  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
   364  			},
   365  			"",
   366  		},
   367  		{
   368  			"edit validator security-contact",
   369  			[]string{
   370  				fmt.Sprintf("--security-contact=%s", securityContact),
   371  				fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
   372  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   373  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
   374  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
   375  			},
   376  			"",
   377  		},
   378  		{
   379  			"edit validator website",
   380  			[]string{
   381  				fmt.Sprintf("--website=%s", website),
   382  				fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
   383  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   384  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
   385  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
   386  			},
   387  			"",
   388  		},
   389  		{
   390  			"edit validator moniker", // https://github.com/cosmos/cosmos-sdk/issues/10660
   391  			[]string{
   392  				fmt.Sprintf("--%s=%s", cli.FlagEditMoniker, moniker),
   393  				fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
   394  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   395  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
   396  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
   397  			},
   398  			"",
   399  		},
   400  		{
   401  			"with all edit flags",
   402  			[]string{
   403  				fmt.Sprintf("--%s=%s", cli.FlagEditMoniker, moniker),
   404  				fmt.Sprintf("--details=%s", details),
   405  				fmt.Sprintf("--identity=%s", identity),
   406  				fmt.Sprintf("--security-contact=%s", securityContact),
   407  				fmt.Sprintf("--website=%s", website),
   408  				fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
   409  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   410  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
   411  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
   412  			},
   413  			"",
   414  		},
   415  	}
   416  
   417  	for _, tc := range testCases {
   418  		tc := tc
   419  
   420  		s.Run(tc.name, func() {
   421  			out, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, tc.args)
   422  			if tc.expectErrMsg != "" {
   423  				s.Require().Error(err)
   424  				s.Require().Contains(err.Error(), tc.expectErrMsg)
   425  			} else {
   426  				s.Require().NoError(err, out.String())
   427  				resp := &sdk.TxResponse{}
   428  				s.Require().NoError(s.clientCtx.Codec.UnmarshalJSON(out.Bytes(), resp))
   429  			}
   430  		})
   431  	}
   432  }
   433  
   434  func (s *CLITestSuite) TestNewDelegateCmd() {
   435  	cmd := cli.NewDelegateCmd(addresscodec.NewBech32Codec("cosmosvaloper"), addresscodec.NewBech32Codec("cosmos"))
   436  
   437  	testCases := []struct {
   438  		name         string
   439  		args         []string
   440  		expectErrMsg string
   441  	}{
   442  		{
   443  			"invalid delegate amount",
   444  			[]string{
   445  				sdk.ValAddress(s.addrs[0]).String(),
   446  				"fooCoin",
   447  				fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
   448  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   449  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
   450  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
   451  			},
   452  			"invalid decimal coin expression: fooCoin",
   453  		},
   454  		{
   455  			"invalid validator address",
   456  			[]string{
   457  				"abc",
   458  				sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(150)).String(),
   459  				fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
   460  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   461  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
   462  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
   463  			},
   464  			"decoding bech32 failed",
   465  		},
   466  		{
   467  			"valid transaction of delegate",
   468  			[]string{
   469  				sdk.ValAddress(s.addrs[0]).String(),
   470  				sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(150)).String(),
   471  				fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
   472  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   473  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
   474  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
   475  			},
   476  			"",
   477  		},
   478  	}
   479  
   480  	for _, tc := range testCases {
   481  		tc := tc
   482  
   483  		s.Run(tc.name, func() {
   484  			out, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, tc.args)
   485  			if tc.expectErrMsg != "" {
   486  				s.Require().Error(err)
   487  				s.Require().Contains(err.Error(), tc.expectErrMsg)
   488  			} else {
   489  				s.Require().NoError(err, out.String())
   490  				resp := &sdk.TxResponse{}
   491  				s.Require().NoError(s.clientCtx.Codec.UnmarshalJSON(out.Bytes(), resp))
   492  			}
   493  		})
   494  	}
   495  }
   496  
   497  func (s *CLITestSuite) TestNewRedelegateCmd() {
   498  	cmd := cli.NewRedelegateCmd(addresscodec.NewBech32Codec("cosmosvaloper"), addresscodec.NewBech32Codec("cosmos"))
   499  
   500  	testCases := []struct {
   501  		name         string
   502  		args         []string
   503  		expectErrMsg string
   504  	}{
   505  		{
   506  			"invalid amount",
   507  			[]string{
   508  				sdk.ValAddress(s.addrs[0]).String(), // src-validator-addr
   509  				sdk.ValAddress(s.addrs[1]).String(), // dst-validator-addr
   510  				"fooCoin",
   511  				fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
   512  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   513  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
   514  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
   515  			},
   516  			"invalid decimal coin expression: fooCoin",
   517  		},
   518  		{
   519  			"wrong src validator",
   520  			[]string{
   521  				"invalid",                           // wrong src-validator-addr
   522  				sdk.ValAddress(s.addrs[1]).String(), // dst-validator-addr
   523  				sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(150)).String(), // amount
   524  				fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
   525  				fmt.Sprintf("--%s=%d", flags.FlagGas, 300000),
   526  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   527  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
   528  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
   529  			},
   530  			"invalid bech32",
   531  		},
   532  		{
   533  			"wrong dst validator",
   534  			[]string{
   535  				sdk.ValAddress(s.addrs[0]).String(), // src-validator-addr
   536  				"invalid",                           // wrong dst-validator-addr
   537  				sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(150)).String(), // amount
   538  				fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
   539  				fmt.Sprintf("--%s=%d", flags.FlagGas, 300000),
   540  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   541  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
   542  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
   543  			},
   544  			"invalid bech32",
   545  		},
   546  		{
   547  			"valid transaction of delegate",
   548  			[]string{
   549  				sdk.ValAddress(s.addrs[0]).String(),                             // src-validator-addr
   550  				sdk.ValAddress(s.addrs[1]).String(),                             // dst-validator-addr
   551  				sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(150)).String(), // amount
   552  				fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
   553  				fmt.Sprintf("--%s=%d", flags.FlagGas, 300000),
   554  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   555  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
   556  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
   557  			},
   558  			"",
   559  		},
   560  	}
   561  
   562  	for _, tc := range testCases {
   563  		tc := tc
   564  
   565  		s.Run(tc.name, func() {
   566  			out, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, tc.args)
   567  			if tc.expectErrMsg != "" {
   568  				s.Require().Error(err)
   569  				s.Require().Contains(err.Error(), tc.expectErrMsg)
   570  			} else {
   571  				s.Require().NoError(err, out.String())
   572  				resp := &sdk.TxResponse{}
   573  				s.Require().NoError(s.clientCtx.Codec.UnmarshalJSON(out.Bytes(), resp))
   574  			}
   575  		})
   576  	}
   577  }
   578  
   579  func (s *CLITestSuite) TestNewUnbondCmd() {
   580  	cmd := cli.NewUnbondCmd(addresscodec.NewBech32Codec("cosmosvaloper"), addresscodec.NewBech32Codec("cosmos"))
   581  
   582  	testCases := []struct {
   583  		name         string
   584  		args         []string
   585  		expectErrMsg string
   586  	}{
   587  		{
   588  			"invalid unbond amount",
   589  			[]string{
   590  				sdk.ValAddress(s.addrs[0]).String(),
   591  				"foo",
   592  				fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
   593  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   594  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
   595  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
   596  			},
   597  			"invalid decimal coin expression: foo",
   598  		},
   599  		{
   600  			"invalid validator address",
   601  			[]string{
   602  				"foo",
   603  				sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(150)).String(),
   604  				fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
   605  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   606  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
   607  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
   608  			},
   609  			"decoding bech32 failed",
   610  		},
   611  		{
   612  			"valid transaction of unbond",
   613  			[]string{
   614  				sdk.ValAddress(s.addrs[0]).String(),
   615  				sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(150)).String(),
   616  				fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
   617  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   618  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
   619  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
   620  			},
   621  			"",
   622  		},
   623  	}
   624  
   625  	for _, tc := range testCases {
   626  		tc := tc
   627  
   628  		s.Run(tc.name, func() {
   629  			out, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, tc.args)
   630  			if tc.expectErrMsg != "" {
   631  				s.Require().Error(err)
   632  				s.Require().Contains(err.Error(), tc.expectErrMsg)
   633  			} else {
   634  				s.Require().NoError(err, out.String())
   635  				resp := &sdk.TxResponse{}
   636  				s.Require().NoError(s.clientCtx.Codec.UnmarshalJSON(out.Bytes(), resp))
   637  			}
   638  		})
   639  	}
   640  }
   641  
   642  func (s *CLITestSuite) TestNewCancelUnbondingDelegationCmd() {
   643  	cmd := cli.NewCancelUnbondingDelegation(addresscodec.NewBech32Codec("cosmosvaloper"), addresscodec.NewBech32Codec("cosmos"))
   644  
   645  	testCases := []struct {
   646  		name         string
   647  		args         []string
   648  		expectErrMsg string
   649  	}{
   650  		{
   651  			"invalid validator address",
   652  			[]string{
   653  				"foo",
   654  				sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(150)).String(),
   655  				sdkmath.NewInt(10000).String(),
   656  				fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
   657  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   658  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
   659  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
   660  			},
   661  			"decoding bech32 failed",
   662  		},
   663  		{
   664  			"invalid canceling unbond delegation amount",
   665  			[]string{
   666  				sdk.ValAddress(s.addrs[0]).String(),
   667  				"fooCoin",
   668  				sdkmath.NewInt(10000).String(),
   669  				fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
   670  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   671  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
   672  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
   673  			},
   674  			"invalid decimal coin expression",
   675  		},
   676  		{
   677  			"without unbond creation height",
   678  			[]string{
   679  				sdk.ValAddress(s.addrs[0]).String(),
   680  				sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(150)).String(),
   681  				"abc",
   682  				fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
   683  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   684  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
   685  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
   686  			},
   687  			"invalid height: invalid height: 0",
   688  		},
   689  		{
   690  			"valid transaction of canceling unbonding delegation",
   691  			[]string{
   692  				sdk.ValAddress(s.addrs[0]).String(),
   693  				sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(5)).String(),
   694  				sdkmath.NewInt(10000).String(),
   695  				fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]),
   696  				fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
   697  				fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync),
   698  				fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()),
   699  			},
   700  			"",
   701  		},
   702  	}
   703  
   704  	for _, tc := range testCases {
   705  		tc := tc
   706  
   707  		s.Run(tc.name, func() {
   708  			out, err := clitestutil.ExecTestCLICmd(s.clientCtx, cmd, tc.args)
   709  			if tc.expectErrMsg != "" {
   710  				s.Require().Error(err)
   711  				s.Require().Contains(err.Error(), tc.expectErrMsg)
   712  			} else {
   713  				s.Require().NoError(err, out.String())
   714  				resp := &sdk.TxResponse{}
   715  				s.Require().NoError(s.clientCtx.Codec.UnmarshalJSON(out.Bytes(), resp))
   716  			}
   717  		})
   718  	}
   719  }
   720  
   721  func TestCLITestSuite(t *testing.T) {
   722  	suite.Run(t, new(CLITestSuite))
   723  }