Skip to content

Commit

Permalink
First run at interchaintests.
Browse files Browse the repository at this point in the history
These include tests for different transaction types, and consumer chain
launches. They are triggered by the docker-push workflow and will test
the pushed image. They can also be triggered manually and will try to
test an image on the branch supplied.
  • Loading branch information
fastfadingviolets committed Jul 18, 2024
1 parent b06e7ea commit b64e1db
Show file tree
Hide file tree
Showing 18 changed files with 4,353 additions and 2 deletions.
13 changes: 12 additions & 1 deletion .github/workflows/docker-push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
build-and-push-image:
runs-on: ubuntu-latest
permissions:
contents: read
contents: write
packages: write

steps:
Expand Down Expand Up @@ -54,3 +54,14 @@ jobs:
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
if: ${{ env.NEW_COMMIT_COUNT > 0 }}

- name: Dispatch Interchain test
uses: peter-evans/repository-dispatch@v3
with:
event-type: image-pushed
client-payload: |
{
"tag_name": "${{ fromJson(steps.meta.outputs.json)['labels']['org.opencontainers.image.version'] }}",
"ref_name": "${{ fromJson(steps.meta.outputs.json)['labels']['org.opencontainers.image.revision'] }}"
}
if: ${{ env.NEW_COMMIT_COUNT > 0 }}
64 changes: 64 additions & 0 deletions .github/workflows/interchain-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Interchain Test
on:
repository_dispatch:
types: [image-pushed]
workflow_dispatch:

jobs:
prepare-matrix:
runs-on: ubuntu-latest
steps:
# We need to figure out a) a ref to clone based on a docker image, and b) which tag to test
# If the event is a registry_package, this comes from the pushed image; for a workflow_dispatch, it's the branch/tag that the user supplied
- name: Get metadata
id: get-metadata
run: |
if [[ "${{ github.event_name }}" == 'repository_dispatch' ]]; then
echo "ref_name=${{ github.event.client_payload.ref_name }}" | tee -a $GITHUB_OUTPUT
echo "tag_name=${{ github.event.client_payload.tag_name }}" | tee -a $GITHUB_OUTPUT
else
echo "ref_name=${{ github.ref_name }}" | tee -a $GITHUB_OUTPUT
echo "tag_name=${{ github.ref_name }}" | tee -a $GITHUB_OUTPUT
fi
- name: Check out repository code
uses: actions/checkout@v3
with:
ref: ${{ steps.get-metadata.outputs.ref_name }}
- name: Setup go
uses: actions/setup-go@v5
- name: Prepare matrix
id: generate-matrix
run: |
cd ./tests/interchain
echo "matrix=$(go run ./matrix_tool/main.go ${{ steps.get-metadata.outputs.tag_name }})" | tee -a $GITHUB_OUTPUT
outputs:
matrix: ${{ steps.generate-matrix.outputs.matrix }}
ref_name: ${{ steps.get-metadata.outputs.ref_name }}
test:
needs: prepare-matrix
runs-on: ubuntu-latest
name: "${{ matrix.previous_version }} -> ${{ matrix.test_version }} test ${{ matrix.test_name }}"
strategy:
matrix:
${{fromJson(needs.prepare-matrix.outputs.matrix)}}
fail-fast: false
max-parallel: 10
steps:
- name: Check out repository code
uses: actions/checkout@v3
with:
ref: ${{ needs.prepare-matrix.outputs.ref_name }}
- name: Setup go
uses: actions/setup-go@v5
- name: Run test
env:
TEST_DOCKER_REGISTRY: "ghcr.io/${{ github.repository_owner }}"
TEST_OLD_GAIA_IMAGE_VERSION: "${{ matrix.previous_version }}"
TEST_NEW_GAIA_IMAGE_VERSION: "${{ matrix.test_version }}"
TEST_UPGRADE_NAME: "${{ matrix.upgrade_name }}"
run: |
# This docker pull/tag is a quick hack only necessary for v19, since there were no official v18 images built.
# Once we're testing 19 -> 20 this can be removed
docker pull "ghcr.io/hyphacoop/gaia:v18.1.0" && docker tag "ghcr.io/hyphacoop/gaia:v18.1.0" "ghcr.io/${{ github.repository_owner }}/gaia:v18.1.0"
cd ./tests/interchain
go test -v ./... -failfast -p 1 -timeout 5h -run="^${{ matrix.test_name }}"
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
- name: test & coverage report creation
if: env.GIT_DIFF
run: |
go test -v -coverprofile=profile.out -covermode=atomic -coverpkg=./... $(go list ./... | grep -v -e '/tests/e2e')
go test -v -coverprofile=profile.out -covermode=atomic -coverpkg=./... $(go list ./... | grep -v -e '/tests/e2e' | grep -v -e '/tests/interchain')
- uses: actions/upload-artifact@v4
if: env.GIT_DIFF
with:
Expand Down
139 changes: 139 additions & 0 deletions tests/interchain/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# Interchain tests for gaia.


