Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reduce Unit Testing Boilerplate #357

Merged
merged 2 commits into from
Sep 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
275 changes: 140 additions & 135 deletions testutil/keeper/unit_test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@ package keeper

import (
"testing"
time "time"

"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/store"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper"
paramstypes "github.com/cosmos/cosmos-sdk/x/params/types"
consumerkeeper "github.com/cosmos/interchain-security/x/ccv/consumer/keeper"
providerkeeper "github.com/cosmos/interchain-security/x/ccv/provider/keeper"
"github.com/cosmos/interchain-security/x/ccv/types"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/libs/log"
Expand All @@ -22,169 +23,173 @@ import (
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"

clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types"
commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types"
ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types"
providertypes "github.com/cosmos/interchain-security/x/ccv/provider/types"
)

// Constructs a provider keeper and context object for unit tests, backed by an in-memory db.
func GetProviderKeeperAndCtx(t testing.TB) (providerkeeper.Keeper, sdk.Context) {
// Parameters needed to instantiate an in-memory keeper
type InMemKeeperParams struct {
Cdc *codec.ProtoCodec
StoreKey *storetypes.KVStoreKey
ParamsSubspace *paramstypes.Subspace
Ctx sdk.Context
}

cdc, storeKey, paramsSubspace, ctx := SetupInMemKeeper(t)
// NewInMemKeeperParams instantiates in-memory keeper params with default values
func NewInMemKeeperParams(t testing.TB) InMemKeeperParams {
storeKey := sdk.NewKVStoreKey(types.StoreKey)
memStoreKey := storetypes.NewMemoryStoreKey(types.MemStoreKey)

db := tmdb.NewMemDB()
stateStore := store.NewCommitMultiStore(db)
shaspitz marked this conversation as resolved.
Show resolved Hide resolved
stateStore.MountStoreWithDB(storeKey, sdk.StoreTypeIAVL, db)
stateStore.MountStoreWithDB(memStoreKey, sdk.StoreTypeMemory, nil)
require.NoError(t, stateStore.LoadLatestVersion())

registry := codectypes.NewInterfaceRegistry()
cdc := codec.NewProtoCodec(registry)

k := providerkeeper.NewKeeper(
cdc,
paramsSubspace := paramstypes.NewSubspace(cdc,
codec.NewLegacyAmino(),
storeKey,
paramsSubspace,
&MockScopedKeeper{},
&MockChannelKeeper{},
&MockPortKeeper{},
&MockConnectionKeeper{},
&MockClientKeeper{},
&MockStakingKeeper{},
&MockSlashingKeeper{},
&MockAccountKeeper{},
"",
memStoreKey,
paramstypes.ModuleName,
)
return k, ctx
}
ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger())
shaspitz marked this conversation as resolved.
Show resolved Hide resolved

// Constructs a consumer keeper and context object for unit tests, backed by an in-memory db.
func GetConsumerKeeperAndCtx(t testing.TB) (consumerkeeper.Keeper, sdk.Context) {
return InMemKeeperParams{
Cdc: cdc,
StoreKey: storeKey,
ParamsSubspace: &paramsSubspace,
Ctx: ctx,
}
}

cdc, storeKey, paramsSubspace, ctx := SetupInMemKeeper(t)
// A struct holding pointers to any mocked external keeper needed for provider/consumer keeper setup.
type MockedKeepers struct {
*MockScopedKeeper
*MockChannelKeeper
*MockPortKeeper
*MockConnectionKeeper
*MockClientKeeper
*MockStakingKeeper
*MockSlashingKeeper
*MockAccountKeeper
*MockBankKeeper
*MockIBCTransferKeeper
*MockIBCCoreKeeper
}
shaspitz marked this conversation as resolved.
Show resolved Hide resolved

k := consumerkeeper.NewKeeper(
cdc,
storeKey,
paramsSubspace,
&MockScopedKeeper{},
&MockChannelKeeper{},
&MockPortKeeper{},
&MockConnectionKeeper{},
&MockClientKeeper{},
&MockSlashingKeeper{},
&MockBankKeeper{},
&MockAccountKeeper{},
&MockIBCTransferKeeper{},
&MockIBCCoreKeeper{},
"",
)
return k, ctx
// NewMockedKeepers instantiates a struct with pointers to properly instantiated mocked keepers.
func NewMockedKeepers(ctrl *gomock.Controller) MockedKeepers {
return MockedKeepers{
MockScopedKeeper: NewMockScopedKeeper(ctrl),
MockChannelKeeper: NewMockChannelKeeper(ctrl),
MockPortKeeper: NewMockPortKeeper(ctrl),
MockConnectionKeeper: NewMockConnectionKeeper(ctrl),
MockClientKeeper: NewMockClientKeeper(ctrl),
MockStakingKeeper: NewMockStakingKeeper(ctrl),
MockSlashingKeeper: NewMockSlashingKeeper(ctrl),
MockAccountKeeper: NewMockAccountKeeper(ctrl),
MockBankKeeper: NewMockBankKeeper(ctrl),
MockIBCTransferKeeper: NewMockIBCTransferKeeper(ctrl),
MockIBCCoreKeeper: NewMockIBCCoreKeeper(ctrl),
}
}

// Constructs a provider keeper for unit tests, backed by an in-memory db,
// with ability to pass mocked or otherwise manipulated parameters.
func GetProviderKeeperWithMocks(
cdc *codec.ProtoCodec,
storeKey *storetypes.KVStoreKey,
paramsSubspace paramstypes.Subspace,
capabilityKeeper capabilitykeeper.ScopedKeeper,
channelKeeper types.ChannelKeeper,
portKeeper types.PortKeeper,
connectionKeeper types.ConnectionKeeper,
clientKeeper types.ClientKeeper,
stakingKeeper types.StakingKeeper,
slashingKeeper types.SlashingKeeper,
accountKeeper types.AccountKeeper,
) providerkeeper.Keeper {
// NewInMemProviderKeeper instantiates an in-mem provider keeper from params and mocked keepers
func NewInMemProviderKeeper(params InMemKeeperParams, mocks MockedKeepers) providerkeeper.Keeper {

return providerkeeper.NewKeeper(
cdc,
storeKey,
paramsSubspace,
capabilityKeeper,
channelKeeper,
portKeeper,
connectionKeeper,
clientKeeper,
stakingKeeper,
slashingKeeper,
accountKeeper,
params.Cdc,
params.StoreKey,
*params.ParamsSubspace,
mocks.MockScopedKeeper,
mocks.MockChannelKeeper,
mocks.MockPortKeeper,
mocks.MockConnectionKeeper,
mocks.MockClientKeeper,
mocks.MockStakingKeeper,
mocks.MockSlashingKeeper,
mocks.MockAccountKeeper,
"",
)
}

// Constructs a consumer keeper for unit tests, backed by an in-memory db,
// with ability to pass mocked or otherwise manipulated parameters.
func GetCustomConsumerKeeperWithMocks(
cdc *codec.ProtoCodec,
storeKey *storetypes.KVStoreKey,
paramsSubspace paramstypes.Subspace,
capabilityKeeper types.ScopedKeeper,
channelKeeper types.ChannelKeeper,
portKeeper types.PortKeeper,
connectionKeeper types.ConnectionKeeper,
clientKeeper types.ClientKeeper,
slashingKeeper types.SlashingKeeper,
bankKeeper types.BankKeeper,
accountKeeper types.AccountKeeper,
ibcTransferKeeper types.IBCTransferKeeper,
ibcCoreKeeper types.IBCCoreKeeper,
) consumerkeeper.Keeper {
// NewInMemConsumerKeeper instantiates an in-mem consumer keeper from params and mocked keepers
func NewInMemConsumerKeeper(params InMemKeeperParams, mocks MockedKeepers) consumerkeeper.Keeper {

return consumerkeeper.NewKeeper(
cdc,
storeKey,
paramsSubspace,
capabilityKeeper,
channelKeeper,
portKeeper,
connectionKeeper,
clientKeeper,
slashingKeeper,
bankKeeper,
accountKeeper,
ibcTransferKeeper,
ibcCoreKeeper,
params.Cdc,
params.StoreKey,
*params.ParamsSubspace,
mocks.MockScopedKeeper,
mocks.MockChannelKeeper,
mocks.MockPortKeeper,
mocks.MockConnectionKeeper,
mocks.MockClientKeeper,
mocks.MockSlashingKeeper,
mocks.MockBankKeeper,
mocks.MockAccountKeeper,
mocks.MockIBCTransferKeeper,
mocks.MockIBCCoreKeeper,
"",
)
}

// Constructs a consumer keeper for unit tests, backed by an in-memory db,
// with ability to pass manipulated parameters, but no mocked keepers.
func GetCustomConsumerKeeper(
cdc *codec.ProtoCodec,
storeKey *storetypes.KVStoreKey,
paramsSubspace paramstypes.Subspace,
) consumerkeeper.Keeper {
// The minimum boilerplate way to obtain an in-memory provider keeper, context, and controller.
//
// Note: Calling ctrl.Finish() at the end of a test function ensures that
// no unexpected calls to external keepers are made.
func GetProviderKeeperAndCtx(t *testing.T) (providerkeeper.Keeper, sdk.Context, *gomock.Controller) {
params := NewInMemKeeperParams(t)
ctrl := gomock.NewController(t)
mocks := NewMockedKeepers(ctrl)
return NewInMemProviderKeeper(params, mocks), params.Ctx, ctrl
}

return consumerkeeper.NewKeeper(
cdc,
storeKey,
paramsSubspace,
&MockScopedKeeper{},
&MockChannelKeeper{},
&MockPortKeeper{},
&MockConnectionKeeper{},
&MockClientKeeper{},
&MockSlashingKeeper{},
&MockBankKeeper{},
&MockAccountKeeper{},
&MockIBCTransferKeeper{},
&MockIBCCoreKeeper{},
"",
)
// The minimum boilerplate way to obtain an-in memory consumer keeper, context, and controller.
//
// Note: Calling ctrl.Finish() at the end of a test function ensures that
// no unexpected calls to external keepers are made.
func GetConsumerKeeperAndCtx(t *testing.T) (consumerkeeper.Keeper, sdk.Context, *gomock.Controller) {
params := NewInMemKeeperParams(t)
ctrl := gomock.NewController(t)
mocks := NewMockedKeepers(ctrl)
return NewInMemConsumerKeeper(params, mocks), params.Ctx, ctrl
}

func SetupInMemKeeper(t testing.TB) (*codec.ProtoCodec, *storetypes.KVStoreKey, paramstypes.Subspace, sdk.Context) {
storeKey := sdk.NewKVStoreKey(types.StoreKey)
memStoreKey := storetypes.NewMemoryStoreKey(types.MemStoreKey)
// Sets a template client state for a params subspace so that the provider's
// GetTemplateClient method will be satisfied.
func SetTemplateClientState(ctx sdk.Context, subspace *paramstypes.Subspace) {
shaspitz marked this conversation as resolved.
Show resolved Hide resolved

db := tmdb.NewMemDB()
stateStore := store.NewCommitMultiStore(db)
stateStore.MountStoreWithDB(storeKey, sdk.StoreTypeIAVL, db)
stateStore.MountStoreWithDB(memStoreKey, sdk.StoreTypeMemory, nil)
require.NoError(t, stateStore.LoadLatestVersion())
keyTable := paramstypes.NewKeyTable(paramstypes.NewParamSetPair(
providertypes.KeyTemplateClient, &ibctmtypes.ClientState{},
func(value interface{}) error { return nil }))

registry := codectypes.NewInterfaceRegistry()
cdc := codec.NewProtoCodec(registry)
*subspace = subspace.WithKeyTable(keyTable)

paramsSubspace := paramstypes.NewSubspace(cdc,
codec.NewLegacyAmino(),
storeKey,
memStoreKey,
paramstypes.ModuleName,
)
ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger())
return cdc, storeKey, paramsSubspace, ctx
templateClientState :=
ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0,
time.Second*10, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(),
[]string{"upgrade", "upgradedIBCState"}, true, true)

subspace.Set(ctx, providertypes.KeyTemplateClient, templateClientState)
}

// Registers proto interfaces for params.Cdc
//
// For now, we explicitly force certain unit tests to register sdk crypto interfaces.
// TODO: This function will be executed automatically once https://github.com/cosmos/interchain-security/issues/273 is solved.
func RegisterSdkCryptoCodecInterfaces(params *InMemKeeperParams) {
ir := codectypes.NewInterfaceRegistry()
// Public key implementation registered here
cryptocodec.RegisterInterfaces(ir)
// Replace default cdc, with a custom (registered) codec
params.Cdc = codec.NewProtoCodec(ir)
}

type PrivateKey struct {
Expand Down
Loading