From 82869fd3ab52faa6584bde40bc00446dd24a7d6c Mon Sep 17 00:00:00 2001 From: Artur Troian Date: Mon, 9 Sep 2024 22:17:47 -0500 Subject: [PATCH] feat: add cli tests Signed-off-by: Artur Troian --- go/cli/auth_suite_test.go | 60 +-- go/cli/authz_query_test.go | 7 +- go/cli/authz_suite_test.go | 16 +- go/cli/authz_tx_test.go | 117 ++--- go/cli/distribution_suite_test.go | 740 ++++++++++++++++++++++++++++++ go/cli/distribution_tx.go | 50 +- go/cli/distribution_tx_test.go | 57 +++ go/cli/evidence_query_test.go | 119 +++++ go/cli/feegrant_query_test.go | 153 ++++++ go/cli/feegrant_suite_test.go | 81 ++++ go/cli/feegrant_tx.go | 8 +- go/cli/feegrant_tx_test.go | 611 ++++++++++++++++++++++++ go/cli/flags/flags.go | 1 + go/cli/gentxs.go | 1 - go/cli/gov_suite_test.go | 92 +++- go/cli/mint_query_test.go | 187 ++++++++ go/cli/params_tx_test.go | 42 ++ go/cli/slashing_query_test.go | 140 ++++++ go/cli/slashing_tx.go | 9 +- go/cli/slashing_tx_test.go | 54 +++ go/cli/staking_query_test.go | 590 ++++++++++++++++++++++++ go/cli/staking_tx.go | 9 +- go/cli/staking_tx_test.go | 620 +++++++++++++++++++++++++ go/cli/suite_test.go | 4 + go/cli/test_helpers.go | 191 +++++++- go/cli/upgrade_parse_test.go | 41 ++ go/cli/upgrade_query.go | 16 +- go/cli/upgrade_query_test.go | 176 +++++++ go/cli/upgrade_tx_test.go | 85 ++++ go/cli/vesting_tx.go | 24 +- 30 files changed, 4129 insertions(+), 172 deletions(-) create mode 100644 go/cli/distribution_suite_test.go create mode 100644 go/cli/distribution_tx_test.go create mode 100644 go/cli/evidence_query_test.go create mode 100644 go/cli/feegrant_query_test.go create mode 100644 go/cli/feegrant_suite_test.go create mode 100644 go/cli/feegrant_tx_test.go delete mode 100644 go/cli/gentxs.go create mode 100644 go/cli/mint_query_test.go create mode 100644 go/cli/params_tx_test.go create mode 100644 go/cli/slashing_query_test.go create mode 100644 go/cli/slashing_tx_test.go create mode 100644 go/cli/staking_query_test.go create mode 100644 go/cli/staking_tx_test.go create mode 100644 go/cli/upgrade_parse_test.go create mode 100644 go/cli/upgrade_query_test.go create mode 100644 go/cli/upgrade_tx_test.go diff --git a/go/cli/auth_suite_test.go b/go/cli/auth_suite_test.go index 7f68ec7d..5f2cf903 100644 --- a/go/cli/auth_suite_test.go +++ b/go/cli/auth_suite_test.go @@ -7,7 +7,7 @@ import ( "io" "strings" - "cosmossdk.io/math" + sdkmath "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/testutil/testdata" "github.com/cosmos/cosmos-sdk/types/tx" @@ -101,8 +101,8 @@ func (s *AuthCLITestSuite) SetupSuite() { func (s *AuthCLITestSuite) TestCLIValidateSignatures() { sendTokens := sdk.NewCoins( - sdk.NewCoin("testtoken", sdk.NewInt(10)), - sdk.NewCoin("uakt", sdk.NewInt(10))) + sdk.NewCoin("testtoken", sdkmath.NewInt(10)), + sdk.NewCoin("uakt", sdkmath.NewInt(10))) res, err := s.createBankMsg( s.cctx, @@ -161,8 +161,8 @@ func (s *AuthCLITestSuite) TestCLIValidateSignatures() { func (s *AuthCLITestSuite) TestCLISignBatch() { sendTokens := sdk.NewCoins( - sdk.NewCoin("testtoken", sdk.NewInt(10)), - sdk.NewCoin("uakt", sdk.NewInt(10)), + sdk.NewCoin("testtoken", sdkmath.NewInt(10)), + sdk.NewCoin("uakt", sdkmath.NewInt(10)), ) generatedStd, err := s.createBankMsg( @@ -347,14 +347,14 @@ func (s *AuthCLITestSuite) TestCLIQueryTxsCmdByEvents() { { "fee event happy case", cli.TestFlags(). - WithEvents(fmt.Sprintf("tx.fee=%s", sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10))).String())). + WithEvents(fmt.Sprintf("tx.fee=%s", sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10))).String())). WithOutputJSON(), "", }, { "no matching fee event", cli.TestFlags(). - WithEvents(fmt.Sprintf("tx.fee=%s", sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(0))).String())). + WithEvents(fmt.Sprintf("tx.fee=%s", sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(0))).String())). WithOutputJSON(), "", }, @@ -372,7 +372,7 @@ func (s *AuthCLITestSuite) TestCLIQueryTxsCmdByEvents() { } func (s *AuthCLITestSuite) TestCLISendGenerateSignAndBroadcast() { - sendTokens := sdk.NewCoin("uakt", sdk.TokensFromConsensusPower(10, sdk.DefaultPowerReduction)) + sendTokens := sdk.NewCoin("uakt", sdk.TokensFromConsensusPower(10, cli.DefaultPowerReduction)) normalGeneratedTx, err := s.createBankMsg( s.cctx, @@ -568,7 +568,7 @@ func (s *AuthCLITestSuite) TestCLIMultisignInsufficientCosigners() { ). WithSkipConfirm(). WithBroadcastModeSync(). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))). WithGenerateOnly()...) s.Require().NoError(err) @@ -627,7 +627,7 @@ func (s *AuthCLITestSuite) TestCLIMultisignInsufficientCosigners() { } func (s *AuthCLITestSuite) TestCLIEncode() { - sendTokens := sdk.NewCoin("uakt", sdk.TokensFromConsensusPower(10, sdk.DefaultPowerReduction)) + sendTokens := sdk.NewCoin("uakt", sdk.TokensFromConsensusPower(10, cli.DefaultPowerReduction)) normalGeneratedTx, err := s.createBankMsg( s.cctx, @@ -699,7 +699,7 @@ func (s *AuthCLITestSuite) TestCLIMultisignSortSignatures() { ). WithSkipConfirm(). WithBroadcastModeSync(). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))). WithGenerateOnly()...) s.Require().NoError(err) @@ -826,7 +826,7 @@ func (s *AuthCLITestSuite) TestSignWithMultisig() { WithSkipConfirm(). WithBroadcastModeSync(). WithGenerateOnly(). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10))))...) + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10))))...) s.Require().NoError(err) // Save multi tx to file @@ -879,7 +879,7 @@ func (s *AuthCLITestSuite) TestCLIMultisign() { WithSkipConfirm(). WithBroadcastModeSync(). WithGenerateOnly(). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10))))..., + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10))))..., ) s.Require().NoError(err) @@ -986,12 +986,12 @@ func (s *AuthCLITestSuite) TestSignBatchMultisig() { addr.String(), s.val.String(), sdk.NewCoins( - sdk.NewCoin("uakt", sdk.NewInt(1)), + sdk.NewCoin("uakt", sdkmath.NewInt(1)), ).String(), ). WithBroadcastModeSync(). WithSkipConfirm(). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))). WithGenerateOnly()..., ) s.Require().NoError(err) @@ -1160,12 +1160,12 @@ func (s *AuthCLITestSuite) TestTxWithoutPublicKey() { s.val, s.val, sdk.NewCoins( - sdk.NewCoin("Stake", sdk.NewInt(10)), + sdk.NewCoin("Stake", sdkmath.NewInt(10)), )) err := txBuilder.SetMsgs(msg) s.Require().NoError(err) - txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin("Stake", sdk.NewInt(150)))) + txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin("Stake", sdkmath.NewInt(150)))) txBuilder.SetGasLimit(testdata.NewTestGasLimit()) // Create a file with the unsigned tx. @@ -1225,8 +1225,8 @@ func (s *AuthCLITestSuite) TestTxWithoutPublicKey() { // transaction to the blockchain. func (s *AuthCLITestSuite) TestSignWithMultiSignersAminoJSON() { val0, val1 := s.val, s.val1 - val0Coin := sdk.NewCoin("test1token", sdk.NewInt(10)) - val1Coin := sdk.NewCoin("test2token", sdk.NewInt(10)) + val0Coin := sdk.NewCoin("test1token", sdkmath.NewInt(10)) + val1Coin := sdk.NewCoin("test2token", sdkmath.NewInt(10)) _, _, addr1 := testdata.KeyTestPubAddr() // Creating a tx with 2 msgs from 2 signers: val0 and val1. @@ -1239,7 +1239,7 @@ func (s *AuthCLITestSuite) TestSignWithMultiSignersAminoJSON() { banktypes.NewMsgSend(val1, addr1, sdk.NewCoins(val1Coin)), ) s.Require().NoError(err) - txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))) + txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))) txBuilder.SetGasLimit(testdata.NewTestGasLimit() * 2) s.Require().Equal([]sdk.AccAddress{val0, val1}, txBuilder.GetTx().GetSigners()) @@ -1300,7 +1300,7 @@ func (s *AuthCLITestSuite) TestSignWithMultiSignersAminoJSON() { } func (s *AuthCLITestSuite) TestAuxSigner() { - val0Coin := sdk.NewCoin("testtoken", sdk.NewInt(10)) + val0Coin := sdk.NewCoin("testtoken", sdkmath.NewInt(10)) testCases := []struct { name string @@ -1364,11 +1364,11 @@ func (s *AuthCLITestSuite) TestAuxToFeeWithTips() { tipper, err := acc.GetAddress() require.NoError(err) - tipperInitialBal := sdk.NewCoin("testtoken", sdk.NewInt(10000)) + tipperInitialBal := sdk.NewCoin("testtoken", sdkmath.NewInt(10000)) feePayer := s.val - fee := sdk.NewCoin("uakt", sdk.NewInt(1000)) - tip := sdk.NewCoin("testtoken", sdk.NewInt(1000)) + fee := sdk.NewCoin("uakt", sdkmath.NewInt(1000)) + tip := sdk.NewCoin("testtoken", sdkmath.NewInt(1000)) _, err = s.createBankMsg(s.cctx, tipper, sdk.NewCoins(tipperInitialBal)) require.NoError(err) @@ -1439,7 +1439,7 @@ func (s *AuthCLITestSuite) TestAuxToFeeWithTips() { name: "--tip flag unset: no error", tipper: tipper, feePayer: feePayer, - tip: sdk.Coin{Denom: "testtoken", Amount: sdk.NewInt(0)}, + tip: sdk.Coin{Denom: "testtoken", Amount: sdkmath.NewInt(0)}, tipperArgs: cli.TestFlags(). WithSignMode(cflags.SignModeDirectAux). WithAux(), @@ -1504,10 +1504,10 @@ func (s *AuthCLITestSuite) TestAuxToFeeWithTips() { name: "wrong denom in tip: error", tipper: tipper, feePayer: feePayer, - tip: sdk.Coin{Denom: "testtoken", Amount: sdk.NewInt(0)}, + tip: sdk.Coin{Denom: "testtoken", Amount: sdkmath.NewInt(0)}, tipperArgs: cli.TestFlags(). WithSignMode(cflags.SignModeDirectAux). - WithTip(sdk.Coin{Denom: "wrongDenom", Amount: sdk.NewInt(100)}). + WithTip(sdk.Coin{Denom: "wrongDenom", Amount: sdkmath.NewInt(100)}). WithAux(), feePayerArgs: cli.TestFlags(). WithSignMode(cflags.SignModeDirect). @@ -1521,7 +1521,7 @@ func (s *AuthCLITestSuite) TestAuxToFeeWithTips() { name: "insufficient fees: error", tipper: tipper, feePayer: feePayer, - tip: sdk.Coin{Denom: "testtoken", Amount: sdk.NewInt(0)}, + tip: sdk.Coin{Denom: "testtoken", Amount: sdkmath.NewInt(0)}, tipperArgs: cli.TestFlags(). WithSignMode(cflags.SignModeDirectAux). WithTip(tip). @@ -1596,7 +1596,7 @@ func (s *AuthCLITestSuite) TestAuxToFeeWithTips() { } } -func (s *AuthCLITestSuite) getBalances(cctx client.Context, addr sdk.AccAddress, denom string) math.Int { +func (s *AuthCLITestSuite) getBalances(cctx client.Context, addr sdk.AccAddress, denom string) sdkmath.Int { resp, err := clitestutil.QueryBalancesExec( context.Background(), cctx, @@ -1622,6 +1622,6 @@ func (s *AuthCLITestSuite) createBankMsg(cctx client.Context, toAddr sdk.AccAddr amount.String()). WithSkipConfirm(). WithBroadcastModeSync(). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))). Append(extraFlags)...) } diff --git a/go/cli/authz_query_test.go b/go/cli/authz_query_test.go index 1591c708..e26ceb52 100644 --- a/go/cli/authz_query_test.go +++ b/go/cli/authz_query_test.go @@ -5,6 +5,7 @@ import ( "fmt" "time" + sdkmath "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/testutil" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/authz" @@ -29,9 +30,9 @@ func (s *AuthzCLITestSuite) TestQueryAuthorizations() { WithSkipConfirm(). WithFrom(val[0].Address.String()). WithBroadcastModeSync(). - WithExpiration(twoHours). + WithExpiration(fmt.Sprintf("%d", twoHours)). WithSignMode("direct"). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10))))..., + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10))))..., ) s.Require().NoError(err) @@ -105,7 +106,7 @@ func (s *AuthzCLITestSuite) TestQueryAuthorization() { fmt.Sprintf("--%s=%s", cflags.FlagFrom, val[0].Address), fmt.Sprintf("--%s=%s", cflags.FlagBroadcastMode, cflags.BroadcastSync), fmt.Sprintf("--%s=%d", cflags.FlagExpiration, twoHours), - fmt.Sprintf("--%s=%s", cflags.FlagFees, sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10))).String()), + fmt.Sprintf("--%s=%s", cflags.FlagFees, sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10))).String()), ) s.Require().NoError(err) diff --git a/go/cli/authz_suite_test.go b/go/cli/authz_suite_test.go index d7c84aea..ad9d2ddc 100644 --- a/go/cli/authz_suite_test.go +++ b/go/cli/authz_suite_test.go @@ -3,9 +3,11 @@ package cli_test import ( "bytes" "context" + "fmt" "io" "time" + sdkmath "cosmossdk.io/math" abci "github.com/cometbft/cometbft/abci/types" rpcclientmock "github.com/cometbft/cometbft/rpc/client/mock" "github.com/cosmos/cosmos-sdk/client" @@ -82,7 +84,7 @@ func (s *AuthzCLITestSuite) SetupSuite() { WithSkipConfirm(). WithDescription("Where is the title!?"). WithProposalType(govv1beta1.ProposalTypeText). - WithDeposit(sdk.NewCoin("uakt", govv1.DefaultMinDepositTokens))...) + WithDeposit(sdk.NewCoin("uakt", sdkmath.NewInt(10000000)))...) s.Require().NoError(err) // Create new account in the keyring. @@ -100,8 +102,8 @@ func (s *AuthzCLITestSuite) SetupSuite() { WithFrom(val[0].Address.String()). WithSkipConfirm(). WithBroadcastModeSync(). - WithFees(sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)))). - WithExpiration(time.Now().Add(time.Minute*time.Duration(120)).Unix())...) + WithFees(sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10)))). + WithExpiration(fmt.Sprintf("%d", time.Now().Add(time.Minute*time.Duration(120)).Unix()))...) s.Require().NoError(err) var response sdk.TxResponse @@ -120,8 +122,8 @@ func (s *AuthzCLITestSuite) SetupSuite() { WithFrom(val[0].Address.String()). WithSkipConfirm(). WithBroadcastModeSync(). - WithFees(sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)))). - WithExpiration(time.Now().Add(time.Minute*time.Duration(120)).Unix())...) + WithFees(sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10)))). + WithExpiration(fmt.Sprintf("%d", time.Now().Add(time.Minute*time.Duration(120)).Unix()))...) s.Require().NoError(err) // Create new accounts in the keyring. @@ -141,8 +143,8 @@ func (s *AuthzCLITestSuite) SetupSuite() { WithFrom(val[0].Address.String()). WithSkipConfirm(). WithBroadcastModeSync(). - WithFees(sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10)))). - WithExpiration(time.Now().Add(time.Minute*time.Duration(120)).Unix()). + WithFees(sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10)))). + WithExpiration(fmt.Sprintf("%d", time.Now().Add(time.Minute*time.Duration(120)).Unix())). WithAllowList(s.grantee[4].String())...) s.Require().NoError(err) diff --git a/go/cli/authz_tx_test.go b/go/cli/authz_tx_test.go index 885d30dc..5d6b9804 100644 --- a/go/cli/authz_tx_test.go +++ b/go/cli/authz_tx_test.go @@ -5,6 +5,7 @@ import ( "fmt" "time" + sdkmath "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/testutil" @@ -39,11 +40,11 @@ func (s *AuthzCLITestSuite) msgSendExec(grantee sdk.AccAddress) { With( val.String(), grantee.String(), - sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(200))).String(), + sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(200))).String(), ). WithSkipConfirm(). WithBroadcastModeSync(). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10))))...) + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10))))...) s.Require().NoError(err) s.Require().Contains(out.String(), `"code":0`) } @@ -72,7 +73,7 @@ func (s *AuthzCLITestSuite) TestCLITxGrantAuthorization() { WithSpendLimit("100uakt"). WithFrom("granter"). WithGenerateOnly(). - WithExpiration(twoHours), + WithExpiration(fmt.Sprintf("%d", twoHours)), true, "key not found", }, @@ -86,7 +87,7 @@ func (s *AuthzCLITestSuite) TestCLITxGrantAuthorization() { WithSpendLimit("100uakt"). WithFrom(val[0].Address.String()). WithGenerateOnly(). - WithExpiration(twoHours), + WithExpiration(fmt.Sprintf("%d", twoHours)), true, "invalid separator index", }, @@ -100,7 +101,7 @@ func (s *AuthzCLITestSuite) TestCLITxGrantAuthorization() { WithSpendLimit("100uakt"). WithFrom(val[0].Address.String()). WithBroadcastModeSync(). - WithExpiration(pastHour), + WithExpiration(fmt.Sprintf("%d", pastHour)), true, "", }, @@ -115,8 +116,8 @@ func (s *AuthzCLITestSuite) TestCLITxGrantAuthorization() { WithFrom(val[0].Address.String()). WithBroadcastModeSync(). WithSkipConfirm(). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))). - WithExpiration(twoHours), + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))). + WithExpiration(fmt.Sprintf("%d", twoHours)), false, "", }, @@ -131,8 +132,8 @@ func (s *AuthzCLITestSuite) TestCLITxGrantAuthorization() { WithSkipConfirm(). WithFrom(val[0].Address.String()). WithBroadcastModeSync(). - WithExpiration(twoHours). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))). + WithExpiration(fmt.Sprintf("%d", twoHours)). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))). WithAllowedValidators(sdk.ValAddress(s.addrs[0]).String()), true, "invalid denom", @@ -148,8 +149,8 @@ func (s *AuthzCLITestSuite) TestCLITxGrantAuthorization() { WithSkipConfirm(). WithFrom(val[0].Address.String()). WithBroadcastModeSync(). - WithExpiration(twoHours). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))). + WithExpiration(fmt.Sprintf("%d", twoHours)). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))). WithDenyValidators(sdk.ValAddress(s.addrs[0]).String()), true, "invalid denom", @@ -165,8 +166,8 @@ func (s *AuthzCLITestSuite) TestCLITxGrantAuthorization() { WithSkipConfirm(). WithFrom(val[0].Address.String()). WithBroadcastModeSync(). - WithExpiration(twoHours). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))). + WithExpiration(fmt.Sprintf("%d", twoHours)). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))). WithAllowedValidators(sdk.ValAddress(s.addrs[0]).String()), true, "invalid denom", @@ -182,8 +183,8 @@ func (s *AuthzCLITestSuite) TestCLITxGrantAuthorization() { WithSkipConfirm(). WithFrom(val[0].Address.String()). WithBroadcastModeSync(). - WithExpiration(twoHours). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))). + WithExpiration(fmt.Sprintf("%d", twoHours)). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))). WithAllowedValidators(sdk.ValAddress(s.addrs[0]).String()), true, "invalid denom", @@ -199,8 +200,8 @@ func (s *AuthzCLITestSuite) TestCLITxGrantAuthorization() { WithSkipConfirm(). WithFrom(val[0].Address.String()). WithBroadcastModeSync(). - WithExpiration(twoHours). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))). + WithExpiration(fmt.Sprintf("%d", twoHours)). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))). WithAllowedValidators(sdk.ValAddress(s.addrs[0]).String()), true, "invalid decimal coin expression", @@ -216,8 +217,8 @@ func (s *AuthzCLITestSuite) TestCLITxGrantAuthorization() { WithSkipConfirm(). WithFrom(val[0].Address.String()). WithBroadcastModeSync(). - WithExpiration(twoHours). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))), + WithExpiration(fmt.Sprintf("%d", twoHours)). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))), false, "", }, @@ -232,8 +233,8 @@ func (s *AuthzCLITestSuite) TestCLITxGrantAuthorization() { WithSkipConfirm(). WithFrom(val[0].Address.String()). WithBroadcastModeSync(). - WithExpiration(twoHours). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))). + WithExpiration(fmt.Sprintf("%d", twoHours)). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))). WithAllowList(s.grantee[1].String()), false, "", @@ -249,8 +250,8 @@ func (s *AuthzCLITestSuite) TestCLITxGrantAuthorization() { WithSkipConfirm(). WithFrom(val[0].Address.String()). WithBroadcastModeSync(). - WithExpiration(twoHours). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))). + WithExpiration(fmt.Sprintf("%d", twoHours)). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))). WithAllowList(fmt.Sprintf("%s,%s", s.grantee[1], s.grantee[1])), true, "duplicate entry", @@ -266,8 +267,8 @@ func (s *AuthzCLITestSuite) TestCLITxGrantAuthorization() { WithSkipConfirm(). WithFrom(val[0].Address.String()). WithBroadcastModeSync(). - WithExpiration(twoHours). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))), + WithExpiration(fmt.Sprintf("%d", twoHours)). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))), false, "", }, @@ -282,8 +283,8 @@ func (s *AuthzCLITestSuite) TestCLITxGrantAuthorization() { WithSkipConfirm(). WithFrom(grantee.String()). WithBroadcastModeSync(). - WithExpiration(twoHours). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))), + WithExpiration(fmt.Sprintf("%d", twoHours)). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))), true, "grantee and granter should be different", }, @@ -298,8 +299,8 @@ func (s *AuthzCLITestSuite) TestCLITxGrantAuthorization() { WithSkipConfirm(). WithFrom(val[0].Address.String()). WithBroadcastModeSync(). - WithExpiration(twoHours). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))). + WithExpiration(fmt.Sprintf("%d", twoHours)). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))). WithSignMode(cflags.SignModeLegacyAminoJSON), false, "", @@ -342,8 +343,8 @@ func (s *AuthzCLITestSuite) TestCmdRevokeAuthorizations() { WithSkipConfirm(). WithFrom(val[0].Address.String()). WithBroadcastModeSync(). - WithExpiration(twoHours). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10))))...) + WithExpiration(fmt.Sprintf("%d", twoHours)). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10))))...) s.Require().NoError(err) // generic-authorization @@ -359,8 +360,8 @@ func (s *AuthzCLITestSuite) TestCmdRevokeAuthorizations() { WithSkipConfirm(). WithFrom(val[0].Address.String()). WithBroadcastModeSync(). - WithExpiration(twoHours). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10))))...) + WithExpiration(fmt.Sprintf("%d", twoHours)). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10))))...) s.Require().NoError(err) // generic-authorization used for amino testing @@ -376,8 +377,8 @@ func (s *AuthzCLITestSuite) TestCmdRevokeAuthorizations() { WithSkipConfirm(). WithFrom(val[0].Address.String()). WithBroadcastModeSync(). - WithExpiration(twoHours). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))). + WithExpiration(fmt.Sprintf("%d", twoHours)). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))). WithSignMode(cflags.SignModeLegacyAminoJSON)...) s.Require().NoError(err) testCases := []struct { @@ -420,7 +421,7 @@ func (s *AuthzCLITestSuite) TestCmdRevokeAuthorizations() { WithFrom(val[0].Address.String()). WithSkipConfirm(). WithBroadcastModeSync(). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))), + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))), &sdk.TxResponse{}, false, }, @@ -434,7 +435,7 @@ func (s *AuthzCLITestSuite) TestCmdRevokeAuthorizations() { WithFrom(val[0].Address.String()). WithSkipConfirm(). WithBroadcastModeSync(). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))), + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))), &sdk.TxResponse{}, false, }, @@ -448,7 +449,7 @@ func (s *AuthzCLITestSuite) TestCmdRevokeAuthorizations() { WithFrom(val[0].Address.String()). WithSkipConfirm(). WithBroadcastModeSync(). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))). WithSignMode(cflags.SignModeLegacyAminoJSON), &sdk.TxResponse{}, false, @@ -487,8 +488,8 @@ func (s *AuthzCLITestSuite) TestExecAuthorizationWithExpiration() { WithSkipConfirm(). WithFrom(val[0].Address.String()). WithBroadcastModeSync(). - WithExpiration(tenSeconds). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10))))...) + WithExpiration(fmt.Sprintf("%d", tenSeconds)). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10))))...) s.Require().NoError(err) // msg vote voteTx := fmt.Sprintf(`{"body":{"messages":[{"@type":"/cosmos.gov.v1.MsgVote","proposal_id":"1","voter":"%s","option":"VOTE_OPTION_YES"}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}`, val[0].Address.String()) @@ -513,7 +514,7 @@ func (s *AuthzCLITestSuite) TestExecAuthorizationWithExpiration() { WithFrom(grantee.String()). WithSkipConfirm(). WithBroadcastModeSync(). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10))))...) + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10))))...) s.Require().NoError(err) var response sdk.TxResponse s.Require().NoError(s.cctx.Codec.UnmarshalJSON(out.Bytes(), &response), out.String()) @@ -536,8 +537,8 @@ func (s *AuthzCLITestSuite) TestNewExecGenericAuthorized() { WithSkipConfirm(). WithFrom(val[0].Address.String()). WithBroadcastModeSync(). - WithExpiration(twoHours). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10))))...) + WithExpiration(fmt.Sprintf("%d", twoHours)). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10))))...) s.Require().NoError(err) // msg vote @@ -585,7 +586,7 @@ func (s *AuthzCLITestSuite) TestNewExecGenericAuthorized() { WithFrom(grantee.String()). WithBroadcastModeSync(). WithSkipConfirm(). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))), + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))), &sdk.TxResponse{}, false, }, @@ -598,7 +599,7 @@ func (s *AuthzCLITestSuite) TestNewExecGenericAuthorized() { WithFrom(grantee.String()). WithBroadcastModeSync(). WithSkipConfirm(). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))). WithSignMode(cflags.SignModeLegacyAminoJSON), &sdk.TxResponse{}, false, @@ -637,12 +638,12 @@ func (s *AuthzCLITestSuite) TestNewExecGrantAuthorized() { WithFrom(val[0].Address.String()). WithBroadcastModeSync(). WithSkipConfirm(). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))). - WithExpiration(twoHours)...) + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))). + WithExpiration(fmt.Sprintf("%d", twoHours))...) s.Require().NoError(err) tokens := sdk.NewCoins( - sdk.NewCoin("testtoken", sdk.NewInt(12)), + sdk.NewCoin("testtoken", sdkmath.NewInt(12)), ) normalGeneratedTx, err := clitestutil.ExecSend( @@ -656,7 +657,7 @@ func (s *AuthzCLITestSuite) TestNewExecGrantAuthorized() { ). WithBroadcastModeSync(). WithSkipConfirm(). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))). WithGenerateOnly()...) s.Require().NoError(err) execMsg := testutil.WriteToNewTempFile(s.T(), normalGeneratedTx.String()) @@ -679,7 +680,7 @@ func (s *AuthzCLITestSuite) TestNewExecGrantAuthorized() { WithFrom(grantee.String()). WithBroadcastModeSync(). WithSkipConfirm(). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))), + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))), false, "", }, @@ -692,7 +693,7 @@ func (s *AuthzCLITestSuite) TestNewExecGrantAuthorized() { WithFrom(grantee.String()). WithBroadcastModeSync(). WithSkipConfirm(). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))), + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))), false, "", }, @@ -742,13 +743,13 @@ func (s *AuthzCLITestSuite) TestExecSendAuthzWithAllowList() { WithFrom(val[0].Address.String()). WithBroadcastModeSync(). WithSkipConfirm(). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))). - WithExpiration(twoHours). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))). + WithExpiration(fmt.Sprintf("%d", twoHours)). WithAllowList(allowedAddr.String())...) s.Require().NoError(err) tokens := sdk.NewCoins( - sdk.NewCoin("stake", sdk.NewInt(12)), + sdk.NewCoin("stake", sdkmath.NewInt(12)), ) validGeneratedTx, err := clitestutil.ExecSend( @@ -762,7 +763,7 @@ func (s *AuthzCLITestSuite) TestExecSendAuthzWithAllowList() { ). WithBroadcastModeSync(). WithSkipConfirm(). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))). WithGenerateOnly()...) s.Require().NoError(err) @@ -782,7 +783,7 @@ func (s *AuthzCLITestSuite) TestExecSendAuthzWithAllowList() { ). WithBroadcastModeSync(). WithSkipConfirm(). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))). WithGenerateOnly()...) s.Require().NoError(err) execMsg1 := testutil.WriteToNewTempFile(s.T(), invalidGeneratedTx.String()) @@ -798,7 +799,7 @@ func (s *AuthzCLITestSuite) TestExecSendAuthzWithAllowList() { WithFrom(grantee.String()). WithBroadcastModeSync(). WithSkipConfirm(). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))) + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))) var response sdk.TxResponse @@ -816,7 +817,7 @@ func (s *AuthzCLITestSuite) TestExecSendAuthzWithAllowList() { WithFrom(grantee.String()). WithBroadcastModeSync(). WithSkipConfirm(). - WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10)))) + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))) out, err = clitestutil.ExecTestCLICmd(context.Background(), s.cctx, cmd, args...) s.Require().NoError(err) diff --git a/go/cli/distribution_suite_test.go b/go/cli/distribution_suite_test.go new file mode 100644 index 00000000..13cd3d2e --- /dev/null +++ b/go/cli/distribution_suite_test.go @@ -0,0 +1,740 @@ +package cli_test + +import ( + "bytes" + "context" + "io" + "strings" + + sdkmath "cosmossdk.io/math" + + abci "github.com/cometbft/cometbft/abci/types" + rpcclientmock "github.com/cometbft/cometbft/rpc/client/mock" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + "github.com/cosmos/cosmos-sdk/testutil" + "github.com/cosmos/cosmos-sdk/testutil/network" + sdk "github.com/cosmos/cosmos-sdk/types" + testutilmod "github.com/cosmos/cosmos-sdk/types/module/testutil" + "github.com/cosmos/cosmos-sdk/x/bank" + distrtestutil "github.com/cosmos/cosmos-sdk/x/distribution/testutil" + "github.com/cosmos/cosmos-sdk/x/gov" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + "github.com/cosmos/gogoproto/proto" + + "pkg.akt.dev/go/cli" + clitestutil "pkg.akt.dev/go/cli/testutil" +) + +type DistributionCLITestSuite struct { + CLITestSuite +} + +func (s *DistributionCLITestSuite) SetupSuite() { + s.encCfg = testutilmod.MakeTestEncodingConfig(gov.AppModuleBasic{}, bank.AppModuleBasic{}) + s.kr = keyring.NewInMemory(s.encCfg.Codec) + s.baseCtx = client.Context{}. + WithKeyring(s.kr). + WithTxConfig(s.encCfg.TxConfig). + WithCodec(s.encCfg.Codec). + WithLegacyAmino(s.encCfg.Amino). + WithClient(clitestutil.MockTendermintRPC{Client: rpcclientmock.Client{}}). + WithAccountRetriever(client.MockAccountRetriever{}). + WithOutput(io.Discard). + WithChainID("test-chain"). + WithSignModeStr("direct") + + var outBuf bytes.Buffer + ctxGen := func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := clitestutil.NewMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + } + s.cctx = ctxGen().WithOutput(&outBuf) + + cfg, err := network.DefaultConfigWithAppConfig(distrtestutil.AppConfig) + s.Require().NoError(err) + + genesisState := cfg.GenesisState + var mintData minttypes.GenesisState + s.Require().NoError(cfg.Codec.UnmarshalJSON(genesisState[minttypes.ModuleName], &mintData)) + + inflation := sdkmath.LegacyMustNewDecFromStr("1.0") + mintData.Minter.Inflation = inflation + mintData.Params.InflationMin = inflation + mintData.Params.InflationMax = inflation + + mintDataBz, err := cfg.Codec.MarshalJSON(&mintData) + s.Require().NoError(err) + genesisState[minttypes.ModuleName] = mintDataBz + + cfg.GenesisState = genesisState +} + +func (s *DistributionCLITestSuite) TestGetCmdQueryParams() { + testCases := []struct { + name string + args []string + expectedOutput string + }{ + { + "json output", + cli.TestFlags(). + WithOutputJSON(), + `{"community_tax":"0","base_proposer_reward":"0","bonus_proposer_reward":"0","withdraw_addr_enabled":false}`, + }, + { + "text output", + cli.TestFlags(). + WithOutputText(), + `base_proposer_reward: "0" +bonus_proposer_reward: "0" +community_tax: "0" +withdraw_addr_enabled: false`, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetQueryDistributionParamsCmd() + + out, err := clitestutil.ExecTestCLICmd(context.Background(), s.cctx, cmd, tc.args...) + s.Require().NoError(err) + s.Require().Equal(tc.expectedOutput, strings.TrimSpace(out.String())) + }) + } +} + +func (s *DistributionCLITestSuite) TestGetCmdQueryValidatorDistributionInfo() { + addr := testutil.CreateKeyringAccounts(s.T(), s.kr, 1) + val := sdk.ValAddress(addr[0].Address.String()) + + testCases := []struct { + name string + args []string + expErr bool + }{ + { + "invalid val address", + cli.TestFlags(). + With("invalid address"). + WithOutputJSON(), + true, + }, + { + "json output", + cli.TestFlags(). + With(val.String()). + WithOutputJSON(), + false, + }, + { + "text output", + cli.TestFlags(). + With(val.String()). + WithOutputText(), + false, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetQueryDistributionValidatorDistributionInfoCmd() + + _, err := clitestutil.ExecTestCLICmd(context.Background(), s.cctx, cmd, tc.args...) + if tc.expErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + } + }) + } +} + +func (s *DistributionCLITestSuite) TestGetCmdQueryValidatorOutstandingRewards() { + val := testutil.CreateKeyringAccounts(s.T(), s.kr, 1) + + testCases := []struct { + name string + args []string + expectErr bool + expectedOutput string + }{ + { + "invalid validator address", + cli.TestFlags(). + With("foo"). + WithHeight(3), + true, + "", + }, + { + "json output", + cli.TestFlags(). + With(sdk.ValAddress(val[0].Address).String()). + WithHeight(3). + WithOutputJSON(), + false, + `{"rewards":[]}`, + }, + { + "text output", + cli.TestFlags(). + With(sdk.ValAddress(val[0].Address).String()). + WithHeight(3). + WithOutputText(), + false, + `rewards: []`, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetQueryDistributionValidatorOutstandingRewardsCmd() + + out, err := clitestutil.ExecTestCLICmd(context.Background(), s.cctx, cmd, tc.args...) + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().Equal(tc.expectedOutput, strings.TrimSpace(out.String())) + } + }) + } +} + +func (s *DistributionCLITestSuite) TestGetCmdQueryValidatorCommission() { + val := testutil.CreateKeyringAccounts(s.T(), s.kr, 1) + + testCases := []struct { + name string + args []string + expectErr bool + expectedOutput string + }{ + { + "invalid validator address", + cli.TestFlags(). + With("foo"). + WithHeight(3), + true, + "", + }, + { + "json output", + cli.TestFlags(). + With(sdk.ValAddress(val[0].Address).String()). + WithHeight(3). + WithOutputJSON(), + false, + `{"commission":[]}`, + }, + { + "text output", + cli.TestFlags(). + With(sdk.ValAddress(val[0].Address).String()). + WithHeight(3). + WithOutputText(), + false, + `commission: []`, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetQueryDistributionValidatorCommissionCmd() + + out, err := clitestutil.ExecTestCLICmd(context.Background(), s.cctx, cmd, tc.args...) + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().Equal(tc.expectedOutput, strings.TrimSpace(out.String())) + } + }) + } +} + +func (s *DistributionCLITestSuite) TestGetCmdQueryValidatorSlashes() { + val := testutil.CreateKeyringAccounts(s.T(), s.kr, 1) + + testCases := []struct { + name string + args []string + expectErr bool + expectedOutput string + }{ + { + "invalid validator address", + cli.TestFlags(). + With( + "foo", + "1", + "3", + ). + WithHeight(3), + true, + "", + }, + { + "invalid start height", + cli.TestFlags(). + With( + sdk.ValAddress(val[0].Address).String(), + "-1", + "3", + ). + WithHeight(3), + true, + "", + }, + { + "invalid end height", + cli.TestFlags(). + With( + sdk.ValAddress(val[0].Address).String(), + "1", + "-3", + ). + WithHeight(3), + true, + "", + }, + { + "json output", + cli.TestFlags(). + With( + sdk.ValAddress(val[0].Address).String(), + "1", + "3", + ). + WithHeight(3). + WithOutputJSON(), + false, + "{\"slashes\":[],\"pagination\":null}", + }, + { + "text output", + cli.TestFlags(). + With( + sdk.ValAddress(val[0].Address).String(), + "1", + "3", + ). + WithHeight(3). + WithOutputText(), + false, + "pagination: null\nslashes: []", + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetQueryDistributionValidatorSlashesCmd() + + out, err := clitestutil.ExecTestCLICmd(context.Background(), s.cctx, cmd, tc.args...) + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().Equal(tc.expectedOutput, strings.TrimSpace(out.String())) + } + }) + } +} + +func (s *DistributionCLITestSuite) TestGetCmdQueryDelegatorRewards() { + val := testutil.CreateKeyringAccounts(s.T(), s.kr, 1) + addr := val[0].Address + valAddr := sdk.ValAddress(addr) + + testCases := []struct { + name string + args []string + expectErr bool + expectedOutput string + }{ + { + "invalid delegator address", + cli.TestFlags(). + With( + "foo", + valAddr.String(), + ). + WithHeight(5), + true, + "", + }, + { + "invalid validator address", + cli.TestFlags(). + With( + addr.String(), + "foo", + ). + WithHeight(5), + true, + "", + }, + { + "json output", + cli.TestFlags(). + With( + addr.String(), + ). + WithHeight(5). + WithOutputJSON(), + false, + `{"rewards":[],"total":[]}`, + }, + { + "json output (specific validator)", + cli.TestFlags(). + With( + addr.String(), + valAddr.String(), + ). + WithHeight(5). + WithOutputJSON(), + false, + `{"rewards":[]}`, + }, + { + "text output", + cli.TestFlags(). + With( + addr.String(), + ). + WithHeight(5). + WithOutputText(), + false, + `rewards: [] +total: []`, + }, + { + "text output (specific validator)", + cli.TestFlags(). + With( + addr.String(), + valAddr.String(), + ). + WithHeight(5). + WithOutputText(), + false, + `rewards: []`, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetQueryDistributionDelegatorRewardsCmd() + + out, err := clitestutil.ExecTestCLICmd(context.Background(), s.cctx, cmd, tc.args...) + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().Equal(tc.expectedOutput, strings.TrimSpace(out.String())) + } + }) + } +} + +func (s *DistributionCLITestSuite) TestGetCmdQueryCommunityPool() { + testCases := []struct { + name string + args []string + expectedOutput string + }{ + { + "json output", + cli.TestFlags(). + WithHeight(3). + WithOutputJSON(), + `{"pool":[]}`, + }, + { + "text output", + cli.TestFlags(). + WithHeight(3). + WithOutputText(), + `pool: []`, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetQueryDistributionCommunityPoolCmd() + + out, err := clitestutil.ExecTestCLICmd(context.Background(), s.cctx, cmd, tc.args...) + s.Require().NoError(err) + s.Require().Equal(tc.expectedOutput, strings.TrimSpace(out.String())) + }) + } +} + +func (s *DistributionCLITestSuite) TestNewWithdrawRewardsCmd() { + val := testutil.CreateKeyringAccounts(s.T(), s.kr, 1) + + testCases := []struct { + name string + args []string + expectErr bool + respType proto.Message + }{ + { + "invalid validator address", + cli.TestFlags(). + With( + val[0].Address.String(), + ). + WithFrom(val[0].Address.String()). + WithSkipConfirm(). + WithBroadcastModeSync(). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))), + true, nil, + }, + { + "valid transaction", + cli.TestFlags(). + With( + sdk.ValAddress(val[0].Address).String(), + ). + WithFrom(val[0].Address.String()). + WithSkipConfirm(). + WithBroadcastModeSync(). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))), + false, &sdk.TxResponse{}, + }, + { + "valid transaction (with commission)", + cli.TestFlags(). + With( + sdk.ValAddress(val[0].Address).String(), + ). + WithFrom(val[0].Address.String()). + WithSkipConfirm(). + WithBroadcastModeSync(). + WithCommission(). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))), + false, &sdk.TxResponse{}, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetTxDistributionWithdrawRewardsCmd() + + bz, err := clitestutil.ExecTestCLICmd(context.Background(), s.cctx, cmd, tc.args...) + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().NoError(s.cctx.Codec.UnmarshalJSON(bz.Bytes(), tc.respType), string(bz.Bytes())) + } + }) + } +} + +func (s *DistributionCLITestSuite) TestNewWithdrawAllRewardsCmd() { + val := testutil.CreateKeyringAccounts(s.T(), s.kr, 1) + + testCases := []struct { + name string + args []string + expectErr bool + expErrMsg string + respType proto.Message + }{ + { + "invalid transaction (offline)", + cli.TestFlags(). + WithFrom(val[0].Address.String()). + WithOffline(). + WithBroadcastModeSync(). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))), + true, + "cannot generate tx in offline mode", + nil, + }, + // { + // "valid transaction", + // cli.TestFlags(). + // WithFrom(val[0].Address.String()). + // WithSkipConfirm(). + // WithBroadcastModeSync(). + // WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))), + // false, "", &sdk.TxResponse{}, + // }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetTxDistributionWithdrawAllRewardsCmd() + out, err := clitestutil.ExecTestCLICmd(context.Background(), s.cctx, cmd, tc.args...) + if tc.expectErr { + s.Require().Error(err) + s.Require().Contains(err.Error(), tc.expErrMsg) + } else { + s.Require().NoError(err) + s.Require().NoError(s.cctx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + } + }) + } +} + +func (s *DistributionCLITestSuite) TestNewSetWithdrawAddrCmd() { + val := testutil.CreateKeyringAccounts(s.T(), s.kr, 1) + + testCases := []struct { + name string + args []string + expectErr bool + respType proto.Message + }{ + { + "invalid withdraw address", + cli.TestFlags(). + With("foo"). + WithFrom(val[0].Address.String()). + WithSkipConfirm(). + WithBroadcastModeSync(). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))), + true, nil, + }, + { + "valid transaction", + cli.TestFlags(). + With(val[0].Address.String()). + WithFrom(val[0].Address.String()). + WithSkipConfirm(). + WithBroadcastModeSync(). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))), + false, &sdk.TxResponse{}, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetTxDistributionSetWithdrawAddrCmd() + out, err := clitestutil.ExecTestCLICmd(context.Background(), s.cctx, cmd, tc.args...) + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().NoError(s.cctx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + } + }) + } +} + +func (s *DistributionCLITestSuite) TestNewFundCommunityPoolCmd() { + val := testutil.CreateKeyringAccounts(s.T(), s.kr, 1) + + testCases := []struct { + name string + args []string + expectErr bool + respType proto.Message + }{ + { + "invalid funding amount", + cli.TestFlags(). + With("-43foocoin"). + WithFrom(val[0].Address.String()). + WithSkipConfirm(). + WithBroadcastModeSync(). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))), + true, nil, + }, + { + "valid transaction", + cli.TestFlags(). + With(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(5431))).String()). + WithFrom(val[0].Address.String()). + WithSkipConfirm(). + WithBroadcastModeSync(). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))), + false, &sdk.TxResponse{}, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetTxDistributionFundCommunityPoolCmd() + + out, err := clitestutil.ExecTestCLICmd(context.Background(), s.cctx, cmd, tc.args...) + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().NoError(s.cctx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + } + }) + } +} + +func (s *DistributionCLITestSuite) TestNewWithdrawAllTokenizeShareRecordRewardCmd() { + val := testutil.CreateKeyringAccounts(s.T(), s.kr, 1) + + testCases := []struct { + name string + args []string + expectErr bool + expectedCode uint32 + respType proto.Message + }{ + { + "valid transaction of withdraw tokenize share record reward", + cli.TestFlags(). + WithFrom(val[0].Address.String()). + WithSkipConfirm(). + WithBroadcastModeSync(). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))), + false, 0, &sdk.TxResponse{}, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetTxDistributionWithdrawAllTokenizeShareRecordRewardCmd() + + out, err := clitestutil.ExecTestCLICmd(context.Background(), s.cctx, cmd, tc.args...) + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err, out.String()) + s.Require().NoError(s.cctx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + + txResp := tc.respType.(*sdk.TxResponse) + s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) + } + }) + } +} diff --git a/go/cli/distribution_tx.go b/go/cli/distribution_tx.go index ea502465..384590be 100644 --- a/go/cli/distribution_tx.go +++ b/go/cli/distribution_tx.go @@ -37,12 +37,12 @@ func getTxDistributionCmd() *cobra.Command { } cmd.AddCommand( - getTxDistributionWithdrawRewardsCmd(), - getTxDistributionWithdrawAllRewardsCmd(), - getTxDistributionSetWithdrawAddrCmd(), - getTxDistributionFundCommunityPoolCmd(), - getTxDistributionWithdrawTokenizeShareRecordRewardCmd(), - getTxDistributionWithdrawAllTokenizeShareRecordRewardCmd(), + GetTxDistributionWithdrawRewardsCmd(), + GetTxDistributionWithdrawAllRewardsCmd(), + GetTxDistributionSetWithdrawAddrCmd(), + GetTxDistributionFundCommunityPoolCmd(), + GetTxDistributionWithdrawTokenizeShareRecordRewardCmd(), + GetTxDistributionWithdrawAllTokenizeShareRecordRewardCmd(), ) return cmd @@ -81,8 +81,8 @@ func newSplitAndApply( return nil } -// getTxDistributionWithdrawRewardsCmd returns a CLI command handler for creating a MsgWithdrawDelegatorReward transaction. -func getTxDistributionWithdrawRewardsCmd() *cobra.Command { +// GetTxDistributionWithdrawRewardsCmd returns a CLI command handler for creating a MsgWithdrawDelegatorReward transaction. +func GetTxDistributionWithdrawRewardsCmd() *cobra.Command { bech32PrefixValAddr := sdk.GetConfig().GetBech32ValidatorAddrPrefix() cmd := &cobra.Command{ @@ -99,7 +99,8 @@ $ %s tx distribution withdraw-rewards %s1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj version.AppName, bech32PrefixValAddr, version.AppName, bech32PrefixValAddr, ), ), - Args: cobra.ExactArgs(1), + Args: cobra.ExactArgs(1), + PersistentPreRunE: TxPersistentPreRunE, RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() cl := MustClientFromContext(ctx) @@ -132,8 +133,8 @@ $ %s tx distribution withdraw-rewards %s1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj return cmd } -// getTxDistributionWithdrawAllRewardsCmd returns a CLI command handler for creating a MsgWithdrawDelegatorReward transaction. -func getTxDistributionWithdrawAllRewardsCmd() *cobra.Command { +// GetTxDistributionWithdrawAllRewardsCmd returns a CLI command handler for creating a MsgWithdrawDelegatorReward transaction. +func GetTxDistributionWithdrawAllRewardsCmd() *cobra.Command { cmd := &cobra.Command{ Use: "withdraw-all-rewards", Short: "withdraw all delegations rewards for a delegator", @@ -147,7 +148,8 @@ $ %[1]s tx distribution withdraw-all-rewards --from mykey version.AppName, flags.FlagBroadcastMode, flags.BroadcastSync, flags.BroadcastAsync, FlagMaxMessagesPerTx, ), ), - Args: cobra.NoArgs, + Args: cobra.NoArgs, + PersistentPreRunE: TxPersistentPreRunE, RunE: func(cmd *cobra.Command, _ []string) error { ctx := cmd.Context() cl := MustClientFromContext(ctx) @@ -161,7 +163,7 @@ $ %[1]s tx distribution withdraw-all-rewards --from mykey return fmt.Errorf("cannot generate tx in offline mode") } - delValsRes, err := cl.Query().Distribution().DelegatorValidators(cmd.Context(), &types.QueryDelegatorValidatorsRequest{DelegatorAddress: delAddr.String()}) + delValsRes, err := cl.Query().Distribution().DelegatorValidators(ctx, &types.QueryDelegatorValidatorsRequest{DelegatorAddress: delAddr.String()}) if err != nil { return err } @@ -191,8 +193,8 @@ $ %[1]s tx distribution withdraw-all-rewards --from mykey return cmd } -// getTxDistributionSetWithdrawAddrCmd returns a CLI command handler for creating a MsgSetWithdrawAddress transaction. -func getTxDistributionSetWithdrawAddrCmd() *cobra.Command { +// GetTxDistributionSetWithdrawAddrCmd returns a CLI command handler for creating a MsgSetWithdrawAddress transaction. +func GetTxDistributionSetWithdrawAddrCmd() *cobra.Command { bech32PrefixAccAddr := sdk.GetConfig().GetBech32AccountAddrPrefix() cmd := &cobra.Command{ @@ -207,7 +209,8 @@ $ %s tx distribution set-withdraw-addr %s1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p version.AppName, bech32PrefixAccAddr, ), ), - Args: cobra.ExactArgs(1), + Args: cobra.ExactArgs(1), + PersistentPreRunE: TxPersistentPreRunE, RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() cl := MustClientFromContext(ctx) @@ -235,8 +238,8 @@ $ %s tx distribution set-withdraw-addr %s1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p return cmd } -// getTxDistributionFundCommunityPoolCmd returns a CLI command handler for creating a MsgFundCommunityPool transaction. -func getTxDistributionFundCommunityPoolCmd() *cobra.Command { +// GetTxDistributionFundCommunityPoolCmd returns a CLI command handler for creating a MsgFundCommunityPool transaction. +func GetTxDistributionFundCommunityPoolCmd() *cobra.Command { cmd := &cobra.Command{ Use: "fund-community-pool [amount]", Args: cobra.ExactArgs(1), @@ -250,6 +253,7 @@ $ %s tx distribution fund-community-pool 100uatom --from mykey version.AppName, ), ), + PersistentPreRunE: TxPersistentPreRunE, RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() cl := MustClientFromContext(ctx) @@ -277,8 +281,8 @@ $ %s tx distribution fund-community-pool 100uatom --from mykey return cmd } -// WithdrawAllTokenizeShareRecordReward defines a method to withdraw reward for all owning TokenizeShareRecord -func getTxDistributionWithdrawAllTokenizeShareRecordRewardCmd() *cobra.Command { +// GetTxDistributionWithdrawAllTokenizeShareRecordRewardCmd defines a method to withdraw reward for all owning TokenizeShareRecord +func GetTxDistributionWithdrawAllTokenizeShareRecordRewardCmd() *cobra.Command { cmd := &cobra.Command{ Use: "withdraw-all-tokenize-share-rewards", Args: cobra.ExactArgs(0), @@ -292,6 +296,7 @@ $ %s tx distribution withdraw-tokenize-share-rewards --from mykey version.AppName, ), ), + PersistentPreRunE: TxPersistentPreRunE, RunE: func(cmd *cobra.Command, _ []string) error { ctx := cmd.Context() cl := MustClientFromContext(ctx) @@ -313,8 +318,8 @@ $ %s tx distribution withdraw-tokenize-share-rewards --from mykey return cmd } -// WithdrawTokenizeShareRecordReward defines a method to withdraw reward for an owning TokenizeShareRecord -func getTxDistributionWithdrawTokenizeShareRecordRewardCmd() *cobra.Command { +// GetTxDistributionWithdrawTokenizeShareRecordRewardCmd defines a method to withdraw reward for an owning TokenizeShareRecord +func GetTxDistributionWithdrawTokenizeShareRecordRewardCmd() *cobra.Command { cmd := &cobra.Command{ Use: "withdraw-tokenize-share-rewards", Args: cobra.ExactArgs(1), @@ -328,6 +333,7 @@ $ %s tx distribution withdraw-tokenize-share-rewards 1 --from mykey version.AppName, ), ), + PersistentPreRunE: TxPersistentPreRunE, RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() cl := MustClientFromContext(ctx) diff --git a/go/cli/distribution_tx_test.go b/go/cli/distribution_tx_test.go new file mode 100644 index 00000000..848aff59 --- /dev/null +++ b/go/cli/distribution_tx_test.go @@ -0,0 +1,57 @@ +package cli + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + cclient "pkg.akt.dev/go/node/client/v1beta3" + + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + "github.com/cosmos/cosmos-sdk/testutil/testdata" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func Test_splitAndCall_NoMessages(t *testing.T) { + // clientCtx := client.Context{} + + err := newSplitAndApply(nil, nil, nil, 10) + require.NoError(t, err, "") +} + +func Test_splitAndCall_Splitting(t *testing.T) { + addr := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) + + // Add five messages + msgs := []sdk.Msg{ + testdata.NewTestMsg(addr), + testdata.NewTestMsg(addr), + testdata.NewTestMsg(addr), + testdata.NewTestMsg(addr), + testdata.NewTestMsg(addr), + } + + // Keep track of number of calls + const chunkSize = 2 + + callCount := 0 + err := newSplitAndApply( + nil, + func(_ context.Context, msgs []sdk.Msg, _ ...cclient.BroadcastOption) (interface{}, error) { + callCount++ + + require.NotNil(t, msgs) + + if callCount < 3 { + require.Equal(t, len(msgs), 2) + } else { + require.Equal(t, len(msgs), 1) + } + + return nil, nil + }, + msgs, chunkSize) + + require.NoError(t, err, "") + require.Equal(t, 3, callCount) +} diff --git a/go/cli/evidence_query_test.go b/go/cli/evidence_query_test.go new file mode 100644 index 00000000..818958f8 --- /dev/null +++ b/go/cli/evidence_query_test.go @@ -0,0 +1,119 @@ +package cli_test + +import ( + "fmt" + "io" + "strings" + "testing" + + abci "github.com/cometbft/cometbft/abci/types" + rpcclientmock "github.com/cometbft/cometbft/rpc/client/mock" + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + sdk "github.com/cosmos/cosmos-sdk/types" + testutilmod "github.com/cosmos/cosmos-sdk/types/module/testutil" + "github.com/cosmos/cosmos-sdk/x/evidence" + + "pkg.akt.dev/go/cli" + cflags "pkg.akt.dev/go/cli/flags" +) + +func TestGetQueryCmd(t *testing.T) { + encCfg := testutilmod.MakeTestEncodingConfig(evidence.AppModuleBasic{}) + kr := keyring.NewInMemory(encCfg.Codec) + baseCtx := client.Context{}. + WithKeyring(kr). + WithTxConfig(encCfg.TxConfig). + WithCodec(encCfg.Codec). + WithLegacyAmino(encCfg.Amino). + WithClient(clitestutil.MockTendermintRPC{Client: rpcclientmock.Client{}}). + WithAccountRetriever(client.MockAccountRetriever{}). + WithOutput(io.Discard). + WithChainID("test-chain"). + WithSignModeStr(cflags.SignModeDirect) + + testCases := map[string]struct { + args []string + ctxGen func() client.Context + expCmdOutput string + expectedOutput string + expectErr bool + }{ + "non-existent evidence": { + cli.TestFlags(). + With("DF0C23E8634E480F84B9D5674A7CDC9816466DEC28A3358F73260F68D28D7660"), + func() client.Context { + bz, _ := encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := clitestutil.NewMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return baseCtx.WithClient(c) + }, + "DF0C23E8634E480F84B9D5674A7CDC9816466DEC28A3358F73260F68D28D7660", + "", + true, + }, + "all evidence (default pagination)": { + cli.TestFlags(). + WithOutputText(), + func() client.Context { + bz, _ := encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := clitestutil.NewMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return baseCtx.WithClient(c) + }, + "", + "evidence: []\npagination: null", + false, + }, + "all evidence (json output)": { + cli.TestFlags(). + WithOutputJSON(), + func() client.Context { + bz, _ := encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := clitestutil.NewMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return baseCtx.WithClient(c) + }, + "", + `{"evidence":[],"pagination":null}`, + false, + }, + } + + for name, tc := range testCases { + tc := tc + + t.Run(name, func(t *testing.T) { + cmd := cli.GetQueryEvidenceCmd() + + // var outBuf bytes.Buffer + // + // clientCtx := tc.ctxGen().WithOutput(&outBuf) + // ctx := svrcmd.CreateExecuteContext(context.Background()) + // + // cmd.SetContext(ctx) + // cmd.SetArgs(tc.args) + + // require.NoError(t, client.SetCmdClientContextHandler(clientCtx, cmd)) + + if len(tc.args) != 0 { + require.Contains(t, fmt.Sprint(cmd), tc.expCmdOutput) + } + + out, err := clitestutil.ExecTestCLICmd(tc.ctxGen(), cmd, tc.args) + if tc.expectErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + require.Contains(t, fmt.Sprint(cmd), "evidence [] [] Query for evidence by hash or for all (paginated) submitted evidence") + require.Contains(t, strings.TrimSpace(out.String()), tc.expectedOutput) + }) + } +} diff --git a/go/cli/feegrant_query_test.go b/go/cli/feegrant_query_test.go new file mode 100644 index 00000000..d2bad8c6 --- /dev/null +++ b/go/cli/feegrant_query_test.go @@ -0,0 +1,153 @@ +package cli_test + +import ( + "context" + "fmt" + + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/x/feegrant" + + "pkg.akt.dev/go/cli" + clitestutil "pkg.akt.dev/go/cli/testutil" +) + +func (s *FeegrantCLITestSuite) TestCmdGetFeeGrant() { + granter := s.addedGranter + grantee := s.addedGrantee + + testCases := []struct { + name string + args []string + expectErrMsg string + expectErr bool + respType *feegrant.QueryAllowanceResponse + resp *feegrant.Grant + }{ + { + "wrong granter", + []string{ + "wrong_granter", + grantee.String(), + fmt.Sprintf("--%s=json", flags.FlagOutput), + }, + "decoding bech32 failed", + true, nil, nil, + }, + { + "wrong grantee", + []string{ + granter.String(), + "wrong_grantee", + fmt.Sprintf("--%s=json", flags.FlagOutput), + }, + "decoding bech32 failed", + true, nil, nil, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetQueryFeeGrantCmd() + out, err := clitestutil.ExecTestCLICmd(context.Background(), s.cctx, cmd, tc.args...) + + if tc.expectErr { + s.Require().Error(err) + s.Require().Contains(err.Error(), tc.expectErrMsg) + } else { + s.Require().NoError(err) + s.Require().NoError(s.cctx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + } + }) + } +} + +func (s *FeegrantCLITestSuite) TestCmdGetFeeGrantsByGrantee() { + grantee := s.addedGrantee + cctx := s.cctx + + testCases := []struct { + name string + args []string + expectErr bool + resp *feegrant.QueryAllowancesResponse + expectLength int + }{ + { + "wrong grantee", + cli.TestFlags(). + With("wrong_grantee"). + WithOutputJSON(), + true, nil, 0, + }, + { + "valid req", + cli.TestFlags(). + With(grantee.String()). + WithOutputJSON(), + false, &feegrant.QueryAllowancesResponse{}, 1, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetQueryFeeGrantsByGranteeCmd() + + out, err := clitestutil.ExecTestCLICmd(context.Background(), cctx, cmd, tc.args...) + + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().NoError(cctx.Codec.UnmarshalJSON(out.Bytes(), tc.resp), out.String()) + } + }) + } +} + +func (s *FeegrantCLITestSuite) TestCmdGetFeeGrantsByGranter() { + granter := s.addedGranter + cctx := s.cctx + + testCases := []struct { + name string + args []string + expectErr bool + resp *feegrant.QueryAllowancesByGranterResponse + expectLength int + }{ + { + "wrong granter", + cli.TestFlags(). + With("wrong_granter"). + WithOutputJSON(), + true, nil, 0, + }, + { + "valid req", + cli.TestFlags(). + With(granter.String()). + WithOutputJSON(), + false, &feegrant.QueryAllowancesByGranterResponse{}, 1, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetQueryFeeGrantsByGranterCmd() + out, err := clitestutil.ExecTestCLICmd(context.Background(), cctx, cmd, tc.args...) + + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().NoError(cctx.Codec.UnmarshalJSON(out.Bytes(), tc.resp), out.String()) + } + }) + } +} diff --git a/go/cli/feegrant_suite_test.go b/go/cli/feegrant_suite_test.go new file mode 100644 index 00000000..63c61bd4 --- /dev/null +++ b/go/cli/feegrant_suite_test.go @@ -0,0 +1,81 @@ +package cli_test + +import ( + "bytes" + "io" + "testing" + + sdkmath "cosmossdk.io/math" + abci "github.com/cometbft/cometbft/abci/types" + rpcclientmock "github.com/cometbft/cometbft/rpc/client/mock" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + "github.com/cosmos/cosmos-sdk/testutil" + sdk "github.com/cosmos/cosmos-sdk/types" + testutilmod "github.com/cosmos/cosmos-sdk/types/module/testutil" + "github.com/cosmos/cosmos-sdk/x/feegrant" + "github.com/cosmos/cosmos-sdk/x/feegrant/module" + + cflags "pkg.akt.dev/go/cli/flags" + clitestutil "pkg.akt.dev/go/cli/testutil" +) + +type FeegrantCLITestSuite struct { + CLITestSuite + + addedGranter sdk.AccAddress + addedGrantee sdk.AccAddress + addedGrant feegrant.Grant + accounts []sdk.AccAddress +} + +func (s *FeegrantCLITestSuite) SetupSuite() { + s.encCfg = testutilmod.MakeTestEncodingConfig(module.AppModuleBasic{}) + s.kr = keyring.NewInMemory(s.encCfg.Codec) + s.baseCtx = client.Context{}. + WithKeyring(s.kr). + WithTxConfig(s.encCfg.TxConfig). + WithCodec(s.encCfg.Codec). + WithLegacyAmino(s.encCfg.Amino). + WithClient(clitestutil.MockTendermintRPC{Client: rpcclientmock.Client{}}). + WithAccountRetriever(client.MockAccountRetriever{}). + WithOutput(io.Discard). + WithChainID("test-chain"). + WithSignModeStr(cflags.SignModeDirect) + + var outBuf bytes.Buffer + ctxGen := func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := clitestutil.NewMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + + return s.baseCtx.WithClient(c) + } + s.cctx = ctxGen().WithOutput(&outBuf) + + if testing.Short() { + s.T().Skip("skipping test in unit-tests mode.") + } + + accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 2) + + granter := accounts[0].Address + grantee := accounts[1].Address + + s.createGrant(granter, grantee) + + grant, err := feegrant.NewGrant(granter, grantee, &feegrant.BasicAllowance{ + SpendLimit: sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(100))), + }) + s.Require().NoError(err) + + s.addedGrant = grant + s.addedGranter = granter + s.addedGrantee = grantee + for _, v := range accounts { + s.accounts = append(s.accounts, v.Address) + } + s.accounts[1] = accounts[1].Address +} + diff --git a/go/cli/feegrant_tx.go b/go/cli/feegrant_tx.go index 44478702..86086539 100644 --- a/go/cli/feegrant_tx.go +++ b/go/cli/feegrant_tx.go @@ -37,7 +37,7 @@ func GetTxFeegrantCmd() *cobra.Command { // GetTxFeegrantGrantCmd returns a CLI command handler for creating a MsgGrantAllowance transaction. func GetTxFeegrantGrantCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "grant [granter_key_or_address] [grantee]", + Use: "grant [grantee]", Short: "Grant Fee allowance to an address", Long: strings.TrimSpace( fmt.Sprintf( @@ -58,7 +58,7 @@ Examples: cl := MustClientFromContext(ctx) cctx := cl.ClientContext() - grantee, err := sdk.AccAddressFromBech32(args[1]) + grantee, err := sdk.AccAddressFromBech32(args[0]) if err != nil { return err } @@ -176,7 +176,7 @@ Examples: // GetTxFeegrantRevokeCmd returns a CLI command handler for creating a MsgRevokeAllowance transaction. func GetTxFeegrantRevokeCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "revoke [granter] [grantee]", + Use: "revoke [grantee]", Short: "revoke fee-grant", Long: strings.TrimSpace( fmt.Sprintf(`revoke fee grant from a granter to a grantee.. @@ -192,7 +192,7 @@ Example: cl := MustClientFromContext(ctx) cctx := cl.ClientContext() - grantee, err := sdk.AccAddressFromBech32(args[1]) + grantee, err := sdk.AccAddressFromBech32(args[0]) if err != nil { return err } diff --git a/go/cli/feegrant_tx_test.go b/go/cli/feegrant_tx_test.go new file mode 100644 index 00000000..623dceb9 --- /dev/null +++ b/go/cli/feegrant_tx_test.go @@ -0,0 +1,611 @@ +package cli_test + +import ( + "context" + "strings" + "time" + + sdkmath "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + sdk "github.com/cosmos/cosmos-sdk/types" + govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + "github.com/cosmos/gogoproto/proto" + + "pkg.akt.dev/go/cli" + cflags "pkg.akt.dev/go/cli/flags" + clitestutil "pkg.akt.dev/go/cli/testutil" +) + +const ( + oneYear = 365 * 24 * 60 * 60 + tenHours = 10 * 60 * 60 + oneHour = 60 * 60 +) + +// createGrant creates a new basic allowance fee grant from granter to grantee. +func (s *FeegrantCLITestSuite) createGrant(granter, grantee sdk.Address) { + args := cli.TestFlags(). + With( + grantee.String(), + ). + WithFrom(granter.String()). + WithSpendLimit(sdk.NewCoin("uakt", sdkmath.NewInt(100)).String()). + WithExpiration(getFormattedExpiration(oneYear)). + WithBroadcastModeSync(). + WithSkipConfirm(). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(100)))) + + cmd := cli.GetTxFeegrantGrantCmd() + out, err := clitestutil.ExecTestCLICmd(context.Background(), s.cctx, cmd, args...) + s.Require().NoError(err) + + var resp sdk.TxResponse + s.Require().NoError(s.cctx.Codec.UnmarshalJSON(out.Bytes(), &resp), out.String()) + s.Require().Equal(resp.Code, uint32(0)) +} + +func (s *FeegrantCLITestSuite) TestNewCmdFeeGrant() { + granter := s.accounts[0] + alreadyExistedGrantee := s.addedGrantee + cctx := s.cctx + + fromAddr, fromName, _, err := client.GetFromFields(s.baseCtx, s.kr, granter.String()) + s.Require().Equal(fromAddr, granter) + s.Require().NoError(err) + + commonArgs := cli.TestFlags(). + WithBroadcastModeSync(). + WithSkipConfirm(). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))) + + testCases := []struct { + name string + args []string + expectErr bool + expectedCode uint32 + respType proto.Message + }{ + { + "wrong grantee address", + cli.TestFlags(). + With( + granter.String(), + "wrong_grantee", + ). + WithFrom(granter.String()). + WithSpendLimit("100uakt"). + Append(commonArgs), + true, 0, nil, + }, + { + "wrong granter key name", + cli.TestFlags(). + With( + "akash16dun6ehcc86e03wreqqww89ey569wuj4em572w", + ). + WithFrom("invalid_granter"). + WithSpendLimit("100uakt"). + Append(commonArgs), + true, 0, nil, + }, + { + "valid basic fee grant", + cli.TestFlags(). + With( + "akash1nph3cfzk6trsmfxkeu943nvach5qw4vwas7t09", + ). + WithFrom(granter.String()). + WithSpendLimit("100uakt"). + Append(commonArgs), + false, 0, &sdk.TxResponse{}, + }, + { + "valid basic fee grant with granter key name", + cli.TestFlags(). + With( + "akash16dun6ehcc86e03wreqqww89ey569wuj45qeen5", + ). + WithFrom(fromName). + WithSpendLimit("100uakt"). + Append(commonArgs), + false, 0, &sdk.TxResponse{}, + }, + { + "valid basic fee grant with amino", + cli.TestFlags(). + With( + "akash1v57fx2l2rt6ehujuu99u2fw05779m5e23ac9nd", + ). + WithFrom(granter.String()). + WithSpendLimit("100uakt"). + WithSignMode(cflags.SignModeLegacyAminoJSON). + Append(commonArgs), + false, 0, &sdk.TxResponse{}, + }, + { + "valid basic fee grant without spend limit", + cli.TestFlags(). + With( + "akash17h5lzptx3ghvsuhk7wx4c4hnl7rsswxj5cgeqp", + ). + WithFrom(granter.String()). + Append(commonArgs), + false, 0, &sdk.TxResponse{}, + }, + { + "valid basic fee grant without expiration", + cli.TestFlags(). + With( + "akash16dlc38dcqt0uralyd8hksxyrny6kaeqflhlfcw", + ). + WithFrom(granter.String()). + WithSpendLimit("100uakt"). + Append(commonArgs), + false, 0, &sdk.TxResponse{}, + }, + { + "valid basic fee grant without spend-limit and expiration", + cli.TestFlags(). + With( + "akash1ku40qup9vwag4wtf8cls9mkszxfthakltdvkpa", + ). + WithFrom(granter.String()). + Append(commonArgs), + false, 0, &sdk.TxResponse{}, + }, + { + "try to add existed grant", + cli.TestFlags(). + With( + alreadyExistedGrantee.String(), + ). + WithFrom(granter.String()). + WithSpendLimit("100uakt"). + Append(commonArgs), + false, 18, &sdk.TxResponse{}, + }, + { + "invalid number of args(periodic fee grant)", + cli.TestFlags(). + With( + "akash1nph3cfzk6trsmfxkeu943nvach5qw4vwstnvkl", + ). + WithFrom(granter.String()). + WithSpendLimit("100uakt"). + WithPeriodLimit("10uakt"). + WithExpiration(getFormattedExpiration(tenHours)). + Append(commonArgs), + true, 0, nil, + }, + { + "period mentioned and period limit omitted, invalid periodic grant", + cli.TestFlags(). + With( + "akash1nph3cfzk6trsmfxkeu943nvach5qw4vwstnvkl", + ). + WithFrom(granter.String()). + WithSpendLimit("100uakt"). + WithPeriod(tenHours). + WithExpiration(getFormattedExpiration(tenHours)). + Append(commonArgs), + true, 0, nil, + }, + { + "period cannot be greater than the actual expiration(periodic fee grant)", + cli.TestFlags(). + With( + "akash1nph3cfzk6trsmfxkeu943nvach5qw4vwstnvkl", + ). + WithFrom(granter.String()). + WithSpendLimit("100uakt"). + WithPeriodLimit("10uakt"). + WithPeriod(tenHours). + WithExpiration(getFormattedExpiration(oneHour)). + Append(commonArgs), + true, 0, nil, + }, + { + "valid periodic fee grant", + cli.TestFlags(). + With( + "akash1nph3cfzk6trsmfxkeu943nvach5qw4vwas7t09", + ). + WithFrom(granter.String()). + WithSpendLimit("100uakt"). + WithPeriodLimit("10uakt"). + WithPeriod(oneHour). + WithExpiration(getFormattedExpiration(tenHours)). + Append(commonArgs), + false, 0, &sdk.TxResponse{}, + }, + { + "valid periodic fee grant without spend-limit", + cli.TestFlags(). + With( + "akash1vevyks8pthkscvgazc97qyfjt40m6g9x5ueyaa", + ). + WithFrom(granter.String()). + WithPeriodLimit("10uakt"). + WithPeriod(oneHour). + WithExpiration(getFormattedExpiration(tenHours)). + Append(commonArgs), + false, 0, &sdk.TxResponse{}, + }, + { + "valid periodic fee grant without expiration", + cli.TestFlags(). + With( + "akash1vevyks8pthkscvgazc97qyfjt40m6g9x5ueyaa", + ). + WithFrom(granter.String()). + WithSpendLimit("100uakt"). + WithPeriodLimit("10uakt"). + WithPeriod(oneHour). + Append(commonArgs), + false, 0, &sdk.TxResponse{}, + }, + { + "valid periodic fee grant without spend-limit and expiration", + cli.TestFlags(). + With( + "akash12nyk4pcf4arshznkpz882e4l4ts0lt0avu47d0", + ). + WithFrom(granter.String()). + WithPeriodLimit("10uakt"). + WithPeriod(oneHour). + Append(commonArgs), + false, 0, &sdk.TxResponse{}, + }, + { + "invalid expiration", + cli.TestFlags(). + With( + "akash1vevyks8pthkscvgazc97qyfjt40m6g9xe85ry8", + ). + WithFrom(granter.String()). + WithPeriodLimit("10uakt"). + WithPeriod(oneHour). + WithExpiration("invalid"). + Append(commonArgs), + true, 0, nil, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetTxFeegrantGrantCmd() + out, err := clitestutil.ExecTestCLICmd(context.Background(), cctx, cmd, tc.args...) + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().NoError(cctx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + } + }) + } +} + +func (s *FeegrantCLITestSuite) TestNewCmdRevokeFeegrant() { + granter := s.addedGranter + grantee := s.addedGrantee + cctx := s.cctx + + commonArgs := cli.TestFlags(). + WithBroadcastModeSync(). + WithSkipConfirm(). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))) + + // Create new fee grant specifically to test amino. + aminoGrantee, err := sdk.AccAddressFromBech32("akash16ydaqh0fcnh4qt7a3jme4mmztm2qel5atrvfk4") + s.Require().NoError(err) + s.createGrant(granter, aminoGrantee) + + testCases := []struct { + name string + args []string + expectErr bool + expectedCode uint32 + respType proto.Message + }{ + { + "invalid grantee", + cli.TestFlags(). + With( + grantee.String(), + ). + WithFrom("wrong_granter"). + Append(commonArgs), + true, 0, nil, + }, + { + "invalid grantee", + cli.TestFlags(). + With( + "wrong_grantee", + ). + WithFrom(granter.String()). + Append(commonArgs), + true, 0, nil, + }, + { + "Valid revoke", + cli.TestFlags(). + With( + grantee.String(), + ). + WithFrom(granter.String()). + Append(commonArgs), + false, 0, &sdk.TxResponse{}, + }, + { + "Valid revoke with amino", + cli.TestFlags(). + With( + aminoGrantee.String(), + ). + WithFrom(granter.String()). + WithSignMode(cflags.SignModeLegacyAminoJSON). + Append(commonArgs), + false, 0, &sdk.TxResponse{}, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetTxFeegrantRevokeCmd() + out, err := clitestutil.ExecTestCLICmd(context.Background(), cctx, cmd, tc.args...) + + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().NoError(cctx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + } + }) + } +} + +func (s *FeegrantCLITestSuite) TestTxWithFeeGrant() { + // s.T().Skip() // TODO to re-enable in #12274 + + cctx := s.cctx + granter := s.addedGranter + + // creating an account manually (This account won't be exist in state) + k, _, err := s.baseCtx.Keyring.NewMnemonic("grantee", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) + s.Require().NoError(err) + pub, err := k.GetPubKey() + s.Require().NoError(err) + grantee := sdk.AccAddress(pub.Address()) + fee := sdk.NewCoin("uakt", sdkmath.NewInt(100)) + + args := cli.TestFlags(). + With( + grantee.String(), + ). + WithFrom(granter.String()). + WithBroadcastModeSync(). + WithSkipConfirm(). + WithSpendLimit(fee.String()). + WithFees(sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(10)))). + WithExpiration(getFormattedExpiration(oneYear)) + + cmd := cli.GetTxFeegrantGrantCmd() + + var res sdk.TxResponse + out, err := clitestutil.ExecTestCLICmd(context.Background(), cctx, cmd, args...) + s.Require().NoError(err) + s.Require().NoError(cctx.Codec.UnmarshalJSON(out.Bytes(), &res), out.String()) + + testcases := []struct { + name string + flags []string + expErrCode uint32 + }{ + { + name: "granted fee allowance for an account which is not in state and creating any tx with it by using --fee-granter shouldn't fail", + flags: cli.TestFlags().WithFrom(grantee.String()).WithFeeGranter(granter), + }, + { + name: "--fee-payer should also sign the tx (direct)", + flags: cli.TestFlags().WithFrom(grantee.String()).WithFeePayer(granter), + expErrCode: 4, + }, + { + name: "--fee-payer should also sign the tx (amino-json)", + flags: cli.TestFlags().WithFrom(grantee.String()).WithFeePayer(granter).WithSignMode(cflags.SignModeLegacyAminoJSON), + expErrCode: 4, + }, + { + name: "use --fee-payer and --fee-granter together works", + flags: cli.TestFlags().WithFrom(grantee.String()).WithFeePayer(grantee).WithFeeGranter(granter), + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + cmd := cli.GetTxGovSubmitLegacyProposalCmd() + + pArgs := cli.TestFlags(). + WithTitle("Text Proposal"). + WithDescription("No desc"). + WithProposalType(govv1beta1.ProposalTypeText). + WithSkipConfirm(). + Append(tc.flags) + + _, err = clitestutil.ExecTestCLICmd(context.Background(), s.cctx, cmd, pArgs...) + s.Require().NoError(err) + + var resp sdk.TxResponse + s.Require().NoError(cctx.Codec.UnmarshalJSON(out.Bytes(), &resp), out.String()) + }) + } +} + +func (s *FeegrantCLITestSuite) TestFilteredFeeAllowance() { + granter := s.addedGranter + k, _, err := s.baseCtx.Keyring.NewMnemonic("grantee1", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) + s.Require().NoError(err) + pub, err := k.GetPubKey() + s.Require().NoError(err) + grantee := sdk.AccAddress(pub.Address()) + + cctx := s.cctx + + args := cli.TestFlags(). + WithBroadcastModeSync(). + WithSkipConfirm(). + WithFees(sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100)))) + + spendLimit := sdk.NewCoin("uakt", sdkmath.NewInt(1000)) + + allowMsgs := strings.Join([]string{sdk.MsgTypeURL(&govv1beta1.MsgSubmitProposal{}), sdk.MsgTypeURL(&govv1.MsgVoteWeighted{})}, ",") + + testCases := []struct { + name string + args []string + expectErr bool + respType proto.Message + expectedCode uint32 + }{ + { + "invalid granter address", + cli.TestFlags(). + With("akash1nph3cfzk6trsmfxkeu943nvach5qw4vwstnvkl"). + WithFrom("not an address"). + WithAllowedMsgs(allowMsgs). + WithSpendLimit(spendLimit.String()). + Append(args), + true, &sdk.TxResponse{}, 0, + }, + { + "invalid grantee address", + cli.TestFlags(). + With("not an address"). + WithFrom(granter.String()). + WithAllowedMsgs(allowMsgs). + WithSpendLimit(spendLimit.String()). + Append(args), + true, &sdk.TxResponse{}, 0, + }, + { + "valid filter fee grant", + cli.TestFlags(). + With(grantee.String()). + WithFrom(granter.String()). + WithAllowedMsgs(allowMsgs). + WithSpendLimit(spendLimit.String()). + Append(args), + false, &sdk.TxResponse{}, 0, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetTxFeegrantGrantCmd() + out, err := clitestutil.ExecTestCLICmd(context.Background(), cctx, cmd, tc.args...) + + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().NoError(cctx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + } + }) + } + + // exec filtered fee allowance + cases := []struct { + name string + malleate func() error + respType proto.Message + expectedCode uint32 + }{ + { + "valid proposal tx", + func() error { + cmd := cli.GetTxGovSubmitLegacyProposalCmd() + + pArgs := cli.TestFlags(). + WithTitle("Text Proposal"). + WithDescription("No desc"). + WithProposalType(govv1beta1.ProposalTypeText). + WithFeeGranter(granter). + WithFrom(grantee.String()). + Append(args) + + out, err := clitestutil.ExecTestCLICmd(context.Background(), s.cctx, cmd, pArgs...) + s.Require().NoError(err) + var resp sdk.TxResponse + s.Require().NoError(cctx.Codec.UnmarshalJSON(out.Bytes(), &resp), out.String()) + + return err + }, + &sdk.TxResponse{}, + 0, + }, + { + "valid weighted_vote tx", + func() error { + sArgs := cli.TestFlags(). + With( + "0", + "yes", + ). + WithFrom(grantee.String()). + Append(args) + + cmd := cli.GetTxGovWeightedVoteCmd() + + out, err := clitestutil.ExecTestCLICmd(context.Background(), cctx, cmd, sArgs...) + + s.Require().NoError(cctx.Codec.UnmarshalJSON(out.Bytes(), &sdk.TxResponse{}), out.String()) + + return err + }, + &sdk.TxResponse{}, + 2, + }, + { + "should fail with unauthorized msgs", + func() error { + sArgs := cli.TestFlags(). + With("akash14cm33pvnrv2497tyt8sp9yavhmw83nwel2kgqa"). + WithFrom(grantee.String()). + WithSpendLimit("100uakt"). + WithFeeGranter(granter). + Append(args) + + cmd := cli.GetTxFeegrantGrantCmd() + out, err := clitestutil.ExecTestCLICmd(context.Background(), cctx, cmd, sArgs...) + s.Require().NoError(cctx.Codec.UnmarshalJSON(out.Bytes(), &sdk.TxResponse{}), out.String()) + + return err + }, + &sdk.TxResponse{}, + 7, + }, + } + + for _, tc := range cases { + tc := tc + + s.Run(tc.name, func() { + err := tc.malleate() + s.Require().NoError(err) + }) + } +} + +func getFormattedExpiration(duration int64) string { + return time.Now().Add(time.Duration(duration) * time.Second).Format(time.RFC3339) +} diff --git a/go/cli/flags/flags.go b/go/cli/flags/flags.go index f306e82f..d3984998 100644 --- a/go/cli/flags/flags.go +++ b/go/cli/flags/flags.go @@ -163,6 +163,7 @@ const ( FlagSecurityContact = "security-contact" FlagDetails = "details" + FlagCommission = "commission" FlagCommissionRate = "commission-rate" FlagCommissionMaxRate = "commission-max-rate" FlagCommissionMaxChangeRate = "commission-max-change-rate" diff --git a/go/cli/gentxs.go b/go/cli/gentxs.go deleted file mode 100644 index 7f1e458c..00000000 --- a/go/cli/gentxs.go +++ /dev/null @@ -1 +0,0 @@ -package cli diff --git a/go/cli/gov_suite_test.go b/go/cli/gov_suite_test.go index b438372d..aab6b6fc 100644 --- a/go/cli/gov_suite_test.go +++ b/go/cli/gov_suite_test.go @@ -2,7 +2,7 @@ package cli_test import ( "bytes" - "fmt" + "context" "io" abci "github.com/cometbft/cometbft/abci/types" @@ -10,14 +10,14 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/testutil" - clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" sdk "github.com/cosmos/cosmos-sdk/types" testutilmod "github.com/cosmos/cosmos-sdk/types/module/testutil" "github.com/cosmos/cosmos-sdk/x/gov" - "github.com/cosmos/cosmos-sdk/x/gov/client/cli" - govclitestutil "github.com/cosmos/cosmos-sdk/x/gov/client/testutil" - v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + + "pkg.akt.dev/go/cli" + cflags "pkg.akt.dev/go/cli/flags" + clitestutil "pkg.akt.dev/go/cli/testutil" ) type GovCLITestSuite struct { @@ -35,7 +35,8 @@ func (s *GovCLITestSuite) SetupSuite() { WithClient(clitestutil.MockTendermintRPC{Client: rpcclientmock.Client{}}). WithAccountRetriever(client.MockAccountRetriever{}). WithOutput(io.Discard). - WithChainID("test-chain") + WithChainID("test-chain"). + WithSignModeStr(cflags.SignModeDirect) var outBuf bytes.Buffer ctxGen := func() client.Context { @@ -50,27 +51,86 @@ func (s *GovCLITestSuite) SetupSuite() { val := testutil.CreateKeyringAccounts(s.T(), s.kr, 1) // create a proposal with deposit - _, err := govclitestutil.MsgSubmitLegacyProposal(s.cctx, val[0].Address.String(), - "Text Proposal 1", "Where is the title!?", v1beta1.ProposalTypeText, - fmt.Sprintf("--%s=%s", cli.FlagDeposit, sdk.NewCoin("uakt", v1.DefaultMinDepositTokens).String())) + cmd := cli.GetTxGovSubmitLegacyProposalCmd() + + _, err := clitestutil.ExecTestCLICmd( + context.Background(), + s.cctx, + cmd, + cli.TestFlags(). + WithFrom(val[0].Address.String()). + WithTitle("Text Proposal 1"). + WithDescription("Where is the title!?"). + WithProposalType(v1beta1.ProposalTypeText). + WithDeposit(sdk.NewCoin("uakt", cli.DefaultMinDepositTokens)). + WithBroadcastModeSync(). + WithSkipConfirm()...) s.Require().NoError(err) // vote for proposal - _, err = govclitestutil.MsgVote(s.cctx, val[0].Address.String(), "1", "yes") + cmd = cli.GetTxGovVoteCmd() + + _, err = clitestutil.ExecTestCLICmd( + context.Background(), + s.cctx, + cmd, + cli.TestFlags(). + With( + "1", + "yes", + ). + WithFrom(val[0].Address.String()). + WithBroadcastModeSync(). + WithSkipConfirm()...) s.Require().NoError(err) // create a proposal without deposit - _, err = govclitestutil.MsgSubmitLegacyProposal(s.cctx, val[0].Address.String(), - "Text Proposal 2", "Where is the title!?", v1beta1.ProposalTypeText) + cmd = cli.GetTxGovSubmitLegacyProposalCmd() + + _, err = clitestutil.ExecTestCLICmd( + context.Background(), + s.cctx, + cmd, + cli.TestFlags(). + WithFrom(val[0].Address.String()). + WithTitle("Text Proposal 2"). + WithDescription("Where is the title!?"). + WithProposalType(v1beta1.ProposalTypeText). + WithBroadcastModeSync(). + WithSkipConfirm()...) s.Require().NoError(err) // create a proposal3 with deposit - _, err = govclitestutil.MsgSubmitLegacyProposal(s.cctx, val[0].Address.String(), - "Text Proposal 3", "Where is the title!?", v1beta1.ProposalTypeText, - fmt.Sprintf("--%s=%s", cli.FlagDeposit, sdk.NewCoin("uakt", v1.DefaultMinDepositTokens).String())) + cmd = cli.GetTxGovSubmitLegacyProposalCmd() + + _, err = clitestutil.ExecTestCLICmd( + context.Background(), + s.cctx, + cmd, + cli.TestFlags(). + WithFrom(val[0].Address.String()). + WithTitle("Text Proposal 3"). + WithDescription("Where is the title!?"). + WithProposalType(v1beta1.ProposalTypeText). + WithDeposit(sdk.NewCoin("uakt", cli.DefaultMinDepositTokens)). + WithBroadcastModeSync(). + WithSkipConfirm()...) s.Require().NoError(err) // vote for proposal3 as val - _, err = govclitestutil.MsgVote(s.cctx, val[0].Address.String(), "3", "yes=0.6,no=0.3,abstain=0.05,no_with_veto=0.05") + cmd = cli.GetTxGovWeightedVoteCmd() + + _, err = clitestutil.ExecTestCLICmd( + context.Background(), + s.cctx, + cmd, + cli.TestFlags(). + With( + "3", + "yes=0.6,no=0.3,abstain=0.05,no_with_veto=0.05", + ). + WithFrom(val[0].Address.String()). + WithBroadcastModeSync(). + WithSkipConfirm()...) s.Require().NoError(err) } diff --git a/go/cli/mint_query_test.go b/go/cli/mint_query_test.go new file mode 100644 index 00000000..1f3d0340 --- /dev/null +++ b/go/cli/mint_query_test.go @@ -0,0 +1,187 @@ +package cli_test + +import ( + "context" + "fmt" + "io" + "strings" + "testing" + + rpcclientmock "github.com/cometbft/cometbft/rpc/client/mock" + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + testutilmod "github.com/cosmos/cosmos-sdk/types/module/testutil" + "github.com/cosmos/cosmos-sdk/x/mint" + + "pkg.akt.dev/go/cli" + clitestutil "pkg.akt.dev/go/cli/testutil" +) + +func TestGetQueryMintParamsCmd(t *testing.T) { + encCfg := testutilmod.MakeTestEncodingConfig(mint.AppModuleBasic{}) + kr := keyring.NewInMemory(encCfg.Codec) + baseCtx := client.Context{}. + WithKeyring(kr). + WithTxConfig(encCfg.TxConfig). + WithCodec(encCfg.Codec). + WithClient(clitestutil.MockTendermintRPC{Client: rpcclientmock.Client{}}). + WithAccountRetriever(client.MockAccountRetriever{}). + WithOutput(io.Discard). + WithChainID("test-chain") + + testCases := []struct { + name string + flagArgs []string + expCmdOutput string + expectedOutput string + }{ + { + "json output", + cli.TestFlags(). + WithHeight(1). + WithOutputJSON(), + `[--height=1 --output=json]`, + `{"mint_denom":"","inflation_rate_change":"0","inflation_max":"0","inflation_min":"0","goal_bonded":"0","blocks_per_year":"0"}`, + }, + { + "text output", + cli.TestFlags(). + WithHeight(1). + WithOutputText(), + `[--height=1 --output=text]`, + `blocks_per_year: "0" +goal_bonded: "0" +inflation_max: "0" +inflation_min: "0" +inflation_rate_change: "0" +mint_denom: ""`, + }, + } + + for _, tc := range testCases { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + cmd := cli.GetQueryMintParamsCmd() + + out, err := clitestutil.ExecTestCLICmd(context.Background(), baseCtx, cmd, tc.flagArgs...) + require.NoError(t, err) + require.Equal(t, tc.expectedOutput, strings.TrimSpace(out.String())) + + if len(tc.flagArgs) != 0 { + require.Contains(t, fmt.Sprint(cmd), "params [] [] Query the current minting parameters") + require.Contains(t, fmt.Sprint(cmd), tc.expCmdOutput) + } + }) + } +} + +func TestGetQueryMintInflationCmd(t *testing.T) { + encCfg := testutilmod.MakeTestEncodingConfig(mint.AppModuleBasic{}) + kr := keyring.NewInMemory(encCfg.Codec) + baseCtx := client.Context{}. + WithKeyring(kr). + WithTxConfig(encCfg.TxConfig). + WithCodec(encCfg.Codec). + WithClient(clitestutil.MockTendermintRPC{Client: rpcclientmock.Client{}}). + WithAccountRetriever(client.MockAccountRetriever{}). + WithOutput(io.Discard). + WithChainID("test-chain") + + testCases := []struct { + name string + flagArgs []string + expCmdOutput string + expectedOutput string + }{ + { + "json output", + cli.TestFlags(). + WithHeight(1). + WithOutputJSON(), + `[--height=1 --output=json]`, + ``, + }, + { + "text output", + cli.TestFlags(). + WithHeight(1). + WithOutputText(), + `[--height=1 --output=text]`, + ``, + }, + } + + for _, tc := range testCases { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + cmd := cli.GetQueryMintInflationCmd() + + out, err := clitestutil.ExecTestCLICmd(context.Background(), baseCtx, cmd, tc.flagArgs...) + require.NoError(t, err) + require.Equal(t, tc.expectedOutput, strings.TrimSpace(out.String())) + + if len(tc.flagArgs) != 0 { + require.Contains(t, fmt.Sprint(cmd), "inflation [] [] Query the current minting inflation value") + require.Contains(t, fmt.Sprint(cmd), tc.expCmdOutput) + } + }) + } +} + +func TestGetCmdQueryAnnualProvisions(t *testing.T) { + encCfg := testutilmod.MakeTestEncodingConfig(mint.AppModuleBasic{}) + kr := keyring.NewInMemory(encCfg.Codec) + baseCtx := client.Context{}. + WithKeyring(kr). + WithTxConfig(encCfg.TxConfig). + WithCodec(encCfg.Codec). + WithClient(clitestutil.MockTendermintRPC{Client: rpcclientmock.Client{}}). + WithAccountRetriever(client.MockAccountRetriever{}). + WithOutput(io.Discard). + WithChainID("test-chain") + + testCases := []struct { + name string + flagArgs []string + expCmdOutput string + expectedOutput string + }{ + { + "json output", + cli.TestFlags(). + WithHeight(1). + WithOutputJSON(), + `[--height=1 --output=json]`, + ``, + }, + { + "text output", + cli.TestFlags(). + WithHeight(1). + WithOutputText(), + `[--height=1 --output=text]`, + ``, + }, + } + + for _, tc := range testCases { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + cmd := cli.GetQueryMintAnnualProvisionsCmd() + + out, err := clitestutil.ExecTestCLICmd(context.Background(), baseCtx, cmd, tc.flagArgs...) + require.NoError(t, err) + require.Equal(t, tc.expectedOutput, strings.TrimSpace(out.String())) + + if len(tc.flagArgs) != 0 { + require.Contains(t, fmt.Sprint(cmd), "annual-provisions [] [] Query the current minting annual provisions value") + require.Contains(t, fmt.Sprint(cmd), tc.expCmdOutput) + } + }) + } +} diff --git a/go/cli/params_tx_test.go b/go/cli/params_tx_test.go new file mode 100644 index 00000000..1e50b397 --- /dev/null +++ b/go/cli/params_tx_test.go @@ -0,0 +1,42 @@ +package cli + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/testutil" + "github.com/cosmos/cosmos-sdk/x/params/client/utils" +) + +func TestParamsParseProposal(t *testing.T) { + cdc := codec.NewLegacyAmino() + okJSON := testutil.WriteToNewTempFile(t, ` +{ + "title": "Staking Param Change", + "description": "Update max validators", + "changes": [ + { + "subspace": "staking", + "key": "MaxValidators", + "value": 1 + } + ], + "deposit": "1000stake" +} +`) + proposal, err := utils.ParseParamChangeProposalJSON(cdc, okJSON.Name()) + require.NoError(t, err) + + require.Equal(t, "Staking Param Change", proposal.Title) + require.Equal(t, "Update max validators", proposal.Description) + require.Equal(t, "1000stake", proposal.Deposit) + require.Equal(t, utils.ParamChangesJSON{ + { + Subspace: "staking", + Key: "MaxValidators", + Value: []byte{0x31}, + }, + }, proposal.Changes) +} diff --git a/go/cli/slashing_query_test.go b/go/cli/slashing_query_test.go new file mode 100644 index 00000000..ee3ebc58 --- /dev/null +++ b/go/cli/slashing_query_test.go @@ -0,0 +1,140 @@ +package cli_test + +import ( + "bytes" + "context" + "io" + + abci "github.com/cometbft/cometbft/abci/types" + rpcclientmock "github.com/cometbft/cometbft/rpc/client/mock" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + testutilmod "github.com/cosmos/cosmos-sdk/types/module/testutil" + "github.com/cosmos/cosmos-sdk/x/nft/module" + + "pkg.akt.dev/go/cli" + cflags "pkg.akt.dev/go/cli/flags" + clitestutil "pkg.akt.dev/go/cli/testutil" +) + +type SlashingCLITestSuite struct { + CLITestSuite + + pub types.PubKey + addr sdk.AccAddress +} + +func (s *SlashingCLITestSuite) SetupSuite() { + s.encCfg = testutilmod.MakeTestEncodingConfig(module.AppModuleBasic{}) + s.kr = keyring.NewInMemory(s.encCfg.Codec) + s.baseCtx = client.Context{}. + WithKeyring(s.kr). + WithTxConfig(s.encCfg.TxConfig). + WithCodec(s.encCfg.Codec). + WithLegacyAmino(s.encCfg.Amino). + WithClient(clitestutil.MockTendermintRPC{Client: rpcclientmock.Client{}}). + WithAccountRetriever(client.MockAccountRetriever{}). + WithOutput(io.Discard). + WithChainID("test-chain"). + WithSignModeStr(cflags.SignModeDirect) + + var outBuf bytes.Buffer + ctxGen := func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := clitestutil.NewMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + + return s.baseCtx.WithClient(c) + } + s.cctx = ctxGen().WithOutput(&outBuf) + + k, _, err := s.cctx.Keyring.NewMnemonic("NewValidator", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) + s.Require().NoError(err) + + pub, err := k.GetPubKey() + s.Require().NoError(err) + + s.pub = pub + s.addr = sdk.AccAddress(pub.Address()) +} + +func (s *SlashingCLITestSuite) TestGetCmdQuerySigningInfo() { + pubKeyBz, err := s.encCfg.Codec.MarshalInterfaceJSON(s.pub) + s.Require().NoError(err) + pubKeyStr := string(pubKeyBz) + + testCases := []struct { + name string + args []string + expectErr bool + }{ + {"invalid address", []string{"foo"}, true}, + { + "valid address (json output)", + cli.TestFlags(). + With(pubKeyStr). + WithHeight(1). + WithOutputJSON(), + false, + }, + { + "valid address (text output)", + cli.TestFlags(). + With(pubKeyStr). + WithHeight(1). + WithOutputText(), + false, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetQuerySlashingSigningInfoCmd() + cctx := s.cctx + + _, err := clitestutil.ExecTestCLICmd(context.Background(), cctx, cmd, tc.args...) + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + } + }) + } +} + +func (s *SlashingCLITestSuite) TestGetCmdQueryParams() { + testCases := []struct { + name string + args []string + }{ + { + "json output", + cli.TestFlags(). + WithOutputJSON(), + }, + { + "text output", + cli.TestFlags(). + WithOutputText(), + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetQuerySlashingParamsCmd() + cctx := s.cctx + + _, err := clitestutil.ExecTestCLICmd(context.Background(), cctx, cmd, tc.args...) + s.Require().NoError(err) + }) + } +} diff --git a/go/cli/slashing_tx.go b/go/cli/slashing_tx.go index 22329ba2..82e35f74 100644 --- a/go/cli/slashing_tx.go +++ b/go/cli/slashing_tx.go @@ -20,12 +20,15 @@ func GetTxSlashingCmd() *cobra.Command { RunE: client.ValidateCmd, } - slashingTxCmd.AddCommand(getTxSlashingUnjailCmd()) + slashingTxCmd.AddCommand( + GetTxSlashingUnjailCmd(), + ) + return slashingTxCmd } -// getTxSlashingUnjailCmd returns a CLI command handler for creating a MsgUnjail transaction. -func getTxSlashingUnjailCmd() *cobra.Command { +// GetTxSlashingUnjailCmd returns a CLI command handler for creating a MsgUnjail transaction. +func GetTxSlashingUnjailCmd() *cobra.Command { cmd := &cobra.Command{ Use: "unjail", Args: cobra.NoArgs, diff --git a/go/cli/slashing_tx_test.go b/go/cli/slashing_tx_test.go new file mode 100644 index 00000000..01d3f6a6 --- /dev/null +++ b/go/cli/slashing_tx_test.go @@ -0,0 +1,54 @@ +package cli_test + +import ( + "context" + + sdkmath "cosmossdk.io/math" + "github.com/cosmos/gogoproto/proto" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "pkg.akt.dev/go/cli" + clitestutil "pkg.akt.dev/go/cli/testutil" +) + +func (s *SlashingCLITestSuite) TestNewUnjailTxCmd() { + val := s.addr + testCases := []struct { + name string + args []string + expectErr bool + expectedCode uint32 + respType proto.Message + }{ + { + "valid transaction", + cli.TestFlags(). + WithFrom(val.String()). + WithSkipConfirm(). + WithBroadcastModeSync(). + WithFees(sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10)))), + false, 0, &sdk.TxResponse{}, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetTxSlashingUnjailCmd() + cctx := s.cctx + + out, err := clitestutil.ExecTestCLICmd(context.Background(), cctx, cmd, tc.args...) + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().NoError(cctx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + + txResp := tc.respType.(*sdk.TxResponse) + s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) + } + }) + } +} diff --git a/go/cli/staking_query_test.go b/go/cli/staking_query_test.go new file mode 100644 index 00000000..03c936b2 --- /dev/null +++ b/go/cli/staking_query_test.go @@ -0,0 +1,590 @@ +package cli_test + +import ( + "context" + "fmt" + "strings" + + "github.com/cosmos/gogoproto/proto" + + "github.com/cosmos/cosmos-sdk/client/flags" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/staking/types" + + "pkg.akt.dev/go/cli" + clitestutil "pkg.akt.dev/go/cli/testutil" +) + +func (s *StakingCLITestSuite) TestGetCmdQueryValidator() { + testCases := []struct { + name string + args []string + expectErr bool + }{ + { + "with invalid address ", + cli.TestFlags(). + With("bla"). + WithOutputJSON(), + true, + }, + { + "happy case", + cli.TestFlags(). + With(sdk.ValAddress(s.addrs[0]).String()). + WithOutputJSON(), + false, + }, + } + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + cmd := cli.GetQueryStakingValidatorCmd() + cctx := s.cctx + out, err := clitestutil.ExecTestCLICmd(context.Background(), cctx, cmd, tc.args...) + if tc.expectErr { + s.Require().Error(err) + s.Require().NotEqual("internal", err.Error()) + } else { + var result types.Validator + s.Require().NoError(cctx.Codec.UnmarshalJSON(out.Bytes(), &result)) + } + }) + } +} + +func (s *StakingCLITestSuite) TestGetCmdQueryValidators() { + testCases := []struct { + name string + args []string + minValidatorCount int + }{ + { + "one validator case", + cli.TestFlags(). + WithLimit(1). + WithOutputJSON(), + 1, + }, + { + "multi validator case", + cli.TestFlags(). + WithOutputJSON(), + 0, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetQueryStakingValidatorsCmd() + cctx := s.cctx + + out, err := clitestutil.ExecTestCLICmd(context.Background(), cctx, cmd, tc.args...) + s.Require().NoError(err) + + var result types.QueryValidatorsResponse + s.Require().NoError(cctx.Codec.UnmarshalJSON(out.Bytes(), &result)) + }) + } +} + +func (s *StakingCLITestSuite) TestGetCmdQueryDelegation() { + testCases := []struct { + name string + args []string + expErr bool + respType proto.Message + }{ + { + "with wrong delegator address", + cli.TestFlags(). + With( + "wrongDelAddr", + s.addrs[1].String(), + ). + WithOutputJSON(), + true, nil, + }, + { + "with wrong validator address", + cli.TestFlags(). + With( + s.addrs[0].String(), + "wrongDelAddr", + ). + WithOutputJSON(), + true, nil, + }, + { + "with json output", + cli.TestFlags(). + With( + s.addrs[0].String(), + sdk.ValAddress(s.addrs[1]).String(), + ). + WithOutputJSON(), + false, + &types.DelegationResponse{}, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + cmd := cli.GetQueryStakingDelegationCmd() + cctx := s.cctx + + _, err := clitestutil.ExecTestCLICmd(context.Background(), cctx, cmd, tc.args...) + if tc.expErr { + s.Require().Error(err) + } else { + s.Require().Contains(err.Error(), "Marshal called with nil") + } + }) + } +} + +func (s *StakingCLITestSuite) TestGetCmdQueryDelegations() { + testCases := []struct { + name string + args []string + expErr bool + respType proto.Message + }{ + { + "with no delegator address", + []string{}, + true, nil, + }, + { + "with wrong delegator address", + cli.TestFlags(). + With("wrongDelAddr"), + true, nil, + }, + { + "valid request (height specific)", + cli.TestFlags(). + With( + s.addrs[0].String(), + ). + WithOutputJSON(). + WithHeight(1), + false, + &types.QueryDelegatorDelegationsResponse{}, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + cmd := cli.GetQueryStakingDelegationsCmd() + cctx := s.cctx + + out, err := clitestutil.ExecTestCLICmd(context.Background(), cctx, cmd, tc.args...) + if tc.expErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().NoError(cctx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + } + }) + } +} + +func (s *StakingCLITestSuite) TestGetCmdQueryValidatorDelegations() { + testCases := []struct { + name string + args []string + expErr bool + respType proto.Message + }{ + { + "with no validator address", + []string{}, + true, nil, + }, + { + "wrong validator address", + cli.TestFlags(). + With("wrongDelAddr"), + true, nil, + }, + { + "valid request(height specific)", + cli.TestFlags(). + With( + s.addrs[0].String(), + ). + WithOutputJSON(). + WithHeight(1), + false, + &types.QueryValidatorDelegationsResponse{}, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + cmd := cli.GetQueryStakingDelegationsCmd() + cctx := s.cctx + + out, err := clitestutil.ExecTestCLICmd(context.Background(), cctx, cmd, tc.args...) + if tc.expErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().NoError(cctx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + } + }) + } +} + +func (s *StakingCLITestSuite) TestGetCmdQueryUnbondingDelegations() { + testCases := []struct { + name string + args []string + expErr bool + }{ + { + "wrong delegator address", + cli.TestFlags(). + With( + "wrongDelAddr", + ). + WithOutputJSON(), + true, + }, + { + "valid request", + cli.TestFlags(). + With( + s.addrs[0].String(), + ). + WithOutputJSON(), + false, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + cmd := cli.GetQueryStakingUnbondingDelegationsCmd() + cctx := s.cctx + + out, err := clitestutil.ExecTestCLICmd(context.Background(), cctx, cmd, tc.args...) + + if tc.expErr { + s.Require().Error(err) + } else { + var ubds types.QueryDelegatorUnbondingDelegationsResponse + err = s.cctx.Codec.UnmarshalJSON(out.Bytes(), &ubds) + + s.Require().NoError(err) + } + }) + } +} + +func (s *StakingCLITestSuite) TestGetCmdQueryUnbondingDelegation() { + testCases := []struct { + name string + args []string + expErr bool + }{ + { + "wrong delegator address", + cli.TestFlags(). + With( + "wrongDelAddr", + s.addrs[0].String(), + ). + WithOutputJSON(), + true, + }, + { + "wrong validator address", + cli.TestFlags(). + With( + s.addrs[0].String(), + "wrongValAddr", + ). + WithOutputJSON(), + true, + }, + { + "valid request", + cli.TestFlags(). + With( + s.addrs[0].String(), + sdk.ValAddress(s.addrs[1]).String(), + ). + WithOutputJSON(), + false, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + cmd := cli.GetQueryStakingUnbondingDelegationCmd() + cctx := s.cctx + + out, err := clitestutil.ExecTestCLICmd(context.Background(), cctx, cmd, tc.args...) + + if tc.expErr { + s.Require().Error(err) + } else { + var ubd types.UnbondingDelegation + + err = s.cctx.Codec.UnmarshalJSON(out.Bytes(), &ubd) + s.Require().NoError(err) + } + }) + } +} + +func (s *StakingCLITestSuite) TestGetCmdQueryValidatorUnbondingDelegations() { + testCases := []struct { + name string + args []string + expErr bool + }{ + { + "wrong validator address", + cli.TestFlags(). + With( + "wrongValAddr", + ). + WithOutputJSON(), + true, + }, + { + "valid request", + cli.TestFlags(). + With( + sdk.ValAddress(s.addrs[0]).String(), + ). + WithOutputJSON(), + false, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + cmd := cli.GetQueryStakingValidatorUnbondingDelegationsCmd() + cctx := s.cctx + + out, err := clitestutil.ExecTestCLICmd(context.Background(), cctx, cmd, tc.args...) + + if tc.expErr { + s.Require().Error(err) + } else { + var ubds types.QueryValidatorUnbondingDelegationsResponse + err = s.cctx.Codec.UnmarshalJSON(out.Bytes(), &ubds) + s.Require().NoError(err) + } + }) + } +} + +func (s *StakingCLITestSuite) TestGetCmdQueryRedelegations() { + testCases := []struct { + name string + args []string + expErr bool + }{ + { + "wrong delegator address", + cli.TestFlags(). + With( + "wrongdeladdr", + ). + WithOutputJSON(), + true, + }, + { + "valid request", + cli.TestFlags(). + With( + s.addrs[0].String(), + ). + WithOutputJSON(), + false, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + cmd := cli.GetQueryStakingRedelegationsCmd() + cctx := s.cctx + + out, err := clitestutil.ExecTestCLICmd(context.Background(), cctx, cmd, tc.args...) + if tc.expErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + var redelegations types.QueryRedelegationsResponse + err = s.cctx.Codec.UnmarshalJSON(out.Bytes(), &redelegations) + s.Require().NoError(err) + } + }) + } +} + +func (s *StakingCLITestSuite) TestGetCmdQueryRedelegation() { + testCases := []struct { + name string + args []string + expErr bool + }{ + { + "wrong delegator address", + cli.TestFlags(). + With( + "wrongdeladdr", + sdk.ValAddress(s.addrs[0]).String(), + sdk.ValAddress(s.addrs[1]).String(), + ). + WithOutputJSON(), + true, + }, + { + "wrong source validator address address", + cli.TestFlags(). + With( + s.addrs[0].String(), + "wrongSrcValAddress", + sdk.ValAddress(s.addrs[1]).String(), + ). + WithOutputJSON(), + true, + }, + { + "wrong destination validator address address", + cli.TestFlags(). + With( + s.addrs[0].String(), + sdk.ValAddress(s.addrs[0]).String(), + "wrongSrcValAddress", + ). + WithOutputJSON(), + true, + }, + { + "valid request", + cli.TestFlags(). + With( + s.addrs[0].String(), + sdk.ValAddress(s.addrs[0]).String(), + sdk.ValAddress(s.addrs[1]).String(), + ). + WithOutputJSON(), + false, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + cmd := cli.GetQueryStakingRedelegationCmd() + cctx := s.cctx + + out, err := clitestutil.ExecTestCLICmd(context.Background(), cctx, cmd, tc.args...) + + if tc.expErr { + s.Require().Error(err) + } else { + var redelegations types.QueryRedelegationsResponse + + err = s.cctx.Codec.UnmarshalJSON(out.Bytes(), &redelegations) + s.Require().NoError(err) + } + }) + } +} + +func (s *StakingCLITestSuite) TestGetCmdQueryValidatorRedelegations() { + testCases := []struct { + name string + args []string + expErr bool + }{ + { + "wrong validator address", + cli.TestFlags(). + With( + "wrongValAddr", + ). + WithOutputJSON(), + true, + }, + { + "valid request", + cli.TestFlags(). + With( + sdk.ValAddress(s.addrs[0]).String(), + ). + WithOutputJSON(), + false, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + cmd := cli.GetQueryStakingValidatorRedelegationsCmd() + cctx := s.cctx + + out, err := clitestutil.ExecTestCLICmd(context.Background(), cctx, cmd, tc.args...) + + if tc.expErr { + s.Require().Error(err) + } else { + var redelegations types.QueryRedelegationsResponse + err = s.cctx.Codec.UnmarshalJSON(out.Bytes(), &redelegations) + s.Require().NoError(err) + } + }) + } +} + +func (s *StakingCLITestSuite) TestGetCmdQueryPool() { + testCases := []struct { + name string + args []string + expectedOutput string + }{ + { + "with text", + []string{ + fmt.Sprintf("--%s=text", flags.FlagOutput), + fmt.Sprintf("--%s=1", flags.FlagHeight), + }, + `bonded_tokens: "0" +not_bonded_tokens: "0"`, + }, + { + "with json", + []string{ + fmt.Sprintf("--%s=json", flags.FlagOutput), + fmt.Sprintf("--%s=1", flags.FlagHeight), + }, + `{"not_bonded_tokens":"0","bonded_tokens":"0"}`, + }, + } + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + cmd := cli.GetQueryStakingPoolCmd() + cctx := s.cctx + out, err := clitestutil.ExecTestCLICmd(context.Background(), cctx, cmd, tc.args...) + s.Require().NoError(err) + s.Require().Equal(tc.expectedOutput, strings.TrimSpace(out.String())) + }) + } +} diff --git a/go/cli/staking_tx.go b/go/cli/staking_tx.go index 29e78762..90574362 100644 --- a/go/cli/staking_tx.go +++ b/go/cli/staking_tx.go @@ -19,8 +19,9 @@ import ( "github.com/cosmos/cosmos-sdk/version" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - cflags "pkg.akt.dev/go/cli/flags" cclient "pkg.akt.dev/go/node/client/v1beta3" + + cflags "pkg.akt.dev/go/cli/flags" ) // default values @@ -49,7 +50,7 @@ func GetTxStakingCmd() *cobra.Command { GetTxStakingRedelegateCmd(), GetTxStakingUnbondCmd(), GetTxStakingUnbondValidatorCmd(), - GetTxStakingCancelUnbondingDelegation(), + GetTxStakingCancelUnbondingDelegationCmd(), GetTxStakingTokenizeSharesCmd(), GetTxStakingRedeemTokensCmd(), GetTxStakingTransferTokenizeShareRecordCmd(), @@ -356,8 +357,8 @@ $ %s tx staking unbond-validator --from mykey return cmd } -// GetTxStakingCancelUnbondingDelegation returns a CLI command handler for creating a MsgCancelUnbondingDelegation transaction. -func GetTxStakingCancelUnbondingDelegation() *cobra.Command { +// GetTxStakingCancelUnbondingDelegationCmd returns a CLI command handler for creating a MsgCancelUnbondingDelegation transaction. +func GetTxStakingCancelUnbondingDelegationCmd() *cobra.Command { bech32PrefixValAddr := sdk.GetConfig().GetBech32ValidatorAddrPrefix() cmd := &cobra.Command{ diff --git a/go/cli/staking_tx_test.go b/go/cli/staking_tx_test.go new file mode 100644 index 00000000..fc7cd2e5 --- /dev/null +++ b/go/cli/staking_tx_test.go @@ -0,0 +1,620 @@ +package cli_test + +import ( + "bytes" + "fmt" + "io" + + sdkmath "cosmossdk.io/math" + abci "github.com/cometbft/cometbft/abci/types" + rpcclientmock "github.com/cometbft/cometbft/rpc/client/mock" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" + sdk "github.com/cosmos/cosmos-sdk/types" + testutilmod "github.com/cosmos/cosmos-sdk/types/module/testutil" + "github.com/cosmos/cosmos-sdk/x/staking" + "github.com/cosmos/gogoproto/proto" + "github.com/spf13/pflag" + "github.com/stretchr/testify/require" + + "pkg.akt.dev/go/cli" + cflags "pkg.akt.dev/go/cli/flags" +) + +var PKs = simtestutil.CreateTestPubKeys(500) + +type StakingCLITestSuite struct { + CLITestSuite + + addrs []sdk.AccAddress +} + +func (s *StakingCLITestSuite) SetupSuite() { + s.encCfg = testutilmod.MakeTestEncodingConfig(staking.AppModuleBasic{}) + s.kr = keyring.NewInMemory(s.encCfg.Codec) + s.baseCtx = client.Context{}. + WithKeyring(s.kr). + WithTxConfig(s.encCfg.TxConfig). + WithCodec(s.encCfg.Codec). + WithLegacyAmino(s.encCfg.Amino). + WithClient(clitestutil.MockTendermintRPC{Client: rpcclientmock.Client{}}). + WithAccountRetriever(client.MockAccountRetriever{}). + WithOutput(io.Discard). + WithChainID("test-chain"). + WithSignModeStr(cflags.SignModeDirect) + + var outBuf bytes.Buffer + ctxGen := func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := clitestutil.NewMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + } + s.cctx = ctxGen().WithOutput(&outBuf) + + s.addrs = make([]sdk.AccAddress, 0) + for i := 0; i < 3; i++ { + k, _, err := s.cctx.Keyring.NewMnemonic("NewValidator", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) + s.Require().NoError(err) + + pub, err := k.GetPubKey() + s.Require().NoError(err) + + newAddr := sdk.AccAddress(pub.Address()) + s.addrs = append(s.addrs, newAddr) + } +} + +func (s *StakingCLITestSuite) TestPrepareConfigForTxCreateValidator() { + chainID := "chainID" + ip := "1.1.1.1" + nodeID := "nodeID" + privKey := ed25519.GenPrivKey() + valPubKey := privKey.PubKey() + moniker := "DefaultMoniker" + mkTxValCfg := func(amount, commission, commissionMax, commissionMaxChange string) cli.TxCreateValidatorConfig { + return cli.TxCreateValidatorConfig{ + IP: ip, + ChainID: chainID, + NodeID: nodeID, + P2PPort: 26656, + PubKey: valPubKey, + Moniker: moniker, + Amount: amount, + CommissionRate: commission, + CommissionMaxRate: commissionMax, + CommissionMaxChangeRate: commissionMaxChange, + } + } + + tests := []struct { + name string + fsModify func(fs *pflag.FlagSet) + expectedCfg cli.TxCreateValidatorConfig + }{ + { + name: "all defaults", + fsModify: func(fs *pflag.FlagSet) {}, + expectedCfg: mkTxValCfg(cli.DefaultTokens.String()+sdk.DefaultBondDenom, "0.1", "0.2", "0.01"), + }, + { + name: "Custom amount", + fsModify: func(fs *pflag.FlagSet) { + err := fs.Set(cflags.FlagAmount, "2000stake") + if err != nil { + panic(err) + } + }, + expectedCfg: mkTxValCfg("2000stake", "0.1", "0.2", "0.01"), + }, + { + name: "Custom commission rate", + fsModify: func(fs *pflag.FlagSet) { + err := fs.Set(cflags.FlagCommissionRate, "0.54") + if err != nil { + panic(err) + } + }, + expectedCfg: mkTxValCfg(cli.DefaultTokens.String()+sdk.DefaultBondDenom, "0.54", "0.2", "0.01"), + }, + { + name: "Custom commission max rate", + fsModify: func(fs *pflag.FlagSet) { + err := fs.Set(cflags.FlagCommissionMaxRate, "0.89") + if err != nil { + panic(err) + } + }, + expectedCfg: mkTxValCfg(cli.DefaultTokens.String()+sdk.DefaultBondDenom, "0.1", "0.89", "0.01"), + }, + { + name: "Custom commission max change rate", + fsModify: func(fs *pflag.FlagSet) { + err := fs.Set(cflags.FlagCommissionMaxChangeRate, "0.55") + if err != nil { + panic(err) + } + }, + expectedCfg: mkTxValCfg(cli.DefaultTokens.String()+sdk.DefaultBondDenom, "0.1", "0.2", "0.55"), + }, + } + + for _, tc := range tests { + tc := tc + s.Run(tc.name, func() { + fs, _ := cli.CreateValidatorMsgFlagSet(ip) + fs.String(flags.FlagName, "", "name of private key with which to sign the gentx") + + tc.fsModify(fs) + + cvCfg, err := cli.PrepareConfigForTxCreateValidator(fs, moniker, nodeID, chainID, valPubKey) + require.NoError(s.T(), err) + + require.Equal(s.T(), tc.expectedCfg, cvCfg) + }) + } +} + +func (s *StakingCLITestSuite) TestNewCreateValidatorCmd() { + args := cli.TestFlags(). + WithSkipConfirm(). + WithBroadcastModeSync(). + WithFees(sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10)))) + + consPrivKey := ed25519.GenPrivKey() + consPubKeyBz, err := s.encCfg.Codec.MarshalInterfaceJSON(consPrivKey.PubKey()) + require.NoError(s.T(), err) + require.NotNil(s.T(), consPubKeyBz) + + testCases := []struct { + name string + args []string + expectErr bool + expectedCode uint32 + respType proto.Message + }{ + { + "invalid transaction (missing amount)", + cli.TestFlags(). + WithIdentity("AFAF00C4"). + WithWebsite("https://newvalidator.io"). + WithSecurityContact("contact@newvalidator.io"). + WithDetails("'Hey, I am a new validator. Please delegate!'"). + WithCommissionRate("0.5"). + WithCommissionMaxRate("1.0"). + WithCommissionMaxChangeRate("0.1"). + WithFrom(s.addrs[0].String()). + Append(args), + true, 0, nil, + }, + { + "invalid transaction (missing pubkey)", + cli.TestFlags(). + WithAmount("100uakt"). + WithIdentity("AFAF00C4"). + WithWebsite("https://newvalidator.io"). + WithSecurityContact("contact@newvalidator.io"). + WithDetails("'Hey, I am a new validator. Please delegate!'"). + WithCommissionRate("0.5"). + WithCommissionMaxRate("1.0"). + WithCommissionMaxChangeRate("0.1"). + WithFrom(s.addrs[0].String()). + Append(args), + true, 0, nil, + }, + { + "invalid transaction (missing moniker)", + cli.TestFlags(). + WithPubkey(string(consPubKeyBz)). + WithAmount("100uakt"). + WithIdentity("AFAF00C4"). + WithWebsite("https://newvalidator.io"). + WithSecurityContact("contact@newvalidator.io"). + WithDetails("'Hey, I am a new validator. Please delegate!'"). + WithCommissionRate("0.5"). + WithCommissionMaxRate("1.0"). + WithCommissionMaxChangeRate("0.1"). + WithFrom(s.addrs[0].String()). + Append(args), + true, 0, nil, + }, + { + "valid transaction", + cli.TestFlags(). + WithPubkey(string(consPubKeyBz)). + WithAmount("100uakt"). + WithMoniker("NewValidator"). + WithIdentity("AFAF00C4"). + WithWebsite("https://newvalidator.io"). + WithSecurityContact("contact@newvalidator.io"). + WithDetails("'Hey, I am a new validator. Please delegate!'"). + WithCommissionRate("0.5"). + WithCommissionMaxRate("1.0"). + WithCommissionMaxChangeRate("0.1"). + WithFrom(s.addrs[0].String()). + Append(args), + false, 0, &sdk.TxResponse{}, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + cmd := cli.GetTxStakingCreateValidatorCmd() + out, err := clitestutil.ExecTestCLICmd(s.cctx, cmd, tc.args) + if tc.expectErr { + require.Error(s.T(), err) + } else { + require.NoError(s.T(), err, "test: %s\noutput: %s", tc.name, out.String()) + err = s.cctx.Codec.UnmarshalJSON(out.Bytes(), tc.respType) + require.NoError(s.T(), err, out.String(), "test: %s, output\n:", tc.name, out.String()) + + txResp := tc.respType.(*sdk.TxResponse) + require.Equal(s.T(), tc.expectedCode, txResp.Code, + "test: %s, output\n:", tc.name, out.String()) + } + }) + } +} + +func (s *StakingCLITestSuite) TestNewEditValidatorCmd() { + details := "bio" + identity := "test identity" + securityContact := "test contact" + website := "https://test.com" + + args := cli.TestFlags(). + WithSkipConfirm(). + WithBroadcastModeSync(). + WithFees(sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10)))) + + testCases := []struct { + name string + args []string + expectErr bool + expectedCode uint32 + respType proto.Message + }{ + { + "with no edit flag (since all are optional)", + cli.TestFlags(). + WithFrom("with wrong from address"). + Append(args), + true, 0, nil, + }, + { + "with no edit flag (since all are optional)", + cli.TestFlags(). + WithFrom(s.addrs[0].String()). + Append(args), + false, 0, &sdk.TxResponse{}, + }, + { + "edit validator details", + cli.TestFlags(). + WithDetails(details). + WithFrom(s.addrs[0].String()). + Append(args), + false, 0, &sdk.TxResponse{}, + }, + { + "edit validator identity", + cli.TestFlags(). + WithIdentity(identity). + WithFrom(s.addrs[0].String()). + Append(args), + false, 0, &sdk.TxResponse{}, + }, + { + "edit validator security-contact", + cli.TestFlags(). + WithSecurityContact(securityContact). + WithFrom(s.addrs[0].String()). + Append(args), + false, 0, &sdk.TxResponse{}, + }, + { + "edit validator website", + cli.TestFlags(). + WithWebsite(website). + WithFrom(s.addrs[0].String()). + Append(args), + false, 0, &sdk.TxResponse{}, + }, + { + "with all edit flags", + cli.TestFlags(). + WithDetails(details). + WithIdentity(identity). + WithSecurityContact(securityContact). + WithWebsite(website). + WithFrom(s.addrs[0].String()). + Append(args), + false, 0, &sdk.TxResponse{}, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetTxStakingEditValidatorCmd() + + out, err := clitestutil.ExecTestCLICmd(s.cctx, cmd, tc.args) + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err, out.String()) + s.Require().NoError(s.cctx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + + txResp := tc.respType.(*sdk.TxResponse) + s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) + } + }) + } +} + +func (s *StakingCLITestSuite) TestNewDelegateCmd() { + args := cli.TestFlags(). + WithSkipConfirm(). + WithBroadcastModeSync(). + WithFees(sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10)))) + + testCases := []struct { + name string + args []string + expectErr bool + expectedCode uint32 + respType proto.Message + }{ + { + "without delegate amount", + cli.TestFlags(). + With(sdk.ValAddress(s.addrs[0]).String()). + WithFrom(s.addrs[0].String()). + Append(args), + true, 0, nil, + }, + { + "without validator address", + cli.TestFlags(). + With(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(150)).String()). + WithFrom(s.addrs[0].String()). + Append(args), + true, 0, nil, + }, + { + "valid transaction of delegate", + cli.TestFlags(). + With( + sdk.ValAddress(s.addrs[0]).String(), + sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(150)).String(), + ). + WithFrom(s.addrs[0].String()). + Append(args), + false, 0, &sdk.TxResponse{}, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetTxStakingDelegateCmd() + + out, err := clitestutil.ExecTestCLICmd(s.cctx, cmd, tc.args) + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err, out.String()) + s.Require().NoError(s.cctx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + + txResp := tc.respType.(*sdk.TxResponse) + s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) + } + }) + } +} + +func (s *StakingCLITestSuite) TestNewRedelegateCmd() { + args := cli.TestFlags(). + WithSkipConfirm(). + WithBroadcastModeSync(). + WithFees(sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10)))) + + testCases := []struct { + name string + args []string + expectErr bool + expectedCode uint32 + respType proto.Message + }{ + { + "without amount", + cli.TestFlags(). + With( + sdk.ValAddress(s.addrs[0]).String(), // src-validator-addr + sdk.ValAddress(s.addrs[1]).String(), // dst-validator-addr + ). + WithFrom(s.addrs[0].String()). + Append(args), + true, 0, nil, + }, + { + "valid transaction of delegate", + cli.TestFlags(). + With( + sdk.ValAddress(s.addrs[0]).String(), // src-validator-addr + sdk.ValAddress(s.addrs[1]).String(), // dst-validator-addr + sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(150)).String(), // amount + ). + WithFrom(s.addrs[0].String()). + Append(args), + false, 0, &sdk.TxResponse{}, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetTxStakingRedelegateCmd() + + out, err := clitestutil.ExecTestCLICmd(s.cctx, cmd, tc.args) + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err, out.String()) + s.Require().NoError(s.cctx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + + txResp := tc.respType.(*sdk.TxResponse) + s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) + } + }) + } +} + +func (s *StakingCLITestSuite) TestNewUnbondCmd() { + testCases := []struct { + name string + args []string + expectErr bool + expectedCode uint32 + respType proto.Message + }{ + { + "Without unbond amount", + []string{ + sdk.ValAddress(s.addrs[0]).String(), + fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()), + }, + true, 0, nil, + }, + { + "Without validator address", + []string{ + sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(150)).String(), + fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()), + }, + true, 0, nil, + }, + { + "valid transaction of unbond", + []string{ + sdk.ValAddress(s.addrs[0]).String(), + sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(150)).String(), + fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()), + }, + false, 0, &sdk.TxResponse{}, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetTxStakingUnbondCmd() + + out, err := clitestutil.ExecTestCLICmd(s.cctx, cmd, tc.args) + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err, out.String()) + s.Require().NoError(s.cctx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + + txResp := tc.respType.(*sdk.TxResponse) + s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) + } + }) + } +} + +func (s *StakingCLITestSuite) TestNewCancelUnbondingDelegationCmd() { + testCases := []struct { + name string + args []string + expectErr bool + expectedCode uint32 + respType proto.Message + }{ + { + "Without validator address", + []string{ + fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()), + }, + true, 0, nil, + }, + { + "Without canceling unbond delegation amount", + []string{ + sdk.ValAddress(s.addrs[0]).String(), + fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()), + }, + true, 0, nil, + }, + { + "Without unbond creation height", + []string{ + sdk.ValAddress(s.addrs[0]).String(), + sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(150)).String(), + fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()), + }, + true, 0, nil, + }, + { + "valid transaction of canceling unbonding delegation", + []string{ + sdk.ValAddress(s.addrs[0]).String(), + sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(5)).String(), + sdkmath.NewInt(10000).String(), + fmt.Sprintf("--%s=%s", flags.FlagFrom, s.addrs[0]), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(10))).String()), + }, + false, 0, &sdk.TxResponse{}, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetTxStakingCancelUnbondingDelegationCmd() + out, err := clitestutil.ExecTestCLICmd(s.cctx, cmd, tc.args) + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err, out.String()) + s.Require().NoError(s.cctx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + + txResp := tc.respType.(*sdk.TxResponse) + s.Require().Equal(tc.expectedCode, txResp.Code, out.String()) + } + }) + } +} diff --git a/go/cli/suite_test.go b/go/cli/suite_test.go index 49bca77f..bca9e6a8 100644 --- a/go/cli/suite_test.go +++ b/go/cli/suite_test.go @@ -23,6 +23,10 @@ func TestCLITestSuite(t *testing.T) { suite.Run(t, new(AuthCLITestSuite)) suite.Run(t, new(AuthzCLITestSuite)) suite.Run(t, new(BankCLITestSuite)) + suite.Run(t, new(DistributionCLITestSuite)) + suite.Run(t, new(FeegrantCLITestSuite)) suite.Run(t, new(GovCLITestSuite)) suite.Run(t, new(GenesisCLITestSuite)) + suite.Run(t, new(SlashingCLITestSuite)) + suite.Run(t, new(StakingCLITestSuite)) } diff --git a/go/cli/test_helpers.go b/go/cli/test_helpers.go index 0fc4cc17..249a7064 100644 --- a/go/cli/test_helpers.go +++ b/go/cli/test_helpers.go @@ -3,11 +3,19 @@ package cli import ( "fmt" + sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" + govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" - cflags "pkg.akt.dev/go/cli/flags" dv1 "pkg.akt.dev/go/node/deployment/v1" mtypes "pkg.akt.dev/go/node/market/v1" + + cflags "pkg.akt.dev/go/cli/flags" +) + +var ( + DefaultPowerReduction = sdkmath.NewIntFromUint64(sdk.DefaultPowerReduction.Uint64()) + DefaultMinDepositTokens = sdkmath.NewIntFromUint64(govv1.DefaultMinDepositTokens.Uint64()) ) type FlagsSet []string @@ -25,6 +33,15 @@ func (df FlagsSet) With(flags ...string) FlagsSet { return res } +func (df FlagsSet) WithLimit(val int64) FlagsSet { + res := make([]string, len(df), len(df)+1) + + copy(res, df) + res = append(res, fmt.Sprintf("--%s=%d", cflags.FlagLimit, val)) + + return res +} + func (df FlagsSet) Append(rhs FlagsSet) FlagsSet { res := make([]string, len(df), len(df)+len(rhs)) @@ -34,8 +51,19 @@ func (df FlagsSet) Append(rhs FlagsSet) FlagsSet { return res } +func (df FlagsSet) WithAllowedMsgs(val string) FlagsSet { + res := make([]string, len(df), len(df)+1) + + copy(res, df) + + res = append(res, fmt.Sprintf("--%s=%s", cflags.FlagAllowedMsgs, val)) + + return res +} + + func (df FlagsSet) WithGas(val int) FlagsSet { - res := make([]string, len(df), len(df)+3) + res := make([]string, len(df), len(df)+1) copy(res, df) @@ -146,6 +174,26 @@ func (df FlagsSet) WithSpendLimit(val string) FlagsSet { return res } +func (df FlagsSet) WithPeriodLimit(val string) FlagsSet { + res := make([]string, len(df), len(df)+1) + + copy(res, df) + + res = append(res, fmt.Sprintf("--%s=%s", cflags.FlagPeriodLimit, val)) + + return res +} + +func (df FlagsSet) WithPeriod(val int64) FlagsSet { + res := make([]string, len(df), len(df)+1) + + copy(res, df) + + res = append(res, fmt.Sprintf("--%s=%d", cflags.FlagPeriod, val)) + + return res +} + func (df FlagsSet) WithEvents(val string) FlagsSet { res := make([]string, len(df), len(df)+1) @@ -186,12 +234,22 @@ func (df FlagsSet) WithBroadcastModeSync() FlagsSet { return res } -func (df FlagsSet) WithExpiration(val int64) FlagsSet { +func (df FlagsSet) WithExpiration(val string) FlagsSet { + res := make([]string, len(df), len(df)+1) + + copy(res, df) + + res = append(res, fmt.Sprintf("--%s=%s", cflags.FlagExpiration, val)) + + return res +} + +func (df FlagsSet) WithCommission() FlagsSet { res := make([]string, len(df), len(df)+1) copy(res, df) - res = append(res, fmt.Sprintf("--%s=%d", cflags.FlagExpiration, val)) + res = append(res, fmt.Sprintf("--%s=true", cflags.FlagCommission)) return res } @@ -396,6 +454,26 @@ func (df FlagsSet) WithFrom(acc string) FlagsSet { return res } +func (df FlagsSet) WithFeeGranter(val sdk.AccAddress) FlagsSet { + res := make([]string, len(df), len(df)+1) + + copy(res, df) + + res = append(res, fmt.Sprintf("--%s=%s", cflags.FlagFeeGranter, val.String())) + + return res +} + +func (df FlagsSet) WithFeePayer(val sdk.AccAddress) FlagsSet { + res := make([]string, len(df), len(df)+1) + + copy(res, df) + + res = append(res, fmt.Sprintf("--%s=%s", cflags.FlagFeePayer, val.String())) + + return res +} + func (df FlagsSet) WithDepositor(acc sdk.Address) FlagsSet { res := make([]string, len(df), len(df)+1) @@ -574,10 +652,115 @@ func (df FlagsSet) WithOutputJSON() FlagsSet { return df.WithOutput("json") } +func (df FlagsSet) WithOutputYAML() FlagsSet { + return df.WithOutput("yaml") +} + func (df FlagsSet) WithOutputText() FlagsSet { return df.WithOutput("text") } +func (df FlagsSet) WithIdentity(val string) FlagsSet { + res := make([]string, len(df), len(df)+1) + + copy(res, df) + + res = append(res, fmt.Sprintf("--%s=%s", cflags.FlagIdentity, val)) + + return res +} + +func (df FlagsSet) WithWebsite(val string) FlagsSet { + res := make([]string, len(df), len(df)+1) + + copy(res, df) + + res = append(res, fmt.Sprintf("--%s=%s", cflags.FlagWebsite, val)) + + return res +} + +func (df FlagsSet) WithSecurityContact(val string) FlagsSet { + res := make([]string, len(df), len(df)+1) + + copy(res, df) + + res = append(res, fmt.Sprintf("--%s=%s", cflags.FlagSecurityContact, val)) + + return res +} + +func (df FlagsSet) WithDetails(val string) FlagsSet { + res := make([]string, len(df), len(df)+1) + + copy(res, df) + + res = append(res, fmt.Sprintf("--%s=%s", cflags.FlagDetails, val)) + + return res +} + +func (df FlagsSet) WithCommissionRate(val string) FlagsSet { + res := make([]string, len(df), len(df)+1) + + copy(res, df) + + res = append(res, fmt.Sprintf("--%s=%s", cflags.FlagCommissionRate, val)) + + return res +} + +func (df FlagsSet) WithCommissionMaxRate(val string) FlagsSet { + res := make([]string, len(df), len(df)+1) + + copy(res, df) + + res = append(res, fmt.Sprintf("--%s=%s", cflags.FlagCommissionMaxRate, val)) + + return res +} + +func (df FlagsSet) WithCommissionMaxChangeRate(val string) FlagsSet { + res := make([]string, len(df), len(df)+1) + + copy(res, df) + + res = append(res, fmt.Sprintf("--%s=%s", cflags.FlagCommissionMaxChangeRate, val)) + + return res +} + +func (df FlagsSet) WithAmount(val string) FlagsSet { + res := make([]string, len(df), len(df)+1) + + copy(res, df) + + res = append(res, fmt.Sprintf("--%s=%s", cflags.FlagAmount, val)) + + + return res +} + +func (df FlagsSet) WithPubkey(val string) FlagsSet { + res := make([]string, len(df), len(df)+1) + + copy(res, df) + + res = append(res, fmt.Sprintf("--%s=%s", cflags.FlagPubKey, val)) + + return res +} + +func (df FlagsSet) WithMoniker(val string) FlagsSet { + res := make([]string, len(df), len(df)+1) + + copy(res, df) + + res = append(res, fmt.Sprintf("--%s=%s", cflags.FlagMoniker, val)) + + return res +} + // // ExecTestCLICmd builds the client context, mocks the output and executes the command. // func ExecTestCLICmd(ctx context.Context, cctx client.Context, cmd *cobra.Command, extraArgs ...string) (sdktest.BufferWriter, error) { // _, out := sdktest.ApplyMockIO(cmd) diff --git a/go/cli/upgrade_parse_test.go b/go/cli/upgrade_parse_test.go new file mode 100644 index 00000000..21abf30f --- /dev/null +++ b/go/cli/upgrade_parse_test.go @@ -0,0 +1,41 @@ +package cli + +import ( + "strconv" + "testing" + + "github.com/cosmos/cosmos-sdk/x/upgrade/types" + "github.com/stretchr/testify/require" + + cflags "pkg.akt.dev/go/cli/flags" +) + +func TestParseArgsToContent(t *testing.T) { + fs := GetTxUpgradeSubmitLegacyUpgradeProposal().Flags() + + proposal := types.SoftwareUpgradeProposal{ + Title: "proposal title", + Description: "proposal description", + Plan: types.Plan{ + Name: "plan name", + Height: 123456, + Info: "plan info", + }, + } + + fs.Set(cflags.FlagTitle, proposal.Title) + fs.Set(cflags.FlagDescription, proposal.Description) + fs.Set(cflags.FlagUpgradeHeight, strconv.FormatInt(proposal.Plan.Height, 10)) + fs.Set(cflags.FlagUpgradeInfo, proposal.Plan.Info) + + content, err := upgradeParseArgsToContent(fs, proposal.Plan.Name) + require.NoError(t, err) + + p, ok := content.(*types.SoftwareUpgradeProposal) + require.Equal(t, ok, true) + require.Equal(t, p.Title, proposal.Title) + require.Equal(t, p.Description, proposal.Description) + require.Equal(t, p.Plan.Name, proposal.Plan.Name) + require.Equal(t, p.Plan.Height, proposal.Plan.Height) + require.Equal(t, p.Plan.Info, proposal.Plan.Info) +} diff --git a/go/cli/upgrade_query.go b/go/cli/upgrade_query.go index 1f46f1a3..1ed1078e 100644 --- a/go/cli/upgrade_query.go +++ b/go/cli/upgrade_query.go @@ -19,16 +19,16 @@ func GetQueryUpgradeCmd() *cobra.Command { } cmd.AddCommand( - getQueryUpgradeCurrentPlanCmd(), - getQueryUpgradeAppliedPlanCmd(), - getQueryUpgradeModuleVersionsCmd(), + GetQueryUpgradeCurrentPlanCmd(), + GetQueryUpgradeAppliedPlanCmd(), + GetQueryUpgradeModuleVersionsCmd(), ) return cmd } -// getQueryUpgradeCurrentPlanCmd returns the query upgrade plan command. -func getQueryUpgradeCurrentPlanCmd() *cobra.Command { +// GetQueryUpgradeCurrentPlanCmd returns the query upgrade plan command. +func GetQueryUpgradeCurrentPlanCmd() *cobra.Command { cmd := &cobra.Command{ Use: "plan", Short: "get upgrade plan (if one exists)", @@ -57,9 +57,9 @@ func getQueryUpgradeCurrentPlanCmd() *cobra.Command { return cmd } -// getQueryUpgradeAppliedPlanCmd returns information about the block at which a completed +// GetQueryUpgradeAppliedPlanCmd returns information about the block at which a completed // upgrade was applied. -func getQueryUpgradeAppliedPlanCmd() *cobra.Command { +func GetQueryUpgradeAppliedPlanCmd() *cobra.Command { cmd := &cobra.Command{ Use: "applied [upgrade-name]", Short: "block header for height at which a completed upgrade was applied", @@ -109,7 +109,7 @@ func getQueryUpgradeAppliedPlanCmd() *cobra.Command { } // GetModuleVersionsCmd returns the module version list from state -func getQueryUpgradeModuleVersionsCmd() *cobra.Command { +func GetQueryUpgradeModuleVersionsCmd() *cobra.Command { cmd := &cobra.Command{ Use: "module_versions [optional module_name]", Short: "get the list of module versions", diff --git a/go/cli/upgrade_query_test.go b/go/cli/upgrade_query_test.go new file mode 100644 index 00000000..4c291ce3 --- /dev/null +++ b/go/cli/upgrade_query_test.go @@ -0,0 +1,176 @@ +package cli_test + +import ( + "context" + "fmt" + "io" + "testing" + + rpcclientmock "github.com/cometbft/cometbft/rpc/client/mock" + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" + testutilmod "github.com/cosmos/cosmos-sdk/types/module/testutil" + "github.com/cosmos/cosmos-sdk/x/upgrade" + + "pkg.akt.dev/go/cli" + clitestutil "pkg.akt.dev/go/cli/testutil" +) + +func TestGetCurrentPlanCmd(t *testing.T) { + encCfg := testutilmod.MakeTestEncodingConfig(upgrade.AppModuleBasic{}) + kr := keyring.NewInMemory(encCfg.Codec) + baseCtx := client.Context{}. + WithKeyring(kr). + WithTxConfig(encCfg.TxConfig). + WithCodec(encCfg.Codec). + WithClient(clitestutil.MockTendermintRPC{Client: rpcclientmock.Client{}}). + WithAccountRetriever(client.MockAccountRetriever{}). + WithOutput(io.Discard). + WithChainID("test-chain") + + testCases := []struct { + name string + args []string + expCmdOutput string + }{ + { + name: "json output", + args: cli.TestFlags().WithOutputJSON(), + expCmdOutput: `[--output=json]`, + }, + { + name: "text output", + args: cli.TestFlags().WithOutputText(), + expCmdOutput: `[--output=text]`, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + ctx := svrcmd.CreateExecuteContext(context.Background()) + + cmd := cli.GetQueryUpgradeCurrentPlanCmd() + cmd.SetOut(io.Discard) + require.NotNil(t, cmd) + + cmd.SetContext(ctx) + cmd.SetArgs(tc.args) + + require.NoError(t, client.SetCmdClientContextHandler(baseCtx, cmd)) + + require.Contains(t, fmt.Sprint(cmd), "plan [] [] get upgrade plan (if one exists)") + require.Contains(t, fmt.Sprint(cmd), tc.expCmdOutput) + }) + } +} + +func TestGetAppliedPlanCmd(t *testing.T) { + encCfg := testutilmod.MakeTestEncodingConfig(upgrade.AppModuleBasic{}) + kr := keyring.NewInMemory(encCfg.Codec) + baseCtx := client.Context{}. + WithKeyring(kr). + WithTxConfig(encCfg.TxConfig). + WithCodec(encCfg.Codec). + WithClient(clitestutil.MockTendermintRPC{Client: rpcclientmock.Client{}}). + WithAccountRetriever(client.MockAccountRetriever{}). + WithOutput(io.Discard). + WithChainID("test-chain") + + testCases := []struct { + name string + args []string + expCmdOutput string + }{ + { + name: "json output", + args: cli.TestFlags().With("test-upgrade").WithOutputJSON(), + expCmdOutput: `[test-upgrade --output=json]`, + }, + { + name: "text output", + args: cli.TestFlags().With("test-upgrade").WithOutputText(), + expCmdOutput: `[test-upgrade --output=text]`, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + ctx := svrcmd.CreateExecuteContext(context.Background()) + + cmd := cli.GetQueryUpgradeAppliedPlanCmd() + cmd.SetOut(io.Discard) + require.NotNil(t, cmd) + + cmd.SetContext(ctx) + cmd.SetArgs(tc.args) + + require.NoError(t, client.SetCmdClientContextHandler(baseCtx, cmd)) + + require.Contains(t, fmt.Sprint(cmd), "applied [upgrade-name] [] [] block header for height at which a completed upgrade was applied") + require.Contains(t, fmt.Sprint(cmd), tc.expCmdOutput) + }) + } +} + +func TestGetModuleVersionsCmd(t *testing.T) { + encCfg := testutilmod.MakeTestEncodingConfig(upgrade.AppModuleBasic{}) + kr := keyring.NewInMemory(encCfg.Codec) + baseCtx := client.Context{}. + WithKeyring(kr). + WithTxConfig(encCfg.TxConfig). + WithCodec(encCfg.Codec). + WithClient(clitestutil.MockTendermintRPC{Client: rpcclientmock.Client{}}). + WithAccountRetriever(client.MockAccountRetriever{}). + WithOutput(io.Discard). + WithChainID("test-chain") + + testCases := []struct { + msg string + args []string + expCmdOutput string + }{ + { + msg: "test full query with json output", + args: cli.TestFlags().WithHeight(1).WithOutputJSON(), + expCmdOutput: `--height=1 --output=json`, + }, + { + msg: "test full query with text output", + args: cli.TestFlags().WithHeight(1).WithOutputText(), + expCmdOutput: `--height=1 --output=text`, + }, + { + msg: "test single module", + args: cli.TestFlags().With("bank").WithHeight(1), + expCmdOutput: `bank --height=1`, + }, + { + msg: "test non-existent module", + args: cli.TestFlags().With("abcdefg").WithHeight(1), + expCmdOutput: `abcdefg --height=1`, + }, + } + + for _, tc := range testCases { + tc := tc + + t.Run(tc.msg, func(t *testing.T) { + ctx := svrcmd.CreateExecuteContext(context.Background()) + + cmd := cli.GetQueryUpgradeModuleVersionsCmd() + cmd.SetOut(io.Discard) + require.NotNil(t, cmd) + + cmd.SetContext(ctx) + cmd.SetArgs(tc.args) + + require.NoError(t, client.SetCmdClientContextHandler(baseCtx, cmd)) + + require.Contains(t, fmt.Sprint(cmd), "module_versions [optional module_name] [] [] get the list of module versions") + require.Contains(t, fmt.Sprint(cmd), tc.expCmdOutput) + }) + } +} diff --git a/go/cli/upgrade_tx_test.go b/go/cli/upgrade_tx_test.go new file mode 100644 index 00000000..ad257657 --- /dev/null +++ b/go/cli/upgrade_tx_test.go @@ -0,0 +1,85 @@ +package cli_test + +import ( + "context" + "fmt" + "io" + "testing" + + rpcclientmock "github.com/cometbft/cometbft/rpc/client/mock" + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + testutilmod "github.com/cosmos/cosmos-sdk/types/module/testutil" + "github.com/cosmos/cosmos-sdk/x/upgrade" + + "pkg.akt.dev/go/cli" + cflags "pkg.akt.dev/go/cli/flags" +) + +func TestModuleVersionsCLI(t *testing.T) { + encCfg := testutilmod.MakeTestEncodingConfig(upgrade.AppModuleBasic{}) + kr := keyring.NewInMemory(encCfg.Codec) + baseCtx := client.Context{}. + WithKeyring(kr). + WithTxConfig(encCfg.TxConfig). + WithCodec(encCfg.Codec). + WithLegacyAmino(encCfg.Amino). + WithClient(clitestutil.MockTendermintRPC{Client: rpcclientmock.Client{}}). + WithAccountRetriever(client.MockAccountRetriever{}). + WithOutput(io.Discard). + WithChainID("test-chain"). + WithSignModeStr(cflags.SignModeDirect) + + testCases := []struct { + msg string + args []string + expCmdOutput string + }{ + { + msg: "test full query with json output", + args: cli.TestFlags().WithHeight(1).WithOutputJSON(), + expCmdOutput: `--height=1 --output=json`, + }, + { + msg: "test full query with text output", + args: cli.TestFlags().WithHeight(1).WithOutputText(), + expCmdOutput: `--height=1 --output=text`, + }, + { + msg: "test single module", + args: cli.TestFlags().With("bank").WithHeight(1), + expCmdOutput: `bank --height=1`, + }, + { + msg: "test non-existent module", + args: cli.TestFlags().With("abcdefg").WithHeight(1), + expCmdOutput: `abcdefg --height=1`, + }, + } + + for _, tc := range testCases { + tc := tc + + t.Run(tc.msg, func(t *testing.T) { + cmd := cli.GetQueryUpgradeModuleVersionsCmd() + + ctx := svrcmd.CreateExecuteContext(context.Background()) + + cmd.SetOut(io.Discard) + require.NotNil(t, cmd) + + cmd.SetContext(ctx) + cmd.SetArgs(tc.args) + + require.NoError(t, client.SetCmdClientContextHandler(baseCtx, cmd)) + + if len(tc.args) != 0 { + require.Contains(t, fmt.Sprint(cmd), tc.expCmdOutput) + } + }) + } +} diff --git a/go/cli/vesting_tx.go b/go/cli/vesting_tx.go index dd3506e6..5a8c8653 100644 --- a/go/cli/vesting_tx.go +++ b/go/cli/vesting_tx.go @@ -17,7 +17,7 @@ import ( // GetTxVestingCmd returns vesting module's transaction commands. func GetTxVestingCmd() *cobra.Command { - txCmd := &cobra.Command{ + cmd := &cobra.Command{ Use: types.ModuleName, Short: "Vesting transaction subcommands", DisableFlagParsing: true, @@ -25,18 +25,18 @@ func GetTxVestingCmd() *cobra.Command { RunE: client.ValidateCmd, } - txCmd.AddCommand( - getTxVestingCreateAccountCmd(), - getTxVestingCreatePermanentLockedAccountCmd(), - getTxVestingCreatePeriodicAccountCmd(), + cmd.AddCommand( + GetTxVestingCreateAccountCmd(), + GetTxVestingCreatePermanentLockedAccountCmd(), + GetTxVestingCreatePeriodicAccountCmd(), ) - return txCmd + return cmd } -// getTxVestingCreateAccountCmd returns a CLI command handler for creating a +// GetTxVestingCreateAccountCmd returns a CLI command handler for creating a // MsgCreateVestingAccount transaction. -func getTxVestingCreateAccountCmd() *cobra.Command { +func GetTxVestingCreateAccountCmd() *cobra.Command { cmd := &cobra.Command{ Use: "create-vesting-account [to_address] [amount] [end_time]", Short: "Create a new vesting account funded with an allocation of tokens.", @@ -85,9 +85,9 @@ timestamp.`, return cmd } -// getTxVestingCreatePermanentLockedAccountCmd returns a CLI command handler for creating a +// GetTxVestingCreatePermanentLockedAccountCmd returns a CLI command handler for creating a // MsgCreatePermanentLockedAccount transaction. -func getTxVestingCreatePermanentLockedAccountCmd() *cobra.Command { +func GetTxVestingCreatePermanentLockedAccountCmd() *cobra.Command { cmd := &cobra.Command{ Use: "create-permanent-locked-account [to_address] [amount]", Short: "Create a new permanently locked account funded with an allocation of tokens.", @@ -136,9 +136,9 @@ type InputPeriod struct { Length int64 `json:"length_seconds"` } -// getTxVestingCreatePeriodicAccountCmd returns a CLI command handler for creating a +// GetTxVestingCreatePeriodicAccountCmd returns a CLI command handler for creating a // MsgCreatePeriodicVestingAccountCmd transaction. -func getTxVestingCreatePeriodicAccountCmd() *cobra.Command { +func GetTxVestingCreatePeriodicAccountCmd() *cobra.Command { cmd := &cobra.Command{ Use: "create-periodic-vesting-account [to_address] [periods_json_file]", Short: "Create a new vesting account funded with an allocation of tokens.",