mukan-sdk/x/gov/keeper/proposal_test.go
Mukan Erkin Törük abb1ff956e
Some checks are pending
Build SimApp / build (amd64) (push) Waiting to run
Build SimApp / build (arm64) (push) Waiting to run
CodeQL / Analyze (push) Waiting to run
Build & Push / build (push) Waiting to run
Run Gosec / Gosec (push) Waiting to run
Lint / golangci-lint (push) Waiting to run
Checks dependencies and mocks generation / Check go mod tidy (push) Waiting to run
Checks dependencies and mocks generation / Check up to date mocks (push) Waiting to run
System Tests / setup (push) Waiting to run
System Tests / test-system (push) Blocked by required conditions
System Tests / test-system-legacy (push) Blocked by required conditions
Tests / Code Coverage / split-test-files (push) Waiting to run
Tests / Code Coverage / tests (00) (push) Blocked by required conditions
Tests / Code Coverage / tests (01) (push) Blocked by required conditions
Tests / Code Coverage / tests (02) (push) Blocked by required conditions
Tests / Code Coverage / tests (03) (push) Blocked by required conditions
Tests / Code Coverage / test-integration (push) Waiting to run
Tests / Code Coverage / test-e2e (push) Waiting to run
Tests / Code Coverage / repo-analysis (push) Blocked by required conditions
Tests / Code Coverage / test-sim-nondeterminism (push) Waiting to run
Tests / Code Coverage / test-clientv2 (push) Waiting to run
Tests / Code Coverage / test-core (push) Waiting to run
Tests / Code Coverage / test-depinject (push) Waiting to run
Tests / Code Coverage / test-errors (push) Waiting to run
Tests / Code Coverage / test-math (push) Waiting to run
Tests / Code Coverage / test-schema (push) Waiting to run
Tests / Code Coverage / test-collections (push) Waiting to run
Tests / Code Coverage / test-cosmovisor (push) Waiting to run
Tests / Code Coverage / test-confix (push) Waiting to run
Tests / Code Coverage / test-store (push) Waiting to run
Tests / Code Coverage / test-log (push) Waiting to run
Tests / Code Coverage / test-x-tx (push) Waiting to run
Tests / Code Coverage / test-x-nft (push) Waiting to run
Tests / Code Coverage / test-x-circuit (push) Waiting to run
Tests / Code Coverage / test-x-feegrant (push) Waiting to run
Tests / Code Coverage / test-x-evidence (push) Waiting to run
Tests / Code Coverage / test-x-upgrade (push) Waiting to run
Tests / Code Coverage / test-tools-benchmark (push) Waiting to run
refactor: complete sovereign stack cleanup — all github.com upstream refs purged
2026-05-11 03:46:06 +03:00

305 lines
10 KiB
Go

