Skip to content

Commit

Permalink
integration tests
Browse files Browse the repository at this point in the history
  • Loading branch information
stana-miric committed Feb 2, 2024
1 parent d9f528e commit 943f051
Show file tree
Hide file tree
Showing 6 changed files with 314 additions and 6 deletions.
28 changes: 28 additions & 0 deletions app/monitored/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ import (
ibcporttypes "github.com/cosmos/ibc-go/v6/modules/core/05-port/types"
ibchost "github.com/cosmos/ibc-go/v6/modules/core/24-host"
ibckeeper "github.com/cosmos/ibc-go/v6/modules/core/keeper"
ibctestingtypes "github.com/cosmos/ibc-go/v6/testing/types"
"github.com/spf13/cast"
abci "github.com/tendermint/tendermint/abci/types"
tmjson "github.com/tendermint/tendermint/libs/json"
Expand Down Expand Up @@ -907,3 +908,30 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino
func (app *App) SimulationManager() *module.SimulationManager {
return app.sm
}

// TestingApp functions

// GetBaseApp implements the TestingApp interface.
func (app *App) GetBaseApp() *baseapp.BaseApp {
return app.BaseApp
}

// GetStakingKeeper implements the TestingApp interface.
func (app *App) GetStakingKeeper() ibctestingtypes.StakingKeeper {
return app.StakingKeeper
}

// GetIBCKeeper implements the TestingApp interface.
func (app *App) GetIBCKeeper() *ibckeeper.Keeper {
return app.IBCKeeper
}

// GetScopedIBCKeeper implements the TestingApp interface.
func (app *App) GetScopedIBCKeeper() capabilitykeeper.ScopedKeeper {
return app.ScopedIBCKeeper
}

// GetTxConfig implements the TestingApp interface.
func (app *App) GetTxConfig() client.TxConfig {
return MakeEncodingConfig().TxConfig
}
28 changes: 28 additions & 0 deletions app/registry/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ import (
ibcporttypes "github.com/cosmos/ibc-go/v6/modules/core/05-port/types"
ibchost "github.com/cosmos/ibc-go/v6/modules/core/24-host"
ibckeeper "github.com/cosmos/ibc-go/v6/modules/core/keeper"
ibctestingtypes "github.com/cosmos/ibc-go/v6/testing/types"
"github.com/spf13/cast"
abci "github.com/tendermint/tendermint/abci/types"
tmjson "github.com/tendermint/tendermint/libs/json"
Expand Down Expand Up @@ -911,3 +912,30 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino
func (app *App) SimulationManager() *module.SimulationManager {
return app.sm
}

// TestingApp functions

// GetBaseApp implements the TestingApp interface.
func (app *App) GetBaseApp() *baseapp.BaseApp {
return app.BaseApp
}

// GetStakingKeeper implements the TestingApp interface.
func (app *App) GetStakingKeeper() ibctestingtypes.StakingKeeper {
return app.StakingKeeper
}

// GetIBCKeeper implements the TestingApp interface.
func (app *App) GetIBCKeeper() *ibckeeper.Keeper {
return app.IBCKeeper
}

// GetScopedIBCKeeper implements the TestingApp interface.
func (app *App) GetScopedIBCKeeper() capabilitykeeper.ScopedKeeper {
return app.ScopedIBCKeeper
}

// GetTxConfig implements the TestingApp interface.
func (app *App) GetTxConfig() client.TxConfig {
return MakeEncodingConfig().TxConfig
}
116 changes: 116 additions & 0 deletions tests/integration/healthcheck_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package integration

import (
registryTypes "healthcheck/x/healthcheck/types"
"healthcheck/x/monitored/types"
commonTypes "healthcheck/x/types"
"testing"
"time"

clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types"
channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types"
ibctesting "github.com/cosmos/ibc-go/v6/testing"
"github.com/stretchr/testify/suite"
)

func TestHealthcheckTestSuite(t *testing.T) {
// Run tests
suite.Run(t, NewHealthcheckTestSuite())
}

func (s *HealthcheckTestSuite) TestHealthcheck() {

//Send few healthcheck packets
for i := 0; i < 5; i++ {
ctx := s.monitoredChain.GetContext()
monitoredBlockTime := ctx.BlockTime()
monitoredBlockHeight := uint64(ctx.BlockHeight())
packet := commonTypes.HealthcheckUpdateData{
Block: monitoredBlockHeight,
Timestamp: uint64(monitoredBlockTime.UnixNano()),
}
packetData, err := types.ModuleCdc.MarshalJSON(&packet)
s.Require().Nil(err)

timeout := uint64(monitoredBlockTime.Add(time.Hour).UnixNano()) //packet timeout
sendHealthcheckPacket(s, s.path, timeout, packetData)

monitoredChainEntry, found := s.registryApp.HealthcheckKeeper.GetMonitoredChain(s.registryChain.GetContext(), MonitoredChainID)
s.Require().True(found)
s.Require().True(monitoredBlockHeight == monitoredChainEntry.Status.Block)
s.Require().True(uint64(monitoredBlockTime.UnixNano()) == monitoredChainEntry.Status.Timestamp)
}
}

func (s *HealthcheckTestSuite) TestHealthcheckTimeout() {

//Send one healthcheck packet
ctx := s.monitoredChain.GetContext()
monitoredBlockTime := ctx.BlockTime()
monitoredBlockHeight := uint64(ctx.BlockHeight())
packet := commonTypes.HealthcheckUpdateData{
Block: monitoredBlockHeight,
Timestamp: uint64(monitoredBlockTime.UnixNano()),
}
packetData, err := types.ModuleCdc.MarshalJSON(&packet)
s.Require().Nil(err)

timeout := uint64(monitoredBlockTime.Add(time.Hour).UnixNano()) //packet timeout
sendHealthcheckPacket(s, s.path, timeout, packetData)

monitoredChainEntry, found := s.registryApp.HealthcheckKeeper.GetMonitoredChain(s.registryChain.GetContext(), MonitoredChainID)
s.Require().True(found)
s.Require().True(monitoredBlockHeight == monitoredChainEntry.Status.Block)
s.Require().True(uint64(monitoredBlockTime.UnixNano()) == monitoredChainEntry.Status.Timestamp)
s.Require().True(monitoredChainEntry.Status.Status == string(registryTypes.Active))
channelID, found := s.registryApp.HealthcheckKeeper.GetChainToChannelMap(s.registryChain.GetContext(), MonitoredChainID)
s.Require().True(found)
channel, found := s.registryApp.GetIBCKeeper().ChannelKeeper.GetChannel(s.registryChain.GetContext(), commonTypes.HealthcheckPortID, channelID)
s.Require().True(found)
s.Require().True(channel.State == channeltypes.OPEN)
updateInterval := int(monitoredChainEntry.UpdateInterval)
timeoutInterval := int(monitoredChainEntry.TimeoutInterval)

//Move registry chain to reach update interval which will set monitored chain to inactive
for i := 0; i <= updateInterval; i++ {
s.coordinator.CommitBlock(s.registryChain)
}

monitoredChainEntry, found = s.registryApp.HealthcheckKeeper.GetMonitoredChain(s.registryChain.GetContext(), MonitoredChainID)
s.Require().True(found)
s.Require().True(monitoredChainEntry.Status.Status == string(registryTypes.Inactive))
channelID, found = s.registryApp.HealthcheckKeeper.GetChainToChannelMap(s.registryChain.GetContext(), MonitoredChainID)
s.Require().True(found)
channel, found = s.registryApp.GetIBCKeeper().ChannelKeeper.GetChannel(s.registryChain.GetContext(), commonTypes.HealthcheckPortID, channelID)
s.Require().True(found)
s.Require().True(channel.State == channeltypes.OPEN)

//Move registry chain to reach timeout interval which will close the channel and remove it from chainToChannel map
for i := 0; i <= timeoutInterval; i++ {
s.coordinator.CommitBlock(s.registryChain)
}
channel, found = s.registryApp.GetIBCKeeper().ChannelKeeper.GetChannel(s.registryChain.GetContext(), commonTypes.HealthcheckPortID, channelID)
s.Require().True(found)
s.Require().True(channel.State == channeltypes.CLOSED)
_, found = s.registryApp.HealthcheckKeeper.GetChainToChannelMap(s.registryChain.GetContext(), MonitoredChainID)
s.Require().False(found)

}

func sendHealthcheckPacket(s *HealthcheckTestSuite, path *ibctesting.Path, timeoutTimestamp uint64, data []byte) channeltypes.Packet {
sequence, err := path.EndpointA.SendPacket(clienttypes.Height{}, timeoutTimestamp, data)
s.Require().NoError(err)

packet := s.newHealthcheckPacket(data, sequence, path, clienttypes.Height{}, timeoutTimestamp)

err = path.EndpointB.RecvPacket(packet)
s.Require().NoError(err)
return packet
}

func (s *HealthcheckTestSuite) newHealthcheckPacket(data []byte, sequence uint64, path *ibctesting.Path, timeoutHeight clienttypes.Height, timeoutTimestamp uint64) channeltypes.Packet {
return channeltypes.NewPacket(data, sequence,
path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID,
path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID,
timeoutHeight, timeoutTimestamp)
}
141 changes: 141 additions & 0 deletions tests/integration/setup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package integration

import (
"encoding/json"
monitoredApp "healthcheck/app/monitored"
registryApp "healthcheck/app/registry"
registryTypes "healthcheck/x/healthcheck/types"
commonTypes "healthcheck/x/types"
"testing"

ibctesting "github.com/cosmos/ibc-go/v6/testing"
"github.com/stretchr/testify/suite"
"github.com/tendermint/tendermint/libs/log"
dbm "github.com/tendermint/tm-db"
)

const (
RegistryChainID = "registry"
MonitoredChainID = "monitored"
)

type SetupRegistryCallback func(t *testing.T, coordinator *ibctesting.Coordinator) (*ibctesting.TestChain, *registryApp.App)
type SetupMonitoredCallback func(t *testing.T, coordinator *ibctesting.Coordinator) (*ibctesting.TestChain, *monitoredApp.App)

type HealthcheckTestSuite struct {
suite.Suite

setupRegistryCallback SetupRegistryCallback
setupMonitoredCallback SetupMonitoredCallback

coordinator *ibctesting.Coordinator
registryChain *ibctesting.TestChain
monitoredChain *ibctesting.TestChain
registryApp *registryApp.App
monitoredApp *monitoredApp.App

path *ibctesting.Path
}

func NewHealthcheckTestSuite() *HealthcheckTestSuite {
healthcheckSuite := new(HealthcheckTestSuite)

healthcheckSuite.setupRegistryCallback = func(t *testing.T, coordinator *ibctesting.Coordinator) (
*ibctesting.TestChain,
*registryApp.App,
) {
t.Helper()
ibctesting.DefaultTestingAppInit = SetupRegistryApp
registry := ibctesting.NewTestChain(t, coordinator, RegistryChainID)
coordinator.Chains[RegistryChainID] = registry

return registry, registry.App.(*registryApp.App)
}

healthcheckSuite.setupMonitoredCallback = func(t *testing.T, coordinator *ibctesting.Coordinator) (
*ibctesting.TestChain,
*monitoredApp.App,
) {
t.Helper()
ibctesting.DefaultTestingAppInit = SetupMonitoredApp
monitored := ibctesting.NewTestChain(t, coordinator, MonitoredChainID)
coordinator.Chains[MonitoredChainID] = monitored

return monitored, monitored.App.(*monitoredApp.App)
}

return healthcheckSuite
}

// SetupTest sets up in-mem state before every test
func (suite *HealthcheckTestSuite) SetupTest() {
suite.coordinator = ibctesting.NewCoordinator(suite.T(), 0)
suite.registryChain, suite.registryApp = suite.setupRegistryCallback(suite.T(), suite.coordinator)
suite.monitoredChain, suite.monitoredApp = suite.setupMonitoredCallback(suite.T(), suite.coordinator)

// create clients and connection
suite.path = ibctesting.NewPath(suite.monitoredChain, suite.registryChain) // clientID, connectionID, channelID empty
suite.coordinator.SetupConnections(suite.path) // clientID, connectionID
suite.Require().Equal("07-tendermint-0", suite.path.EndpointA.ClientID)
suite.Require().Equal("connection-0", suite.path.EndpointA.ConnectionID)
suite.Require().Equal("07-tendermint-0", suite.path.EndpointB.ClientID)
suite.Require().Equal("connection-0", suite.path.EndpointB.ConnectionID)

//register monitored chain
var newMonitoredChain = registryTypes.MonitoredChain{
ChainId: MonitoredChainID,
ConnectionId: suite.path.EndpointA.ConnectionID,
}
suite.registryApp.HealthcheckKeeper.SetMonitoredChain(suite.registryChain.GetContext(), newMonitoredChain)

// - channel config
suite.path.EndpointA.ChannelConfig.PortID = commonTypes.MonitoredPortID
suite.path.EndpointB.ChannelConfig.PortID = commonTypes.HealthcheckPortID
suite.path.EndpointA.ChannelConfig.Version = commonTypes.Version
suite.path.EndpointB.ChannelConfig.Version = commonTypes.Version
suite.coordinator.CreateChannels(suite.path) // setup channel
suite.Require().Equal("channel-0", suite.path.EndpointA.ChannelID)
suite.Require().Equal("channel-0", suite.path.EndpointB.ChannelID)
}

func SetupRegistryApp() (ibctesting.TestingApp, map[string]json.RawMessage) {
db := dbm.NewMemDB()
encCdc := registryApp.MakeEncodingConfig()
app := registryApp.New(
log.NewNopLogger(),
db,
nil,
true,
map[int64]bool{},
registryApp.DefaultNodeHome,
5,
encCdc,
EmptyAppOptions{},
)
return app, registryApp.NewDefaultGenesisState(encCdc.Marshaler)
}

func SetupMonitoredApp() (ibctesting.TestingApp, map[string]json.RawMessage) {
db := dbm.NewMemDB()
encCdc := monitoredApp.MakeEncodingConfig()
app := monitoredApp.New(
log.NewNopLogger(),
db,
nil,
true,
map[int64]bool{},
monitoredApp.DefaultNodeHome,
5,
encCdc,
EmptyAppOptions{},
)
return app, monitoredApp.NewDefaultGenesisState(encCdc.Marshaler)
}

// EmptyAppOptions is a stub implementing AppOptions
type EmptyAppOptions struct{}

// Get implements AppOptions
func (ao EmptyAppOptions) Get(o string) interface{} {
return nil
}
2 changes: 1 addition & 1 deletion x/healthcheck/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.Val
channelID, ok := am.keeper.GetChainToChannelMap(ctx, chain.ChainId)
if ok {
am.keeper.CloseChannel(ctx, channelID)
am.keeper.RemoveChanFromChainToChannelMap(ctx, channelID)
am.keeper.RemoveChanFromChainToChannelMap(ctx, chain.ChainId)
}
}

Expand Down
5 changes: 0 additions & 5 deletions x/monitored/module_ibc.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,10 +207,5 @@ func (im IBCModule) OnTimeoutPacket(
modulePacket channeltypes.Packet,
relayer sdk.AccAddress,
) error {
var packetData commonTypes.HealthcheckPacketData
if err := packetData.Unmarshal(modulePacket.GetData()); err != nil {
return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal packet data: %s", err.Error())
}

return nil
}

0 comments on commit 943f051

Please sign in to comment.