feat: add unit test with mocks to x/genutil (#13007)

## Description

Closes: [#12759](https://github.com/cosmos/cosmos-sdk/issues/12759)



---

### Author Checklist

*All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.*

I have...

- [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] added `!` to the type prefix if API or client breaking change
- [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/main/CONTRIBUTING.md#pr-targeting))
- [ ] provided a link to the relevant issue or specification
- [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/main/docs/building-modules)
- [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/main/CONTRIBUTING.md#testing)
- [ ] added a changelog entry to `CHANGELOG.md`
- [ ] included comments for [documenting Go code](https://blog.golang.org/godoc)
- [ ] updated the relevant documentation or specification
- [ ] reviewed "Files changed" and left comments if necessary
- [ ] confirmed all CI checks have passed

### Reviewers Checklist

*All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.*

I have...

- [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] confirmed `!` in the type prefix if API or client breaking change
- [ ] confirmed all author checklist items have been addressed 
- [ ] reviewed state machine logic
- [ ] reviewed API design and naming
- [ ] reviewed documentation is accurate
- [ ] reviewed tests and test coverage
- [ ] manually tested (if applicable)
This commit is contained in:
Jeancarlo Barrios 2022-08-24 08:25:11 -06:00 committed by GitHub
parent ef4ad67c9e
commit 07c549bfbe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 524 additions and 0 deletions

View File

@ -22,3 +22,4 @@ $mockgen_cmd -source=x/bank/types/expected_keepers.go -package testutil -destina
$mockgen_cmd -source=x/group/testutil/expected_keepers.go -package testutil -destination x/group/testutil/expected_keepers_mocks.go
$mockgen_cmd -source=x/evidence/types/expected_keepers.go -package testutil -destination x/evidence/testutil/expected_keepers_mocks.go
$mockgen_cmd -source=x/slashing/types/expected_keepers.go -package testutil -destination x/slashing/testutil/expected_keepers_mocks.go
$mockgen_cmd -source=x/genutil/types/expected_keepers.go -package testutil -destination x/genutil/testutil/expected_keepers_mocks.go

337
x/genutil/gentx_test.go Normal file
View File

@ -0,0 +1,337 @@
package genutil_test
import (
"cosmossdk.io/math"
"encoding/json"
"fmt"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
"github.com/cosmos/cosmos-sdk/testutil"
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/cosmos/cosmos-sdk/x/genutil"
genutiltestutil "github.com/cosmos/cosmos-sdk/x/genutil/testutil"
"github.com/cosmos/cosmos-sdk/x/genutil/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/suite"
abci "github.com/tendermint/tendermint/abci/types"
"math/rand"
"testing"
"time"
)
var (
priv1 = secp256k1.GenPrivKey()
priv2 = secp256k1.GenPrivKey()
pk1 = priv1.PubKey()
pk2 = priv2.PubKey()
addr1 = sdk.AccAddress(pk1.Address())
addr2 = sdk.AccAddress(pk2.Address())
desc = stakingtypes.NewDescription("testname", "", "", "", "")
comm = stakingtypes.CommissionRates{}
)
// GenTxTestSuite is a test suite to be used with gentx tests.
type GenTxTestSuite struct {
suite.Suite
ctx sdk.Context
stakingKeeper *genutiltestutil.MockStakingKeeper
encodingConfig moduletestutil.TestEncodingConfig
msg1, msg2 *stakingtypes.MsgCreateValidator
}
func (suite *GenTxTestSuite) SetupTest() {
suite.encodingConfig = moduletestutil.MakeTestEncodingConfig(genutil.AppModuleBasic{})
key := sdk.NewKVStoreKey("a_Store_Key")
tkey := sdk.NewTransientStoreKey("a_transient_store")
suite.ctx = testutil.DefaultContext(key, tkey)
ctrl := gomock.NewController(suite.T())
suite.stakingKeeper = genutiltestutil.NewMockStakingKeeper(ctrl)
stakingtypes.RegisterInterfaces(suite.encodingConfig.InterfaceRegistry)
banktypes.RegisterInterfaces(suite.encodingConfig.InterfaceRegistry)
var err error
amount := sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)
one := math.OneInt()
suite.msg1, err = stakingtypes.NewMsgCreateValidator(
sdk.ValAddress(pk1.Address()), pk1, amount, desc, comm, one)
suite.NoError(err)
suite.msg2, err = stakingtypes.NewMsgCreateValidator(
sdk.ValAddress(pk2.Address()), pk1, amount, desc, comm, one)
suite.NoError(err)
}
func (suite *GenTxTestSuite) setAccountBalance(balances []banktypes.Balance) json.RawMessage {
bankGenesisState := banktypes.GenesisState{
Params: banktypes.Params{DefaultSendEnabled: true},
Balances: []banktypes.Balance{
{
Address: "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh",
Coins: sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000000)},
},
{
Address: "cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl",
Coins: sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 2059726)},
},
{
Address: "cosmos1k5lndq46x9xpejdxq52q3ql3ycrphg4qxlfqn7",
Coins: sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 100000000000000)},
},
},
Supply: sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 0)},
}
for _, balance := range balances {
bankGenesisState.Balances = append(bankGenesisState.Balances, balance)
}
for _, balance := range bankGenesisState.Balances {
bankGenesisState.Supply.Add(balance.Coins...)
}
bankGenesis, err := suite.encodingConfig.Amino.MarshalJSON(bankGenesisState) // TODO switch this to use Marshaler
suite.Require().NoError(err)
return bankGenesis
}
func (suite *GenTxTestSuite) TestSetGenTxsInAppGenesisState() {
var (
txBuilder = suite.encodingConfig.TxConfig.NewTxBuilder()
genTxs []sdk.Tx
)
testCases := []struct {
msg string
malleate func()
expPass bool
}{
{
"one genesis transaction",
func() {
err := txBuilder.SetMsgs(suite.msg1)
suite.Require().NoError(err)
tx := txBuilder.GetTx()
genTxs = []sdk.Tx{tx}
},
true,
},
{
"two genesis transactions",
func() {
err := txBuilder.SetMsgs(suite.msg1, suite.msg2)
suite.Require().NoError(err)
tx := txBuilder.GetTx()
genTxs = []sdk.Tx{tx}
},
true,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest()
cdc := suite.encodingConfig.Codec
txJSONEncoder := suite.encodingConfig.TxConfig.TxJSONEncoder()
tc.malleate()
appGenesisState, err := genutil.SetGenTxsInAppGenesisState(cdc, txJSONEncoder, make(map[string]json.RawMessage), genTxs)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().NotNil(appGenesisState[types.ModuleName])
var genesisState types.GenesisState
err := cdc.UnmarshalJSON(appGenesisState[types.ModuleName], &genesisState)
suite.Require().NoError(err)
suite.Require().NotNil(genesisState.GenTxs)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *GenTxTestSuite) TestValidateAccountInGenesis() {
var (
appGenesisState = make(map[string]json.RawMessage)
coins sdk.Coins
)
testCases := []struct {
msg string
malleate func()
expPass bool
}{
{
"no accounts",
func() {
coins = sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 0)}
},
false,
},
{
"account without balance in the genesis state",
func() {
coins = sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 0)}
balances := banktypes.Balance{
Address: addr2.String(),
Coins: sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)},
}
appGenesisState[banktypes.ModuleName] = suite.setAccountBalance([]banktypes.Balance{balances})
},
false,
},
{
"account without enough funds of default bond denom",
func() {
coins = sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)}
balances := banktypes.Balance{
Address: addr1.String(),
Coins: sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 25)},
}
appGenesisState[banktypes.ModuleName] = suite.setAccountBalance([]banktypes.Balance{balances})
},
false,
},
{
"account with enough funds of default bond denom",
func() {
coins = sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 10)}
balances := banktypes.Balance{
Address: addr1.String(),
Coins: sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 25)},
}
appGenesisState[banktypes.ModuleName] = suite.setAccountBalance([]banktypes.Balance{balances})
},
true,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest()
cdc := suite.encodingConfig.Codec
stakingGenesis, err := cdc.MarshalJSON(&stakingtypes.GenesisState{Params: stakingtypes.DefaultParams()}) // TODO switch this to use Marshaler
suite.Require().NoError(err)
appGenesisState[stakingtypes.ModuleName] = stakingGenesis
tc.malleate()
err = genutil.ValidateAccountInGenesis(
appGenesisState, banktypes.GenesisBalancesIterator{},
addr1, coins, cdc,
)
if tc.expPass {
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *GenTxTestSuite) TestDeliverGenTxs() {
var (
genTxs []json.RawMessage
txBuilder = suite.encodingConfig.TxConfig.NewTxBuilder()
)
testCases := []struct {
msg string
malleate func()
deliverTxFn func(abci.RequestDeliverTx) abci.ResponseDeliverTx
expPass bool
}{
{
"no signature supplied",
func() {
err := txBuilder.SetMsgs(suite.msg1)
suite.Require().NoError(err)
genTxs = make([]json.RawMessage, 1)
tx, err := suite.encodingConfig.TxConfig.TxJSONEncoder()(txBuilder.GetTx())
suite.Require().NoError(err)
genTxs[0] = tx
},
func(_ abci.RequestDeliverTx) abci.ResponseDeliverTx {
return abci.ResponseDeliverTx{
Code: sdkerrors.ErrNoSignatures.ABCICode(),
GasWanted: int64(10000000),
GasUsed: int64(41913),
Log: "no signatures supplied",
}
},
false,
},
{
"success",
func() {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
msg := banktypes.NewMsgSend(addr1, addr2, sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 1)})
tx, err := simtestutil.GenSignedMockTx(
r,
suite.encodingConfig.TxConfig,
[]sdk.Msg{msg},
sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 10)},
simtestutil.DefaultGenTxGas,
suite.ctx.ChainID(),
[]uint64{7},
[]uint64{0},
priv1,
)
suite.Require().NoError(err)
genTxs = make([]json.RawMessage, 1)
genTx, err := suite.encodingConfig.TxConfig.TxJSONEncoder()(tx)
suite.Require().NoError(err)
genTxs[0] = genTx
},
func(tx abci.RequestDeliverTx) abci.ResponseDeliverTx {
return abci.ResponseDeliverTx{
Code: sdkerrors.ErrUnauthorized.ABCICode(),
GasWanted: int64(10000000),
GasUsed: int64(41353),
Log: "signature verification failed; please verify account number (4) and chain-id (): unauthorized",
Codespace: "sdk",
}
},
true,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest()
tc.malleate()
if tc.expPass {
suite.Require().NotPanics(func() {
genutil.DeliverGenTxs(
suite.ctx, genTxs, suite.stakingKeeper, tc.deliverTxFn,
suite.encodingConfig.TxConfig,
)
})
} else {
_, err := genutil.DeliverGenTxs(
suite.ctx, genTxs, suite.stakingKeeper, tc.deliverTxFn,
suite.encodingConfig.TxConfig,
)
suite.Require().Error(err)
}
})
}
}
func TestGenTxTestSuite(t *testing.T) {
suite.Run(t, new(GenTxTestSuite))
}

