feat(tests): add simapp setup helpers (#10020)

This commit is contained in:
MD Aleem 2021-09-16 02:48:01 +05:30 committed by GitHub
parent fcd6733b9b
commit 22cd77870a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 182 additions and 73 deletions

View File

@ -39,7 +39,15 @@ import (
func TestSimAppExportAndBlockedAddrs(t *testing.T) {
encCfg := MakeTestEncodingConfig()
db := dbm.NewMemDB()
app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encCfg, EmptyAppOptions{})
app := NewSimappWithCustomOptions(t, false, SetupOptions{
Logger: log.NewTMLogger(log.NewSyncWriter(os.Stdout)),
DB: db,
InvCheckPeriod: 0,
EncConfig: encCfg,
HomePath: DefaultNodeHome,
SkipUpgradeHeights: map[int64]bool{},
AppOpts: EmptyAppOptions{},
})
for acc := range maccPerms {
require.True(
@ -49,22 +57,11 @@ func TestSimAppExportAndBlockedAddrs(t *testing.T) {
)
}
genesisState := NewDefaultGenesisState(encCfg.Codec)
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
require.NoError(t, err)
// Initialize the chain
app.InitChain(
abci.RequestInitChain{
Validators: []abci.ValidatorUpdate{},
AppStateBytes: stateBytes,
},
)
app.Commit()
// Making a new app object with the db, so that initchain hasn't been called
app2 := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encCfg, EmptyAppOptions{})
_, err = app2.ExportAppStateAndValidators(false, []string{})
_, err := app2.ExportAppStateAndValidators(false, []string{})
require.NoError(t, err, "ExportAppStateAndValidators should not have an error")
}
@ -249,18 +246,15 @@ func TestInitGenesisOnMigration(t *testing.T) {
func TestUpgradeStateOnGenesis(t *testing.T) {
encCfg := MakeTestEncodingConfig()
db := dbm.NewMemDB()
app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encCfg, EmptyAppOptions{})
genesisState := NewDefaultGenesisState(encCfg.Codec)
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
require.NoError(t, err)
// Initialize the chain
app.InitChain(
abci.RequestInitChain{
Validators: []abci.ValidatorUpdate{},
AppStateBytes: stateBytes,
},
)
app := NewSimappWithCustomOptions(t, false, SetupOptions{
Logger: log.NewTMLogger(log.NewSyncWriter(os.Stdout)),
DB: db,
InvCheckPeriod: 0,
EncConfig: encCfg,
HomePath: DefaultNodeHome,
SkipUpgradeHeights: map[int64]bool{},
AppOpts: EmptyAppOptions{},
})
// make sure the upgrade keeper has version map in state
ctx := app.NewContext(false, tmproto.Header{})

View File

@ -11,6 +11,7 @@ import (
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
tmjson "github.com/tendermint/tendermint/libs/json"
"github.com/tendermint/tendermint/libs/log"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
tmtypes "github.com/tendermint/tendermint/types"
@ -21,8 +22,12 @@ import (
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/server/types"
"github.com/cosmos/cosmos-sdk/simapp/helpers"
"github.com/cosmos/cosmos-sdk/simapp/params"
"github.com/cosmos/cosmos-sdk/testutil/mock"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/errors"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
@ -50,6 +55,17 @@ var DefaultConsensusParams = &abci.ConsensusParams{
},
}
// SetupOptions defines arguments that are passed into `Simapp` constructor.
type SetupOptions struct {
Logger log.Logger
DB *dbm.MemDB
InvCheckPeriod uint
HomePath string
SkipUpgradeHeights map[int64]bool
EncConfig params.EncodingConfig
AppOpts types.AppOptions
}
func setup(withGenesis bool, invCheckPeriod uint) (*SimApp, GenesisState) {
db := dbm.NewMemDB()
encCdc := MakeTestEncodingConfig()
@ -60,6 +76,47 @@ func setup(withGenesis bool, invCheckPeriod uint) (*SimApp, GenesisState) {
return app, GenesisState{}
}
// NewSimappWithCustomOptions initializes a new SimApp with custom options.
func NewSimappWithCustomOptions(t *testing.T, isCheckTx bool, options SetupOptions) *SimApp {
t.Helper()
privVal := mock.NewPV()
pubKey, err := privVal.GetPubKey()
require.NoError(t, err)
// create validator set with single validator
validator := tmtypes.NewValidator(pubKey, 1)
valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator})
// generate genesis account
senderPrivKey := secp256k1.GenPrivKey()
acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), 0, 0)
balance := banktypes.Balance{
Address: acc.GetAddress().String(),
Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100000000000000))),
}
app := NewSimApp(options.Logger, options.DB, nil, true, options.SkipUpgradeHeights, options.HomePath, options.InvCheckPeriod, options.EncConfig, options.AppOpts)
genesisState := NewDefaultGenesisState(app.appCodec)
genesisState = genesisStateWithValSet(t, app, genesisState, valSet, []authtypes.GenesisAccount{acc}, balance)
if !isCheckTx {
// init chain must be called to stop deliverState from being nil
stateBytes, err := tmjson.MarshalIndent(genesisState, "", " ")
require.NoError(t, err)
// Initialize the chain
app.InitChain(
abci.RequestInitChain{
Validators: []abci.ValidatorUpdate{},
ConsensusParams: DefaultConsensusParams,
AppStateBytes: stateBytes,
},
)
}
return app
}
// Setup initializes a new SimApp. A Nop logger is set in SimApp.
func Setup(t *testing.T, isCheckTx bool) *SimApp {
t.Helper()
@ -83,12 +140,10 @@ func Setup(t *testing.T, isCheckTx bool) *SimApp {
return app
}
// SetupWithGenesisValSet initializes a new SimApp with a validator set and genesis accounts
// that also act as delegators. For simplicity, each validator is bonded with a delegation
// of one consensus engine unit (10^6) in the default token of the simapp from first genesis
// account. A Nop logger is set in SimApp.
func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) *SimApp {
app, genesisState := setup(true, 5)
func genesisStateWithValSet(t *testing.T,
app *SimApp, genesisState GenesisState,
valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount,
balances ...banktypes.Balance) GenesisState {
// set genesis accounts
authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs)
genesisState[authtypes.ModuleName] = app.AppCodec().MustMarshalJSON(authGenesis)
@ -96,7 +151,7 @@ func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs
validators := make([]stakingtypes.Validator, 0, len(valSet.Validators))
delegations := make([]stakingtypes.Delegation, 0, len(valSet.Validators))
bondAmt := sdk.NewInt(1000000)
bondAmt := sdk.DefaultPowerReduction
for _, val := range valSet.Validators {
pk, err := cryptocodec.FromTmPubKeyInterface(val.PubKey)
@ -140,6 +195,19 @@ func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs
bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, totalSupply, []banktypes.Metadata{})
genesisState[banktypes.ModuleName] = app.AppCodec().MustMarshalJSON(bankGenesis)
return genesisState
}
// SetupWithGenesisValSet initializes a new SimApp with a validator set and genesis accounts
// that also act as delegators. For simplicity, each validator is bonded with a delegation
// of one consensus engine unit in the default token of the simapp from first genesis
// account. A Nop logger is set in SimApp.
func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) *SimApp {
t.Helper()
app, genesisState := setup(true, 5)
genesisState = genesisStateWithValSet(t, app, genesisState, valSet, genAccs, balances...)
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
require.NoError(t, err)
@ -166,7 +234,9 @@ func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs
// SetupWithGenesisAccounts initializes a new SimApp with the provided genesis
// accounts and possible balances.
func SetupWithGenesisAccounts(genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) *SimApp {
func SetupWithGenesisAccounts(t *testing.T, genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) *SimApp {
t.Helper()
app, genesisState := setup(true, 0)
authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs)
genesisState[authtypes.ModuleName] = app.AppCodec().MustMarshalJSON(authGenesis)
@ -180,9 +250,7 @@ func SetupWithGenesisAccounts(genAccs []authtypes.GenesisAccount, balances ...ba
genesisState[banktypes.ModuleName] = app.AppCodec().MustMarshalJSON(bankGenesis)
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
if err != nil {
panic(err)
}
require.NoError(t, err)
app.InitChain(
abci.RequestInitChain{

50
testutil/mock/privval.go Normal file
View File

@ -0,0 +1,50 @@
package mock
import (
"github.com/tendermint/tendermint/crypto"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
tmtypes "github.com/tendermint/tendermint/types"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
)
var _ tmtypes.PrivValidator = PV{}
// MockPV implements PrivValidator without any safety or persistence.
// Only use it for testing.
type PV struct {
PrivKey cryptotypes.PrivKey
}
func NewPV() PV {
return PV{ed25519.GenPrivKey()}
}
// GetPubKey implements PrivValidator interface
func (pv PV) GetPubKey() (crypto.PubKey, error) {
return cryptocodec.ToTmPubKeyInterface(pv.PrivKey.PubKey())
}
// SignVote implements PrivValidator interface
func (pv PV) SignVote(chainID string, vote *tmproto.Vote) error {
signBytes := tmtypes.VoteSignBytes(chainID, vote)
sig, err := pv.PrivKey.Sign(signBytes)
if err != nil {
return err
}
vote.Signature = sig
return nil
}
// SignProposal implements PrivValidator interface
func (pv PV) SignProposal(chainID string, proposal *tmproto.Proposal) error {
signBytes := tmtypes.ProposalSignBytes(chainID, proposal)
sig, err := pv.PrivKey.Sign(signBytes)
if err != nil {
return err
}
proposal.Signature = sig
return nil
}

View File

@ -92,7 +92,7 @@ func TestSendNotEnoughBalance(t *testing.T) {
}
genAccs := []authtypes.GenesisAccount{acc}
app := simapp.SetupWithGenesisAccounts(genAccs)
app := simapp.SetupWithGenesisAccounts(t, genAccs)
ctx := app.BaseApp.NewContext(false, tmproto.Header{})
require.NoError(t, testutil.FundAccount(app.BankKeeper, ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 67))))
@ -127,7 +127,7 @@ func TestMsgMultiSendWithAccounts(t *testing.T) {
}
genAccs := []authtypes.GenesisAccount{acc}
app := simapp.SetupWithGenesisAccounts(genAccs)
app := simapp.SetupWithGenesisAccounts(t, genAccs)
ctx := app.BaseApp.NewContext(false, tmproto.Header{})
require.NoError(t, testutil.FundAccount(app.BankKeeper, ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 67))))
@ -197,7 +197,7 @@ func TestMsgMultiSendMultipleOut(t *testing.T) {
}
genAccs := []authtypes.GenesisAccount{acc1, acc2}
app := simapp.SetupWithGenesisAccounts(genAccs)
app := simapp.SetupWithGenesisAccounts(t, genAccs)
ctx := app.BaseApp.NewContext(false, tmproto.Header{})
require.NoError(t, testutil.FundAccount(app.BankKeeper, ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))))
@ -246,7 +246,7 @@ func TestMsgMultiSendMultipleInOut(t *testing.T) {
}
genAccs := []authtypes.GenesisAccount{acc1, acc2, acc4}
app := simapp.SetupWithGenesisAccounts(genAccs)
app := simapp.SetupWithGenesisAccounts(t, genAccs)
ctx := app.BaseApp.NewContext(false, tmproto.Header{})
require.NoError(t, testutil.FundAccount(app.BankKeeper, ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))))
@ -293,7 +293,7 @@ func TestMsgMultiSendDependent(t *testing.T) {
require.NoError(t, err)
genAccs := []authtypes.GenesisAccount{acc1, acc2}
app := simapp.SetupWithGenesisAccounts(genAccs)
app := simapp.SetupWithGenesisAccounts(t, genAccs)
ctx := app.BaseApp.NewContext(false, tmproto.Header{})
require.NoError(t, testutil.FundAccount(app.BankKeeper, ctx, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))))

