cosmos-sdk/testutil/integration/example_test.go
Likhita Polavarapu fb257ae9d9
feat: add Context as arg to NewIntegrationApp (#15779)
## Description

Closes: #XXXX

This PR adds `sdk.Context` arg to `NewIntegrationApp`. This allows us to set the context updatable while verifying `begin/end block` logic in integration tests.

---

### 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/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)
2023-04-11 14:55:55 +00:00

193 lines
6.7 KiB
Go

package integration_test
import (
"fmt"
"io"
"cosmossdk.io/log"
storetypes "cosmossdk.io/store/types"
cmtproto "github.com/cometbft/cometbft/proto/tendermint/types"
"github.com/google/go-cmp/cmp"
"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"
)
// 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.
func Example() {
// 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.NewLogger(io.Discard, log.OutputJSONOption())
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}},
"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, 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,
authModule, 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)
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 := mintKeeper.GetParams(sdkCtx)
if diff := cmp.Diff(got, params); diff != "" {
panic(diff)
}
fmt.Println(got.BlocksPerYear)
// Output: 10000
}
// 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.
func Example_oneModule() {
// 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}},
"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,
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.WithAutomaticBeginEndBlock(),
// 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
}