View File

@ -0,0 +1,186 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: x/genutil/types/expected_keepers.go
// Package testutil is a generated GoMock package.
package testutil
import (
json "encoding/json"
reflect "reflect"
codec "github.com/cosmos/cosmos-sdk/codec"
types "github.com/cosmos/cosmos-sdk/types"
types0 "github.com/cosmos/cosmos-sdk/x/auth/types"
exported "github.com/cosmos/cosmos-sdk/x/bank/exported"
gomock "github.com/golang/mock/gomock"
types1 "github.com/tendermint/tendermint/abci/types"
)
// MockStakingKeeper is a mock of StakingKeeper interface.
type MockStakingKeeper struct {
ctrl *gomock.Controller
recorder *MockStakingKeeperMockRecorder
}
// MockStakingKeeperMockRecorder is the mock recorder for MockStakingKeeper.
type MockStakingKeeperMockRecorder struct {
mock *MockStakingKeeper
}
// NewMockStakingKeeper creates a new mock instance.
func NewMockStakingKeeper(ctrl *gomock.Controller) *MockStakingKeeper {
mock := &MockStakingKeeper{ctrl: ctrl}
mock.recorder = &MockStakingKeeperMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockStakingKeeper) EXPECT() *MockStakingKeeperMockRecorder {
return m.recorder
}
// ApplyAndReturnValidatorSetUpdates mocks base method.
func (m *MockStakingKeeper) ApplyAndReturnValidatorSetUpdates(arg0 types.Context) ([]types1.ValidatorUpdate, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ApplyAndReturnValidatorSetUpdates", arg0)
ret0, _ := ret[0].([]types1.ValidatorUpdate)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// ApplyAndReturnValidatorSetUpdates indicates an expected call of ApplyAndReturnValidatorSetUpdates.
func (mr *MockStakingKeeperMockRecorder) ApplyAndReturnValidatorSetUpdates(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ApplyAndReturnValidatorSetUpdates", reflect.TypeOf((*MockStakingKeeper)(nil).ApplyAndReturnValidatorSetUpdates), arg0)
}
// MockAccountKeeper is a mock of AccountKeeper interface.
type MockAccountKeeper struct {
ctrl *gomock.Controller
recorder *MockAccountKeeperMockRecorder
}
// MockAccountKeeperMockRecorder is the mock recorder for MockAccountKeeper.
type MockAccountKeeperMockRecorder struct {
mock *MockAccountKeeper
}
// NewMockAccountKeeper creates a new mock instance.
func NewMockAccountKeeper(ctrl *gomock.Controller) *MockAccountKeeper {
mock := &MockAccountKeeper{ctrl: ctrl}
mock.recorder = &MockAccountKeeperMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockAccountKeeper) EXPECT() *MockAccountKeeperMockRecorder {
return m.recorder
}
// IterateAccounts mocks base method.
func (m *MockAccountKeeper) IterateAccounts(ctx types.Context, process func(types0.AccountI) bool) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "IterateAccounts", ctx, process)
}
// IterateAccounts indicates an expected call of IterateAccounts.
func (mr *MockAccountKeeperMockRecorder) IterateAccounts(ctx, process interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateAccounts", reflect.TypeOf((*MockAccountKeeper)(nil).IterateAccounts), ctx, process)
}
// NewAccount mocks base method.
func (m *MockAccountKeeper) NewAccount(arg0 types.Context, arg1 types0.AccountI) types0.AccountI {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "NewAccount", arg0, arg1)
ret0, _ := ret[0].(types0.AccountI)
return ret0
}
// NewAccount indicates an expected call of NewAccount.
func (mr *MockAccountKeeperMockRecorder) NewAccount(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewAccount", reflect.TypeOf((*MockAccountKeeper)(nil).NewAccount), arg0, arg1)
}
// SetAccount mocks base method.
func (m *MockAccountKeeper) SetAccount(arg0 types.Context, arg1 types0.AccountI) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "SetAccount", arg0, arg1)
}
// SetAccount indicates an expected call of SetAccount.
func (mr *MockAccountKeeperMockRecorder) SetAccount(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetAccount", reflect.TypeOf((*MockAccountKeeper)(nil).SetAccount), arg0, arg1)
}
// MockGenesisAccountsIterator is a mock of GenesisAccountsIterator interface.
type MockGenesisAccountsIterator struct {
ctrl *gomock.Controller
recorder *MockGenesisAccountsIteratorMockRecorder
}
// MockGenesisAccountsIteratorMockRecorder is the mock recorder for MockGenesisAccountsIterator.
type MockGenesisAccountsIteratorMockRecorder struct {
mock *MockGenesisAccountsIterator
}
// NewMockGenesisAccountsIterator creates a new mock instance.
func NewMockGenesisAccountsIterator(ctrl *gomock.Controller) *MockGenesisAccountsIterator {
mock := &MockGenesisAccountsIterator{ctrl: ctrl}
mock.recorder = &MockGenesisAccountsIteratorMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockGenesisAccountsIterator) EXPECT() *MockGenesisAccountsIteratorMockRecorder {
return m.recorder
}
// IterateGenesisAccounts mocks base method.
func (m *MockGenesisAccountsIterator) IterateGenesisAccounts(cdc *codec.LegacyAmino, appGenesis map[string]json.RawMessage, cb func(types0.AccountI) bool) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "IterateGenesisAccounts", cdc, appGenesis, cb)
}
// IterateGenesisAccounts indicates an expected call of IterateGenesisAccounts.
func (mr *MockGenesisAccountsIteratorMockRecorder) IterateGenesisAccounts(cdc, appGenesis, cb interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateGenesisAccounts", reflect.TypeOf((*MockGenesisAccountsIterator)(nil).IterateGenesisAccounts), cdc, appGenesis, cb)
}
// MockGenesisBalancesIterator is a mock of GenesisBalancesIterator interface.
type MockGenesisBalancesIterator struct {
ctrl *gomock.Controller
recorder *MockGenesisBalancesIteratorMockRecorder
}
// MockGenesisBalancesIteratorMockRecorder is the mock recorder for MockGenesisBalancesIterator.
type MockGenesisBalancesIteratorMockRecorder struct {
mock *MockGenesisBalancesIterator
}
// NewMockGenesisBalancesIterator creates a new mock instance.
func NewMockGenesisBalancesIterator(ctrl *gomock.Controller) *MockGenesisBalancesIterator {
mock := &MockGenesisBalancesIterator{ctrl: ctrl}
mock.recorder = &MockGenesisBalancesIteratorMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockGenesisBalancesIterator) EXPECT() *MockGenesisBalancesIteratorMockRecorder {
return m.recorder
}
// IterateGenesisBalances mocks base method.
func (m *MockGenesisBalancesIterator) IterateGenesisBalances(cdc codec.JSONCodec, appGenesis map[string]json.RawMessage, cb func(exported.GenesisBalance) bool) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "IterateGenesisBalances", cdc, appGenesis, cb)
}
// IterateGenesisBalances indicates an expected call of IterateGenesisBalances.
func (mr *MockGenesisBalancesIteratorMockRecorder) IterateGenesisBalances(cdc, appGenesis, cb interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateGenesisBalances", reflect.TypeOf((*MockGenesisBalancesIterator)(nil).IterateGenesisBalances), cdc, appGenesis, cb)
}