diff --git a/x/budget/simulation/genesis.go b/x/budget/simulation/genesis.go index 6f0b5b5..5317f87 100644 --- a/x/budget/simulation/genesis.go +++ b/x/budget/simulation/genesis.go @@ -8,6 +8,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/address" "github.com/cosmos/cosmos-sdk/types/module" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/tendermint/budget/x/budget/types" ) @@ -20,29 +21,31 @@ const ( Budgets = "budgets" ) -// GenEpochBlocks return default DefaultEpochBlocks +// GenEpochBlocks returns randomized epoch blocks. func GenEpochBlocks(r *rand.Rand) uint32 { - // TODO: randomize - return types.DefaultEpochBlocks + return uint32(simtypes.RandIntBetween(r, int(types.DefaultEpochBlocks), 10)) } -// GenGenBudgets return randomized budgets +// GenBudgets returns randomized budgets. func GenBudgets(r *rand.Rand) []types.Budget { - // TODO: randomize - budgetSamples := []types.Budget{ - { - Name: "budget1", - Rate: sdk.MustNewDecFromStr("0.5"), - BudgetSourceAddress: "cosmos17xpfvakm2amg962yls6f84z3kell8c5lserqta", // Address corresponding to fee_collector module account in cosmoshub case + ranBudgets := make([]types.Budget, 0) + + for i := 0; i < simtypes.RandIntBetween(r, 1, 3); i++ { + budget := types.Budget{ + Name: "simulation-test-" + simtypes.RandStringOfLength(r, 5), + Rate: sdk.NewDecFromIntWithPrec(sdk.NewInt(int64(simtypes.RandIntBetween(r, 1, 4))), 1), // 10~30% + BudgetSourceAddress: "cosmos17xpfvakm2amg962yls6f84z3kell8c5lserqta", // Cosmos Hub's FeeCollector module account CollectionAddress: sdk.AccAddress(address.Module(types.ModuleName, []byte("GravityDEXFarmingBudget"))).String(), StartTime: types.ParseTime("2000-01-01T00:00:00Z"), EndTime: types.ParseTime("9999-12-31T00:00:00Z"), - }, + } + ranBudgets = append(ranBudgets, budget) } - return budgetSamples + + return ranBudgets } -// RandomizedGenState generates a random GenesisState for budget +// RandomizedGenState generates a random GenesisState for budget. func RandomizedGenState(simState *module.SimulationState) { var epochBlocks uint32 var budgets []types.Budget diff --git a/x/budget/simulation/genesis_test.go b/x/budget/simulation/genesis_test.go new file mode 100644 index 0000000..cae79f6 --- /dev/null +++ b/x/budget/simulation/genesis_test.go @@ -0,0 +1,75 @@ +package simulation_test + +import ( + "encoding/json" + "math/rand" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + + "github.com/tendermint/budget/x/budget/simulation" + "github.com/tendermint/budget/x/budget/types" +) + +// TestRandomizedGenState tests the normal scenario of applying RandomizedGenState. +// Abnormal scenarios are not tested here. +func TestRandomizedGenState(t *testing.T) { + interfaceRegistry := codectypes.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(interfaceRegistry) + s := rand.NewSource(1) + r := rand.New(s) + + simState := module.SimulationState{ + AppParams: make(simtypes.AppParams), + Cdc: cdc, + Rand: r, + NumBonded: 3, + Accounts: simtypes.RandomAccounts(r, 3), + InitialStake: 1000, + GenState: make(map[string]json.RawMessage), + } + + simulation.RandomizedGenState(&simState) + + var genState types.GenesisState + simState.Cdc.MustUnmarshalJSON(simState.GenState[types.ModuleName], &genState) + + require.Equal(t, sdk.MustNewDecFromStr("0.3"), genState.Params.Budgets[0].Rate) + require.Equal(t, "cosmos17xpfvakm2amg962yls6f84z3kell8c5lserqta", genState.Params.Budgets[0].BudgetSourceAddress) + require.Equal(t, "cosmos1ke7rn6vl3vmeasmcrxdm3pfrt37fsg5jfrex80pp3hvhwgu4h4usxgvk3e", genState.Params.Budgets[0].CollectionAddress) + require.Equal(t, uint32(9), genState.Params.EpochBlocks) +} + +// TestRandomizedGenState tests abnormal scenarios of applying RandomizedGenState. +func TestRandomizedGenState1(t *testing.T) { + interfaceRegistry := codectypes.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(interfaceRegistry) + + s := rand.NewSource(1) + r := rand.New(s) + + // all these tests will panic + tests := []struct { + simState module.SimulationState + panicMsg string + }{ + { // panic => reason: incomplete initialization of the simState + module.SimulationState{}, "invalid memory address or nil pointer dereference"}, + { // panic => reason: incomplete initialization of the simState + module.SimulationState{ + AppParams: make(simtypes.AppParams), + Cdc: cdc, + Rand: r, + }, "assignment to entry in nil map"}, + } + + for _, tt := range tests { + require.Panicsf(t, func() { simulation.RandomizedGenState(&tt.simState) }, tt.panicMsg) + } +} diff --git a/x/budget/simulation/params.go b/x/budget/simulation/params.go index 88122dc..85caa66 100644 --- a/x/budget/simulation/params.go +++ b/x/budget/simulation/params.go @@ -1,6 +1,9 @@ package simulation +// DONTCOVER + import ( + "encoding/json" "fmt" "math/rand" @@ -10,8 +13,6 @@ import ( "github.com/tendermint/budget/x/budget/types" ) -// DONTCOVER - // ParamChanges defines the parameters that can be modified by param change proposals // on the simulation func ParamChanges(r *rand.Rand) []simtypes.ParamChange { @@ -21,12 +22,14 @@ func ParamChanges(r *rand.Rand) []simtypes.ParamChange { return fmt.Sprintf("%d", GenEpochBlocks(r)) }, ), - // TODO: Randomize structured ParamChange - // ref. /~https://github.com/cosmos/cosmos-sdk/blob/49102b1d988f542c4293af7a85e403d858f348a8/x/gov/simulation/params.go#L39 - //simulation.NewSimParamChange(types.ModuleName, string(types.KeyBudgets), - // func(r *rand.Rand) string { - // return fmt.Sprintf("%s", GenBudgets(r)) - // }, - //), + simulation.NewSimParamChange(types.ModuleName, string(types.KeyBudgets), + func(r *rand.Rand) string { + bz, err := json.Marshal(GenBudgets(r)) + if err != nil { + panic(err) + } + return string(bz) + }, + ), } } diff --git a/x/budget/simulation/params_test.go b/x/budget/simulation/params_test.go index 8590250..bc8e722 100644 --- a/x/budget/simulation/params_test.go +++ b/x/budget/simulation/params_test.go @@ -1,28 +1,36 @@ package simulation_test -// TODO: write testcode after Randomize - -//func TestParamChanges(t *testing.T) { -// s := rand.NewSource(1) -// r := rand.New(s) -// -// expected := []struct { -// composedKey string -// key string -// simValue string -// subspace string -// }{ -// {"budget/", "", "\"\"", "budget"}, -// } -// -// paramChanges := simulation.ParamChanges(r) -// -// require.Len(t, paramChanges, 1) -// -// for i, p := range paramChanges { -// require.Equal(t, expected[i].composedKey, p.ComposedKey()) -// require.Equal(t, expected[i].key, p.Key()) -// require.Equal(t, expected[i].simValue, p.SimValue()(r)) -// require.Equal(t, expected[i].subspace, p.Subspace()) -// } -//} +import ( + "math/rand" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/tendermint/budget/x/budget/simulation" +) + +func TestParamChanges(t *testing.T) { + s := rand.NewSource(1) + r := rand.New(s) + + expected := []struct { + composedKey string + key string + simValue string + subspace string + }{ + {"budget/EpochBlocks", "EpochBlocks", "6", "budget"}, + {"budget/Budgets", "Budgets", `[{"name":"simulation-test-MLxiD","rate":"0.300000000000000000","budget_source_address":"cosmos17xpfvakm2amg962yls6f84z3kell8c5lserqta","collection_address":"cosmos1ke7rn6vl3vmeasmcrxdm3pfrt37fsg5jfrex80pp3hvhwgu4h4usxgvk3e","start_time":"2000-01-01T00:00:00Z","end_time":"9999-12-31T00:00:00Z"},{"name":"simulation-test-nhwJy","rate":"0.200000000000000000","budget_source_address":"cosmos17xpfvakm2amg962yls6f84z3kell8c5lserqta","collection_address":"cosmos1ke7rn6vl3vmeasmcrxdm3pfrt37fsg5jfrex80pp3hvhwgu4h4usxgvk3e","start_time":"2000-01-01T00:00:00Z","end_time":"9999-12-31T00:00:00Z"}]`, "budget"}, + } + + paramChanges := simulation.ParamChanges(r) + + require.Len(t, paramChanges, 2) + + for i, p := range paramChanges { + require.Equal(t, expected[i].composedKey, p.ComposedKey()) + require.Equal(t, expected[i].key, p.Key()) + require.Equal(t, expected[i].simValue, p.SimValue()(r)) + require.Equal(t, expected[i].subspace, p.Subspace()) + } +}