feat(x/group): autocli tx support (#18102)

This commit is contained in:
atheeshp 2023-10-12 20:37:26 +05:30 committed by GitHub
parent fe99b0c2f8
commit b8b32cf494
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 101 additions and 955 deletions

View File

@ -171,18 +171,14 @@ func (s *E2ETestSuite) SetupSuite() {
s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &txResp), out.String())
s.Require().NoError(clitestutil.CheckTxCode(s.network, val.ClientCtx, txResp.TxHash, 0))
msg := &group.MsgVote{
ProposalId: uint64(1),
Voter: val.Address.String(),
Option: group.VOTE_OPTION_YES,
}
// vote
out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, client.MsgVoteCmd(),
append(
[]string{
"1",
val.Address.String(),
"VOTE_OPTION_YES",
"",
},
s.commonFlags...,
),
)
out, err = clitestutil.SubmitTestTx(val.ClientCtx, msg, val.Address, clitestutil.TestTxConfig{})
s.Require().NoError(err, out.String())
s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &txResp), out.String())
s.Require().NoError(clitestutil.CheckTxCode(s.network, val.ClientCtx, txResp.TxHash, 0))

View File

@ -4,7 +4,6 @@ import (
"errors"
"fmt"
"strconv"
"strings"
"github.com/spf13/cobra"
@ -38,19 +37,11 @@ func TxCmd(name string, ac address.Codec) *cobra.Command {
txCmd.AddCommand(
MsgCreateGroupCmd(),
MsgUpdateGroupAdminCmd(),
MsgUpdateGroupMetadataCmd(),
MsgUpdateGroupMembersCmd(),
MsgCreateGroupWithPolicyCmd(),
MsgCreateGroupPolicyCmd(),
MsgUpdateGroupPolicyAdminCmd(),
MsgUpdateGroupPolicyDecisionPolicyCmd(ac),
MsgUpdateGroupPolicyMetadataCmd(),
MsgWithdrawProposalCmd(),
MsgSubmitProposalCmd(),
MsgVoteCmd(),
MsgExecCmd(),
MsgLeaveGroupCmd(),
NewCmdDraftProposal(),
)
@ -58,6 +49,8 @@ func TxCmd(name string, ac address.Codec) *cobra.Command {
}
// MsgCreateGroupCmd creates a CLI command for Msg/CreateGroup.
//
// This command is being handled better here, not converting to autocli
func MsgCreateGroupCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create-group [admin] [metadata] [members-json-file]",
@ -122,6 +115,8 @@ Where members.json contains:
}
// MsgUpdateGroupMembersCmd creates a CLI command for Msg/UpdateGroupMembers.
//
// This command is being handled better here, not converting to autocli
func MsgUpdateGroupMembersCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "update-group-members [admin] [group-id] [members-json-file]",
@ -195,92 +190,9 @@ Set a member's weight to "0" to delete it.
return cmd
}
// MsgUpdateGroupAdminCmd creates a CLI command for Msg/UpdateGroupAdmin.
func MsgUpdateGroupAdminCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "update-group-admin [admin] [group-id] [new-admin]",
Short: "Update a group's admin",
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
if err := cmd.Flags().Set(flags.FlagFrom, args[0]); err != nil {
return err
}
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
groupID, err := strconv.ParseUint(args[1], 10, 64)
if err != nil {
return err
}
if groupID == 0 {
return errZeroGroupID
}
if strings.EqualFold(args[0], args[2]) {
return errors.New("new admin cannot be the same as the current admin")
}
msg := &group.MsgUpdateGroupAdmin{
Admin: clientCtx.GetFromAddress().String(),
NewAdmin: args[2],
GroupId: groupID,
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}
// MsgUpdateGroupMetadataCmd creates a CLI command for Msg/UpdateGroupMetadata.
func MsgUpdateGroupMetadataCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "update-group-metadata [admin] [group-id] [metadata]",
Short: "Update a group's metadata",
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
err := cmd.Flags().Set(flags.FlagFrom, args[0])
if err != nil {
return err
}
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
groupID, err := strconv.ParseUint(args[1], 10, 64)
if err != nil {
return err
}
if groupID == 0 {
return errZeroGroupID
}
msg := &group.MsgUpdateGroupMetadata{
Admin: clientCtx.GetFromAddress().String(),
Metadata: args[2],
GroupId: groupID,
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}
// MsgCreateGroupWithPolicyCmd creates a CLI command for Msg/CreateGroupWithPolicy.
//
// This command is being handled better here, not converting to autocli
func MsgCreateGroupWithPolicyCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create-group-with-policy [admin] [group-metadata] [group-policy-metadata] [members-json-file] [decision-policy-json-file]",
@ -379,6 +291,8 @@ and policy.json contains:
}
// MsgCreateGroupPolicyCmd creates a CLI command for Msg/CreateGroupPolicy.
//
// This command is being handled better here, not converting to autocli
func MsgCreateGroupPolicyCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create-group-policy [admin] [group-id] [metadata] [decision-policy-json-file]",
@ -456,42 +370,9 @@ Here, we can use percentage decision policy when needed, where 0 < percentage <=
return cmd
}
// MsgUpdateGroupPolicyAdminCmd creates a CLI command for Msg/UpdateGroupPolicyAdmin.
func MsgUpdateGroupPolicyAdminCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "update-group-policy-admin [admin] [group-policy-account] [new-admin]",
Short: "Update a group policy admin",
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
if err := cmd.Flags().Set(flags.FlagFrom, args[0]); err != nil {
return err
}
if strings.EqualFold(args[0], args[2]) {
return errors.New("new admin cannot be the same as the current admin")
}
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
msg := &group.MsgUpdateGroupPolicyAdmin{
Admin: clientCtx.GetFromAddress().String(),
GroupPolicyAddress: args[1],
NewAdmin: args[2],
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}
// MsgUpdateGroupPolicyDecisionPolicyCmd creates a CLI command for Msg/UpdateGroupPolicyDecisionPolicy.
//
// This command is being handled better here, not converting to autocli
func MsgUpdateGroupPolicyDecisionPolicyCmd(ac address.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "update-group-policy-decision-policy [admin] [group-policy-account] [decision-policy-json-file]",
@ -536,38 +417,9 @@ func MsgUpdateGroupPolicyDecisionPolicyCmd(ac address.Codec) *cobra.Command {
return cmd
}
// MsgUpdateGroupPolicyMetadataCmd creates a CLI command for Msg/UpdateGroupPolicyMetadata.
func MsgUpdateGroupPolicyMetadataCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "update-group-policy-metadata [admin] [group-policy-account] [new-metadata]",
Short: "Update a group policy metadata",
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
if err := cmd.Flags().Set(flags.FlagFrom, args[0]); err != nil {
return err
}
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
msg := &group.MsgUpdateGroupPolicyMetadata{
Admin: clientCtx.GetFromAddress().String(),
GroupPolicyAddress: args[1],
Metadata: args[2],
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}
// MsgSubmitProposalCmd creates a CLI command for Msg/SubmitProposal.
//
// This command is being handled better here, not converting to autocli
func MsgSubmitProposalCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "submit-proposal [proposal_json_file]",
@ -659,186 +511,3 @@ metadata example:
return cmd
}
// MsgWithdrawProposalCmd creates a CLI command for Msg/WithdrawProposal.
func MsgWithdrawProposalCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "withdraw-proposal [proposal-id] [group-policy-admin-or-proposer]",
Short: "Withdraw a submitted proposal",
Long: `Withdraw a submitted proposal.
Parameters:
proposal-id: unique ID of the proposal.
group-policy-admin-or-proposer: either admin of the group policy or one the proposer of the proposal.
Note: --from flag will be ignored here.
`,
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
if err := cmd.Flags().Set(flags.FlagFrom, args[1]); err != nil {
return err
}
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
proposalID, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
return err
}
if proposalID == 0 {
return fmt.Errorf("invalid proposal id: %d", proposalID)
}
msg := &group.MsgWithdrawProposal{
ProposalId: proposalID,
Address: clientCtx.GetFromAddress().String(),
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}
// MsgVoteCmd creates a CLI command for Msg/Vote.
func MsgVoteCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "vote [proposal-id] [voter] [vote-option] [metadata]",
Short: "Vote on a proposal",
Long: `Vote on a proposal.
Parameters:
proposal-id: unique ID of the proposal
voter: voter account addresses.
vote-option: choice of the voter(s)
VOTE_OPTION_UNSPECIFIED: no-op
VOTE_OPTION_NO: no
VOTE_OPTION_YES: yes
VOTE_OPTION_ABSTAIN: abstain
VOTE_OPTION_NO_WITH_VETO: no-with-veto
Metadata: metadata for the vote
`,
Args: cobra.ExactArgs(4),
RunE: func(cmd *cobra.Command, args []string) error {
err := cmd.Flags().Set(flags.FlagFrom, args[1])
if err != nil {
return err
}
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
proposalID, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
return err
}
voteOption, err := group.VoteOptionFromString(args[2])
if err != nil {
return err
}
execStr, _ := cmd.Flags().GetString(FlagExec)
msg := &group.MsgVote{
ProposalId: proposalID,
Voter: args[1],
Option: voteOption,
Metadata: args[3],
Exec: execFromString(execStr),
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
cmd.Flags().String(FlagExec, "", "Set to 1 to try to execute proposal immediately after voting")
flags.AddTxFlagsToCmd(cmd)
return cmd
}
// MsgExecCmd creates a CLI command for Msg/Exec.
func MsgExecCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "exec [proposal-id]",
Short: "Execute a proposal",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
proposalID, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
return err
}
msg := &group.MsgExec{
ProposalId: proposalID,
Executor: clientCtx.GetFromAddress().String(),
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}
// MsgLeaveGroupCmd creates a CLI command for Msg/LeaveGroup.
func MsgLeaveGroupCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "leave-group [member-address] [group-id]",
Short: "Remove member from the group",
Long: `Remove member from the group
Parameters:
group-id: unique id of the group
member-address: account address of the group member
Note, the '--from' flag is ignored as it is implied from [member-address]
`,
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
err := cmd.Flags().Set(flags.FlagFrom, args[0])
if err != nil {
return err
}
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
groupID, err := strconv.ParseUint(args[1], 10, 64)
if err != nil {
return err
}
if groupID == 0 {
return errZeroGroupID
}
msg := &group.MsgLeaveGroup{
Address: clientCtx.GetFromAddress().String(),
GroupId: groupID,
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}