View File

@ -29,7 +29,7 @@ func BenchmarkOneBankSendTxPerBlock(b *testing.B) {
// construct genesis state
genAccs := []types.GenesisAccount{&acc}
benchmarkApp := simapp.SetupWithGenesisAccounts(genAccs)
benchmarkApp := simapp.SetupWithGenesisAccounts(&testing.T{}, genAccs)
ctx := benchmarkApp.BaseApp.NewContext(false, tmproto.Header{})
// some value conceivably higher than the benchmarks would ever go
@ -73,7 +73,7 @@ func BenchmarkOneBankMultiSendTxPerBlock(b *testing.B) {
// Construct genesis state
genAccs := []authtypes.GenesisAccount{&acc}
benchmarkApp := simapp.SetupWithGenesisAccounts(genAccs)
benchmarkApp := simapp.SetupWithGenesisAccounts(&testing.T{}, genAccs)
ctx := benchmarkApp.BaseApp.NewContext(false, tmproto.Header{})
// some value conceivably higher than the benchmarks would ever go

View File

@ -57,7 +57,7 @@ func TestSlashingMsgs(t *testing.T) {
},
}
app := simapp.SetupWithGenesisAccounts(accs, balances...)
app := simapp.SetupWithGenesisAccounts(t, accs, balances...)
simapp.CheckBalance(t, app, addr1, sdk.Coins{genCoin})
description := stakingtypes.NewDescription("foo_moniker", "", "", "", "")

View File

@ -59,7 +59,7 @@ func TestStakingMsgs(t *testing.T) {
},
}
app := simapp.SetupWithGenesisAccounts(accs, balances...)
app := simapp.SetupWithGenesisAccounts(t, accs, balances...)
simapp.CheckBalance(t, app, addr1, sdk.Coins{genCoin})
simapp.CheckBalance(t, app, addr2, sdk.Coins{genCoin})

