From 193e41480dc8a8994902d14b9f13d72a23df2734 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Tue, 19 Jul 2022 10:18:43 +0100 Subject: [PATCH] Add fee middleware test suite functions (E2E #5) (#1710) --- e2e/fee_middleware_test.go | 58 ++++++++++++++++++++++++++++++++- e2e/testsuite/testsuite.go | 66 +++++++++++++++++++++++++++++++++++++- 2 files changed, 122 insertions(+), 2 deletions(-) diff --git a/e2e/fee_middleware_test.go b/e2e/fee_middleware_test.go index 03017ab22e2..a6532a8fd1f 100644 --- a/e2e/fee_middleware_test.go +++ b/e2e/fee_middleware_test.go @@ -4,10 +4,16 @@ import ( "context" "testing" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/strangelove-ventures/ibctest/broadcast" + "github.com/strangelove-ventures/ibctest/chain/cosmos" "github.com/strangelove-ventures/ibctest/ibc" "github.com/stretchr/testify/suite" "e2e/testsuite" + + feetypes "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" ) func TestFeeMiddlewareTestSuite(t *testing.T) { @@ -18,13 +24,63 @@ type FeeMiddlewareTestSuite struct { testsuite.E2ETestSuite } +// RegisterCounterPartyPayee broadcasts a MsgRegisterCounterpartyPayee message. +func (s *FeeMiddlewareTestSuite) RegisterCounterPartyPayee(ctx context.Context, chain *cosmos.CosmosChain, + user broadcast.User, portID, channelID, relayerAddr, counterpartyPayeeAddr string) (sdk.TxResponse, error) { + msg := feetypes.NewMsgRegisterCounterpartyPayee(portID, channelID, relayerAddr, counterpartyPayeeAddr) + return s.BroadcastMessages(ctx, chain, user, msg) +} + +// QueryCounterPartyPayee queries the counterparty payee of the given chain and relayer address on the specified channel. +func (s *FeeMiddlewareTestSuite) QueryCounterPartyPayee(ctx context.Context, chain ibc.Chain, relayerAddress, channelID string) (string, error) { + queryClient := s.GetChainGRCPClients(chain).FeeQueryClient + res, err := queryClient.CounterpartyPayee(ctx, &feetypes.QueryCounterpartyPayeeRequest{ + ChannelId: channelID, + Relayer: relayerAddress, + }) + + if err != nil { + return "", err + } + return res.CounterpartyPayee, nil +} + +// PayPacketFeeAsync broadcasts a MsgPayPacketFeeAsync message. +func (s *FeeMiddlewareTestSuite) PayPacketFeeAsync( + ctx context.Context, + chain *cosmos.CosmosChain, + user broadcast.User, + packetID channeltypes.PacketId, + packetFee feetypes.PacketFee, +) (sdk.TxResponse, error) { + msg := feetypes.NewMsgPayPacketFeeAsync(packetID, packetFee) + return s.BroadcastMessages(ctx, chain, user, msg) +} + +// QueryIncentivizedPacketsForChannel queries the incentivized packets on the specified channel. +func (s *FeeMiddlewareTestSuite) QueryIncentivizedPacketsForChannel( + ctx context.Context, + chain *cosmos.CosmosChain, + portId, + channelId string, +) ([]*feetypes.IdentifiedPacketFees, error) { + queryClient := s.GetChainGRCPClients(chain).FeeQueryClient + res, err := queryClient.IncentivizedPacketsForChannel(ctx, &feetypes.QueryIncentivizedPacketsForChannelRequest{ + PortId: portId, + ChannelId: channelId, + }) + if err != nil { + return nil, err + } + return res.IncentivizedPackets, err +} + func (s *FeeMiddlewareTestSuite) TestPlaceholder() { ctx := context.Background() r := s.SetupChainsRelayerAndChannel(ctx, feeMiddlewareChannelOptions()) s.T().Run("start relayer", func(t *testing.T) { s.StartRelayer(r) }) - } // feeMiddlewareChannelOptions configures both of the chains to have fee middleware enabled. diff --git a/e2e/testsuite/testsuite.go b/e2e/testsuite/testsuite.go index b99d150e255..76307590d9e 100644 --- a/e2e/testsuite/testsuite.go +++ b/e2e/testsuite/testsuite.go @@ -7,16 +7,23 @@ import ( "strings" "time" + "e2e/testconfig" + + sdk "github.com/cosmos/cosmos-sdk/types" dockerclient "github.com/docker/docker/client" "github.com/strangelove-ventures/ibctest" + "github.com/strangelove-ventures/ibctest/broadcast" "github.com/strangelove-ventures/ibctest/chain/cosmos" "github.com/strangelove-ventures/ibctest/ibc" + "github.com/strangelove-ventures/ibctest/test" "github.com/strangelove-ventures/ibctest/testreporter" "github.com/stretchr/testify/suite" "go.uber.org/zap" "go.uber.org/zap/zaptest" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" - "e2e/testconfig" + feetypes "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" ) const ( @@ -29,6 +36,8 @@ const ( // E2ETestSuite has methods and functionality which can be shared among all test suites. type E2ETestSuite struct { suite.Suite + + grpcClients map[string]GRPCClients paths map[string]path logger *zap.Logger DockerClient *dockerclient.Client @@ -36,6 +45,13 @@ type E2ETestSuite struct { startRelayerFn func(relayer ibc.Relayer) } +// GRPCClients holds a reference to any GRPC clients that are needed by the tests. +// These should typically be used for query clients only. If we need to make changes, we should +// use E2ETestSuite.BroadcastMessages to broadcast transactions instead. +type GRPCClients struct { + FeeQueryClient feetypes.QueryClient +} + // path is a pairing of two chains which will be used in a test. type path struct { chainA, chainB *cosmos.CosmosChain @@ -102,6 +118,9 @@ func (s *E2ETestSuite) SetupChainsRelayerAndChannel(ctx context.Context, channel time.Sleep(time.Second * 10) } + s.initGRPCClients(chainA) + s.initGRPCClients(chainB) + return r } @@ -129,6 +148,20 @@ func (s *E2ETestSuite) GetChains(chainOpts ...testconfig.ChainOptionConfiguratio return path.chainA, path.chainB } +// BroadcastMessages broadcasts the provided messages to the given chain and signs them on behalf of the provided user. +// Once the broadcast response is returned, we wait for a few blocks to be created on both chain A and chain B. +func (s *E2ETestSuite) BroadcastMessages(ctx context.Context, chain *cosmos.CosmosChain, user broadcast.User, msgs ...sdk.Msg) (sdk.TxResponse, error) { + broadcaster := cosmos.NewBroadcaster(s.T(), chain) + resp, err := ibctest.BroadcastTx(ctx, broadcaster, user, msgs...) + if err != nil { + return sdk.TxResponse{}, err + } + + chainA, chainB := s.GetChains() + err = test.WaitForBlocks(ctx, 2, chainA, chainB) + return resp, err +} + // GetRelayerWallets returns the relayer wallets associated with the chains. func (s *E2ETestSuite) GetRelayerWallets(relayer ibc.Relayer) (ibc.RelayerWallet, ibc.RelayerWallet, error) { chainA, chainB := s.GetChains() @@ -196,6 +229,37 @@ func (s *E2ETestSuite) GetChainBNativeBalance(ctx context.Context, user *ibctest return GetNativeChainBalance(ctx, chainB, user) } +// GetChainGRCPClients gets the GRPC clients associated with the given chain. +func (s *E2ETestSuite) GetChainGRCPClients(chain ibc.Chain) GRPCClients { + cs, ok := s.grpcClients[chain.Config().ChainID] + s.Require().True(ok, "chain %s does not have GRPC clients", chain.Config().ChainID) + return cs +} + +// initGRPCClients establishes GRPC clients with the given chain. +// The created GRPCClients can be retrieved with GetChainGRCPClients. +func (s *E2ETestSuite) initGRPCClients(chain *cosmos.CosmosChain) { + // Create a connection to the gRPC server. + grpcConn, err := grpc.Dial( + chain.GetHostGRPCAddress(), + grpc.WithTransportCredentials(insecure.NewCredentials()), + ) + s.Require().NoError(err) + s.T().Cleanup(func() { + if err := grpcConn.Close(); err != nil { + s.T().Logf("failed closing GRPC connection to chain %s: %s", chain.Config().ChainID, err) + } + }) + + if s.grpcClients == nil { + s.grpcClients = make(map[string]GRPCClients) + } + + s.grpcClients[chain.Config().ChainID] = GRPCClients{ + FeeQueryClient: feetypes.NewQueryClient(grpcConn), + } +} + // createCosmosChains creates two separate chains in docker containers. // test and can be retrieved with GetChains. func (s *E2ETestSuite) createCosmosChains(chainOptions testconfig.ChainOptions) (*cosmos.CosmosChain, *cosmos.CosmosChain) {