These tests use [interchaintest](https://github.com/strangelove-ventures/interchaintest/) to
create, upgrade, and test chains.

They dockerize the validators, so they depend on a `gaia` docker image being built.
You can build a docker image using the [docker-push](../../.github/workflows/docker-push.yml) workflow.
`docker-push` runs nightly on the `main` branch, and for all new releases, but you can also
[run it manually on any branch](https://github.com/cosmos/gaia/actions/workflows/docker-push.yml)

Once the `gaia` image is built, the `docker-push` action workflow automatically invoke the
[interchain-test](../../.github/workflows/interchain-test.yml) workflow.

Read on to learn how these tests work.

## Upgrade testing

The tests will make sure it's possible to upgrade from a previous version of
`gaia` to the current version being tested. It does so by starting a chain from genesis
on the previous version, then upgrading it to the current version.

## Version selection

The `interchain-test` workflow will start by selecting versions to test upgrading from.

The [`matrix_tool`](./matrix_tool/main.go) tool will take the tag of the image
being tested (e.g. `v18.0.0`, or `main`, or `some-feature-branch`), and figure
out a corresponding semver. If the tag is already a valid semver, that's the
version. Otherwise, it will take the major version from the module line in `go.mod`,
and append `.999.0`. Given that semver, it'll figure out:

* The previous rc (if the current version is itself an rc)
* The previous minor version (if applicable)
* The previous major version

For instance, for `v15.1.0-rc1`, we'll test upgrading from:
* `v15.1.0-rc0`
* `v15.0.0`
* `v14.2.0`

The workflow will then test upgrading from each of those three to the current
version. When it's a major upgrade, it will do so via governance proposal,
otherwise it'll simply stop the old image and start the new one.

## Test Suites

Each of the *_test.go files in this directory contains a test suite. These
share some common scaffolding (a `SetupSuite`) to create and upgrade a chain,
and then run a set of tests on that chain.

So, for instance, a transactions suite:

```go
type TxSuite struct {
*chainsuite.Suite
}
```

It extends `chainsuite.Suite,` so its SetupSuite will create and upgrade a
chain (more on this later). The individual `Test*` methods then run the gaia
version being tested:

```go
func (s *TxSuite) TestBankSend() {
balanceBefore, err := s.Chain.GetBalance(s.GetContext(), s.Chain.ValidatorWallets[1].Address, chainsuite.Uatom)
s.Require().NoError(err)

_, err = s.Chain.Validators[0].ExecTx(
s.GetContext(),
s.Chain.ValidatorWallets[0].Moniker,
"bank", "send",
s.Chain.ValidatorWallets[0].Address, s.Chain.ValidatorWallets[1].Address, txAmountUatom(),
)
s.Require().NoError(err)

balanceAfter, err := s.Chain.GetBalance(s.GetContext(), s.Chain.ValidatorWallets[1].Address, chainsuite.Uatom)
s.Require().NoError(err)
s.Require().Equal(balanceBefore.Add(sdkmath.NewInt(txAmount)), balanceAfter)
}
```

Because of how testify works, we have to instantiate each suite to run it.
This is also where we tell the suite to run an upgrade on Setup:

```go
func TestTransactions(t *testing.T) {
txSuite := TxSuite{chainsuite.NewSuite(chainsuite.SuiteConfig{UpgradeOnSetup: true})}
suite.Run(t, &txSuite)
}
```

Of course, we can also parameterize the test suites themselves. This enables us
to write tests once and run them a bunch of times on different configurations:

```go
type ConsumerLaunchSuite struct {
*chainsuite.Suite
OtherChain string
OtherChainVersion string
ShouldCopyProviderKey [chainsuite.ValidatorCount]bool
}

func TestICS40ChainLaunch(t *testing.T) {
s := &ConsumerLaunchSuite{
Suite: chainsuite.NewSuite(chainsuite.SuiteConfig{}),
OtherChain: "ics-consumer",
OtherChainVersion: "v4.0.0",
ShouldCopyProviderKey: noProviderKeysCopied(),
}
suite.Run(t, s)
}

func TestICS33ConsumerAllKeysChainLaunch(t *testing.T) {
s := &ConsumerLaunchSuite{
Suite: chainsuite.NewSuite(chainsuite.SuiteConfig{}),
OtherChain: "ics-consumer",
OtherChainVersion: "v3.3.0",
ShouldCopyProviderKey: allProviderKeysCopied(),
}
suite.Run(t, s)
}
```

Notice also how `UpgradeOnSetup` isn't set here: the ConsumerLaunchSuite needs
to be handed a pre-upgrade chain so it can make sure that a consumer chain that
launched before the upgrade keeps working after the upgrade.


## Writing new tests

All you need to start writing new tests is a test suite as described above.
The suite will have an `s.Chain` that you can test. Check out utilities in
[`chainsuite/chain.go`](./chainsuite/chain.go) and
[`chain_ics.go`](./chainsuite/chain_ics.go) for some convenience methods.

In addition, the s.Chain object extends the `interchaintest` chain object, so
check out [the docs](https://pkg.go.dev/github.com/strangelove-ventures/interchaintest/v7) to
see what else is available.
Loading

0 comments on commit b64e1db

Please sign in to comment.