View File

@ -239,231 +239,6 @@ func (s *CLITestSuite) TestTxCreateGroup() {
}
}
func (s *CLITestSuite) TestTxUpdateGroupAdmin() {
accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 2)
cmd := groupcli.MsgUpdateGroupAdminCmd()
cmd.SetOutput(io.Discard)
ctx := svrcmd.CreateExecuteContext(context.Background())
cmd.SetContext(ctx)
s.Require().NoError(client.SetCmdClientContextHandler(s.baseCtx, cmd))
groupIDs := make([]string, 2)
for i := 0; i < 2; i++ {
validMembers := fmt.Sprintf(`{"members": [{
"address": "%s",
"weight": "1",
"metadata": "%s"
}]}`, accounts[0].Address.String(), validMetadata)
validMembersFile := testutil.WriteToNewTempFile(s.T(), validMembers)
out, err := clitestutil.ExecTestCLICmd(s.baseCtx, groupcli.MsgCreateGroupCmd(),
append(
[]string{
accounts[0].Address.String(),
validMetadata,
validMembersFile.Name(),
},
s.commonFlags...,
),
)
s.Require().NoError(err, out.String())
groupIDs[i] = fmt.Sprintf("%d", i+1)
}
testCases := []struct {
name string
ctxGen func() client.Context
args []string
expCmdOutput string
expectErrMsg string
}{
{
"correct data",
func() client.Context {
bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{})
c := clitestutil.NewMockCometRPC(abci.ResponseQuery{
Value: bz,
})
return s.baseCtx.WithClient(c)
},
append(
[]string{
accounts[0].Address.String(),
groupIDs[0],
accounts[1].Address.String(),
},
s.commonFlags...,
),
fmt.Sprintf("%s %s %s", accounts[0].Address.String(), groupIDs[0], accounts[1].Address.String()),
"",
},
{
"with amino-json",
func() client.Context {
bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{})
c := clitestutil.NewMockCometRPC(abci.ResponseQuery{
Value: bz,
})
return s.baseCtx.WithClient(c)
},
append(
[]string{
accounts[0].Address.String(),
groupIDs[1],
accounts[1].Address.String(),
fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON),
},
s.commonFlags...,
),
fmt.Sprintf("%s %s %s --%s=%s", accounts[0].Address.String(), groupIDs[1], accounts[1].Address.String(), flags.FlagSignMode, flags.SignModeLegacyAminoJSON),
"",
},
{
"group id invalid",
func() client.Context {
bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{})
c := clitestutil.NewMockCometRPC(abci.ResponseQuery{
Value: bz,
})
return s.baseCtx.WithClient(c)
},
append(
[]string{
accounts[0].Address.String(),
"",
accounts[1].Address.String(),
},
s.commonFlags...,
),
fmt.Sprintf("%s %s %s", accounts[0].Address.String(), "", accounts[1].Address.String()),
"strconv.ParseUint: parsing \"\": invalid syntax",
},
}
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) TestTxUpdateGroupMetadata() {
accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 1)
cmd := groupcli.MsgUpdateGroupMetadataCmd()
cmd.SetOutput(io.Discard)
testCases := []struct {
name string
args []string
expCmdOutput string
expectErrMsg string
}{
{
"correct data",
append(
[]string{
accounts[0].Address.String(),
"1",
validMetadata,
},
s.commonFlags...,
),
fmt.Sprintf("%s %s %s", accounts[0].Address.String(), "1", validMetadata),
"",
},
{
"with amino-json",
append(
[]string{
accounts[0].Address.String(),
"1",
validMetadata,
fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON),
},
s.commonFlags...,
),
fmt.Sprintf("%s %s %s --%s=%s", accounts[0].Address.String(), "1", validMetadata, flags.FlagSignMode, flags.SignModeLegacyAminoJSON),
"",
},
{
"invalid group id",
append(
[]string{
accounts[0].Address.String(),
"abc",
validMetadata,
},
s.commonFlags...,
),
fmt.Sprintf("%s %s %s", accounts[0].Address.String(), "abc", validMetadata),
"Error: strconv.ParseUint: parsing \"abc\"",
},
{
"empty group id",
append(
[]string{
accounts[0].Address.String(),
"0",
validMetadata,
},
s.commonFlags...,
),
fmt.Sprintf("%s %s %s", accounts[0].Address.String(), "0", validMetadata),
"group id cannot be 0",
},
}
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]
@ -836,107 +611,6 @@ func (s *CLITestSuite) TestTxCreateGroupPolicy() {
}
}
func (s *CLITestSuite) TestTxUpdateGroupPolicyAdmin() {
accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 4)
newAdmin := accounts[0]
groupPolicyAdmin := accounts[1]
groupPolicyAddress := accounts[2]
commonFlags := s.commonFlags
commonFlags = append(commonFlags, fmt.Sprintf("--%s=%d", flags.FlagGas, 300000))
cmd := groupcli.MsgUpdateGroupPolicyAdminCmd()
cmd.SetOutput(io.Discard)
testCases := []struct {
name string
args []string
expCmdOutput string
expectErrMsg string
}{
{
"correct data",
append(
[]string{
groupPolicyAdmin.Address.String(),
groupPolicyAddress.Address.String(),
newAdmin.Address.String(),
},
commonFlags...,
),
fmt.Sprintf("%s %s %s", groupPolicyAdmin.Address.String(), groupPolicyAddress.Address.String(), newAdmin.Address.String()),
"",
},
{
"with amino-json",
append(
[]string{
groupPolicyAdmin.Address.String(),
groupPolicyAddress.Address.String(),
newAdmin.Address.String(),
fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON),
},
commonFlags...,
),
fmt.Sprintf("%s %s %s --%s=%s", groupPolicyAdmin.Address.String(), groupPolicyAddress.Address.String(), newAdmin.Address.String(), flags.FlagSignMode, flags.SignModeLegacyAminoJSON),
"",
},
{
"wrong admin",
append(
[]string{
"wrong admin",
groupPolicyAddress.Address.String(),
newAdmin.Address.String(),
},
commonFlags...,
),
fmt.Sprintf("%s %s %s", "wrong admin", groupPolicyAddress.Address.String(), newAdmin.Address.String()),
"key not found",
},
{
"identical admin and new admin",
append(
[]string{
groupPolicyAdmin.Address.String(),
groupPolicyAddress.Address.String(),
groupPolicyAdmin.Address.String(),
},
commonFlags...,
),
fmt.Sprintf("%s %s %s", groupPolicyAdmin.Address.String(), groupPolicyAddress.Address.String(), groupPolicyAdmin.Address.String()),
"new admin cannot be the same as the current admin",
},
}
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) TestTxUpdateGroupPolicyDecisionPolicy() {
accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 3)
newAdmin := accounts[0]
@ -1041,93 +715,6 @@ func (s *CLITestSuite) TestTxUpdateGroupPolicyDecisionPolicy() {
}
}
func (s *CLITestSuite) TestTxUpdateGroupPolicyMetadata() {
accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 2)
groupPolicyAdmin := accounts[0].Address
groupPolicyAddress := accounts[1].Address
commonFlags := s.commonFlags
commonFlags = append(commonFlags, fmt.Sprintf("--%s=%d", flags.FlagGas, 300000))
cmd := groupcli.MsgUpdateGroupPolicyMetadataCmd()
cmd.SetOutput(io.Discard)
testCases := []struct {
name string
args []string
expCmdOutput string
expectErrMsg string
}{
{
"correct data",
append(
[]string{
groupPolicyAdmin.String(),
groupPolicyAddress.String(),
validMetadata,
},
commonFlags...,
),
fmt.Sprintf("%s %s %s", groupPolicyAdmin.String(), groupPolicyAddress.String(), validMetadata),
"",
},
{
"with amino-json",
append(
[]string{
groupPolicyAdmin.String(),
groupPolicyAddress.String(),
validMetadata,
fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON),
},
commonFlags...,
),
fmt.Sprintf("%s %s %s --%s=%s", groupPolicyAdmin.String(), groupPolicyAddress.String(), validMetadata, flags.FlagSignMode, flags.SignModeLegacyAminoJSON),
"",
},
{
"wrong admin",
append(
[]string{
"wrong admin",
groupPolicyAddress.String(),
validMetadata,
},
commonFlags...,
),
fmt.Sprintf("%s %s %s", "wrong admin", groupPolicyAddress.String(), validMetadata),
"key not found",
},
}
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 := accounts[1].Address
@ -1227,190 +814,3 @@ func (s *CLITestSuite) TestTxSubmitProposal() {
})
}
}
func (s *CLITestSuite) TestTxVote() {
accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 4)
cmd := groupcli.MsgVoteCmd()
cmd.SetOutput(io.Discard)
ids := make([]string, 4)
for i := 0; i < len(ids); i++ {
ids[i] = fmt.Sprint(i + 1)
}
testCases := []struct {
name string
args []string
expCmdOutput string
expectErrMsg string
}{
{
"invalid vote",
append(
[]string{
ids[0],
accounts[0].Address.String(),
"AYE",
"",
},
s.commonFlags...,
),
fmt.Sprintf("%s %s %s", ids[0], accounts[0].Address.String(), "AYE"),
"Error: 'AYE' is not a valid vote option",
},
{
"correct data",
append(
[]string{
ids[0],
accounts[0].Address.String(),
"VOTE_OPTION_YES",
"",
},
s.commonFlags...,
),
fmt.Sprintf("%s %s %s", ids[0], accounts[0].Address.String(), "VOTE_OPTION_YES"),
"",
},
{
"with try exec",
append(
[]string{
ids[1],
accounts[0].Address.String(),
"VOTE_OPTION_YES",
"",
fmt.Sprintf("--%s=try", groupcli.FlagExec),
},
s.commonFlags...,
),
fmt.Sprintf("%s %s %s %s --%s=try", ids[1], accounts[0].Address.String(), "VOTE_OPTION_YES", "", groupcli.FlagExec),
"",
},
{
"with amino-json",
append(
[]string{
ids[3],
accounts[0].Address.String(),
"VOTE_OPTION_YES",
"",
fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON),
},
s.commonFlags...,
),
fmt.Sprintf("%s %s %s %s --%s=%s", ids[3], accounts[0].Address.String(), "VOTE_OPTION_YES", "", 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())
}
})
}
}
func (s *CLITestSuite) TestTxWithdrawProposal() {
accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 1)
cmd := groupcli.MsgWithdrawProposalCmd()
cmd.SetOutput(io.Discard)
ids := make([]string, 2)
ids[0] = "1"
ids[1] = "2"
testCases := []struct {
name string
args []string
expCmdOutput string
expectErrMsg string
}{
{
"correct data",
append(
[]string{
ids[0],
accounts[0].Address.String(),
},
s.commonFlags...,
),
fmt.Sprintf("%s %s", ids[0], accounts[0].Address.String()),
"",
},
{
"wrong admin",
append(
[]string{
ids[1],
"wrongAdmin",
},
s.commonFlags...,
),
fmt.Sprintf("%s %s", ids[1], "wrongAdmin"),
"key not found",
},
{
"wrong proposal id",
append(
[]string{
"abc",
accounts[0].Address.String(),
},
s.commonFlags...,
),
fmt.Sprintf("%s %s", "abc", accounts[0].Address.String()),
"Error: strconv.ParseUint: parsing \"abc\"",
},
}
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())
}
})
}
}

