diff --git a/x/gov/keeper/common_test.go b/x/gov/keeper/common_test.go index 7d6632e2..ac89e703 100644 --- a/x/gov/keeper/common_test.go +++ b/x/gov/keeper/common_test.go @@ -46,12 +46,34 @@ func getTestProposal() []sdk.Msg { } } +type mocks struct { + acctKeeper *govtestutil.MockAccountKeeper + bankKeeper *govtestutil.MockBankKeeper + stakingKeeper *govtestutil.MockStakingKeeper +} + +func mockAccountKeeperExpectations(ctx sdk.Context, m mocks) { + m.acctKeeper.EXPECT().GetModuleAddress(types.ModuleName).Return(govAcct).AnyTimes() + m.acctKeeper.EXPECT().GetModuleAccount(gomock.Any(), types.ModuleName).Return(authtypes.NewEmptyModuleAccount(types.ModuleName)).AnyTimes() +} + +func mockDefaultExpectations(ctx sdk.Context, m mocks) { + mockAccountKeeperExpectations(ctx, m) + trackMockBalances(m.bankKeeper) + m.stakingKeeper.EXPECT().TokensFromConsensusPower(ctx, gomock.Any()).DoAndReturn(func(ctx sdk.Context, power int64) math.Int { + return sdk.TokensFromConsensusPower(power, math.NewIntFromUint64(1000000)) + }).AnyTimes() + + m.stakingKeeper.EXPECT().BondDenom(ctx).Return("stake").AnyTimes() + m.stakingKeeper.EXPECT().IterateBondedValidatorsByPower(gomock.Any(), gomock.Any()).AnyTimes() + m.stakingKeeper.EXPECT().IterateDelegations(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() + m.stakingKeeper.EXPECT().TotalBondedTokens(gomock.Any()).Return(math.NewInt(10000000)).AnyTimes() +} + // setupGovKeeper creates a govKeeper as well as all its dependencies. -func setupGovKeeper(t *testing.T) ( +func setupGovKeeper(t *testing.T, expectations ...func(sdk.Context, mocks)) ( *keeper.Keeper, - *govtestutil.MockAccountKeeper, - *govtestutil.MockBankKeeper, - *govtestutil.MockStakingKeeper, + mocks, moduletestutil.TestEncodingConfig, sdk.Context, ) { @@ -69,23 +91,23 @@ func setupGovKeeper(t *testing.T) ( // gomock initializations ctrl := gomock.NewController(t) - acctKeeper := govtestutil.NewMockAccountKeeper(ctrl) - bankKeeper := govtestutil.NewMockBankKeeper(ctrl) - stakingKeeper := govtestutil.NewMockStakingKeeper(ctrl) - acctKeeper.EXPECT().GetModuleAddress(types.ModuleName).Return(govAcct).AnyTimes() - acctKeeper.EXPECT().GetModuleAccount(gomock.Any(), types.ModuleName).Return(authtypes.NewEmptyModuleAccount(types.ModuleName)).AnyTimes() - trackMockBalances(bankKeeper) - stakingKeeper.EXPECT().TokensFromConsensusPower(ctx, gomock.Any()).DoAndReturn(func(ctx sdk.Context, power int64) math.Int { - return sdk.TokensFromConsensusPower(power, math.NewIntFromUint64(1000000)) - }).AnyTimes() - stakingKeeper.EXPECT().BondDenom(ctx).Return("stake").AnyTimes() - stakingKeeper.EXPECT().IterateBondedValidatorsByPower(gomock.Any(), gomock.Any()).AnyTimes() - stakingKeeper.EXPECT().IterateDelegations(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() - stakingKeeper.EXPECT().TotalBondedTokens(gomock.Any()).Return(math.NewInt(10000000)).AnyTimes() + m := mocks{ + acctKeeper: govtestutil.NewMockAccountKeeper(ctrl), + bankKeeper: govtestutil.NewMockBankKeeper(ctrl), + stakingKeeper: govtestutil.NewMockStakingKeeper(ctrl), + } + if len(expectations) == 0 { + mockDefaultExpectations(ctx, m) + } else { + for _, exp := range expectations { + exp(ctx, m) + } + } // Gov keeper initializations - govKeeper := keeper.NewKeeper(encCfg.Codec, key, acctKeeper, bankKeeper, stakingKeeper, msr, types.DefaultConfig(), govAcct.String()) + govKeeper := keeper.NewKeeper(encCfg.Codec, key, m.acctKeeper, m.bankKeeper, m.stakingKeeper, msr, types.DefaultConfig(), govAcct.String()) govKeeper.SetProposalID(ctx, 1) + govRouter := v1beta1.NewRouter() // Also register legacy gov handlers to test them too. govRouter.AddRoute(types.RouterKey, v1beta1.ProposalHandler) govKeeper.SetLegacyRouter(govRouter) @@ -96,7 +118,7 @@ func setupGovKeeper(t *testing.T) ( v1.RegisterMsgServer(msr, keeper.NewMsgServerImpl(govKeeper)) banktypes.RegisterMsgServer(msr, nil) // Nil is fine here as long as we never execute the proposal's Msgs. - return govKeeper, acctKeeper, bankKeeper, stakingKeeper, encCfg, ctx + return govKeeper, m, encCfg, ctx } // trackMockBalances sets up expected calls on the Mock BankKeeper, and also diff --git a/x/gov/keeper/deposit_test.go b/x/gov/keeper/deposit_test.go index 204dc665..d37cb53b 100644 --- a/x/gov/keeper/deposit_test.go +++ b/x/gov/keeper/deposit_test.go @@ -16,7 +16,8 @@ const ( ) func TestDeposits(t *testing.T) { - govKeeper, _, bankKeeper, stakingKeeper, _, ctx := setupGovKeeper(t) + govKeeper, mocks, _, ctx := setupGovKeeper(t) + bankKeeper, stakingKeeper := mocks.bankKeeper, mocks.stakingKeeper trackMockBalances(bankKeeper) TestAddrs := simtestutil.AddTestAddrsIncremental(bankKeeper, stakingKeeper, ctx, 2, sdk.NewInt(10000000)) @@ -193,7 +194,7 @@ func TestValidateInitialDeposit(t *testing.T) { for name, tc := range testcases { t.Run(name, func(t *testing.T) { - govKeeper, _, _, _, _, ctx := setupGovKeeper(t) + govKeeper, _, _, ctx := setupGovKeeper(t) params := v1.DefaultParams() params.MinDeposit = tc.minDeposit diff --git a/x/gov/keeper/hooks_test.go b/x/gov/keeper/hooks_test.go index b7fe0541..69084ccc 100644 --- a/x/gov/keeper/hooks_test.go +++ b/x/gov/keeper/hooks_test.go @@ -48,7 +48,8 @@ func (h *MockGovHooksReceiver) AfterProposalVotingPeriodEnded(ctx sdk.Context, p func TestHooks(t *testing.T) { minDeposit := v1.DefaultParams().MinDeposit - govKeeper, _, bankKeeper, stakingKeeper, _, ctx := setupGovKeeper(t) + govKeeper, mocks, _, ctx := setupGovKeeper(t) + bankKeeper, stakingKeeper := mocks.bankKeeper, mocks.stakingKeeper addrs := simtestutil.AddTestAddrs(bankKeeper, stakingKeeper, ctx, 1, minDeposit[0].Amount) govHooksReceiver := MockGovHooksReceiver{} diff --git a/x/gov/keeper/keeper_test.go b/x/gov/keeper/keeper_test.go index e5663db1..0c0f2e7c 100644 --- a/x/gov/keeper/keeper_test.go +++ b/x/gov/keeper/keeper_test.go @@ -40,7 +40,8 @@ func (suite *KeeperTestSuite) SetupSuite() { } func (suite *KeeperTestSuite) reset() { - govKeeper, acctKeeper, bankKeeper, stakingKeeper, encCfg, ctx := setupGovKeeper(suite.T()) + govKeeper, mocks, encCfg, ctx := setupGovKeeper(suite.T()) + acctKeeper, bankKeeper, stakingKeeper := mocks.acctKeeper, mocks.bankKeeper, mocks.stakingKeeper // Populate the gov account with some coins, as the TestProposal we have // is a MsgSend from the gov account. @@ -72,7 +73,7 @@ func (suite *KeeperTestSuite) reset() { } func TestIncrementProposalNumber(t *testing.T) { - govKeeper, _, _, _, _, ctx := setupGovKeeper(t) + govKeeper, _, _, ctx := setupGovKeeper(t) tp := TestProposal _, err := govKeeper.SubmitProposal(ctx, tp, "", "test", "summary", sdk.AccAddress("cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r")) @@ -92,7 +93,7 @@ func TestIncrementProposalNumber(t *testing.T) { } func TestProposalQueues(t *testing.T) { - govKeeper, _, _, _, _, ctx := setupGovKeeper(t) + govKeeper, _, _, ctx := setupGovKeeper(t) // create test proposals tp := TestProposal diff --git a/x/gov/keeper/tally.go b/x/gov/keeper/tally.go index dda2ec61..2d06d945 100644 --- a/x/gov/keeper/tally.go +++ b/x/gov/keeper/tally.go @@ -95,12 +95,13 @@ func (keeper Keeper) Tally(ctx sdk.Context, proposal v1.Proposal) (passes bool, // TODO: Upgrade the spec to cover all of these cases & remove pseudocode. // If there is no staked coins, the proposal fails - if keeper.sk.TotalBondedTokens(ctx).IsZero() { + totalBondedTokens := keeper.sk.TotalBondedTokens(ctx) + if totalBondedTokens.IsZero() { return false, false, tallyResults } // If there is not enough quorum of votes, the proposal fails - percentVoting := totalVotingPower.Quo(sdk.NewDecFromInt(keeper.sk.TotalBondedTokens(ctx))) + percentVoting := totalVotingPower.Quo(sdk.NewDecFromInt(totalBondedTokens)) quorum, _ := sdk.NewDecFromStr(params.Quorum) if percentVoting.LT(quorum) { return false, params.BurnVoteQuorum, tallyResults diff --git a/x/gov/keeper/tally_test.go b/x/gov/keeper/tally_test.go new file mode 100644 index 00000000..fad8ad21 --- /dev/null +++ b/x/gov/keeper/tally_test.go @@ -0,0 +1,383 @@ +package keeper_test + +import ( + "context" + "testing" + + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + sdkmath "cosmossdk.io/math" + + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" + sdk "github.com/cosmos/cosmos-sdk/types" + v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + "github.com/atomone-hub/atomone/x/gov/keeper" +) + +type tallyFixture struct { + t *testing.T + + proposal v1.Proposal + valAddrs []sdk.ValAddress + delAddrs []sdk.AccAddress + totalBonded int64 + validators []stakingtypes.Validator + delegations []stakingtypes.Delegation + + keeper *keeper.Keeper + ctx sdk.Context + mocks mocks +} + +// newTallyFixture returns a configured fixture for testing the govKeeper.Tally +// method. +// - setup TotalBondedTokens call +// - initiates the validators with a self delegation of 1: +// - setup IterateBondedValidatorsByPower call +// - setup IterateDelegations call for validators +func newTallyFixture(t *testing.T, ctx sdk.Context, proposal v1.Proposal, + valAddrs []sdk.ValAddress, delAddrs []sdk.AccAddress, govKeeper *keeper.Keeper, + mocks mocks, +) *tallyFixture { + s := &tallyFixture{ + t: t, + ctx: ctx, + proposal: proposal, + valAddrs: valAddrs, + delAddrs: delAddrs, + keeper: govKeeper, + mocks: mocks, + } + mocks.stakingKeeper.EXPECT().TotalBondedTokens(gomock.Any()). + DoAndReturn(func(_ context.Context) sdkmath.Int { + return sdkmath.NewInt(s.totalBonded) + }).MaxTimes(1) + // Mocks a bunch of validators + for i := 0; i < len(valAddrs); i++ { + s.validators = append(s.validators, stakingtypes.Validator{ + OperatorAddress: valAddrs[i].String(), + Status: stakingtypes.Bonded, + Tokens: sdkmath.ZeroInt(), + DelegatorShares: sdkmath.LegacyZeroDec(), + }) + // validator self delegation + s.delegate(sdk.AccAddress(valAddrs[i]), valAddrs[i], 1) + } + mocks.stakingKeeper.EXPECT(). + IterateBondedValidatorsByPower(ctx, gomock.Any()). + DoAndReturn( + func(ctx context.Context, fn func(index int64, validator stakingtypes.ValidatorI) bool) error { + for i := 0; i < len(valAddrs); i++ { + fn(int64(i), s.validators[i]) + } + return nil + }) + mocks.stakingKeeper.EXPECT(). + IterateDelegations(ctx, gomock.Any(), gomock.Any()). + DoAndReturn( + func(ctx context.Context, voter sdk.AccAddress, fn func(index int64, d stakingtypes.DelegationI) bool) error { + for i, d := range s.delegations { + if d.DelegatorAddress == voter.String() { + fn(int64(i), d) + } + } + return nil + }).AnyTimes() + return s +} + +// delegate updates the tallyFixture delegations and validators fields. +func (s *tallyFixture) delegate(delegator sdk.AccAddress, validator sdk.ValAddress, m int64) { + // Increment total bonded according to each delegations + s.totalBonded += m + delegation := stakingtypes.Delegation{ + DelegatorAddress: delegator.String(), + ValidatorAddress: validator.String(), + } + for i := 0; i < len(s.validators); i++ { + if s.validators[i].OperatorAddress == validator.String() { + s.validators[i], delegation.Shares = s.validators[i].AddTokensFromDel(sdk.NewInt(m)) + break + } + } + s.delegations = append(s.delegations, delegation) +} + +// vote calls govKeeper.Vote() +func (s *tallyFixture) vote(voter sdk.AccAddress, vote v1.VoteOption) { + err := s.keeper.AddVote(s.ctx, s.proposal.Id, voter, v1.NewNonSplitVoteOption(vote), "") + require.NoError(s.t, err) +} + +func (s *tallyFixture) validatorVote(voter sdk.ValAddress, vote v1.VoteOption) { + s.vote(sdk.AccAddress(voter), vote) +} + +func TestTally(t *testing.T) { + tests := []struct { + name string + setup func(*tallyFixture) + expectedPass bool + expectedBurn bool + expectedTally v1.TallyResult + expectedError string + }{ + { + name: "no votes: prop fails/burn deposit", + expectedPass: false, + expectedBurn: true, + expectedTally: v1.TallyResult{ + YesCount: "0", + AbstainCount: "0", + NoCount: "0", + NoWithVetoCount: "0", + }, + }, + { + name: "one validator votes: prop fails/burn deposit", + setup: func(s *tallyFixture) { + s.validatorVote(s.valAddrs[0], v1.VoteOption_VOTE_OPTION_NO) + }, + expectedPass: false, + expectedBurn: true, // burn because quorum not reached + expectedTally: v1.TallyResult{ + YesCount: "0", + AbstainCount: "0", + NoCount: "1", + NoWithVetoCount: "0", + }, + }, + { + name: "one account votes without delegation: prop fails/burn deposit", + setup: func(s *tallyFixture) { + s.vote(s.delAddrs[0], v1.VoteOption_VOTE_OPTION_YES) + }, + expectedPass: false, + expectedBurn: true, // burn because quorum not reached + expectedTally: v1.TallyResult{ + YesCount: "0", + AbstainCount: "0", + NoCount: "0", + NoWithVetoCount: "0", + }, + }, + { + name: "one delegator votes: prop fails/burn deposit", + setup: func(s *tallyFixture) { + s.delegate(s.delAddrs[0], s.valAddrs[0], 2) + s.vote(s.delAddrs[0], v1.VoteOption_VOTE_OPTION_YES) + }, + expectedPass: false, + expectedBurn: true, // burn because quorum not reached + expectedTally: v1.TallyResult{ + YesCount: "2", + AbstainCount: "0", + NoCount: "0", + NoWithVetoCount: "0", + }, + }, + { + name: "one delegator votes yes, validator votes also yes: prop fails/burn deposit", + setup: func(s *tallyFixture) { + s.delegate(s.delAddrs[0], s.valAddrs[0], 2) + s.vote(s.delAddrs[0], v1.VoteOption_VOTE_OPTION_YES) + s.validatorVote(s.valAddrs[0], v1.VoteOption_VOTE_OPTION_YES) + }, + expectedPass: false, + expectedBurn: true, // burn because quorum not reached + expectedTally: v1.TallyResult{ + YesCount: "3", + AbstainCount: "0", + NoCount: "0", + NoWithVetoCount: "0", + }, + }, + { + name: "one delegator votes yes, validator votes no: prop fails/burn deposit", + setup: func(s *tallyFixture) { + s.delegate(s.delAddrs[0], s.valAddrs[0], 2) + s.vote(s.delAddrs[0], v1.VoteOption_VOTE_OPTION_YES) + s.validatorVote(s.valAddrs[0], v1.VoteOption_VOTE_OPTION_NO) + }, + expectedPass: false, + expectedBurn: true, // burn because quorum not reached + expectedTally: v1.TallyResult{ + YesCount: "2", + AbstainCount: "0", + NoCount: "1", + NoWithVetoCount: "0", + }, + }, + { + name: "validator votes yes, inherit delegations", + setup: func(s *tallyFixture) { + s.delegate(s.delAddrs[0], s.valAddrs[0], 2) + s.delegate(s.delAddrs[1], s.valAddrs[0], 2) + s.validatorVote(s.valAddrs[0], v1.VoteOption_VOTE_OPTION_NO) + }, + expectedPass: false, + expectedBurn: false, + expectedTally: v1.TallyResult{ + YesCount: "0", + AbstainCount: "0", + NoCount: "5", + NoWithVetoCount: "0", + }, + }, + { + // one delegator delegates 42 shares to 2 different validators (21 each) + // delegator votes yes + // first validator votes yes + // second validator votes no + // third validator (no delegation) votes abstain + name: "delegator with mixed delegations: prop pass", + setup: func(s *tallyFixture) { + s.delegate(s.delAddrs[0], s.valAddrs[0], 2) + s.delegate(s.delAddrs[0], s.valAddrs[1], 2) + s.vote(s.delAddrs[0], v1.VoteOption_VOTE_OPTION_YES) + s.validatorVote(s.valAddrs[0], v1.VoteOption_VOTE_OPTION_NO) + s.validatorVote(s.valAddrs[1], v1.VoteOption_VOTE_OPTION_YES) + s.validatorVote(s.valAddrs[2], v1.VoteOption_VOTE_OPTION_ABSTAIN) + }, + expectedPass: true, + expectedBurn: false, + expectedTally: v1.TallyResult{ + YesCount: "5", + AbstainCount: "1", + NoCount: "1", + NoWithVetoCount: "0", + }, + }, + { + name: "quorum reached with only abstain: prop fails", + setup: func(s *tallyFixture) { + s.validatorVote(s.valAddrs[0], v1.VoteOption_VOTE_OPTION_ABSTAIN) + s.validatorVote(s.valAddrs[1], v1.VoteOption_VOTE_OPTION_ABSTAIN) + s.validatorVote(s.valAddrs[2], v1.VoteOption_VOTE_OPTION_ABSTAIN) + s.validatorVote(s.valAddrs[3], v1.VoteOption_VOTE_OPTION_ABSTAIN) + }, + expectedPass: false, + expectedBurn: false, + expectedTally: v1.TallyResult{ + YesCount: "0", + AbstainCount: "4", + NoCount: "0", + NoWithVetoCount: "0", + }, + }, + { + name: "quorum reached with veto>1/3: prop fails/burn deposit", + setup: func(s *tallyFixture) { + s.validatorVote(s.valAddrs[0], v1.VoteOption_VOTE_OPTION_YES) + s.validatorVote(s.valAddrs[1], v1.VoteOption_VOTE_OPTION_YES) + s.validatorVote(s.valAddrs[2], v1.VoteOption_VOTE_OPTION_YES) + s.validatorVote(s.valAddrs[3], v1.VoteOption_VOTE_OPTION_YES) + s.validatorVote(s.valAddrs[4], v1.VoteOption_VOTE_OPTION_NO_WITH_VETO) + s.validatorVote(s.valAddrs[5], v1.VoteOption_VOTE_OPTION_NO_WITH_VETO) + s.validatorVote(s.valAddrs[6], v1.VoteOption_VOTE_OPTION_NO_WITH_VETO) + }, + expectedPass: false, + expectedBurn: true, + expectedTally: v1.TallyResult{ + YesCount: "4", + AbstainCount: "0", + NoCount: "0", + NoWithVetoCount: "3", + }, + }, + { + name: "quorum reached with yes<=.5: prop fails", + setup: func(s *tallyFixture) { + s.validatorVote(s.valAddrs[0], v1.VoteOption_VOTE_OPTION_YES) + s.validatorVote(s.valAddrs[1], v1.VoteOption_VOTE_OPTION_YES) + s.validatorVote(s.valAddrs[2], v1.VoteOption_VOTE_OPTION_NO) + s.validatorVote(s.valAddrs[3], v1.VoteOption_VOTE_OPTION_NO) + }, + expectedPass: false, + expectedBurn: false, + expectedTally: v1.TallyResult{ + YesCount: "2", + AbstainCount: "0", + NoCount: "2", + NoWithVetoCount: "0", + }, + }, + { + name: "quorum reached with yes>.5: prop succeeds", + setup: func(s *tallyFixture) { + s.validatorVote(s.valAddrs[0], v1.VoteOption_VOTE_OPTION_YES) + s.validatorVote(s.valAddrs[1], v1.VoteOption_VOTE_OPTION_YES) + s.validatorVote(s.valAddrs[2], v1.VoteOption_VOTE_OPTION_YES) + s.validatorVote(s.valAddrs[3], v1.VoteOption_VOTE_OPTION_YES) + s.validatorVote(s.valAddrs[4], v1.VoteOption_VOTE_OPTION_NO) + s.validatorVote(s.valAddrs[5], v1.VoteOption_VOTE_OPTION_NO) + s.validatorVote(s.valAddrs[6], v1.VoteOption_VOTE_OPTION_NO_WITH_VETO) + }, + expectedPass: true, + expectedBurn: false, + expectedTally: v1.TallyResult{ + YesCount: "4", + AbstainCount: "0", + NoCount: "2", + NoWithVetoCount: "1", + }, + }, + { + name: "quorum reached thanks to abstain, yes>.5: prop succeeds", + setup: func(s *tallyFixture) { + s.validatorVote(s.valAddrs[0], v1.VoteOption_VOTE_OPTION_YES) + s.validatorVote(s.valAddrs[1], v1.VoteOption_VOTE_OPTION_YES) + s.validatorVote(s.valAddrs[2], v1.VoteOption_VOTE_OPTION_NO) + s.validatorVote(s.valAddrs[3], v1.VoteOption_VOTE_OPTION_ABSTAIN) + s.validatorVote(s.valAddrs[4], v1.VoteOption_VOTE_OPTION_ABSTAIN) + s.validatorVote(s.valAddrs[5], v1.VoteOption_VOTE_OPTION_ABSTAIN) + }, + expectedPass: true, + expectedBurn: false, + expectedTally: v1.TallyResult{ + YesCount: "2", + AbstainCount: "3", + NoCount: "1", + NoWithVetoCount: "0", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + govKeeper, mocks, _, ctx := setupGovKeeper(t, mockAccountKeeperExpectations) + params := v1.DefaultParams() + // Ensure params value are different than false + params.BurnVoteQuorum = true + params.BurnVoteVeto = true + err := govKeeper.SetParams(ctx, params) + require.NoError(t, err) + var ( + numVals = 10 + numDelegators = 5 + addrs = simtestutil.CreateRandomAccounts(numVals + numDelegators) + valAddrs = simtestutil.ConvertAddrsToValAddrs(addrs[:numVals]) + delAddrs = addrs[numVals:] + ) + // Submit and activate a proposal + proposal, err := govKeeper.SubmitProposal(ctx, TestProposal, "", "title", "summary", delAddrs[0]) + require.NoError(t, err) + govKeeper.ActivateVotingPeriod(ctx, proposal) + // Create the test fixture + s := newTallyFixture(t, ctx, proposal, valAddrs, delAddrs, govKeeper, mocks) + if tt.setup != nil { + tt.setup(s) + } + + pass, burn, tally := govKeeper.Tally(ctx, proposal) + + assert.Equal(t, tt.expectedPass, pass, "wrong pass") + assert.Equal(t, tt.expectedBurn, burn, "wrong burn") + assert.Equal(t, tt.expectedTally, tally) + assert.Empty(t, govKeeper.GetVotes(ctx, proposal.Id), "votes not be removed after tally") + }) + } +} diff --git a/x/gov/keeper/vote_test.go b/x/gov/keeper/vote_test.go index 048b75c3..0e4a665f 100644 --- a/x/gov/keeper/vote_test.go +++ b/x/gov/keeper/vote_test.go @@ -5,14 +5,17 @@ import ( "github.com/stretchr/testify/require" + sdkmath "cosmossdk.io/math" + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" sdk "github.com/cosmos/cosmos-sdk/types" v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" ) func TestVotes(t *testing.T) { - govKeeper, _, bankKeeper, stakingKeeper, _, ctx := setupGovKeeper(t) - addrs := simtestutil.AddTestAddrsIncremental(bankKeeper, stakingKeeper, ctx, 2, sdk.NewInt(10000000)) + govKeeper, mocks, _, ctx := setupGovKeeper(t) + bankKeeper, stakingKeeper := mocks.bankKeeper, mocks.stakingKeeper + addrs := simtestutil.AddTestAddrsIncremental(bankKeeper, stakingKeeper, ctx, 2, sdkmath.NewInt(10000000)) tp := TestProposal proposal, err := govKeeper.SubmitProposal(ctx, tp, "", "title", "description", sdk.AccAddress("cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r"))