View File

@ -1,7 +1,6 @@
package upgrade_test
import (
"encoding/json"
"errors"
"fmt"
"os"
@ -34,20 +33,18 @@ type TestSuite struct {
var s TestSuite
func setupTest(height int64, skip map[int64]bool) TestSuite {
func setupTest(t *testing.T, height int64, skip map[int64]bool) TestSuite {
db := dbm.NewMemDB()
app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, skip, simapp.DefaultNodeHome, 0, simapp.MakeTestEncodingConfig(), simapp.EmptyAppOptions{})
genesisState := simapp.NewDefaultGenesisState(app.AppCodec())
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
if err != nil {
panic(err)
}
app.InitChain(
abci.RequestInitChain{
Validators: []abci.ValidatorUpdate{},
AppStateBytes: stateBytes,
},
)
app := simapp.NewSimappWithCustomOptions(t, false, simapp.SetupOptions{
Logger: log.NewNopLogger(),
SkipUpgradeHeights: skip,
DB: db,
InvCheckPeriod: 0,
HomePath: simapp.DefaultNodeHome,
EncConfig: simapp.MakeTestEncodingConfig(),
AppOpts: simapp.EmptyAppOptions{},
})
s.keeper = app.UpgradeKeeper
s.ctx = app.BaseApp.NewContext(false, tmproto.Header{Height: height, Time: time.Now()})
@ -59,7 +56,7 @@ func setupTest(height int64, skip map[int64]bool) TestSuite {
}
func TestRequireName(t *testing.T) {
s := setupTest(10, map[int64]bool{})
s := setupTest(t, 10, map[int64]bool{})
err := s.handler(s.ctx, &types.SoftwareUpgradeProposal{Title: "prop", Plan: types.Plan{}})
require.NotNil(t, err)
@ -67,14 +64,14 @@ func TestRequireName(t *testing.T) {
}
func TestRequireFutureBlock(t *testing.T) {
s := setupTest(10, map[int64]bool{})
s := setupTest(t, 10, map[int64]bool{})
err := s.handler(s.ctx, &types.SoftwareUpgradeProposal{Title: "prop", Plan: types.Plan{Name: "test", Height: s.ctx.BlockHeight()}})
require.NotNil(t, err)
require.True(t, errors.Is(sdkerrors.ErrInvalidRequest, err), err)
}
func TestDoHeightUpgrade(t *testing.T) {
s := setupTest(10, map[int64]bool{})
s := setupTest(t, 10, map[int64]bool{})
t.Log("Verify can schedule an upgrade")
err := s.handler(s.ctx, &types.SoftwareUpgradeProposal{Title: "prop", Plan: types.Plan{Name: "test", Height: s.ctx.BlockHeight() + 1}})
require.Nil(t, err)
@ -83,7 +80,7 @@ func TestDoHeightUpgrade(t *testing.T) {
}
func TestCanOverwriteScheduleUpgrade(t *testing.T) {
s := setupTest(10, map[int64]bool{})
s := setupTest(t, 10, map[int64]bool{})
t.Log("Can overwrite plan")
err := s.handler(s.ctx, &types.SoftwareUpgradeProposal{Title: "prop", Plan: types.Plan{Name: "bad_test", Height: s.ctx.BlockHeight() + 10}})
require.Nil(t, err)
@ -132,7 +129,7 @@ func VerifyDoUpgradeWithCtx(t *testing.T, newCtx sdk.Context, proposalName strin
}
func TestHaltIfTooNew(t *testing.T) {
s := setupTest(10, map[int64]bool{})
s := setupTest(t, 10, map[int64]bool{})
t.Log("Verify that we don't panic with registered plan not in database at all")
var called int
s.keeper.SetUpgradeHandler("future", func(ctx sdk.Context, plan types.Plan, vm module.VersionMap) (module.VersionMap, error) {
@ -175,7 +172,7 @@ func VerifyCleared(t *testing.T, newCtx sdk.Context) {
}
func TestCanClear(t *testing.T) {
s := setupTest(10, map[int64]bool{})
s := setupTest(t, 10, map[int64]bool{})
t.Log("Verify upgrade is scheduled")
err := s.handler(s.ctx, &types.SoftwareUpgradeProposal{Title: "prop", Plan: types.Plan{Name: "test", Height: s.ctx.BlockHeight() + 100}})
require.Nil(t, err)
@ -187,7 +184,7 @@ func TestCanClear(t *testing.T) {
}
func TestCantApplySameUpgradeTwice(t *testing.T) {
s := setupTest(10, map[int64]bool{})
s := setupTest(t, 10, map[int64]bool{})
height := s.ctx.BlockHeader().Height + 1
err := s.handler(s.ctx, &types.SoftwareUpgradeProposal{Title: "prop", Plan: types.Plan{Name: "test", Height: height}})
require.Nil(t, err)
@ -199,7 +196,7 @@ func TestCantApplySameUpgradeTwice(t *testing.T) {
}
func TestNoSpuriousUpgrades(t *testing.T) {
s := setupTest(10, map[int64]bool{})
s := setupTest(t, 10, map[int64]bool{})
t.Log("Verify that no upgrade panic is triggered in the BeginBlocker when we haven't scheduled an upgrade")
req := abci.RequestBeginBlock{Header: s.ctx.BlockHeader()}
require.NotPanics(t, func() {
@ -243,7 +240,7 @@ func TestContains(t *testing.T) {
var (
skipOne int64 = 11
)
s := setupTest(10, map[int64]bool{skipOne: true})
s := setupTest(t, 10, map[int64]bool{skipOne: true})
VerifySet(t, map[int64]bool{skipOne: true})
t.Log("case where array contains the element")
@ -258,7 +255,7 @@ func TestSkipUpgradeSkippingAll(t *testing.T) {
skipOne int64 = 11
skipTwo int64 = 20
)
s := setupTest(10, map[int64]bool{skipOne: true, skipTwo: true})
s := setupTest(t, 10, map[int64]bool{skipOne: true, skipTwo: true})
newCtx := s.ctx
@ -295,7 +292,7 @@ func TestUpgradeSkippingOne(t *testing.T) {
skipOne int64 = 11
skipTwo int64 = 20
)
s := setupTest(10, map[int64]bool{skipOne: true})
s := setupTest(t, 10, map[int64]bool{skipOne: true})
newCtx := s.ctx
@ -330,7 +327,7 @@ func TestUpgradeSkippingOnlyTwo(t *testing.T) {
skipTwo int64 = 20
skipThree int64 = 25
)
s := setupTest(10, map[int64]bool{skipOne: true, skipTwo: true})
s := setupTest(t, 10, map[int64]bool{skipOne: true, skipTwo: true})
newCtx := s.ctx
@ -369,7 +366,7 @@ func TestUpgradeSkippingOnlyTwo(t *testing.T) {
}
func TestUpgradeWithoutSkip(t *testing.T) {
s := setupTest(10, map[int64]bool{})
s := setupTest(t, 10, map[int64]bool{})
newCtx := s.ctx.WithBlockHeight(s.ctx.BlockHeight() + 1).WithBlockTime(time.Now())
req := abci.RequestBeginBlock{Header: newCtx.BlockHeader()}
err := s.handler(s.ctx, &types.SoftwareUpgradeProposal{Title: "prop", Plan: types.Plan{Name: "test", Height: s.ctx.BlockHeight() + 1}})
@ -384,7 +381,7 @@ func TestUpgradeWithoutSkip(t *testing.T) {
}
func TestDumpUpgradeInfoToFile(t *testing.T) {
s := setupTest(10, map[int64]bool{})
s := setupTest(t, 10, map[int64]bool{})
require := require.New(t)
// require no error when the upgrade info file does not exist