Skip to content

Commit

Permalink
Importable e2e tests (#401)
Browse files Browse the repository at this point in the history
  • Loading branch information
shaspitz authored Oct 20, 2022
1 parent 9dda4b6 commit 00ea78b
Show file tree
Hide file tree
Showing 17 changed files with 601 additions and 232 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ Unit tests are useful for simple standalone functionality, and CRUD operations.

### End to End (e2e) Tests

[e2e-tests](./tests/e2e/) utilize the [IBC Testing Package](https://github.com/cosmos/ibc-go/tree/main/testing), and test functionality that is wider in scope than a unit test, but still able to be validated in-memory. Ie. code where advancing blocks would be useful, simulated handshakes, simulated packet relays, etc.
[e2e-tests](./tests/e2e/) utilize the [IBC Testing Package](https://github.com/cosmos/ibc-go/tree/main/testing), and test functionality that is wider in scope than a unit test, but still able to be validated in-memory. Ie. code where advancing blocks would be useful, simulated handshakes, simulated packet relays, etc.

To run e2e tests against your own consumer/provider implementations, use [instance_test.go](./tests/e2e/instance_test.go) as an example. All you'll need to do is make sure your applications implement the necessary interfaces defined in [interfaces.go](./testutil/e2e/interfaces.go), then pass in an appropriate callback to the testing suites.

### Differential Tests (WIP)

Expand Down
48 changes: 48 additions & 0 deletions app/consumer-democracy/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ import (
ccvdistrclient "github.com/cosmos/cosmos-sdk/x/distribution/client"
ccvdistrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper"
ccvdistrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
"github.com/cosmos/interchain-security/testutil/e2e"
ccvdistr "github.com/cosmos/interchain-security/x/ccv/democracy/distribution"

ccvstakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
Expand Down Expand Up @@ -757,6 +758,53 @@ func (app *App) SimulationManager() *module.SimulationManager {
return app.sm
}

// DemocConsumerApp interface implementations for e2e tests

// GetConsumerKeeper implements the ConsumerApp interface.
func (app *App) GetConsumerKeeper() ibcconsumerkeeper.Keeper {
return app.ConsumerKeeper
}

// GetE2eBankKeeper implements the ConsumerApp interface.
func (app *App) GetE2eBankKeeper() e2e.E2eBankKeeper {
return app.BankKeeper
}

// GetE2eAccountKeeper implements the ConsumerApp interface.
func (app *App) GetE2eAccountKeeper() e2e.E2eAccountKeeper {
return app.AccountKeeper
}

// GetE2eSlashingKeeper implements the ConsumerApp interface.
func (app *App) GetE2eSlashingKeeper() e2e.E2eSlashingKeeper {
return app.SlashingKeeper
}

// GetE2eEvidenceKeeper implements the ConsumerApp interface.
func (app *App) GetE2eEvidenceKeeper() e2e.E2eEvidenceKeeper {
return app.EvidenceKeeper
}

// GetE2eStakingKeeper implements the ConsumerApp interface.
func (app *App) GetE2eStakingKeeper() e2e.E2eStakingKeeper {
return app.StakingKeeper
}

// GetE2eDistributionKeeper implements the ConsumerApp interface.
func (app *App) GetE2eDistributionKeeper() e2e.E2eDistributionKeeper {
return app.DistrKeeper
}

// GetE2eMintKeeper implements the ConsumerApp interface.
func (app *App) GetE2eMintKeeper() e2e.E2eMintKeeper {
return app.MintKeeper
}

// GetE2eGovKeeper implements the ConsumerApp interface.
func (app *App) GetE2eGovKeeper() e2e.E2eGovKeeper {
return app.GovKeeper
}

// TestingApp functions

// GetBaseApp implements the TestingApp interface.
Expand Down
28 changes: 28 additions & 0 deletions app/consumer/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ import (
tmos "github.com/tendermint/tendermint/libs/os"
dbm "github.com/tendermint/tm-db"

"github.com/cosmos/interchain-security/testutil/e2e"
ibcconsumer "github.com/cosmos/interchain-security/x/ccv/consumer"
ibcconsumerkeeper "github.com/cosmos/interchain-security/x/ccv/consumer/keeper"
ibcconsumertypes "github.com/cosmos/interchain-security/x/ccv/consumer/types"
Expand Down Expand Up @@ -651,6 +652,33 @@ func (app *App) SimulationManager() *module.SimulationManager {
return app.sm
}

// ConsumerApp interface implementations for e2e tests

// GetConsumerKeeper implements the ConsumerApp interface.
func (app *App) GetConsumerKeeper() ibcconsumerkeeper.Keeper {
return app.ConsumerKeeper
}

// GetE2eBankKeeper implements the ConsumerApp interface.
func (app *App) GetE2eBankKeeper() e2e.E2eBankKeeper {
return app.BankKeeper
}

// GetE2eAccountKeeper implements the ConsumerApp interface.
func (app *App) GetE2eAccountKeeper() e2e.E2eAccountKeeper {
return app.AccountKeeper
}

// GetE2eSlashingKeeper implements the ConsumerApp interface.
func (app *App) GetE2eSlashingKeeper() e2e.E2eSlashingKeeper {
return app.SlashingKeeper
}

// GetE2eEvidenceKeeper implements the ConsumerApp interface.
func (app *App) GetE2eEvidenceKeeper() e2e.E2eEvidenceKeeper {
return app.EvidenceKeeper
}

// TestingApp functions

// GetBaseApp implements the TestingApp interface.
Expand Down
29 changes: 29 additions & 0 deletions app/provider/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ import (
ibcproviderkeeper "github.com/cosmos/interchain-security/x/ccv/provider/keeper"
providertypes "github.com/cosmos/interchain-security/x/ccv/provider/types"

e2e "github.com/cosmos/interchain-security/testutil/e2e"

"github.com/tendermint/spm/cosmoscmd"

// unnamed import of statik for swagger UI support
Expand Down Expand Up @@ -796,6 +798,33 @@ func (app *App) SimulationManager() *module.SimulationManager {
return app.sm
}

// ProviderApp interface implementations for e2e tests

// GetProviderKeeper implements the ProviderApp interface.
func (app *App) GetProviderKeeper() ibcproviderkeeper.Keeper {
return app.ProviderKeeper
}

// GetE2eStakingKeeper implements the ProviderApp interface.
func (app *App) GetE2eStakingKeeper() e2e.E2eStakingKeeper {
return app.StakingKeeper
}

// GetE2eBankKeeper implements the ProviderApp interface.
func (app *App) GetE2eBankKeeper() e2e.E2eBankKeeper {
return app.BankKeeper
}

// GetE2eSlashingKeeper implements the ProviderApp interface.
func (app *App) GetE2eSlashingKeeper() e2e.E2eSlashingKeeper {
return app.SlashingKeeper
}

// GetE2eDistributionKeeper implements the ProviderApp interface.
func (app *App) GetE2eDistributionKeeper() e2e.E2eDistributionKeeper {
return app.DistrKeeper
}

// TestingApp functions

// GetBaseApp implements the TestingApp interface.
Expand Down
24 changes: 14 additions & 10 deletions tests/e2e/README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
## End To End Testing

# End To End Testing

E2e tests are categorized into files as follows:

- `setup_test.go` - setup for the e2e tests
- `common_test.go` - helper functions
- `channel_init_test.go` - e2e tests for the _Channel Initialization_ sub-protocol
- `valset_update_test.go` - e2e tests for the _Validator Set Update_ sub-protocol
- `unbonding_test.go` - e2e tests for the _Completion of Unbonding Operations_
- `slashing_test.go` - e2e tests for the _Consumer Initiated Slashing_ sub-protocol
- `distribution_test.go` - e2e tests for the _Reward Distribution_ sub-protocol
- `stop_consumer_test.go` - e2e tests for the _Consumer Chain Removal_ sub-protocol
- `normal_operations_test.go` - e2e tests for _normal operations_ of ICS enabled chains
- `setup.go` - setup for the e2e tests
- `common.go` - helper functions
- `channel_init.go` - e2e tests for the _Channel Initialization_ sub-protocol
- `valset_update.go` - e2e tests for the _Validator Set Update_ sub-protocol
- `unbonding.go` - e2e tests for the _Completion of Unbonding Operations_
- `slashing.go` - e2e tests for the _Consumer Initiated Slashing_ sub-protocol
- `distribution.go` - e2e tests for the _Reward Distribution_ sub-protocol
- `stop_consumer.go` - e2e tests for the _Consumer Chain Removal_ sub-protocol
- `normal_operations.go` - e2e tests for _normal operations_ of ICS enabled chains
- `instance_test.go` - ties the e2e test structure into golang's standard test mechanism, with appropriate definitions for concrete app types and setup callback

To run the e2e tests defined in this repo on any arbitrary consumer and provider implementation, copy the pattern exemplified in `instance_test.go`
33 changes: 17 additions & 16 deletions tests/e2e/channel_init_test.go → tests/e2e/channel_init.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
package e2e_test
package e2e

import (
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"

app "github.com/cosmos/interchain-security/app/consumer"

tmtypes "github.com/tendermint/tendermint/types"

channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types"

appConsumer "github.com/cosmos/interchain-security/app/consumer"
ccv "github.com/cosmos/interchain-security/x/ccv/types"

abci "github.com/tendermint/tendermint/abci/types"
Expand All @@ -19,24 +16,28 @@ import (
)

func (suite *CCVTestSuite) TestConsumerGenesis() {
genesis := suite.consumerChain.App.(*app.App).ConsumerKeeper.ExportGenesis(suite.consumerChain.GetContext())

consumerKeeper := suite.consumerApp.GetConsumerKeeper()

genesis := consumerKeeper.ExportGenesis(suite.consumerChain.GetContext())

suite.Require().Equal(suite.providerClient, genesis.ProviderClientState)
suite.Require().Equal(suite.providerConsState, genesis.ProviderConsensusState)

suite.Require().NotPanics(func() {
suite.consumerChain.App.(*app.App).ConsumerKeeper.InitGenesis(suite.consumerChain.GetContext(), genesis)
consumerKeeper.InitGenesis(suite.consumerChain.GetContext(), genesis)
// reset suite to reset provider client
suite.SetupTest()
consumerKeeper = suite.consumerApp.GetConsumerKeeper()
})

ctx := suite.consumerChain.GetContext()
portId := suite.consumerChain.App.(*app.App).ConsumerKeeper.GetPort(ctx)
portId := consumerKeeper.GetPort(ctx)
suite.Require().Equal(ccv.ConsumerPortID, portId)

clientId, ok := suite.consumerChain.App.(*app.App).ConsumerKeeper.GetProviderClientID(ctx)
clientId, ok := consumerKeeper.GetProviderClientID(ctx)
suite.Require().True(ok)
clientState, ok := suite.consumerChain.App.GetIBCKeeper().ClientKeeper.GetClientState(ctx, clientId)
clientState, ok := suite.consumerApp.GetIBCKeeper().ClientKeeper.GetClientState(ctx, clientId)
suite.Require().True(ok)
suite.Require().Equal(genesis.ProviderClientState, clientState, "client state not set correctly after InitGenesis")

Expand Down Expand Up @@ -66,30 +67,30 @@ func (suite *CCVTestSuite) TestConsumerGenesis() {
ccv.ProviderPortID, suite.path.EndpointB.ChannelID,
ccv.ConsumerPortID, suite.path.EndpointA.ChannelID,
clienttypes.NewHeight(1, 0), 0)
suite.consumerChain.App.(*app.App).ConsumerKeeper.OnRecvVSCPacket(suite.consumerChain.GetContext(), packet, pd)
consumerKeeper.OnRecvVSCPacket(suite.consumerChain.GetContext(), packet, pd)
valUpdates := tmtypes.TM2PB.ValidatorUpdates(suite.providerChain.Vals)

restartGenesis := suite.consumerChain.App.(*app.App).ConsumerKeeper.ExportGenesis(suite.consumerChain.GetContext())
restartGenesis := consumerKeeper.ExportGenesis(suite.consumerChain.GetContext())
suite.Require().Equal(valUpdates, restartGenesis.InitialValSet)

// ensure reset genesis is set correctly
providerChannel := suite.path.EndpointA.ChannelID
suite.Require().Equal(providerChannel, restartGenesis.ProviderChannelId)
maturityTime := suite.consumerChain.App.(*app.App).ConsumerKeeper.GetPacketMaturityTime(suite.consumerChain.GetContext(), 1)
unbondingPeriod, found := suite.consumerChain.App.(*appConsumer.App).ConsumerKeeper.GetUnbondingTime(suite.consumerCtx())
maturityTime := consumerKeeper.GetPacketMaturityTime(suite.consumerChain.GetContext(), 1)
unbondingPeriod, found := consumerKeeper.GetUnbondingTime(suite.consumerCtx())
suite.Require().True(found)
suite.Require().Equal(uint64(origTime.Add(unbondingPeriod).UnixNano()), maturityTime, "maturity time is not set correctly in genesis")

suite.Require().NotPanics(func() {
suite.consumerChain.App.(*app.App).ConsumerKeeper.InitGenesis(suite.consumerChain.GetContext(), restartGenesis)
consumerKeeper.InitGenesis(suite.consumerChain.GetContext(), restartGenesis)
})
}

// TestProviderClientMatches tests that the provider client managed by the consumer keeper matches the client keeper's client state
func (suite *CCVTestSuite) TestProviderClientMatches() {
providerClientID, ok := suite.consumerChain.App.(*appConsumer.App).ConsumerKeeper.GetProviderClientID(suite.consumerCtx())
providerClientID, ok := suite.consumerApp.GetConsumerKeeper().GetProviderClientID(suite.consumerCtx())
suite.Require().True(ok)

clientState, _ := suite.consumerChain.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.consumerCtx(), providerClientID)
clientState, _ := suite.consumerApp.GetIBCKeeper().ClientKeeper.GetClientState(suite.consumerCtx(), providerClientID)
suite.Require().Equal(suite.providerClient, clientState, "stored client state does not match genesis provider client")
}
Loading

0 comments on commit 00ea78b

Please sign in to comment.