View File

@ -124,7 +124,88 @@ func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
},
},
Tx: &autocliv1.ServiceCommandDescriptor{
Service: groupv1.Query_ServiceDesc.ServiceName,
Service: groupv1.Msg_ServiceDesc.ServiceName,
EnhanceCustomCommand: true,
RpcCommandOptions: []*autocliv1.RpcCommandOptions{
{
RpcMethod: "UpdateGroupAdmin",
Use: "update-group-admin [admin] [group-id] [new-admin]",
Short: "Update a group's admin",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "admin"}, {ProtoField: "group_id"}, {ProtoField: "new_admin"},
},
},
{
RpcMethod: "UpdateGroupMetadata",
Use: "update-group-metadata [admin] [group-id] [metadata]",
Short: "Update a group's metadata",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "admin"}, {ProtoField: "group_id"}, {ProtoField: "metadata"},
},
},
{
RpcMethod: "UpdateGroupPolicyAdmin",
Use: "update-group-policy-admin [admin] [group-policy-account] [new-admin]",
Short: "Update a group policy admin",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "admin"}, {ProtoField: "group_policy_address"}, {ProtoField: "new_admin"},
},
},
{
RpcMethod: "UpdateGroupPolicyMetadata",
Use: "update-group-policy-admin [admin] [group-policy-account] [new-admin]",
Short: "Update a group policy admin",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "admin"}, {ProtoField: "group_policy_address"}, {ProtoField: "metadata"},
},
},
{
RpcMethod: "WithdrawProposal",
Use: "withdraw-proposal [proposal-id] [group-policy-admin-or-proposer]",
Short: "Withdraw a submitted proposal",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "proposal_id"}, {ProtoField: "address"},
},
},
{
RpcMethod: "Vote",
Use: "vote [proposal-id] [voter] [vote-option] [metadata]",
Long: `Vote on a proposal.
Parameters:
proposal-id: unique ID of the proposal
voter: voter account addresses.
vote-option: choice of the voter(s)
VOTE_OPTION_UNSPECIFIED: no-op
VOTE_OPTION_NO: no
VOTE_OPTION_YES: yes
VOTE_OPTION_ABSTAIN: abstain
VOTE_OPTION_NO_WITH_VETO: no-with-veto
Metadata: metadata for the vote
`,
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "proposal_id"}, {ProtoField: "voter"}, {ProtoField: "option"}, {ProtoField: "metadata"},
},
FlagOptions: map[string]*autocliv1.FlagOptions{
"exec": {Name: "exec", DefaultValue: "", Usage: "Set to 'try' for trying to execute proposal immediately after voting"},
},
},
{
RpcMethod: "Exec",
Use: "exec [proposal-id]",
Short: "Execute a proposal",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "proposal_id"},
},
},
{
RpcMethod: "LeaveGroup",
Use: "leave-group [member-address] [group-id]",
Short: "Remove member from the group",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{ProtoField: "address"}, {ProtoField: "group_id"},
},
},
},
},
}
}