Documentation ¶
Overview ¶
Integration contains the integration test setup used for SDK modules.
Example ¶
Example shows how to use the integration test framework to test the integration of SDK modules. Panics are used in this example, but in a real test case, you should use the testing.T object and assertions.
package main import ( "fmt" cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" "github.com/google/go-cmp/cmp" "cosmossdk.io/core/appmodule" "cosmossdk.io/log" storetypes "cosmossdk.io/store/types" addresscodec "github.com/cosmos/cosmos-sdk/codec/address" "github.com/cosmos/cosmos-sdk/runtime" "github.com/cosmos/cosmos-sdk/testutil/integration" sdk "github.com/cosmos/cosmos-sdk/types" moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" "github.com/cosmos/cosmos-sdk/x/auth" authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/mint" mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" ) func main() { // in this example we are testing the integration of the following modules: // - mint, which directly depends on auth, bank and staking encodingCfg := moduletestutil.MakeTestEncodingConfig(auth.AppModuleBasic{}, mint.AppModuleBasic{}) keys := storetypes.NewKVStoreKeys(authtypes.StoreKey, minttypes.StoreKey) authority := authtypes.NewModuleAddress("gov").String() // replace the logger by testing values in a real test case (e.g. log.NewTestLogger(t)) logger := log.NewNopLogger() cms := integration.CreateMultiStore(keys, logger) newCtx := sdk.NewContext(cms, cmtproto.Header{}, true, logger) accountKeeper := authkeeper.NewAccountKeeper( encodingCfg.Codec, runtime.NewKVStoreService(keys[authtypes.StoreKey]), authtypes.ProtoBaseAccount, map[string][]string{minttypes.ModuleName: {authtypes.Minter}}, addresscodec.NewBech32Codec("cosmos"), "cosmos", authority, ) // subspace is nil because we don't test params (which is legacy anyway) authModule := auth.NewAppModule(encodingCfg.Codec, accountKeeper, authsims.RandomGenesisAccounts, nil) // here bankkeeper and staking keeper is nil because we are not testing them // subspace is nil because we don't test params (which is legacy anyway) mintKeeper := mintkeeper.NewKeeper(encodingCfg.Codec, runtime.NewKVStoreService(keys[minttypes.StoreKey]), nil, accountKeeper, nil, authtypes.FeeCollectorName, authority) mintModule := mint.NewAppModule(encodingCfg.Codec, mintKeeper, accountKeeper, nil, nil) // create the application and register all the modules from the previous step integrationApp := integration.NewIntegrationApp( newCtx, logger, keys, encodingCfg.Codec, map[string]appmodule.AppModule{ authtypes.ModuleName: authModule, minttypes.ModuleName: mintModule, }, ) // register the message and query servers authtypes.RegisterMsgServer(integrationApp.MsgServiceRouter(), authkeeper.NewMsgServerImpl(accountKeeper)) minttypes.RegisterMsgServer(integrationApp.MsgServiceRouter(), mintkeeper.NewMsgServerImpl(mintKeeper)) minttypes.RegisterQueryServer(integrationApp.QueryHelper(), mintkeeper.NewQueryServerImpl(mintKeeper)) params := minttypes.DefaultParams() params.BlocksPerYear = 10000 // now we can use the application to test a mint message result, err := integrationApp.RunMsg(&minttypes.MsgUpdateParams{ Authority: authority, Params: params, }) if err != nil { panic(err) } // in this example the result is an empty response, a nil check is enough // in other cases, it is recommended to check the result value. if result == nil { panic(fmt.Errorf("unexpected nil result")) } // we now check the result resp := minttypes.MsgUpdateParamsResponse{} err = encodingCfg.Codec.Unmarshal(result.Value, &resp) if err != nil { panic(err) } sdkCtx := sdk.UnwrapSDKContext(integrationApp.Context()) // we should also check the state of the application got, err := mintKeeper.Params.Get(sdkCtx) if err != nil { panic(err) } if diff := cmp.Diff(got, params); diff != "" { panic(diff) } fmt.Println(got.BlocksPerYear) }
Output: 10000
Example (OneModule) ¶
ExampleOneModule shows how to use the integration test framework to test the integration of a single module. That module has no dependency on other modules.
package main import ( "fmt" "io" cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" "github.com/google/go-cmp/cmp" "cosmossdk.io/core/appmodule" "cosmossdk.io/log" storetypes "cosmossdk.io/store/types" addresscodec "github.com/cosmos/cosmos-sdk/codec/address" "github.com/cosmos/cosmos-sdk/runtime" "github.com/cosmos/cosmos-sdk/testutil/integration" sdk "github.com/cosmos/cosmos-sdk/types" moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" "github.com/cosmos/cosmos-sdk/x/auth" authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" ) func main() { // in this example we are testing the integration of the auth module: encodingCfg := moduletestutil.MakeTestEncodingConfig(auth.AppModuleBasic{}) keys := storetypes.NewKVStoreKeys(authtypes.StoreKey) authority := authtypes.NewModuleAddress("gov").String() // replace the logger by testing values in a real test case (e.g. log.NewTestLogger(t)) logger := log.NewLogger(io.Discard) cms := integration.CreateMultiStore(keys, logger) newCtx := sdk.NewContext(cms, cmtproto.Header{}, true, logger) accountKeeper := authkeeper.NewAccountKeeper( encodingCfg.Codec, runtime.NewKVStoreService(keys[authtypes.StoreKey]), authtypes.ProtoBaseAccount, map[string][]string{minttypes.ModuleName: {authtypes.Minter}}, addresscodec.NewBech32Codec("cosmos"), "cosmos", authority, ) // subspace is nil because we don't test params (which is legacy anyway) authModule := auth.NewAppModule(encodingCfg.Codec, accountKeeper, authsims.RandomGenesisAccounts, nil) // create the application and register all the modules from the previous step integrationApp := integration.NewIntegrationApp( newCtx, logger, keys, encodingCfg.Codec, map[string]appmodule.AppModule{ authtypes.ModuleName: authModule, }, ) // register the message and query servers authtypes.RegisterMsgServer(integrationApp.MsgServiceRouter(), authkeeper.NewMsgServerImpl(accountKeeper)) params := authtypes.DefaultParams() params.MaxMemoCharacters = 1000 // now we can use the application to test a mint message result, err := integrationApp.RunMsg(&authtypes.MsgUpdateParams{ Authority: authority, Params: params, }, // this allows to the begin and end blocker of the module before and after the message integration.WithAutomaticFinalizeBlock(), // this allows to commit the state after the message integration.WithAutomaticCommit(), ) if err != nil { panic(err) } // verify that the begin and end blocker were called // NOTE: in this example, we are testing auth, which doesn't have any begin or end blocker // so verifying the block height is enough if integrationApp.LastBlockHeight() != 2 { panic(fmt.Errorf("expected block height to be 2, got %d", integrationApp.LastBlockHeight())) } // in this example the result is an empty response, a nil check is enough // in other cases, it is recommended to check the result value. if result == nil { panic(fmt.Errorf("unexpected nil result")) } // we now check the result resp := authtypes.MsgUpdateParamsResponse{} err = encodingCfg.Codec.Unmarshal(result.Value, &resp) if err != nil { panic(err) } sdkCtx := sdk.UnwrapSDKContext(integrationApp.Context()) // we should also check the state of the application got := accountKeeper.GetParams(sdkCtx) if diff := cmp.Diff(got, params); diff != "" { panic(diff) } fmt.Println(got.MaxMemoCharacters) }
Output: 1000
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CreateMultiStore ¶
func CreateMultiStore(keys map[string]*storetypes.KVStoreKey, logger log.Logger) storetypes.CommitMultiStore
CreateMultiStore is a helper for setting up multiple stores for provided modules.
Types ¶
type App ¶
App is a test application that can be used to test the integration of modules.
func NewIntegrationApp ¶
func NewIntegrationApp( sdkCtx sdk.Context, logger log.Logger, keys map[string]*storetypes.KVStoreKey, appCodec codec.Codec, modules map[string]appmodule.AppModule, baseAppOptions ...func(*baseapp.BaseApp), ) *App
NewIntegrationApp creates an application for testing purposes. This application is able to route messages to their respective handlers.
func (*App) Context ¶
Context returns the application context. It can be unwrapped to a sdk.Context, with the sdk.UnwrapSDKContext function.
func (*App) QueryHelper ¶
func (app *App) QueryHelper() *baseapp.QueryServiceTestHelper
QueryHelper returns the application query helper. It can be used when registering query services.
func (*App) RunMsg ¶
RunMsg provides the ability to run a message and return the response. In order to run a message, the application must have a handler for it. These handlers are registered on the application message service router. The result of the message execution is returned as an Any type. That any type can be unmarshaled to the expected response type. If the message execution fails, an error is returned.
type Option ¶
type Option func(*Config)
Option is a function that can be used to configure the integration app.
func WithAutomaticCommit ¶
func WithAutomaticCommit() Option
WithAutomaticCommit enables automatic commit. This means that the integration app will automatically commit the state after each msgs.
func WithAutomaticFinalizeBlock ¶
func WithAutomaticFinalizeBlock() Option
WithAutomaticFinalizeBlock calls ABCI finalize block.