github.com/Finschia/finschia-sdk@v0.48.1/x/gov/simulation/operations_test.go (about) 1 package simulation_test 2 3 import ( 4 "fmt" 5 "math/rand" 6 "testing" 7 "time" 8 9 ocabci "github.com/Finschia/ostracon/abci/types" 10 "github.com/stretchr/testify/require" 11 tmproto "github.com/tendermint/tendermint/proto/tendermint/types" 12 13 "github.com/Finschia/finschia-sdk/simapp" 14 simappparams "github.com/Finschia/finschia-sdk/simapp/params" 15 sdk "github.com/Finschia/finschia-sdk/types" 16 simtypes "github.com/Finschia/finschia-sdk/types/simulation" 17 govcodec "github.com/Finschia/finschia-sdk/x/gov/codec" 18 "github.com/Finschia/finschia-sdk/x/gov/simulation" 19 "github.com/Finschia/finschia-sdk/x/gov/types" 20 minttypes "github.com/Finschia/finschia-sdk/x/mint/types" 21 ) 22 23 type MockWeightedProposalContent struct { 24 n int 25 } 26 27 func (m MockWeightedProposalContent) AppParamsKey() string { 28 return fmt.Sprintf("AppParamsKey-%d", m.n) 29 } 30 31 func (m MockWeightedProposalContent) DefaultWeight() int { 32 return m.n 33 } 34 35 func (m MockWeightedProposalContent) ContentSimulatorFn() simtypes.ContentSimulatorFn { 36 return func(r *rand.Rand, _ sdk.Context, _ []simtypes.Account) simtypes.Content { 37 return types.NewTextProposal( 38 fmt.Sprintf("title-%d: %s", m.n, simtypes.RandStringOfLength(r, 100)), 39 fmt.Sprintf("description-%d: %s", m.n, simtypes.RandStringOfLength(r, 4000)), 40 ) 41 } 42 } 43 44 // make sure the MockWeightedProposalContent satisfied the WeightedProposalContent interface 45 var _ simtypes.WeightedProposalContent = MockWeightedProposalContent{} 46 47 func mockWeightedProposalContent(n int) []simtypes.WeightedProposalContent { 48 wpc := make([]simtypes.WeightedProposalContent, n) 49 for i := 0; i < n; i++ { 50 wpc[i] = MockWeightedProposalContent{i} 51 } 52 return wpc 53 } 54 55 // TestWeightedOperations tests the weights of the operations. 56 func TestWeightedOperations(t *testing.T) { 57 app, ctx := createTestApp(false) 58 ctx.WithChainID("test-chain") 59 60 cdc := app.AppCodec() 61 appParams := make(simtypes.AppParams) 62 63 weightesOps := simulation.WeightedOperations(appParams, cdc, app.AccountKeeper, 64 app.BankKeeper, app.GovKeeper, mockWeightedProposalContent(3), 65 ) 66 67 // setup 3 accounts 68 s := rand.NewSource(1) 69 r := rand.New(s) 70 accs := getTestingAccounts(t, r, app, ctx, 3) 71 72 expected := []struct { 73 weight int 74 opMsgRoute string 75 opMsgName string 76 }{ 77 {0, types.ModuleName, "submit_proposal"}, 78 {1, types.ModuleName, "submit_proposal"}, 79 {2, types.ModuleName, "submit_proposal"}, 80 {simappparams.DefaultWeightMsgDeposit, types.ModuleName, types.TypeMsgDeposit}, 81 {simappparams.DefaultWeightMsgVote, types.ModuleName, types.TypeMsgVote}, 82 {simappparams.DefaultWeightMsgVoteWeighted, types.ModuleName, types.TypeMsgVoteWeighted}, 83 } 84 85 for i, w := range weightesOps { 86 operationMsg, _, _ := w.Op()(r, app.BaseApp, ctx, accs, ctx.ChainID()) 87 // the following checks are very much dependent from the ordering of the output given 88 // by WeightedOperations. if the ordering in WeightedOperations changes some tests 89 // will fail 90 require.Equal(t, expected[i].weight, w.Weight(), "weight should be the same") 91 require.Equal(t, expected[i].opMsgRoute, operationMsg.Route, "route should be the same") 92 require.Equal(t, expected[i].opMsgName, operationMsg.Name, "operation Msg name should be the same") 93 } 94 } 95 96 // TestSimulateMsgSubmitProposal tests the normal scenario of a valid message of type TypeMsgSubmitProposal. 97 // Abonormal scenarios, where the message is created by an errors are not tested here. 98 func TestSimulateMsgSubmitProposal(t *testing.T) { 99 app, ctx := createTestApp(false) 100 101 // setup 3 accounts 102 s := rand.NewSource(1) 103 r := rand.New(s) 104 accounts := getTestingAccounts(t, r, app, ctx, 3) 105 106 // begin a new block 107 app.BeginBlock(ocabci.RequestBeginBlock{Header: tmproto.Header{Height: app.LastBlockHeight() + 1, AppHash: app.LastCommitID().Hash}}) 108 109 // execute operation 110 op := simulation.SimulateMsgSubmitProposal(app.AccountKeeper, app.BankKeeper, app.GovKeeper, MockWeightedProposalContent{3}.ContentSimulatorFn()) 111 operationMsg, _, err := op(r, app.BaseApp, ctx, accounts, "") 112 require.NoError(t, err) 113 114 var msg types.MsgSubmitProposal 115 err = govcodec.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg) 116 require.NoError(t, err) 117 118 require.True(t, operationMsg.OK) 119 require.Equal(t, "link1p8wcgrjr4pjju90xg6u9cgq55dxwq8j7fmx8x8", msg.Proposer) 120 require.Equal(t, "2686011stake", msg.InitialDeposit.String()) 121 require.Equal(t, "title-3: ZBSpYuLyYggwexjxusrBqDOTtGTOWeLrQKjLxzIivHSlcxgdXhhuTSkuxKGLwQvuyNhYFmBZHeAerqyNEUzXPFGkqEGqiQWIXnku", msg.GetContent().GetTitle()) 122 require.Equal(t, "description-3: NJWzHdBNpAXKJPHWQdrGYcAHSctgVlqwqHoLfHsXUdStwfefwzqLuKEhmMyYLdbZrcPgYqjNHxPexsruwEGStAneKbWkQDDIlCWBLSiAASNhZqNFlPtfqPJoxKsgMdzjWqLWdqKQuJqWPMvwPQWZUtVMOTMYKJbfdlZsjdsomuScvDmbDkgRualsxDvRJuCAmPOXitIbcyWsKGSdrEunFAOdmXnsuyFVgJqEjbklvmwrUlsxjRSfKZxGcpayDdgoFcnVSutxjRgOSFzPwidAjubMncNweqpbxhXGchpZUxuFDOtpnhNUycJICRYqsPhPSCjPTWZFLkstHWJxvdPEAyEIxXgLwbNOjrgzmaujiBABBIXvcXpLrbcEWNNQsbjvgJFgJkflpRohHUutvnaUqoopuKjTDaemDeSdqbnOzcfJpcTuAQtZoiLZOoAIlboFDAeGmSNwkvObPRvRWQgWkGkxwtPauYgdkmypLjbqhlHJIQTntgWjXwZdOyYEdQRRLfMSdnxqppqUofqLbLQDUjwKVKfZJUJQPsWIPwIVaSTrmKskoAhvmZyJgeRpkaTfGgrJzAigcxtfshmiDCFkuiluqtMOkidknnTBtumyJYlIsWLnCQclqdVmikUoMOPdPWwYbJxXyqUVicNxFxyqJTenNblyyKSdlCbiXxUiYUiMwXZASYfvMDPFgxniSjWaZTjHkqlJvtBsXqwPpyVxnJVGFWhfSxgOcduoxkiopJvFjMmFabrGYeVtTXLhxVUEiGwYUvndjFGzDVntUvibiyZhfMQdMhgsiuysLMiePBNXifRLMsSmXPkwlPloUbJveCvUlaalhZHuvdkCnkSHbMbmOnrfEGPwQiACiPlnihiaOdbjPqPiTXaHDoJXjSlZmltGqNHHNrcKdlFSCdmVOuvDcBLdSklyGJmcLTbSFtALdGlPkqqecJrpLCXNPWefoTJNgEJlyMEPneVaxxduAAEqQpHWZodWyRkDAxzyMnFMcjSVqeRXLqsNyNtQBbuRvunZflWSbbvXXdkyLikYqutQhLPONXbvhcQZJPSWnOulqQaXmbfFxAkqfYeseSHOQidHwbcsOaMnSrrmGjjRmEMQNuknupMxJiIeVjmgZvbmjPIQTEhQFULQLBMPrxcFPvBinaOPYWGvYGRKxLZdwamfRQQFngcdSlvwjfaPbURasIsGJVHtcEAxnIIrhSriiXLOlbEBLXFElXJFGxHJczRBIxAuPKtBisjKBwfzZFagdNmjdwIRvwzLkFKWRTDPxJCmpzHUcrPiiXXHnOIlqNVoGSXZewdnCRhuxeYGPVTfrNTQNOxZmxInOazUYNTNDgzsxlgiVEHPKMfbesvPHUqpNkUqbzeuzfdrsuLDpKHMUbBMKczKKWOdYoIXoPYtEjfOnlQLoGnbQUCuERdEFaptwnsHzTJDsuZkKtzMpFaZobynZdzNydEeJJHDYaQcwUxcqvwfWwNUsCiLvkZQiSfzAHftYgAmVsXgtmcYgTqJIawstRYJrZdSxlfRiqTufgEQVambeZZmaAyRQbcmdjVUZZCgqDrSeltJGXPMgZnGDZqISrGDOClxXCxMjmKqEPwKHoOfOeyGmqWqihqjINXLqnyTesZePQRqaWDQNqpLgNrAUKulklmckTijUltQKuWQDwpLmDyxLppPVMwsmBIpOwQttYFMjgJQZLYFPmxWFLIeZihkRNnkzoypBICIxgEuYsVWGIGRbbxqVasYnstWomJnHwmtOhAFSpttRYYzBmyEtZXiCthvKvWszTXDbiJbGXMcrYpKAgvUVFtdKUfvdMfhAryctklUCEdjetjuGNfJjajZtvzdYaqInKtFPPLYmRaXPdQzxdSQfmZDEVHlHGEGNSPRFJuIfKLLfUmnHxHnRjmzQPNlqrXgifUdzAGKVabYqvcDeYoTYgPsBUqehrBhmQUgTvDnsdpuhUoxskDdppTsYMcnDIPSwKIqhXDCIxOuXrywahvVavvHkPuaenjLmEbMgrkrQLHEAwrhHkPRNvonNQKqprqOFVZKAtpRSpvQUxMoXCMZLSSbnLEFsjVfANdQNQVwTmGxqVjVqRuxREAhuaDrFgEZpYKhwWPEKBevBfsOIcaZKyykQafzmGPLRAKDtTcJxJVgiiuUkmyMYuDUNEUhBEdoBLJnamtLmMJQgmLiUELIhLpiEvpOXOvXCPUeldLFqkKOwfacqIaRcnnZvERKRMCKUkMABbDHytQqQblrvoxOZkwzosQfDKGtIdfcXRJNqlBNwOCWoQBcEWyqrMlYZIAXYJmLfnjoJepgSFvrgajaBAIksoyeHqgqbGvpAstMIGmIhRYGGNPRIfOQKsGoKgxtsidhTaAePRCBFqZgPDWCIkqOJezGVkjfYUCZTlInbxBXwUAVRsxHTQtJFnnpmMvXDYCVlEmnZBKhmmxQOIQzxFWpJQkQoSAYzTEiDWEOsVLNrbfzeHFRyeYATakQQWmFDLPbVMCJcWjFGJjfqCoVzlbNNEsqxdSmNPjTjHYOkuEMFLkXYGaoJlraLqayMeCsTjWNRDPBywBJLAPVkGQqTwApVVwYAetlwSbzsdHWsTwSIcctkyKDuRWYDQikRqsKTMJchrliONJeaZIzwPQrNbTwxsGdwuduvibtYndRwpdsvyCktRHFalvUuEKMqXbItfGcNGWsGzubdPMYayOUOINjpcFBeESdwpdlTYmrPsLsVDhpTzoMegKrytNVZkfJRPuDCUXxSlSthOohmsuxmIZUedzxKmowKOdXTMcEtdpHaPWgIsIjrViKrQOCONlSuazmLuCUjLltOGXeNgJKedTVrrVCpWYWHyVrdXpKgNaMJVjbXxnVMSChdWKuZdqpisvrkBJPoURDYxWOtpjzZoOpWzyUuYNhCzRoHsMjmmWDcXzQiHIyjwdhPNwiPqFxeUfMVFQGImhykFgMIlQEoZCaRoqSBXTSWAeDumdbsOGtATwEdZlLfoBKiTvodQBGOEcuATWXfiinSjPmJKcWgQrTVYVrwlyMWhxqNbCMpIQNoSMGTiWfPTCezUjYcdWppnsYJihLQCqbNLRGgqrwHuIvsazapTpoPZIyZyeeSueJuTIhpHMEJfJpScshJubJGfkusuVBgfTWQoywSSliQQSfbvaHKiLnyjdSbpMkdBgXepoSsHnCQaYuHQqZsoEOmJCiuQUpJkmfyfbIShzlZpHFmLCsbknEAkKXKfRTRnuwdBeuOGgFbJLbDksHVapaRayWzwoYBEpmrlAxrUxYMUekKbpjPNfjUCjhbdMAnJmYQVZBQZkFVweHDAlaqJjRqoQPoOMLhyvYCzqEuQsAFoxWrzRnTVjStPadhsESlERnKhpEPsfDxNvxqcOyIulaCkmPdambLHvGhTZzysvqFauEgkFRItPfvisehFmoBhQqmkfbHVsgfHXDPJVyhwPllQpuYLRYvGodxKjkarnSNgsXoKEMlaSKxKdcVgvOkuLcfLFfdtXGTclqfPOfeoVLbqcjcXCUEBgAGplrkgsmIEhWRZLlGPGCwKWRaCKMkBHTAcypUrYjWwCLtOPVygMwMANGoQwFnCqFrUGMCRZUGJKTZIGPyldsifauoMnJPLTcDHmilcmahlqOELaAUYDBuzsVywnDQfwRLGIWozYaOAilMBcObErwgTDNGWnwQMUgFFSKtPDMEoEQCTKVREqrXZSGLqwTMcxHfWotDllNkIJPMbXzjDVjPOOjCFuIvTyhXKLyhUScOXvYthRXpPfKwMhptXaxIxgqBoUqzrWbaoLTVpQoottZyPFfNOoMioXHRuFwMRYUiKvcWPkrayyTLOCFJlAyslDameIuqVAuxErqFPEWIScKpBORIuZqoXlZuTvAjEdlEWDODFRregDTqGNoFBIHxvimmIZwLfFyKUfEWAnNBdtdzDmTPXtpHRGdIbuucfTjOygZsTxPjfweXhSUkMhPjMaxKlMIJMOXcnQfyzeOcbWwNbeH", msg.GetContent().GetDescription()) 123 require.Equal(t, "gov", msg.Route()) 124 require.Equal(t, types.TypeMsgSubmitProposal, msg.Type()) 125 } 126 127 // TestSimulateMsgDeposit tests the normal scenario of a valid message of type TypeMsgDeposit. 128 // Abonormal scenarios, where the message is created by an errors are not tested here. 129 func TestSimulateMsgDeposit(t *testing.T) { 130 app, ctx := createTestApp(false) 131 blockTime := time.Now().UTC() 132 ctx = ctx.WithBlockTime(blockTime) 133 134 // setup 3 accounts 135 s := rand.NewSource(1) 136 r := rand.New(s) 137 accounts := getTestingAccounts(t, r, app, ctx, 3) 138 139 // setup a proposal 140 content := types.NewTextProposal("Test", "description") 141 142 submitTime := ctx.BlockHeader().Time 143 depositPeriod := app.GovKeeper.GetDepositParams(ctx).MaxDepositPeriod 144 145 proposal, err := types.NewProposal(content, 1, submitTime, submitTime.Add(depositPeriod)) 146 require.NoError(t, err) 147 148 app.GovKeeper.SetProposal(ctx, proposal) 149 150 // begin a new block 151 app.BeginBlock(ocabci.RequestBeginBlock{Header: tmproto.Header{Height: app.LastBlockHeight() + 1, AppHash: app.LastCommitID().Hash, Time: blockTime}}) 152 153 // execute operation 154 op := simulation.SimulateMsgDeposit(app.AccountKeeper, app.BankKeeper, app.GovKeeper) 155 operationMsg, _, err := op(r, app.BaseApp, ctx, accounts, "") 156 require.NoError(t, err) 157 158 var msg types.MsgDeposit 159 err = govcodec.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg) 160 require.NoError(t, err) 161 162 require.True(t, operationMsg.OK) 163 require.Equal(t, uint64(1), msg.ProposalId) 164 require.Equal(t, "link1ghekyjucln7y67ntx7cf27m9dpuxxemnqk82wt", msg.Depositor) 165 require.Equal(t, "560969stake", msg.Amount.String()) 166 require.Equal(t, "gov", msg.Route()) 167 require.Equal(t, types.TypeMsgDeposit, msg.Type()) 168 } 169 170 // TestSimulateMsgVote tests the normal scenario of a valid message of type TypeMsgVote. 171 // Abonormal scenarios, where the message is created by an errors are not tested here. 172 func TestSimulateMsgVote(t *testing.T) { 173 app, ctx := createTestApp(false) 174 blockTime := time.Now().UTC() 175 ctx = ctx.WithBlockTime(blockTime) 176 177 // setup 3 accounts 178 s := rand.NewSource(1) 179 r := rand.New(s) 180 accounts := getTestingAccounts(t, r, app, ctx, 3) 181 182 // setup a proposal 183 content := types.NewTextProposal("Test", "description") 184 185 submitTime := ctx.BlockHeader().Time 186 depositPeriod := app.GovKeeper.GetDepositParams(ctx).MaxDepositPeriod 187 188 proposal, err := types.NewProposal(content, 1, submitTime, submitTime.Add(depositPeriod)) 189 require.NoError(t, err) 190 191 app.GovKeeper.ActivateVotingPeriod(ctx, proposal) 192 193 // begin a new block 194 app.BeginBlock(ocabci.RequestBeginBlock{Header: tmproto.Header{Height: app.LastBlockHeight() + 1, AppHash: app.LastCommitID().Hash, Time: blockTime}}) 195 196 // execute operation 197 op := simulation.SimulateMsgVote(app.AccountKeeper, app.BankKeeper, app.GovKeeper) 198 operationMsg, _, err := op(r, app.BaseApp, ctx, accounts, "") 199 require.NoError(t, err) 200 201 var msg types.MsgVote 202 err = govcodec.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg) 203 require.NoError(t, err) 204 205 require.True(t, operationMsg.OK) 206 require.Equal(t, uint64(1), msg.ProposalId) 207 require.Equal(t, "link1ghekyjucln7y67ntx7cf27m9dpuxxemnqk82wt", msg.Voter) 208 require.Equal(t, types.OptionYes, msg.Option) 209 require.Equal(t, "gov", msg.Route()) 210 require.Equal(t, types.TypeMsgVote, msg.Type()) 211 } 212 213 // TestSimulateMsgVoteWeighted tests the normal scenario of a valid message of type TypeMsgVoteWeighted. 214 // Abonormal scenarios, where the message is created by an errors are not tested here. 215 func TestSimulateMsgVoteWeighted(t *testing.T) { 216 app, ctx := createTestApp(false) 217 blockTime := time.Now().UTC() 218 ctx = ctx.WithBlockTime(blockTime) 219 220 // setup 3 accounts 221 s := rand.NewSource(1) 222 r := rand.New(s) 223 accounts := getTestingAccounts(t, r, app, ctx, 3) 224 225 // setup a proposal 226 content := types.NewTextProposal("Test", "description") 227 228 submitTime := ctx.BlockHeader().Time 229 depositPeriod := app.GovKeeper.GetDepositParams(ctx).MaxDepositPeriod 230 231 proposal, err := types.NewProposal(content, 1, submitTime, submitTime.Add(depositPeriod)) 232 require.NoError(t, err) 233 234 app.GovKeeper.ActivateVotingPeriod(ctx, proposal) 235 236 // begin a new block 237 app.BeginBlock(ocabci.RequestBeginBlock{Header: tmproto.Header{Height: app.LastBlockHeight() + 1, AppHash: app.LastCommitID().Hash, Time: blockTime}}) 238 239 // execute operation 240 op := simulation.SimulateMsgVoteWeighted(app.AccountKeeper, app.BankKeeper, app.GovKeeper) 241 operationMsg, _, err := op(r, app.BaseApp, ctx, accounts, "") 242 require.NoError(t, err) 243 244 var msg types.MsgVoteWeighted 245 err = govcodec.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg) 246 require.NoError(t, err) 247 248 require.True(t, operationMsg.OK) 249 require.Equal(t, uint64(1), msg.ProposalId) 250 require.Equal(t, "link1ghekyjucln7y67ntx7cf27m9dpuxxemnqk82wt", msg.Voter) 251 require.True(t, len(msg.Options) >= 1) 252 require.Equal(t, "gov", msg.Route()) 253 require.Equal(t, types.TypeMsgVoteWeighted, msg.Type()) 254 } 255 256 // returns context and an app with updated mint keeper 257 func createTestApp(isCheckTx bool) (*simapp.SimApp, sdk.Context) { 258 app := simapp.Setup(isCheckTx) 259 260 ctx := app.BaseApp.NewContext(isCheckTx, tmproto.Header{}) 261 app.MintKeeper.SetParams(ctx, minttypes.DefaultParams()) 262 app.MintKeeper.SetMinter(ctx, minttypes.DefaultInitialMinter()) 263 264 return app, ctx 265 } 266 267 func getTestingAccounts(t *testing.T, r *rand.Rand, app *simapp.SimApp, ctx sdk.Context, n int) []simtypes.Account { 268 accounts := simtypes.RandomAccounts(r, n) 269 270 initAmt := app.StakingKeeper.TokensFromConsensusPower(ctx, 200) 271 initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt)) 272 273 // add coins to the accounts 274 for _, account := range accounts { 275 acc := app.AccountKeeper.NewAccountWithAddress(ctx, account.Address) 276 app.AccountKeeper.SetAccount(ctx, acc) 277 require.NoError(t, simapp.FundAccount(app, ctx, account.Address, initCoins)) 278 } 279 280 return accounts 281 }