package keeper_test import ( "strings" "github.com/cosmos/cosmos-sdk/testutil/testdata" sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" ) func (suite *KeeperTestSuite) TestSubmitProposalReq() { govAcct := suite.app.GovKeeper.GetGovernanceAccount(suite.ctx).GetAddress() addrs := suite.addrs proposer := addrs[0] coins := sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(100))) initialDeposit := coins minDeposit := suite.app.GovKeeper.GetDepositParams(suite.ctx).MinDeposit bankMsg := &banktypes.MsgSend{ FromAddress: govAcct.String(), ToAddress: proposer.String(), Amount: coins, } cases := map[string]struct { preRun func() (*v1.MsgSubmitProposal, error) expErr bool expErrMsg string }{ "metadata too long": { preRun: func() (*v1.MsgSubmitProposal, error) { return v1.NewMsgSubmitProposal( []sdk.Msg{bankMsg}, initialDeposit, proposer.String(), strings.Repeat("1", 300), ) }, expErr: true, expErrMsg: "metadata too long", }, "many signers": { preRun: func() (*v1.MsgSubmitProposal, error) { return v1.NewMsgSubmitProposal( []sdk.Msg{testdata.NewTestMsg(govAcct, addrs[0])}, initialDeposit, proposer.String(), "", ) }, expErr: true, expErrMsg: "expected gov account as only signer for proposal message", }, "signer isn't gov account": { preRun: func() (*v1.MsgSubmitProposal, error) { return v1.NewMsgSubmitProposal( []sdk.Msg{testdata.NewTestMsg(addrs[0])}, initialDeposit, proposer.String(), "", ) }, expErr: true, expErrMsg: "expected gov account as only signer for proposal message", }, "invalid msg handler": { preRun: func() (*v1.MsgSubmitProposal, error) { return v1.NewMsgSubmitProposal( []sdk.Msg{testdata.NewTestMsg(govAcct)}, initialDeposit, proposer.String(), "", ) }, expErr: true, expErrMsg: "proposal message not recognized by router", }, "all good": { preRun: func() (*v1.MsgSubmitProposal, error) { return v1.NewMsgSubmitProposal( []sdk.Msg{bankMsg}, initialDeposit, proposer.String(), "", ) }, expErr: false, }, "all good with min deposit": { preRun: func() (*v1.MsgSubmitProposal, error) { return v1.NewMsgSubmitProposal( []sdk.Msg{bankMsg}, minDeposit, proposer.String(), "", ) }, expErr: false, }, } for name, tc := range cases { suite.Run(name, func() { msg, err := tc.preRun() suite.Require().NoError(err) res, err := suite.msgSrvr.SubmitProposal(suite.ctx, msg) if tc.expErr { suite.Require().Error(err) suite.Require().Contains(err.Error(), tc.expErrMsg) } else { suite.Require().NoError(err) suite.Require().NotNil(res.ProposalId) } }) } } func (suite *KeeperTestSuite) TestVoteReq() { govAcct := suite.app.GovKeeper.GetGovernanceAccount(suite.ctx).GetAddress() addrs := suite.addrs proposer := addrs[0] coins := sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(100))) minDeposit := suite.app.GovKeeper.GetDepositParams(suite.ctx).MinDeposit bankMsg := &banktypes.MsgSend{ FromAddress: govAcct.String(), ToAddress: proposer.String(), Amount: coins, } msg, err := v1.NewMsgSubmitProposal( []sdk.Msg{bankMsg}, minDeposit, proposer.String(), "", ) suite.Require().NoError(err) res, err := suite.msgSrvr.SubmitProposal(suite.ctx, msg) suite.Require().NoError(err) suite.Require().NotNil(res.ProposalId) proposalId := res.ProposalId cases := map[string]struct { preRun func() uint64 expErr bool expErrMsg string option v1.VoteOption metadata string voter sdk.AccAddress }{ "vote on inactive proposal": { preRun: func() uint64 { msg, err := v1.NewMsgSubmitProposal( []sdk.Msg{bankMsg}, coins, proposer.String(), "", ) suite.Require().NoError(err) res, err := suite.msgSrvr.SubmitProposal(suite.ctx, msg) suite.Require().NoError(err) suite.Require().NotNil(res.ProposalId) return res.ProposalId }, option: v1.VoteOption_VOTE_OPTION_YES, voter: proposer, metadata: "", expErr: true, expErrMsg: "inactive proposal", }, "metadata too long": { preRun: func() uint64 { return proposalId }, option: v1.VoteOption_VOTE_OPTION_YES, voter: proposer, metadata: strings.Repeat("a", 300), expErr: true, expErrMsg: "metadata too long", }, "voter error": { preRun: func() uint64 { return proposalId }, option: v1.VoteOption_VOTE_OPTION_YES, voter: sdk.AccAddress(strings.Repeat("a", 300)), metadata: "", expErr: true, expErrMsg: "address max length is 255", }, "all good": { preRun: func() uint64 { msg, err := v1.NewMsgSubmitProposal( []sdk.Msg{bankMsg}, minDeposit, proposer.String(), "", ) suite.Require().NoError(err) res, err := suite.msgSrvr.SubmitProposal(suite.ctx, msg) suite.Require().NoError(err) suite.Require().NotNil(res.ProposalId) return res.ProposalId }, option: v1.VoteOption_VOTE_OPTION_YES, voter: proposer, metadata: "", expErr: false, }, } for name, tc := range cases { suite.Run(name, func() { pId := tc.preRun() voteReq := v1.NewMsgVote(tc.voter, pId, tc.option, tc.metadata) _, err := suite.msgSrvr.Vote(suite.ctx, voteReq) if tc.expErr { suite.Require().Error(err) suite.Require().Contains(err.Error(), tc.expErrMsg) } else { suite.Require().NoError(err) } }) } } func (suite *KeeperTestSuite) TestVoteWeightedReq() { govAcct := suite.app.GovKeeper.GetGovernanceAccount(suite.ctx).GetAddress() addrs := suite.addrs proposer := addrs[0] coins := sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(100))) minDeposit := suite.app.GovKeeper.GetDepositParams(suite.ctx).MinDeposit bankMsg := &banktypes.MsgSend{ FromAddress: govAcct.String(), ToAddress: proposer.String(), Amount: coins, } msg, err := v1.NewMsgSubmitProposal( []sdk.Msg{bankMsg}, minDeposit, proposer.String(), "", ) suite.Require().NoError(err) res, err := suite.msgSrvr.SubmitProposal(suite.ctx, msg) suite.Require().NoError(err) suite.Require().NotNil(res.ProposalId) proposalId := res.ProposalId cases := map[string]struct { preRun func() uint64 vote *v1.MsgVote expErr bool expErrMsg string option v1.VoteOption metadata string voter sdk.AccAddress }{ "vote on inactive proposal": { preRun: func() uint64 { msg, err := v1.NewMsgSubmitProposal( []sdk.Msg{bankMsg}, coins, proposer.String(), "", ) suite.Require().NoError(err) res, err := suite.msgSrvr.SubmitProposal(suite.ctx, msg) suite.Require().NoError(err) suite.Require().NotNil(res.ProposalId) return res.ProposalId }, option: v1.VoteOption_VOTE_OPTION_YES, voter: proposer, metadata: "", expErr: true, expErrMsg: "inactive proposal", }, "metadata too long": { preRun: func() uint64 { return proposalId }, option: v1.VoteOption_VOTE_OPTION_YES, voter: proposer, metadata: strings.Repeat("a", 300), expErr: true, expErrMsg: "metadata too long", }, "voter error": { preRun: func() uint64 { return proposalId }, option: v1.VoteOption_VOTE_OPTION_YES, voter: sdk.AccAddress(strings.Repeat("a", 300)), metadata: "", expErr: true, expErrMsg: "address max length is 255", }, "all good": { preRun: func() uint64 { msg, err := v1.NewMsgSubmitProposal( []sdk.Msg{bankMsg}, minDeposit, proposer.String(), "", ) suite.Require().NoError(err) res, err := suite.msgSrvr.SubmitProposal(suite.ctx, msg) suite.Require().NoError(err) suite.Require().NotNil(res.ProposalId) return res.ProposalId }, option: v1.VoteOption_VOTE_OPTION_YES, voter: proposer, metadata: "", expErr: false, }, } for name, tc := range cases { suite.Run(name, func() { pId := tc.preRun() voteReq := v1.NewMsgVoteWeighted(tc.voter, pId, v1.NewNonSplitVoteOption(tc.option), tc.metadata) _, err := suite.msgSrvr.VoteWeighted(suite.ctx, voteReq) if tc.expErr { suite.Require().Error(err) suite.Require().Contains(err.Error(), tc.expErrMsg) } else { suite.Require().NoError(err) } }) } } func (suite *KeeperTestSuite) TestDepositReq() { govAcct := suite.app.GovKeeper.GetGovernanceAccount(suite.ctx).GetAddress() addrs := suite.addrs proposer := addrs[0] coins := sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(100))) minDeposit := suite.app.GovKeeper.GetDepositParams(suite.ctx).MinDeposit bankMsg := &banktypes.MsgSend{ FromAddress: govAcct.String(), ToAddress: proposer.String(), Amount: coins, } msg, err := v1.NewMsgSubmitProposal( []sdk.Msg{bankMsg}, coins, proposer.String(), "", ) suite.Require().NoError(err) res, err := suite.msgSrvr.SubmitProposal(suite.ctx, msg) suite.Require().NoError(err) suite.Require().NotNil(res.ProposalId) pId := res.ProposalId cases := map[string]struct { preRun func() uint64 expErr bool proposalId uint64 depositor sdk.AccAddress deposit sdk.Coins options v1.WeightedVoteOptions }{ "wrong proposal id": { preRun: func() uint64 { return 0 }, depositor: proposer, deposit: coins, expErr: true, options: v1.NewNonSplitVoteOption(v1.OptionYes), }, "all good": { preRun: func() uint64 { return pId }, depositor: proposer, deposit: minDeposit, expErr: false, options: v1.NewNonSplitVoteOption(v1.OptionYes), }, } for name, tc := range cases { suite.Run(name, func() { proposalId := tc.preRun() depositReq := v1.NewMsgDeposit(tc.depositor, proposalId, tc.deposit) _, err := suite.msgSrvr.Deposit(suite.ctx, depositReq) if tc.expErr { suite.Require().Error(err) } else { suite.Require().NoError(err) } }) } } // legacy msg server tests func (suite *KeeperTestSuite) TestLegacyMsgSubmitProposal() { addrs := suite.addrs proposer := addrs[0] coins := sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(100))) initialDeposit := coins minDeposit := suite.app.GovKeeper.GetDepositParams(suite.ctx).MinDeposit cases := map[string]struct { preRun func() (*v1beta1.MsgSubmitProposal, error) expErr bool }{ "all good": { preRun: func() (*v1beta1.MsgSubmitProposal, error) { return v1beta1.NewMsgSubmitProposal( v1beta1.NewTextProposal("test", "I am test"), initialDeposit, proposer, ) }, expErr: false, }, "all good with min deposit": { preRun: func() (*v1beta1.MsgSubmitProposal, error) { return v1beta1.NewMsgSubmitProposal( v1beta1.NewTextProposal("test", "I am test"), minDeposit, proposer, ) }, expErr: false, }, } for name, c := range cases { suite.Run(name, func() { msg, err := c.preRun() suite.Require().NoError(err) res, err := suite.legacyMsgSrvr.SubmitProposal(suite.ctx, msg) if c.expErr { suite.Require().Error(err) } else { suite.Require().NoError(err) suite.Require().NotNil(res.ProposalId) } }) } } func (suite *KeeperTestSuite) TestLegacyMsgVote() { govAcct := suite.app.GovKeeper.GetGovernanceAccount(suite.ctx).GetAddress() addrs := suite.addrs proposer := addrs[0] coins := sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(100))) minDeposit := suite.app.GovKeeper.GetDepositParams(suite.ctx).MinDeposit bankMsg := &banktypes.MsgSend{ FromAddress: govAcct.String(), ToAddress: proposer.String(), Amount: coins, } msg, err := v1.NewMsgSubmitProposal( []sdk.Msg{bankMsg}, minDeposit, proposer.String(), "", ) suite.Require().NoError(err) res, err := suite.msgSrvr.SubmitProposal(suite.ctx, msg) suite.Require().NoError(err) suite.Require().NotNil(res.ProposalId) proposalId := res.ProposalId cases := map[string]struct { preRun func() uint64 expErr bool expErrMsg string option v1beta1.VoteOption metadata string voter sdk.AccAddress }{ "vote on inactive proposal": { preRun: func() uint64 { msg, err := v1.NewMsgSubmitProposal( []sdk.Msg{bankMsg}, coins, proposer.String(), "", ) suite.Require().NoError(err) res, err := suite.msgSrvr.SubmitProposal(suite.ctx, msg) suite.Require().NoError(err) suite.Require().NotNil(res.ProposalId) return res.ProposalId }, option: v1beta1.OptionYes, voter: proposer, metadata: "", expErr: true, expErrMsg: "inactive proposal", }, "voter error": { preRun: func() uint64 { return proposalId }, option: v1beta1.OptionYes, voter: sdk.AccAddress(strings.Repeat("a", 300)), metadata: "", expErr: true, expErrMsg: "address max length is 255", }, "all good": { preRun: func() uint64 { msg, err := v1.NewMsgSubmitProposal( []sdk.Msg{bankMsg}, minDeposit, proposer.String(), "", ) suite.Require().NoError(err) res, err := suite.msgSrvr.SubmitProposal(suite.ctx, msg) suite.Require().NoError(err) suite.Require().NotNil(res.ProposalId) return res.ProposalId }, option: v1beta1.OptionYes, voter: proposer, metadata: "", expErr: false, }, } for name, tc := range cases { suite.Run(name, func() { pId := tc.preRun() voteReq := v1beta1.NewMsgVote(tc.voter, pId, tc.option) _, err := suite.legacyMsgSrvr.Vote(suite.ctx, voteReq) if tc.expErr { suite.Require().Error(err) suite.Require().Contains(err.Error(), tc.expErrMsg) } else { suite.Require().NoError(err) } }) } } func (suite *KeeperTestSuite) TestLegacyVoteWeighted() { govAcct := suite.app.GovKeeper.GetGovernanceAccount(suite.ctx).GetAddress() addrs := suite.addrs proposer := addrs[0] coins := sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(100))) minDeposit := suite.app.GovKeeper.GetDepositParams(suite.ctx).MinDeposit bankMsg := &banktypes.MsgSend{ FromAddress: govAcct.String(), ToAddress: proposer.String(), Amount: coins, } msg, err := v1.NewMsgSubmitProposal( []sdk.Msg{bankMsg}, minDeposit, proposer.String(), "", ) suite.Require().NoError(err) res, err := suite.msgSrvr.SubmitProposal(suite.ctx, msg) suite.Require().NoError(err) suite.Require().NotNil(res.ProposalId) proposalId := res.ProposalId cases := map[string]struct { preRun func() uint64 vote *v1beta1.MsgVote expErr bool expErrMsg string option v1beta1.VoteOption metadata string voter sdk.AccAddress }{ "vote on inactive proposal": { preRun: func() uint64 { msg, err := v1.NewMsgSubmitProposal( []sdk.Msg{bankMsg}, coins, proposer.String(), "", ) suite.Require().NoError(err) res, err := suite.msgSrvr.SubmitProposal(suite.ctx, msg) suite.Require().NoError(err) suite.Require().NotNil(res.ProposalId) return res.ProposalId }, option: v1beta1.OptionYes, voter: proposer, metadata: "", expErr: true, expErrMsg: "inactive proposal", }, "voter error": { preRun: func() uint64 { return proposalId }, option: v1beta1.OptionYes, voter: sdk.AccAddress(strings.Repeat("a", 300)), metadata: "", expErr: true, expErrMsg: "address max length is 255", }, "all good": { preRun: func() uint64 { msg, err := v1.NewMsgSubmitProposal( []sdk.Msg{bankMsg}, minDeposit, proposer.String(), "", ) suite.Require().NoError(err) res, err := suite.msgSrvr.SubmitProposal(suite.ctx, msg) suite.Require().NoError(err) suite.Require().NotNil(res.ProposalId) return res.ProposalId }, option: v1beta1.OptionYes, voter: proposer, metadata: "", expErr: false, }, } for name, tc := range cases { suite.Run(name, func() { pId := tc.preRun() voteReq := v1beta1.NewMsgVoteWeighted(tc.voter, pId, v1beta1.NewNonSplitVoteOption(v1beta1.VoteOption(tc.option))) _, err := suite.legacyMsgSrvr.VoteWeighted(suite.ctx, voteReq) if tc.expErr { suite.Require().Error(err) suite.Require().Contains(err.Error(), tc.expErrMsg) } else { suite.Require().NoError(err) } }) } } func (suite *KeeperTestSuite) TestLegacyMsgDeposit() { govAcct := suite.app.GovKeeper.GetGovernanceAccount(suite.ctx).GetAddress() addrs := suite.addrs proposer := addrs[0] coins := sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(100))) minDeposit := suite.app.GovKeeper.GetDepositParams(suite.ctx).MinDeposit bankMsg := &banktypes.MsgSend{ FromAddress: govAcct.String(), ToAddress: proposer.String(), Amount: coins, } msg, err := v1.NewMsgSubmitProposal( []sdk.Msg{bankMsg}, coins, proposer.String(), "", ) suite.Require().NoError(err) res, err := suite.msgSrvr.SubmitProposal(suite.ctx, msg) suite.Require().NoError(err) suite.Require().NotNil(res.ProposalId) pId := res.ProposalId cases := map[string]struct { preRun func() uint64 expErr bool proposalId uint64 depositor sdk.AccAddress deposit sdk.Coins options v1beta1.WeightedVoteOptions }{ "wrong proposal id": { preRun: func() uint64 { return 0 }, depositor: proposer, deposit: coins, expErr: true, options: v1beta1.NewNonSplitVoteOption(v1beta1.OptionYes), }, "all good": { preRun: func() uint64 { return pId }, depositor: proposer, deposit: minDeposit, expErr: false, options: v1beta1.NewNonSplitVoteOption(v1beta1.OptionYes), }, } for name, tc := range cases { suite.Run(name, func() { proposalId := tc.preRun() depositReq := v1beta1.NewMsgDeposit(tc.depositor, proposalId, tc.deposit) _, err := suite.legacyMsgSrvr.Deposit(suite.ctx, depositReq) if tc.expErr { suite.Require().Error(err) } else { suite.Require().NoError(err) } }) } }