diff --git a/.github/workflows/e2e-test-workflow-call.yml b/.github/workflows/e2e-test-workflow-call.yml index 633dfbdaff4..3ed7f572c11 100644 --- a/.github/workflows/e2e-test-workflow-call.yml +++ b/.github/workflows/e2e-test-workflow-call.yml @@ -6,6 +6,11 @@ on: required: false type: string default: "" # empty string means run all tests + test: + description: "test name to run as standalone" + required: false + type: string + default: "" test-exclusions: description: "Comma separated list of tests to skip" required: false @@ -31,6 +36,16 @@ on: description: "The chain binary" required: false type: string + chain-upgrade-tag: + default: "" + description: "The image tag that the chain will be upgraded to" + required: false + type: string + upgrade-plan-name: + default: "" + description: "The upgrade plan name" + required: false + type: string relayer-type: description: "The type of relayer to use" required: false @@ -57,12 +72,15 @@ jobs: steps: - name: Display Inputs run: | - echo "Chain Image: ${{ inputs.chain-image }}" - echo "Chain A Tag: ${{ inputs.chain-a-tag }}" - echo "Chain B Tag: ${{ inputs.chain-b-tag }}" - echo "Relayer Type: ${{ inputs.relayer-type }}" - echo "Relayer Tag: ${{ inputs.relayer-tag }}" - echo "Test Entry Point: ${{ inputs.test-entry-point }}" + echo "Chain Image: ${{ inputs.chain-image }}" + echo "Chain A Tag: ${{ inputs.chain-a-tag }}" + echo "Chain B Tag: ${{ inputs.chain-b-tag }}" + echo "Chain Upgrade Tag: ${{ inputs.chain-upgrade-tag }}" + echo "Upgrade Plan Name: ${{ inputs.upgrade-plan-name }}" + echo "Relayer Type: ${{ inputs.relayer-type }}" + echo "Relayer Tag: ${{ inputs.relayer-tag }}" + echo "Test Entry Point: ${{ inputs.test-entry-point }}" + echo "Test: ${{ inputs.test }}" echo "Github Ref Name: ${{ github.ref_name }}" # we skip individual steps rather than the full job as e2e-tests will not run if this task @@ -105,6 +123,8 @@ jobs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - uses: actions/checkout@v3 + with: + repository: cosmos/ibc-go - uses: actions/setup-go@v3 with: go-version: 1.19 @@ -113,6 +133,7 @@ jobs: env: TEST_ENTRYPOINT: "${{ inputs.test-entry-point }}" TEST_EXCLUSIONS: "${{ inputs.test-exclusions }}" + TEST_NAME: "${{ inputs.test }}" e2e-tests: runs-on: ubuntu-latest @@ -126,11 +147,15 @@ jobs: RELAYER_TAG: "${{ inputs.relayer-tag }}" RELAYER_TYPE: "${{ inputs.relayer-type }}" CHAIN_BINARY: "${{ inputs.chain-binary }}" + CHAIN_UPGRADE_TAG: "${{ inputs.chain-upgrade-tag }}" + CHAIN_UPGRADE_PLAN: "${{ inputs.upgrade-plan-name }}" strategy: fail-fast: false matrix: ${{ fromJSON(needs.build-test-matrix.outputs.matrix) }} steps: - uses: actions/checkout@v3 + with: + repository: cosmos/ibc-go - uses: actions/setup-go@v3 with: go-version: 1.19 diff --git a/.github/workflows/e2e-upgrade.yaml b/.github/workflows/e2e-upgrade.yaml index 18494d3a07b..b596f22a9ce 100644 --- a/.github/workflows/e2e-upgrade.yaml +++ b/.github/workflows/e2e-upgrade.yaml @@ -1,42 +1,43 @@ name: Tests / E2E Upgrade -on: workflow_dispatch +on: + workflow_dispatch: + + schedule: + - cron: '0 0 * * *' jobs: - upgrade-tests: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - include: - - test: TestV4ToV5ChainUpgrade - chain-image: ghcr.io/cosmos/ibc-go-simd - chain-a-tag: v4.3.0 - chain-b-tag: v4.3.0 - chain-upgrade-tag: v5.1.0 - - test: TestV5ToV6ChainUpgrade - chain-image: ghcr.io/cosmos/ibc-go-icad - chain-binary: icad - chain-a-tag: v0.3.5 - chain-b-tag: v0.3.5 - chain-upgrade-tag: v0.4.1 - - test: TestV6ToV7ChainUpgrade - chain-image: ghcr.io/cosmos/ibc-go-simd - chain-binary: simd - chain-a-tag: v6.1.0 - chain-b-tag: v6.1.0 - chain-upgrade-tag: v7.0.0-rc0 # TODO: needs v7.0.0-rc1 when cut - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v3 - with: - go-version: 1.19 - - name: Run e2e upgrade test - run: | - cd e2e - make e2e-test entrypoint=TestUpgradeTestSuite test=${{ matrix.test }} - env: - CHAIN_IMAGE: ${{ matrix.chain-image }} - CHAIN_BINARY: ${{ matrix.chain-binary }} - CHAIN_A_TAG: ${{ matrix.chain-a-tag }} - CHAIN_B_TAG: ${{ matrix.chain-b-tag }} - CHAIN_UPGRADE_TAG: ${{ matrix.chain-upgrade-tag }} + upgrade-v5: + uses: cosmos/ibc-go/.github/workflows/e2e-test-workflow-call.yml@main + with: + chain-image: ghcr.io/cosmos/ibc-go-simd + chain-binary: simd + chain-a-tag: v4.3.0 + chain-b-tag: v4.3.0 + chain-upgrade-tag: v5.1.0 + upgrade-plan-name: "normal upgrade" + test-entry-point: "TestUpgradeTestSuite" + test: "TestIBCChainUpgrade" + + upgrade-v6: + uses: cosmos/ibc-go/.github/workflows/e2e-test-workflow-call.yml@main + with: + chain-image: ghcr.io/cosmos/ibc-go-icad + chain-binary: icad + chain-a-tag: v0.3.5 + chain-b-tag: v0.3.5 + chain-upgrade-tag: v0.4.1 + upgrade-plan-name: "ibc-go/v6" + test-entry-point: "TestUpgradeTestSuite" + test: "TestV5ToV6ChainUpgrade" + + upgrade-v7: + uses: cosmos/ibc-go/.github/workflows/e2e-test-workflow-call.yml@main + with: + chain-image: ghcr.io/cosmos/ibc-go-simd + chain-binary: simd + chain-a-tag: v6.1.0 + chain-b-tag: v6.1.0 + chain-upgrade-tag: v7.0.0-rc0 # TODO: needs v7.0.0-rc1 when cut + upgrade-plan-name: "v7" + test-entry-point: "TestUpgradeTestSuite" + test: "TestV6ToV7ChainUpgrade" diff --git a/cmd/build_test_matrix/main.go b/cmd/build_test_matrix/main.go index c5eac952cd8..58997687e3c 100644 --- a/cmd/build_test_matrix/main.go +++ b/cmd/build_test_matrix/main.go @@ -21,6 +21,8 @@ const ( // testExclusionsEnv is a comma separated list of test function names that will not be included // in the results of this script. testExclusionsEnv = "TEST_EXCLUSIONS" + // testNameEnv if provided returns a single test entry so that only one test is actually run. + testNameEnv = "TEST_NAME" ) // GithubActionTestMatrix represents @@ -102,6 +104,13 @@ func getGithubActionMatrixForTests(e2eRootDirectory, suite string, exlcudedItems return fmt.Errorf("failed extracting test suite name and test cases: %s", err) } + testName := os.Getenv(testNameEnv) + if testName != "" && contains(testName, testCases) { + testCases = []string{testName} + } else if testName != "" { + return fmt.Errorf("failed to find test case: %s", testName) + } + if contains(suiteNameForFile, exlcudedItems) { return nil } diff --git a/e2e/scripts/run-e2e.sh b/e2e/scripts/run-e2e.sh index e0afbe5abbf..e280be0ddee 100755 --- a/e2e/scripts/run-e2e.sh +++ b/e2e/scripts/run-e2e.sh @@ -9,11 +9,4 @@ export CHAIN_A_TAG="${CHAIN_A_TAG:-latest}" export CHAIN_IMAGE="${CHAIN_IMAGE:-ibc-go-simd}" export CHAIN_BINARY="${CHAIN_BINARY:-simd}" -# In CI, the docker images will be built separately. -# context for building the image is one directory up. -if [ "${CI:-}" != "true" ] -then - (cd ..; docker build . -t "${CHAIN_IMAGE}:${CHAIN_A_TAG}" --build-arg="IBC_GO_VERSION=${CHAIN_A_TAG}") -fi - go test -v ./tests/... --run ${ENTRY_POINT} -testify.m ^${TEST}$ diff --git a/e2e/testconfig/testconfig.go b/e2e/testconfig/testconfig.go index 0564d93175c..4cadcee57e2 100644 --- a/e2e/testconfig/testconfig.go +++ b/e2e/testconfig/testconfig.go @@ -39,6 +39,8 @@ const ( ChainBinaryEnv = "CHAIN_BINARY" // ChainUpgradeTagEnv specifies the upgrade version tag ChainUpgradeTagEnv = "CHAIN_UPGRADE_TAG" + // ChainUpgradePlanEnv specifies the upgrade plan name + ChainUpgradePlanEnv = "CHAIN_UPGRADE_PLAN" // defaultBinary is the default binary that will be used by the chains. defaultBinary = "simd" @@ -60,10 +62,11 @@ func getChainImage(binary string) string { // TestConfig holds various fields used in the E2E tests. type TestConfig struct { - ChainAConfig ChainConfig - ChainBConfig ChainConfig - RelayerConfig relayer.Config - UpgradeTag string + ChainAConfig ChainConfig + ChainBConfig ChainConfig + RelayerConfig relayer.Config + UpgradeTag string + UpgradePlanName string } // ChainConfig holds information about an individual chain used in the tests. @@ -102,6 +105,11 @@ func FromEnv() TestConfig { upgradeTag = "" } + upgradePlan, ok := os.LookupEnv(ChainUpgradePlanEnv) + if !ok { + upgradePlan = "" + } + return TestConfig{ ChainAConfig: ChainConfig{ Image: chainAImage, @@ -113,8 +121,9 @@ func FromEnv() TestConfig { Tag: chainBTag, Binary: chainBinary, }, - UpgradeTag: upgradeTag, - RelayerConfig: GetRelayerConfigFromEnv(), + UpgradeTag: upgradeTag, + UpgradePlanName: upgradePlan, + RelayerConfig: GetRelayerConfigFromEnv(), } } diff --git a/e2e/tests/upgrades/upgrade_test.go b/e2e/tests/upgrades/upgrade_test.go index e9d912e6594..c8500e830dc 100644 --- a/e2e/tests/upgrades/upgrade_test.go +++ b/e2e/tests/upgrades/upgrade_test.go @@ -10,7 +10,6 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" "github.com/cosmos/gogoproto/proto" - v6upgrades "github.com/cosmos/interchain-accounts/app/upgrades/v6" intertxtypes "github.com/cosmos/interchain-accounts/x/inter-tx/types" interchaintest "github.com/strangelove-ventures/interchaintest/v7" "github.com/strangelove-ventures/interchaintest/v7/chain/cosmos" @@ -29,8 +28,6 @@ import ( "github.com/cosmos/ibc-go/v7/modules/core/exported" solomachine "github.com/cosmos/ibc-go/v7/modules/light-clients/06-solomachine" ibctesting "github.com/cosmos/ibc-go/v7/testing" - simappupgrades "github.com/cosmos/ibc-go/v7/testing/simapp/upgrades" - v7upgrades "github.com/cosmos/ibc-go/v7/testing/simapp/upgrades/v7" ) const ( @@ -39,6 +36,11 @@ const ( ) func TestUpgradeTestSuite(t *testing.T) { + testCfg := testconfig.FromEnv() + if testCfg.UpgradeTag == "" || testCfg.UpgradePlanName == "" { + t.Fatal("upgrade tag and upgrade plan name must be provided in test configuration") + } + suite.Run(t, new(UpgradeTestSuite)) } @@ -91,7 +93,7 @@ func (s *UpgradeTestSuite) UpgradeChain(ctx context.Context, chain *cosmos.Cosmo s.Require().Greater(height, haltHeight, "height did not increment after upgrade") } -func (s *UpgradeTestSuite) TestV4ToV5ChainUpgrade() { +func (s *UpgradeTestSuite) TestIBCChainUpgrade() { t := s.T() testCfg := testconfig.FromEnv() @@ -150,7 +152,7 @@ func (s *UpgradeTestSuite) TestV4ToV5ChainUpgrade() { s.Require().NoError(test.WaitForBlocks(ctx, 5, chainA, chainB), "failed to wait for blocks") t.Run("upgrade chainA", func(t *testing.T) { - s.UpgradeChain(ctx, chainA, chainAUpgradeProposalWallet, simappupgrades.DefaultUpgradeName, testCfg.ChainAConfig.Tag, testCfg.UpgradeTag) + s.UpgradeChain(ctx, chainA, chainAUpgradeProposalWallet, testCfg.UpgradePlanName, testCfg.ChainAConfig.Tag, testCfg.UpgradeTag) }) t.Run("restart relayer", func(t *testing.T) { @@ -197,6 +199,59 @@ func (s *UpgradeTestSuite) TestV4ToV5ChainUpgrade() { }) } +func (s *UpgradeTestSuite) TestChainUpgrade() { + t := s.T() + + ctx := context.Background() + chain := s.SetupSingleChain(ctx) + + userWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount) + userWalletAddr := userWallet.FormattedAddress() + + s.Require().NoError(test.WaitForBlocks(ctx, 1, chain), "failed to wait for blocks") + + t.Run("send funds to test wallet", func(t *testing.T) { + err := chain.SendFunds(ctx, interchaintest.FaucetAccountKeyName, ibc.WalletAmount{ + Address: userWalletAddr, + Amount: testvalues.StartingTokenAmount, + Denom: chain.Config().Denom, + }) + s.Require().NoError(err) + }) + + t.Run("verify tokens sent", func(t *testing.T) { + balance, err := chain.GetBalance(ctx, userWalletAddr, chain.Config().Denom) + s.Require().NoError(err) + + expected := testvalues.StartingTokenAmount * 2 + s.Require().Equal(expected, balance) + }) + + t.Run("upgrade chain", func(t *testing.T) { + testCfg := testconfig.FromEnv() + proposerWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount) + + s.UpgradeChain(ctx, chain, proposerWallet, testCfg.UpgradePlanName, testCfg.ChainAConfig.Tag, testCfg.UpgradeTag) + }) + + t.Run("send funds to test wallet", func(t *testing.T) { + err := chain.SendFunds(ctx, interchaintest.FaucetAccountKeyName, ibc.WalletAmount{ + Address: userWalletAddr, + Amount: testvalues.StartingTokenAmount, + Denom: chain.Config().Denom, + }) + s.Require().NoError(err) + }) + + t.Run("verify tokens sent", func(t *testing.T) { + balance, err := chain.GetBalance(ctx, userWalletAddr, chain.Config().Denom) + s.Require().NoError(err) + + expected := testvalues.StartingTokenAmount * 3 + s.Require().Equal(expected, balance) + }) +} + func (s *UpgradeTestSuite) TestV5ToV6ChainUpgrade() { t := s.T() testCfg := testconfig.FromEnv() @@ -297,7 +352,7 @@ func (s *UpgradeTestSuite) TestV5ToV6ChainUpgrade() { s.Require().NoError(test.WaitForBlocks(ctx, 5, chainA, chainB), "failed to wait for blocks") t.Run("upgrade chainA", func(t *testing.T) { - s.UpgradeChain(ctx, chainA, chainAUpgradeProposalWallet, v6upgrades.UpgradeName, testCfg.ChainAConfig.Tag, testCfg.UpgradeTag) + s.UpgradeChain(ctx, chainA, chainAUpgradeProposalWallet, testCfg.UpgradePlanName, testCfg.ChainAConfig.Tag, testCfg.UpgradeTag) }) t.Run("restart relayer", func(t *testing.T) { @@ -513,7 +568,7 @@ func (s *UpgradeTestSuite) TestV6ToV7ChainUpgrade() { chainAUpgradeProposalWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount) t.Run("upgrade chainA", func(t *testing.T) { - s.UpgradeChain(ctx, chainA, chainAUpgradeProposalWallet, v7upgrades.UpgradeName, testCfg.ChainAConfig.Tag, testCfg.UpgradeTag) + s.UpgradeChain(ctx, chainA, chainAUpgradeProposalWallet, testCfg.UpgradePlanName, testCfg.ChainAConfig.Tag, testCfg.UpgradeTag) }) t.Run("check that the tendermint clients are active again after upgrade", func(t *testing.T) { diff --git a/e2e/testsuite/testsuite.go b/e2e/testsuite/testsuite.go index a8c8fb01661..edd4642dcb5 100644 --- a/e2e/testsuite/testsuite.go +++ b/e2e/testsuite/testsuite.go @@ -172,6 +172,29 @@ func (s *E2ETestSuite) SetupChainsRelayerAndChannel(ctx context.Context, channel return r, chainAChannels[len(chainAChannels)-1] } +// SetupSingleChain creates and returns a single CosmosChain for usage in e2e tests. +// This is useful for testing single chain functionality when performing coordinated upgrades as well as testing localhost ibc client functionality. +// TODO: Actually setup a single chain. Seeing panic: runtime error: index out of range [0] with length 0 when using a single chain. +// issue: https://github.com/strangelove-ventures/interchaintest/issues/401 +func (s *E2ETestSuite) SetupSingleChain(ctx context.Context) *cosmos.CosmosChain { + chainA, chainB := s.GetChains() + + ic := interchaintest.NewInterchain().AddChain(chainA).AddChain(chainB) + + eRep := s.GetRelayerExecReporter() + s.Require().NoError(ic.Build(ctx, eRep, interchaintest.InterchainBuildOptions{ + TestName: s.T().Name(), + Client: s.DockerClient, + NetworkID: s.network, + SkipPathCreation: true, + })) + + s.InitGRPCClients(chainA) + s.InitGRPCClients(chainB) + + return chainA +} + // generatePathName generates the path name using the test suites name func (s *E2ETestSuite) generatePathName() string { pathName := fmt.Sprintf("%s-path-%d", s.T().Name(), s.pathNameIndex)