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

Add testing for client events #5686

Merged
merged 24 commits into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
452167b
test: adding TestMsgConnectionOpenInitEvents
chatton Jan 22, 2024
b885208
test: adding TestMsgConnectionOpenTryEvents
chatton Jan 22, 2024
27d266e
test: adding TestMsgConnectionOpenAckEvents
chatton Jan 22, 2024
c2adf1b
test: adding TestMsgConnectionOpenConfirmEvents
chatton Jan 22, 2024
1aa723e
test: adding TestMsgCreateClientEvent
chatton Jan 22, 2024
3e038fd
test: adding TestMsgUpdateClientEvents
chatton Jan 22, 2024
8f8258e
test: adding TestMsgUpgradeClientEvents
chatton Jan 22, 2024
4db951d
test: adding event test for recover client
chatton Jan 23, 2024
c848868
test: refactor upgrade client test to use existing test
chatton Jan 23, 2024
cbd165e
test: add test for ibc software upgrade
chatton Jan 23, 2024
a1a8acb
chore: linting
chatton Jan 23, 2024
d2c70bc
Merge branch 'main' into cian/issue#2823-client-events
chatton Jan 23, 2024
e836ae2
Merge branch 'main' into cian/issue#2823-client-events
chatton Jan 23, 2024
1b20be9
Merge branch 'main' into cian/issue#2823-client-events
chatton Jan 23, 2024
785dd7a
Merge branch 'main' into cian/issue#2823-client-events
chatton Jan 23, 2024
93f406f
Merge branch 'main' into cian/issue#2823-client-events
chatton Jan 23, 2024
32aede9
Merge branch 'main' into cian/issue#2823-client-events
chatton Jan 24, 2024
fd9d9b1
Merge branch 'main' into cian/issue#2823-client-events
chatton Jan 24, 2024
6b27961
Merge branch 'main' into cian/issue#2823-client-events
chatton Jan 24, 2024
58bfa91
Merge branch 'main' into cian/issue#2823-client-events
chatton Jan 24, 2024
6e93f77
Merge branch 'main' into cian/issue#2823-client-events
damiannolan Jan 24, 2024
ab454ce
Merge branch 'main' into cian/issue#2823-client-events
chatton Jan 24, 2024
6aef5e0
chore: addressing PR feedback
chatton Jan 25, 2024
e22c6fc
Merge branch 'main' into cian/issue#2823-client-events
chatton Jan 25, 2024
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
17 changes: 16 additions & 1 deletion modules/core/02-client/keeper/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (

upgradetypes "cosmossdk.io/x/upgrade/types"

sdk "github.com/cosmos/cosmos-sdk/types"

clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"
commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types"
"github.com/cosmos/ibc-go/v8/modules/core/exported"
Expand Down Expand Up @@ -652,16 +654,29 @@ func (suite *KeeperTestSuite) TestRecoverClient() {

tc.malleate()

err = suite.chainA.App.GetIBCKeeper().ClientKeeper.RecoverClient(suite.chainA.GetContext(), subject, substitute)
ctx := suite.chainA.GetContext()
err = suite.chainA.App.GetIBCKeeper().ClientKeeper.RecoverClient(ctx, subject, substitute)

expPass := tc.expErr == nil
if expPass {
suite.Require().NoError(err)

expectedEvents := sdk.Events{
sdk.NewEvent(
clienttypes.EventTypeRecoverClient,
sdk.NewAttribute(clienttypes.AttributeKeySubjectClientID, subjectPath.EndpointA.ClientID),
sdk.NewAttribute(clienttypes.AttributeKeyClientType, subjectPath.EndpointA.GetClientState().ClientType()),
),
}.ToABCIEvents()

expectedEvents = sdk.MarkEventsToIndex(expectedEvents, map[string]struct{}{})
ibctesting.AssertEvents(&suite.Suite, expectedEvents, ctx.EventManager().Events().ToABCIEvents())

// Assert that client status is now Active
clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), subjectPath.EndpointA.ClientID)
tmClientState := subjectPath.EndpointA.GetClientState().(*ibctm.ClientState)
suite.Require().Equal(tmClientState.Status(suite.chainA.GetContext(), clientStore, suite.chainA.App.AppCodec()), exported.Active)

} else {
suite.Require().Error(err)
suite.Require().ErrorIs(err, tc.expErr)
Expand Down
88 changes: 88 additions & 0 deletions modules/core/02-client/keeper/events_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package keeper_test

import (
sdk "github.com/cosmos/cosmos-sdk/types"

clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"
commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types"
ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint"
ibctesting "github.com/cosmos/ibc-go/v8/testing"
)

func (suite *KeeperTestSuite) TestMsgCreateClientEvents() {
suite.SetupTest()
path := ibctesting.NewPath(suite.chainA, suite.chainB)

path.EndpointA.Counterparty.Chain.NextBlock()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this line might not be necessary anymore

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like the test fails without this.


tmConfig, ok := path.EndpointA.ClientConfig.(*ibctesting.TendermintConfig)
suite.Require().True(ok)

height := path.EndpointA.Counterparty.Chain.LatestCommittedHeader.GetHeight().(clienttypes.Height)
clientState := ibctm.NewClientState(
path.EndpointA.Counterparty.Chain.ChainID, tmConfig.TrustLevel, tmConfig.TrustingPeriod, tmConfig.UnbondingPeriod, tmConfig.MaxClockDrift,
height, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath)
consensusState := path.EndpointA.Counterparty.Chain.LatestCommittedHeader.ConsensusState()

msg, err := clienttypes.NewMsgCreateClient(
clientState, consensusState, path.EndpointA.Chain.SenderAccount.GetAddress().String(),
)
suite.Require().NoError(err)

res, err := suite.chainA.SendMsgs(msg)
suite.Require().NoError(err)
suite.Require().NotNil(res)

events := res.Events
expectedEvents := sdk.Events{
sdk.NewEvent(
clienttypes.EventTypeCreateClient,
sdk.NewAttribute(clienttypes.AttributeKeyClientID, ibctesting.FirstClientID),
sdk.NewAttribute(clienttypes.AttributeKeyClientType, clientState.ClientType()),
sdk.NewAttribute(clienttypes.AttributeKeyConsensusHeight, clientState.GetLatestHeight().String()),
),
}.ToABCIEvents()

var indexSet map[string]struct{}
expectedEvents = sdk.MarkEventsToIndex(expectedEvents, indexSet)
ibctesting.AssertEvents(&suite.Suite, expectedEvents, events)
}

func (suite *KeeperTestSuite) TestMsgUpdateClientEvents() {
suite.SetupTest()
path := ibctesting.NewPath(suite.chainA, suite.chainB)

suite.Require().NoError(path.EndpointA.CreateClient())

suite.chainB.Coordinator.CommitBlock(suite.chainB)

header, err := suite.chainA.ConstructUpdateTMClientHeader(suite.chainB, ibctesting.FirstClientID)
suite.Require().NoError(err)
suite.Require().NotNil(header)

msg, err := clienttypes.NewMsgUpdateClient(
ibctesting.FirstClientID, header,
path.EndpointA.Chain.SenderAccount.GetAddress().String(),
)

suite.Require().NoError(err)

res, err := suite.chainA.SendMsgs(msg)
suite.Require().NoError(err)
suite.Require().NotNil(res)

events := res.Events
expectedEvents := sdk.Events{
sdk.NewEvent(
clienttypes.EventTypeUpdateClient,
sdk.NewAttribute(clienttypes.AttributeKeyClientID, ibctesting.FirstClientID),
sdk.NewAttribute(clienttypes.AttributeKeyClientType, path.EndpointA.GetClientState().ClientType()),
sdk.NewAttribute(clienttypes.AttributeKeyConsensusHeight, path.EndpointA.GetClientState().GetLatestHeight().String()),
sdk.NewAttribute(clienttypes.AttributeKeyConsensusHeights, path.EndpointA.GetClientState().GetLatestHeight().String()),
),
}.ToABCIEvents()

var indexSet map[string]struct{}
expectedEvents = sdk.MarkEventsToIndex(expectedEvents, indexSet)
ibctesting.AssertEvents(&suite.Suite, expectedEvents, events)
}
16 changes: 15 additions & 1 deletion modules/core/02-client/keeper/keeper_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package keeper_test

import (
"fmt"
"math/rand"
"testing"
"time"
Expand Down Expand Up @@ -554,7 +555,8 @@ func (suite *KeeperTestSuite) TestIBCSoftwareUpgrade() {
suite.Require().NoError(suite.chainA.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainA.GetContext(), oldPlan.Height, bz))
}

err := suite.chainA.App.GetIBCKeeper().ClientKeeper.ScheduleIBCSoftwareUpgrade(suite.chainA.GetContext(), plan, upgradedClientState)
ctx := suite.chainA.GetContext()
err := suite.chainA.App.GetIBCKeeper().ClientKeeper.ScheduleIBCSoftwareUpgrade(ctx, plan, upgradedClientState)

if tc.expError == nil {
suite.Require().NoError(err)
Expand All @@ -575,6 +577,18 @@ func (suite *KeeperTestSuite) TestIBCSoftwareUpgrade() {
clientState, err := types.UnmarshalClientState(suite.chainA.App.AppCodec(), storedClientState)
suite.Require().NoError(err)
suite.Require().Equal(upgradedClientState, clientState)

expectedEvents := sdk.Events{
sdk.NewEvent(
types.EventTypeScheduleIBCSoftwareUpgrade,
sdk.NewAttribute(types.AttributeKeyUpgradePlanTitle, plan.Name),
sdk.NewAttribute(types.AttributeKeyUpgradePlanHeight, fmt.Sprintf("%d", plan.Height)),
),
}.ToABCIEvents()

expectedEvents = sdk.MarkEventsToIndex(expectedEvents, map[string]struct{}{})
ibctesting.AssertEvents(&suite.Suite, expectedEvents, ctx.EventManager().Events().ToABCIEvents())

} else {
// check that the new plan wasn't stored
storedPlan, err := suite.chainA.GetSimApp().UpgradeKeeper.GetUpgradePlan(suite.chainA.GetContext())
Expand Down
16 changes: 15 additions & 1 deletion modules/core/keeper/msg_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -888,14 +888,28 @@ func (suite *KeeperTestSuite) TestUpgradeClient() {

tc.setup()

_, err = keeper.Keeper.UpgradeClient(*suite.chainA.App.GetIBCKeeper(), suite.chainA.GetContext(), msg)
ctx := suite.chainA.GetContext()
_, err = keeper.Keeper.UpgradeClient(*suite.chainA.App.GetIBCKeeper(), ctx, msg)

if tc.expPass {
suite.Require().NoError(err, "upgrade handler failed on valid case: %s", tc.name)
newClient, ok := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID)
suite.Require().True(ok)
newChainSpecifiedClient := newClient.ZeroCustomFields()
suite.Require().Equal(upgradedClient, newChainSpecifiedClient)

expectedEvents := sdk.Events{
sdk.NewEvent(
clienttypes.EventTypeUpgradeClient,
sdk.NewAttribute(clienttypes.AttributeKeyClientID, ibctesting.FirstClientID),
sdk.NewAttribute(clienttypes.AttributeKeyClientType, path.EndpointA.GetClientState().ClientType()),
sdk.NewAttribute(clienttypes.AttributeKeyConsensusHeight, path.EndpointA.GetClientState().GetLatestHeight().String()),
),
}.ToABCIEvents()

expectedEvents = sdk.MarkEventsToIndex(expectedEvents, map[string]struct{}{})
ibctesting.AssertEvents(&suite.Suite, expectedEvents, ctx.EventManager().Events().ToABCIEvents())

} else {
suite.Require().Error(err, "upgrade handler passed on invalid case: %s", tc.name)
}
Expand Down
46 changes: 38 additions & 8 deletions testing/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package ibctesting

import (
"fmt"
"slices"
"strconv"

testifysuite "github.com/stretchr/testify/suite"
Expand Down Expand Up @@ -207,17 +206,12 @@ func AssertEvents(

for i, expectedEvent := range expected {
for _, actualEvent := range actual {
// the actual event will have an extra attribute added automatically
// by Cosmos SDK since v0.50, that's why we subtract 1 when comparing
// with the number of attributes in the expected event.
if expectedEvent.Type == actualEvent.Type && (len(expectedEvent.Attributes) == len(actualEvent.Attributes)-1) {
// multiple events with the same type may be emitted, only mark the expected event as found
// if all of the attributes match
if shouldProcessEvent(expectedEvent, actualEvent) {
attributeMatch := true
for _, expectedAttr := range expectedEvent.Attributes {
// any expected attributes that are not contained in the actual events will cause this event
// not to match
attributeMatch = attributeMatch && slices.Contains(actualEvent.Attributes, expectedAttr)
attributeMatch = attributeMatch && containsAttribute(actualEvent.Attributes, expectedAttr.Key, expectedAttr.Value)
}

if attributeMatch {
Expand All @@ -231,3 +225,39 @@ func AssertEvents(
suite.Require().True(foundEvents[i], "event: %s was not found in events", expectedEvent.Type)
}
}

// shouldProcessEvent returns true if the given expected event should be processed based on event type.
func shouldProcessEvent(expectedEvent abci.Event, actualEvent abci.Event) bool {
if expectedEvent.Type != actualEvent.Type {
return false
}
// the actual event will have an extra attribute added automatically
// by Cosmos SDK since v0.50, that's why we subtract 1 when comparing
// with the number of attributes in the expected event.
if containsAttributeKey(actualEvent.Attributes, "msg_index") {
return len(expectedEvent.Attributes) == len(actualEvent.Attributes)-1
}

return len(expectedEvent.Attributes) == len(actualEvent.Attributes)
}

// containsAttribute returns true if the given key/value pair is contained in the given attributes.
// NOTE: this ignores the indexed field, which can be set or unset depending on how the events are retrieved.
func containsAttribute(attrs []abci.EventAttribute, key, value string) bool {
for _, attr := range attrs {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a slices.ContainsFn() can be used on these?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice suggestion we can use

	return slices.ContainsFunc(attrs, func(attr abci.EventAttribute) bool {
		return attr.Key == key && attr.Value == value
	})

if attr.Key == key && attr.Value == value {
return true
}
}
return false
}

// containsAttributeKey returns true if the given key is contained in the given attributes.
func containsAttributeKey(attrs []abci.EventAttribute, key string) bool {
for _, attr := range attrs {
if attr.Key == key {
return true
}
}
return false
}
Loading