package cli_test import ( "context" "encoding/json" "fmt" "io" "testing" abci "github.com/cometbft/cometbft/api/cometbft/abci/v1" rpcclientmock "github.com/cometbft/cometbft/rpc/client/mock" "github.com/stretchr/testify/suite" // without this import amino json encoding will fail when resolving any types _ "cosmossdk.io/api/cosmos/group/v1" sdkmath "cosmossdk.io/math" banktypes "cosmossdk.io/x/bank/types" "cosmossdk.io/x/group" groupcli "cosmossdk.io/x/group/client/cli" groupmodule "cosmossdk.io/x/group/module" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" addresscodec "github.com/cosmos/cosmos-sdk/codec/address" codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil" "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" "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" ) var validMetadata = "metadata" type CLITestSuite struct { suite.Suite kr keyring.Keyring encCfg testutilmod.TestEncodingConfig baseCtx client.Context clientCtx client.Context group *group.GroupInfo commonFlags []string } func TestCLITestSuite(t *testing.T) { suite.Run(t, new(CLITestSuite)) } func (s *CLITestSuite) SetupSuite() { s.encCfg = testutilmod.MakeTestEncodingConfig(codectestutil.CodecOptions{}, groupmodule.AppModule{}) s.kr = keyring.NewInMemory(s.encCfg.Codec) s.baseCtx = client.Context{}. WithKeyring(s.kr). WithTxConfig(s.encCfg.TxConfig). WithCodec(s.encCfg.Codec). WithClient(clitestutil.MockCometRPC{Client: rpcclientmock.Client{}}). WithAccountRetriever(client.MockAccountRetriever{}). WithOutput(io.Discard). WithChainID("test-chain"). WithAddressCodec(addresscodec.NewBech32Codec("cosmos")). WithValidatorAddressCodec(addresscodec.NewBech32Codec("cosmosvaloper")). WithConsensusAddressCodec(addresscodec.NewBech32Codec("cosmosvalcons")) s.commonFlags = []string{ fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin("stake", sdkmath.NewInt(10))).String()), } accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 1) val := accounts[0] valAddr, err := s.baseCtx.AddressCodec.BytesToString(val.Address) s.Require().NoError(err) ctxGen := func() client.Context { bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) c := clitestutil.NewMockCometRPC(abci.QueryResponse{ Value: bz, }) return s.baseCtx.WithClient(c) } s.clientCtx = ctxGen() // create a new account info, _, err := s.clientCtx.Keyring.NewMnemonic("NewValidator", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) s.Require().NoError(err) pk, err := info.GetPubKey() s.Require().NoError(err) account := sdk.AccAddress(pk.Address()) from := val.Address coins := sdk.NewCoins(sdk.NewCoin("stake", sdkmath.NewInt(2000))) fromAddr, err := s.baseCtx.AddressCodec.BytesToString(from) s.Require().NoError(err) toAddr, err := s.baseCtx.AddressCodec.BytesToString(account) s.Require().NoError(err) msgSend := &banktypes.MsgSend{ FromAddress: fromAddr, ToAddress: toAddr, Amount: coins, } _, err = clitestutil.SubmitTestTx(s.clientCtx, msgSend, from, clitestutil.TestTxConfig{}) s.Require().NoError(err) // create a group validMembers := fmt.Sprintf(` { "members": [ { "address": "%s", "weight": "3", "metadata": "%s" } ] }`, valAddr, validMetadata) validMembersFile := testutil.WriteToNewTempFile(s.T(), validMembers) out, err := clitestutil.ExecTestCLICmd(s.clientCtx, groupcli.MsgCreateGroupCmd(), append( []string{ valAddr, validMetadata, validMembersFile.Name(), }, s.commonFlags..., ), ) s.Require().NoError(err, out.String()) txResp := sdk.TxResponse{} s.Require().NoError(s.clientCtx.Codec.UnmarshalJSON(out.Bytes(), &txResp), out.String()) s.Require().Equal(uint32(0), txResp.Code, out.String()) s.group = &group.GroupInfo{Id: 1, Admin: valAddr, Metadata: validMetadata, TotalWeight: "3", Version: 1} } func (s *CLITestSuite) TestTxCreateGroup() { accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 1) account0Addr, err := s.baseCtx.AddressCodec.BytesToString(accounts[0].Address) s.Require().NoError(err) cmd := groupcli.MsgCreateGroupCmd() cmd.SetOutput(io.Discard) validMembers := fmt.Sprintf(`{"members": [{ "address": "%s", "weight": "1", "metadata": "%s" }]}`, account0Addr, validMetadata) validMembersFile := testutil.WriteToNewTempFile(s.T(), validMembers) invalidMembersWeight := fmt.Sprintf(`{"members": [{ "address": "%s", "weight": "0" }]}`, account0Addr) invalidMembersWeightFile := testutil.WriteToNewTempFile(s.T(), invalidMembersWeight) testCases := []struct { name string args []string expCmdOutput string expectErrMsg string }{ { name: "correct data", args: append( []string{ account0Addr, "", validMembersFile.Name(), }, s.commonFlags..., ), expCmdOutput: fmt.Sprintf("%s %s %s", account0Addr, "", validMembersFile.Name()), expectErrMsg: "", }, { "with amino-json", append( []string{ account0Addr, "", validMembersFile.Name(), fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON), }, s.commonFlags..., ), fmt.Sprintf("%s %s %s", account0Addr, "", validMembersFile.Name()), "", }, { "invalid members weight", append( []string{ account0Addr, "null", invalidMembersWeightFile.Name(), }, s.commonFlags..., ), "", "weight must be positive", }, { "no member provided", append( []string{ account0Addr, "null", "doesnotexist.json", }, s.commonFlags..., ), "", "no such file or directory", }, } for _, tc := range testCases { tc := tc s.Run(tc.name, func() { ctx := svrcmd.CreateExecuteContext(context.Background()) cmd.SetContext(ctx) cmd.SetArgs(tc.args) s.Require().NoError(client.SetCmdClientContextHandler(s.baseCtx, cmd)) if len(tc.args) != 0 { s.Require().Contains(fmt.Sprint(cmd), tc.expCmdOutput) } out, err := clitestutil.ExecTestCLICmd(s.baseCtx, cmd, tc.args) if tc.expectErrMsg != "" { s.Require().Error(err) s.Require().Contains(out.String(), tc.expectErrMsg) } else { s.Require().NoError(err) msg := &sdk.TxResponse{} s.Require().NoError(s.baseCtx.Codec.UnmarshalJSON(out.Bytes(), msg), out.String()) } }) } } func (s *CLITestSuite) TestTxUpdateGroupMembers() { accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 3) groupPolicyAddress := accounts[2] account0Addr, err := s.baseCtx.AddressCodec.BytesToString(accounts[0].Address) s.Require().NoError(err) cmd := groupcli.MsgUpdateGroupMembersCmd() cmd.SetOutput(io.Discard) groupID := "1" validUpdatedMembersFileName := testutil.WriteToNewTempFile(s.T(), fmt.Sprintf(`{"members": [{ "address": "%s", "weight": "0", "metadata": "%s" }, { "address": "%s", "weight": "1", "metadata": "%s" }]}`, accounts[1], validMetadata, groupPolicyAddress, validMetadata)).Name() invalidMembersMetadata := fmt.Sprintf(`{"members": [{ "address": "%s", "weight": "-1", "metadata": "foo" }]}`, accounts[1]) invalidMembersMetadataFileName := testutil.WriteToNewTempFile(s.T(), invalidMembersMetadata).Name() testCases := []struct { name string args []string expCmdOutput string expectErrMsg string }{ { "correct data", append( []string{ account0Addr, groupID, validUpdatedMembersFileName, }, s.commonFlags..., ), fmt.Sprintf("%s %s %s", account0Addr, groupID, validUpdatedMembersFileName), "", }, { "with amino-json", append( []string{ account0Addr, groupID, validUpdatedMembersFileName, fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON), }, s.commonFlags..., ), fmt.Sprintf("%s %s %s --%s=%s", account0Addr, groupID, validUpdatedMembersFileName, flags.FlagSignMode, flags.SignModeLegacyAminoJSON), "", }, { "group id invalid", append( []string{ account0Addr, "0", validUpdatedMembersFileName, }, s.commonFlags..., ), fmt.Sprintf("%s %s %s", account0Addr, "0", validUpdatedMembersFileName), "group id cannot be 0", }, { "group member weight invalid", append( []string{ account0Addr, groupID, invalidMembersMetadataFileName, }, s.commonFlags..., ), fmt.Sprintf("%s %s %s", account0Addr, groupID, invalidMembersMetadataFileName), "invalid weight -1", }, } for _, tc := range testCases { tc := tc s.Run(tc.name, func() { ctx := svrcmd.CreateExecuteContext(context.Background()) cmd.SetContext(ctx) cmd.SetArgs(tc.args) s.Require().NoError(client.SetCmdClientContextHandler(s.baseCtx, cmd)) if len(tc.args) != 0 { s.Require().Contains(fmt.Sprint(cmd), tc.expCmdOutput) } out, err := clitestutil.ExecTestCLICmd(s.baseCtx, cmd, tc.args) if tc.expectErrMsg != "" { s.Require().Error(err) s.Require().Contains(out.String(), tc.expectErrMsg) } else { s.Require().NoError(err) msg := &sdk.TxResponse{} s.Require().NoError(s.baseCtx.Codec.UnmarshalJSON(out.Bytes(), msg), out.String()) } }) } } func (s *CLITestSuite) TestTxCreateGroupWithPolicy() { accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 1) account0Addr, err := s.baseCtx.AddressCodec.BytesToString(accounts[0].Address) s.Require().NoError(err) cmd := groupcli.MsgCreateGroupWithPolicyCmd() cmd.SetOutput(io.Discard) validMembers := fmt.Sprintf(`{"members": [{ "address": "%s", "weight": "1", "metadata": "%s" }]}`, account0Addr, validMetadata) validMembersFile := testutil.WriteToNewTempFile(s.T(), validMembers) invalidMembersWeight := fmt.Sprintf(`{"members": [{ "address": "%s", "weight": "0" }]}`, account0Addr) invalidMembersWeightFile := testutil.WriteToNewTempFile(s.T(), invalidMembersWeight) thresholdDecisionPolicyFile := testutil.WriteToNewTempFile(s.T(), `{"@type": "/cosmos.group.v1.ThresholdDecisionPolicy","threshold": "1","windows": {"voting_period":"1s"}}`) testCases := []struct { name string args []string expectErrMsg string expCmdOutput string }{ { "correct data", append( []string{ account0Addr, validMetadata, validMetadata, validMembersFile.Name(), thresholdDecisionPolicyFile.Name(), fmt.Sprintf("--%s=%v", groupcli.FlagGroupPolicyAsAdmin, false), }, s.commonFlags..., ), "", fmt.Sprintf("%s %s %s %s %s --%s=%v", account0Addr, validMetadata, validMetadata, validMembersFile.Name(), thresholdDecisionPolicyFile.Name(), groupcli.FlagGroupPolicyAsAdmin, false), }, { "group-policy-as-admin is true", append( []string{ account0Addr, validMetadata, validMetadata, validMembersFile.Name(), thresholdDecisionPolicyFile.Name(), fmt.Sprintf("--%s=%v", groupcli.FlagGroupPolicyAsAdmin, true), }, s.commonFlags..., ), "", fmt.Sprintf("%s %s %s %s %s --%s=%v", account0Addr, validMetadata, validMetadata, validMembersFile.Name(), thresholdDecisionPolicyFile.Name(), groupcli.FlagGroupPolicyAsAdmin, true), }, { "with amino-json", append( []string{ account0Addr, validMetadata, validMetadata, validMembersFile.Name(), thresholdDecisionPolicyFile.Name(), fmt.Sprintf("--%s=%v", groupcli.FlagGroupPolicyAsAdmin, false), fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON), }, s.commonFlags..., ), "", fmt.Sprintf("%s %s %s %s %s --%s=%v --%s=%s", account0Addr, validMetadata, validMetadata, validMembersFile.Name(), thresholdDecisionPolicyFile.Name(), groupcli.FlagGroupPolicyAsAdmin, false, flags.FlagSignMode, flags.SignModeLegacyAminoJSON), }, { "invalid members weight", append( []string{ account0Addr, validMetadata, validMetadata, invalidMembersWeightFile.Name(), thresholdDecisionPolicyFile.Name(), fmt.Sprintf("--%s=%v", groupcli.FlagGroupPolicyAsAdmin, false), }, s.commonFlags..., ), "weight must be positive", fmt.Sprintf("%s %s %s %s %s --%s=%v", account0Addr, validMetadata, validMetadata, invalidMembersWeightFile.Name(), thresholdDecisionPolicyFile.Name(), groupcli.FlagGroupPolicyAsAdmin, false), }, } for _, tc := range testCases { tc := tc s.Run(tc.name, func() { ctx := svrcmd.CreateExecuteContext(context.Background()) cmd.SetContext(ctx) cmd.SetArgs(tc.args) s.Require().NoError(client.SetCmdClientContextHandler(s.baseCtx, cmd)) if len(tc.args) != 0 { s.Require().Contains(fmt.Sprint(cmd), tc.expCmdOutput) } out, err := clitestutil.ExecTestCLICmd(s.baseCtx, cmd, tc.args) if tc.expectErrMsg != "" { s.Require().Error(err) s.Require().Contains(out.String(), tc.expectErrMsg) } else { s.Require().NoError(err, out.String()) msg := &sdk.TxResponse{} s.Require().NoError(s.baseCtx.Codec.UnmarshalJSON(out.Bytes(), msg), out.String()) } }) } } func (s *CLITestSuite) TestTxCreateGroupPolicy() { accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 2) valAddr, err := s.baseCtx.AddressCodec.BytesToString(accounts[0].Address) s.Require().NoError(err) groupID := s.group.Id thresholdDecisionPolicyFile := testutil.WriteToNewTempFile(s.T(), `{"@type": "/cosmos.group.v1.ThresholdDecisionPolicy","threshold": "1","windows": {"voting_period":"1s"}}`) percentageDecisionPolicyFile := testutil.WriteToNewTempFile(s.T(), `{"@type":"/cosmos.group.v1.PercentageDecisionPolicy", "percentage":"0.5", "windows":{"voting_period":"1s"}}`) invalidNegativePercentageDecisionPolicyFile := testutil.WriteToNewTempFile(s.T(), `{"@type":"/cosmos.group.v1.PercentageDecisionPolicy", "percentage":"-0.5", "windows":{"voting_period":"1s"}}`) invalidPercentageDecisionPolicyFile := testutil.WriteToNewTempFile(s.T(), `{"@type":"/cosmos.group.v1.PercentageDecisionPolicy", "percentage":"2", "windows":{"voting_period":"1s"}}`) cmd := groupcli.MsgCreateGroupPolicyCmd() cmd.SetOutput(io.Discard) testCases := []struct { name string args []string expectErrMsg string expCmdOutput string }{ { "correct data", append( []string{ valAddr, fmt.Sprintf("%v", groupID), validMetadata, thresholdDecisionPolicyFile.Name(), }, s.commonFlags..., ), "", fmt.Sprintf("%s %s %s %s", valAddr, fmt.Sprintf("%v", groupID), validMetadata, thresholdDecisionPolicyFile.Name()), }, { "correct data with percentage decision policy", append( []string{ valAddr, fmt.Sprintf("%v", groupID), validMetadata, percentageDecisionPolicyFile.Name(), }, s.commonFlags..., ), "", fmt.Sprintf("%s %s %s %s", valAddr, fmt.Sprintf("%v", groupID), validMetadata, percentageDecisionPolicyFile.Name()), }, { "with amino-json", append( []string{ valAddr, fmt.Sprintf("%v", groupID), validMetadata, thresholdDecisionPolicyFile.Name(), fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON), }, s.commonFlags..., ), "", fmt.Sprintf("%s %s %s %s --%s=%s", valAddr, fmt.Sprintf("%v", groupID), validMetadata, thresholdDecisionPolicyFile.Name(), flags.FlagSignMode, flags.SignModeLegacyAminoJSON), }, { "wrong admin", append( []string{ "wrongAdmin", fmt.Sprintf("%v", groupID), validMetadata, thresholdDecisionPolicyFile.Name(), }, s.commonFlags..., ), "key not found", fmt.Sprintf("%s %s %s %s", "wrongAdmin", fmt.Sprintf("%v", groupID), validMetadata, thresholdDecisionPolicyFile.Name()), }, { "invalid percentage decision policy with negative value", append( []string{ valAddr, fmt.Sprintf("%v", groupID), validMetadata, invalidNegativePercentageDecisionPolicyFile.Name(), }, s.commonFlags..., ), "expected a positive decimal", fmt.Sprintf("%s %s %s %s", valAddr, fmt.Sprintf("%v", groupID), validMetadata, invalidNegativePercentageDecisionPolicyFile.Name()), }, { "invalid percentage decision policy with value greater than 1", append( []string{ valAddr, fmt.Sprintf("%v", groupID), validMetadata, invalidPercentageDecisionPolicyFile.Name(), }, s.commonFlags..., ), "percentage must be > 0 and <= 1", fmt.Sprintf("%s %s %s %s", valAddr, fmt.Sprintf("%v", groupID), validMetadata, invalidPercentageDecisionPolicyFile.Name()), }, } for _, tc := range testCases { tc := tc s.Run(tc.name, func() { ctx := svrcmd.CreateExecuteContext(context.Background()) cmd.SetContext(ctx) cmd.SetArgs(tc.args) s.Require().NoError(client.SetCmdClientContextHandler(s.baseCtx, cmd)) if len(tc.args) != 0 { s.Require().Contains(fmt.Sprint(cmd), tc.expCmdOutput) } out, err := clitestutil.ExecTestCLICmd(s.baseCtx, cmd, tc.args) if tc.expectErrMsg != "" { s.Require().Error(err) s.Require().Contains(out.String(), tc.expectErrMsg) } else { s.Require().NoError(err, out.String()) msg := &sdk.TxResponse{} s.Require().NoError(s.baseCtx.Codec.UnmarshalJSON(out.Bytes(), msg), out.String()) } }) } } func (s *CLITestSuite) TestTxUpdateGroupPolicyDecisionPolicy() { accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 3) newAdmin, err := s.baseCtx.AddressCodec.BytesToString(accounts[0].Address) s.Require().NoError(err) groupPolicyAdmin, err := s.baseCtx.AddressCodec.BytesToString(accounts[1].Address) s.Require().NoError(err) groupPolicyAddress, err := s.baseCtx.AddressCodec.BytesToString(accounts[2].Address) s.Require().NoError(err) commonFlags := s.commonFlags commonFlags = append(commonFlags, fmt.Sprintf("--%s=%d", flags.FlagGas, 300000)) thresholdDecisionPolicy := testutil.WriteToNewTempFile(s.T(), `{"@type":"/cosmos.group.v1.ThresholdDecisionPolicy", "threshold":"1", "windows":{"voting_period":"40000s"}}`) percentageDecisionPolicy := testutil.WriteToNewTempFile(s.T(), `{"@type":"/cosmos.group.v1.PercentageDecisionPolicy", "percentage":"0.5", "windows":{"voting_period":"40000s"}}`) cmd := groupcli.MsgUpdateGroupPolicyDecisionPolicyCmd() cmd.SetOutput(io.Discard) testCases := []struct { name string args []string expCmdOutput string expectErrMsg string }{ { "correct data", append( []string{ groupPolicyAdmin, groupPolicyAddress, thresholdDecisionPolicy.Name(), }, commonFlags..., ), fmt.Sprintf("%s %s %s", groupPolicyAdmin, groupPolicyAddress, thresholdDecisionPolicy.Name()), "", }, { "correct data with percentage decision policy", append( []string{ groupPolicyAdmin, groupPolicyAddress, percentageDecisionPolicy.Name(), }, commonFlags..., ), fmt.Sprintf("%s %s %s", groupPolicyAdmin, groupPolicyAddress, percentageDecisionPolicy.Name()), "", }, { "with amino-json", append( []string{ groupPolicyAdmin, groupPolicyAddress, thresholdDecisionPolicy.Name(), fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON), }, commonFlags..., ), fmt.Sprintf("%s %s %s --%s=%s", groupPolicyAdmin, groupPolicyAddress, thresholdDecisionPolicy.Name(), flags.FlagSignMode, flags.SignModeLegacyAminoJSON), "", }, { "wrong admin", append( []string{ newAdmin, "invalid", thresholdDecisionPolicy.Name(), }, commonFlags..., ), fmt.Sprintf("%s %s %s", newAdmin, "invalid", thresholdDecisionPolicy.Name()), "decoding bech32 failed", }, } for _, tc := range testCases { tc := tc s.Run(tc.name, func() { ctx := svrcmd.CreateExecuteContext(context.Background()) cmd.SetContext(ctx) cmd.SetArgs(tc.args) s.Require().NoError(client.SetCmdClientContextHandler(s.baseCtx, cmd)) if len(tc.args) != 0 { s.Require().Contains(fmt.Sprint(cmd), tc.expCmdOutput) } out, err := clitestutil.ExecTestCLICmd(s.baseCtx, cmd, tc.args) if tc.expectErrMsg != "" { s.Require().Error(err) s.Require().Contains(out.String(), tc.expectErrMsg) } else { s.Require().NoError(err) msg := &sdk.TxResponse{} s.Require().NoError(s.baseCtx.Codec.UnmarshalJSON(out.Bytes(), msg), out.String()) } }) } } func (s *CLITestSuite) TestTxSubmitProposal() { accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 2) groupPolicyAddress, err := s.baseCtx.AddressCodec.BytesToString(accounts[1].Address) s.Require().NoError(err) account0Addr, err := s.baseCtx.AddressCodec.BytesToString(accounts[0].Address) s.Require().NoError(err) p := groupcli.Proposal{ GroupPolicyAddress: groupPolicyAddress, Messages: []json.RawMessage{}, Metadata: validMetadata, Proposers: []string{account0Addr}, } bz, err := json.Marshal(&p) s.Require().NoError(err) proposalFile := testutil.WriteToNewTempFile(s.T(), string(bz)) cmd := groupcli.MsgSubmitProposalCmd() cmd.SetOutput(io.Discard) testCases := []struct { name string args []string expCmdOutput string expectErrMsg string }{ { "correct data", append( []string{ proposalFile.Name(), }, s.commonFlags..., ), proposalFile.Name(), "", }, { "with try exec", append( []string{ proposalFile.Name(), fmt.Sprintf("--%s=try", groupcli.FlagExec), }, s.commonFlags..., ), fmt.Sprintf("%s --%s=try", proposalFile.Name(), groupcli.FlagExec), "", }, { "with try exec, not enough yes votes for proposal to pass", append( []string{ proposalFile.Name(), fmt.Sprintf("--%s=try", groupcli.FlagExec), }, s.commonFlags..., ), fmt.Sprintf("%s --%s=try", proposalFile.Name(), groupcli.FlagExec), "", }, { "with amino-json", append( []string{ proposalFile.Name(), fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON), }, s.commonFlags..., ), fmt.Sprintf("%s --%s=%s", proposalFile.Name(), flags.FlagSignMode, flags.SignModeLegacyAminoJSON), "", }, } for _, tc := range testCases { tc := tc s.Run(tc.name, func() { ctx := svrcmd.CreateExecuteContext(context.Background()) cmd.SetContext(ctx) cmd.SetArgs(tc.args) s.Require().NoError(client.SetCmdClientContextHandler(s.baseCtx, cmd)) if len(tc.args) != 0 { s.Require().Contains(fmt.Sprint(cmd), tc.expCmdOutput) } out, err := clitestutil.ExecTestCLICmd(s.baseCtx, cmd, tc.args) if tc.expectErrMsg != "" { s.Require().Error(err) s.Require().Contains(out.String(), tc.expectErrMsg) } else { s.Require().NoError(err) msg := &sdk.TxResponse{} s.Require().NoError(s.baseCtx.Codec.UnmarshalJSON(out.Bytes(), msg), out.String()) } }) } }