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 }