Skip to content

Commit

Permalink
ci: First run at interchaintests. (#3205)
Browse files Browse the repository at this point in the history
* First run at interchaintests.

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.

* Upgrade interchaintest to v8 and use upstream

* Add jq to the docker image.

This is used by some features of interchaintest and is just generally
useful to have.
  • Loading branch information
fastfadingviolets authored Jul 29, 2024
1 parent 59574b5 commit bb6f13f
Show file tree
Hide file tree
Showing 19 changed files with 4,370 additions and 3 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
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ RUN echo "Ensuring binary is statically linked ..." \
&& file /src/app/build/gaiad | grep "statically linked"

FROM alpine:$IMG_TAG
RUN apk add --no-cache build-base
RUN apk add --no-cache build-base jq
RUN addgroup -g 1025 nonroot
RUN adduser -D nonroot -u 1025 -G nonroot
ARG IMG_TAG
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 bb6f13f

Please sign in to comment.