package keeper_test
import (
"errors"
"strings"
"testing"
"github.com/stretchr/testify/require"
"cosmossdk.io/collections"
"git.cw.tr/mukan-network/mukan-sdk/testutil/testdata"
sdk "git.cw.tr/mukan-network/mukan-sdk/types"
"git.cw.tr/mukan-network/mukan-sdk/x/gov/types"
v1 "git.cw.tr/mukan-network/mukan-sdk/x/gov/types/v1"
"git.cw.tr/mukan-network/mukan-sdk/x/gov/types/v1beta1"
)
// TODO(tip): remove this
func (suite *KeeperTestSuite) TestGetSetProposal() {
testCases := map[string]struct {
expedited bool
}{
"regular proposal": {},
"expedited proposal": {
expedited: true,
},
}
for _, tc := range testCases {
tp := TestProposal
proposal, err := suite.govKeeper.SubmitProposal(suite.ctx, tp, "", "test", "summary", suite.addrs[0], tc.expedited)
suite.Require().NoError(err)
proposalID := proposal.Id
suite.Require().NoError(suite.govKeeper.SetProposal(suite.ctx, proposal))
gotProposal, err := suite.govKeeper.Proposals.Get(suite.ctx, proposalID)
suite.Require().Nil(err)
suite.Require().Equal(proposal, gotProposal)
}
}
// TODO(tip): remove this
func (suite *KeeperTestSuite) TestDeleteProposal() {
testCases := map[string]struct {
expedited bool
}{
"regular proposal": {},
"expedited proposal": {
expedited: true,
},
}
for _, tc := range testCases {
// delete non-existing proposal
suite.Require().ErrorIs(suite.govKeeper.DeleteProposal(suite.ctx, 10), collections.ErrNotFound)
tp := TestProposal
proposal, err := suite.govKeeper.SubmitProposal(suite.ctx, tp, "", "test", "summary", suite.addrs[0], tc.expedited)
suite.Require().NoError(err)
proposalID := proposal.Id
suite.Require().NoError(suite.govKeeper.SetProposal(suite.ctx, proposal))
suite.Require().NotPanics(func() {
suite.Require().NoError(suite.govKeeper.DeleteProposal(suite.ctx, proposalID))
}, "")
}
}
func (suite *KeeperTestSuite) TestActivateVotingPeriod() {
testCases := []struct {
name string
expedited bool
}{
{name: "regular proposal"},
{name: "expedited proposal", expedited: true},
}
for _, tc := range testCases {
tp := TestProposal
proposal, err := suite.govKeeper.SubmitProposal(suite.ctx, tp, "", "test", "summary", suite.addrs[0], tc.expedited)
suite.Require().NoError(err)
suite.Require().Nil(proposal.VotingStartTime)
suite.Require().NoError(suite.govKeeper.ActivateVotingPeriod(suite.ctx, proposal))
proposal, err = suite.govKeeper.Proposals.Get(suite.ctx, proposal.Id)
suite.Require().Nil(err)
suite.Require().True(proposal.VotingStartTime.Equal(suite.ctx.BlockHeader().Time))
has, err := suite.govKeeper.ActiveProposalsQueue.Has(suite.ctx, collections.Join(*proposal.VotingEndTime, proposal.Id))
suite.Require().NoError(err)
suite.Require().True(has)
suite.Require().NoError(suite.govKeeper.DeleteProposal(suite.ctx, proposal.Id))
}
}
func (suite *KeeperTestSuite) TestDeleteProposalInVotingPeriod() {
testCases := []struct {
name string
expedited bool
}{
{name: "regular proposal"},
{name: "expedited proposal", expedited: true},
}
for _, tc := range testCases {
suite.reset()
tp := TestProposal
proposal, err := suite.govKeeper.SubmitProposal(suite.ctx, tp, "", "test", "summary", suite.addrs[0], tc.expedited)
suite.Require().NoError(err)
suite.Require().Nil(proposal.VotingStartTime)
suite.Require().NoError(suite.govKeeper.ActivateVotingPeriod(suite.ctx, proposal))
proposal, err = suite.govKeeper.Proposals.Get(suite.ctx, proposal.Id)
suite.Require().Nil(err)
suite.Require().True(proposal.VotingStartTime.Equal(suite.ctx.BlockHeader().Time))
has, err := suite.govKeeper.ActiveProposalsQueue.Has(suite.ctx, collections.Join(*proposal.VotingEndTime, proposal.Id))
suite.Require().NoError(err)
suite.Require().True(has)
// add vote
voteOptions := []*v1.WeightedVoteOption{{Option: v1.OptionYes, Weight: "1.0"}}
err = suite.govKeeper.AddVote(suite.ctx, proposal.Id, suite.addrs[0], voteOptions, "")
suite.Require().NoError(err)
suite.Require().NoError(suite.govKeeper.DeleteProposal(suite.ctx, proposal.Id))
// add vote but proposal is deleted along with its VotingPeriodProposalKey
err = suite.govKeeper.AddVote(suite.ctx, proposal.Id, suite.addrs[0], voteOptions, "")
suite.Require().ErrorContains(err, ": inactive proposal")
}
}
type invalidProposalRoute struct{ v1beta1.TextProposal }
func (invalidProposalRoute) ProposalRoute() string { return "nonexistingroute" }
func (suite *KeeperTestSuite) TestSubmitProposal() {
govAcct := suite.govKeeper.GetGovernanceAccount(suite.ctx).GetAddress().String()
_, _, randomAddr := testdata.KeyTestPubAddr()
tp := v1beta1.TextProposal{Title: "title", Description: "description"}
testCases := []struct {
content v1beta1.Content
authority string
metadata string
expedited bool
expectedErr error
}{
{&tp, govAcct, "", false, nil},
{&tp, govAcct, "", true, nil},
// Keeper does not check the validity of title and description, no error
{&v1beta1.TextProposal{Title: "", Description: "description"}, govAcct, "", false, nil},
{&v1beta1.TextProposal{Title: strings.Repeat("1234567890", 100), Description: "description"}, govAcct, "", false, nil},
{&v1beta1.TextProposal{Title: "title", Description: ""}, govAcct, "", false, nil},
{&v1beta1.TextProposal{Title: "title", Description: strings.Repeat("1234567890", 1000)}, govAcct, "", true, nil},
// error when metadata is too long (>10000)
{&tp, govAcct, strings.Repeat("a", 100001), true, types.ErrMetadataTooLong},
// error when signer is not gov acct
{&tp, randomAddr.String(), "", false, types.ErrInvalidSigner},
// error only when invalid route
{&invalidProposalRoute{}, govAcct, "", false, types.ErrNoProposalHandlerExists},
}
for i, tc := range testCases {
prop, err := v1.NewLegacyContent(tc.content, tc.authority)
suite.Require().NoError(err)
_, err = suite.govKeeper.SubmitProposal(suite.ctx, []sdk.Msg{prop}, tc.metadata, "title", "", suite.addrs[0], tc.expedited)
suite.Require().True(errors.Is(tc.expectedErr, err), "tc #%d; got: %v, expected: %v", i, err, tc.expectedErr)
}
}
func (suite *KeeperTestSuite) TestCancelProposal() {
govAcct := suite.govKeeper.GetGovernanceAccount(suite.ctx).GetAddress().String()
tp := v1beta1.TextProposal{Title: "title", Description: "description"}
prop, err := v1.NewLegacyContent(&tp, govAcct)
suite.Require().NoError(err)
proposal, err := suite.govKeeper.SubmitProposal(suite.ctx, []sdk.Msg{prop}, "", "title", "summary", suite.addrs[0], false)
suite.Require().NoError(err)
proposalID := proposal.Id
proposal2, err := suite.govKeeper.SubmitProposal(suite.ctx, []sdk.Msg{prop}, "", "title", "summary", suite.addrs[1], true)
suite.Require().NoError(err)
proposal2ID := proposal2.Id
// proposal3 is only used to check the votes for proposals which doesn't go through `CancelProposal` are still present in state
proposal3, err := suite.govKeeper.SubmitProposal(suite.ctx, []sdk.Msg{prop}, "", "title", "summary", suite.addrs[2], false)
suite.Require().NoError(err)
proposal3ID := proposal3.Id
// add votes for proposal 3
suite.Require().NoError(suite.govKeeper.ActivateVotingPeriod(suite.ctx, proposal3))
proposal3, err = suite.govKeeper.Proposals.Get(suite.ctx, proposal3ID)
suite.Require().Nil(err)
suite.Require().True(proposal3.VotingStartTime.Equal(suite.ctx.BlockHeader().Time))
// add vote
voteOptions := []*v1.WeightedVoteOption{{Option: v1.OptionYes, Weight: "1.0"}}
err = suite.govKeeper.AddVote(suite.ctx, proposal3ID, suite.addrs[0], voteOptions, "")
suite.Require().NoError(err)
testCases := []struct {
name string
malleate func() (proposalID uint64, proposer string)
proposalID uint64
proposer string
expectedErr bool
}{
{
name: "without proposer",
malleate: func() (uint64, string) {
return 1, ""
},
expectedErr: true,
},
{
name: "invalid proposal id",
malleate: func() (uint64, string) {
return 1, suite.addrs[1].String()
},
expectedErr: true,
},
{
name: "valid proposalID but invalid proposer",
malleate: func() (uint64, string) {
return proposalID, suite.addrs[1].String()
},
expectedErr: true,
},
{
name: "valid proposalID but invalid proposal which has already passed",
malleate: func() (uint64, string) {
// making proposal status pass
proposal2, err := suite.govKeeper.Proposals.Get(suite.ctx, proposal2ID)
suite.Require().Nil(err)
proposal2.Status = v1.ProposalStatus_PROPOSAL_STATUS_PASSED
suite.Require().NoError(suite.govKeeper.SetProposal(suite.ctx, proposal2))
return proposal2ID, suite.addrs[1].String()
},
expectedErr: true,
},
{
name: "valid proposer and proposal id",
malleate: func() (uint64, string) {
return proposalID, suite.addrs[0].String()
},
expectedErr: false,
},
{
name: "valid case with deletion of votes",
malleate: func() (uint64, string) {
suite.Require().NoError(suite.govKeeper.ActivateVotingPeriod(suite.ctx, proposal))
proposal, err = suite.govKeeper.Proposals.Get(suite.ctx, proposal.Id)
suite.Require().Nil(err)
suite.Require().True(proposal.VotingStartTime.Equal(suite.ctx.BlockHeader().Time))
// add vote
voteOptions := []*v1.WeightedVoteOption{{Option: v1.OptionYes, Weight: "1.0"}}
err = suite.govKeeper.AddVote(suite.ctx, proposalID, suite.addrs[0], voteOptions, "")
suite.Require().NoError(err)
vote, err := suite.govKeeper.Votes.Get(suite.ctx, collections.Join(proposalID, suite.addrs[0]))
suite.Require().NoError(err)
suite.Require().NotNil(vote)
return proposalID, suite.addrs[0].String()
},
expectedErr: false,
},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
pID, proposer := tc.malleate()
err = suite.govKeeper.CancelProposal(suite.ctx, pID, proposer)
if tc.expectedErr {
suite.Require().Error(err)
} else {
suite.Require().NoError(err)
}
})
}
_, err = suite.govKeeper.Votes.Get(suite.ctx, collections.Join(proposalID, suite.addrs[0]))
suite.Require().ErrorContains(err, collections.ErrNotFound.Error())
// check that proposal 3 votes are still present in the state
votes, err := suite.govKeeper.Votes.Get(suite.ctx, collections.Join(proposal3ID, suite.addrs[0]))
suite.Require().NoError(err)
suite.Require().NotNil(votes)
}
func TestMigrateProposalMessages(t *testing.T) {
content := v1beta1.NewTextProposal("Test", "description")
contentMsg, err := v1.NewLegacyContent(content, sdk.AccAddress("test1").String())
require.NoError(t, err)
content, err = v1.LegacyContentFromMessage(contentMsg)
require.NoError(t, err)
require.Equal(t, "Test", content.GetTitle())
require.Equal(t, "description", content.GetDescription())
}