Skip to content

Commit 370b12b

Browse files
authored
Merge branch 'main' into charly/remove_ref_allow_update
2 parents 6065354 + 045ab6f commit 370b12b

File tree

1 file changed

+316
-0
lines changed

1 file changed

+316
-0
lines changed

e2e/README.md

+316
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,316 @@
1+
2+
## Table of Contents
3+
1. [How to write tests](#how-to-write-tests)
4+
- a. [Adding a new test](#adding-a-new-test)
5+
- b. [Running tests locally](#running-tests-locally)
6+
- b. [Code samples](#code-samples)
7+
- [Setup](#setup)
8+
- [Creating test users](#creating-test-users)
9+
- [Waiting](#waiting)
10+
- [Query wallet balances](#query-wallet-balances)
11+
- [Broadcasting messages](#broadcasting-messages)
12+
- [Starting the relayer](#starting-the-relayer)
13+
- [Arbitrary commands](#arbitrary-commands)
14+
- [IBC transfer](#ibc-transfer)
15+
2. [Test design](#test-design)
16+
- a. [ibctest](#ibctest)
17+
- b. [CI configuration](#ci-configuration)
18+
3. [Troubleshooting](#troubleshooting)
19+
20+
21+
## How to write tests
22+
23+
### Adding a new test
24+
25+
All tests should go under the [e2e](https://github.com/cosmos/ibc-go/tree/main/e2e) directory. When adding a new test, either add a new test function
26+
to an existing test suite **_in the same file_**, or create a new test suite in a new file and add test functions there.
27+
New test files should follow the convention of `module_name_test.go`.
28+
29+
New test suites should be composed of `testsuite.E2ETestSuite`. This type has lots of useful helper functionality that will
30+
be quite common in most tests.
31+
32+
> Note: see [here](#how-tests-are-run) for details about these requirements.
33+
34+
35+
### Running tests locally
36+
37+
Tests can be run using a Makefile target under the e2e directory. `e2e/Makefile`
38+
39+
There are several envinronment variables that alter the behaviour of the make target.
40+
41+
| Environment Variable | Description | Default Value|
42+
| ----------- | ----------- | ----------- |
43+
| SIMD_IMAGE | The image that will be used for simd | ibc-go-simd-e2e |
44+
| SIMD_TAG | The tag used for simd | latest|
45+
| RLY_TAG | The tag used for the go relayer | main|
46+
47+
48+
> Note: when running tests locally, **no images are pushed** to the `ghcr.io/cosmos/ibc-go-simd-e2e` registry.
49+
The images which are used only exist on your machine.
50+
51+
These environment variables allow us to run tests with arbitrary verions (from branches or released) of simd
52+
and the go relayer.
53+
54+
Every time changes are pushed to a branch or to `main`, a new `simd` image is built and pushed [here](https://github.com/cosmos/ibc-go/pkgs/container/ibc-go-simd-e2e).
55+
56+
57+
#### Example Command:
58+
59+
```sh
60+
export SIMD_IMAGE="ghcr.io/cosmos/ibc-go-simd-e2e"
61+
export SIMD_TAG="pr-1650"
62+
export RLY_TAG="v2.0.0-rc2"
63+
make e2e-test suite=FeeMiddlewareTestSuite test=TestMultiMsg_MsgPayPacketFeeSingleSender
64+
```
65+
66+
67+
> Note: sometimes it can be useful to make changes to [ibctest](https://github.com/strangelove-ventures/ibctest) when running tests locally. In order to do this, add the following line to
68+
e2e/go.mod
69+
70+
`replace github.com/strangelove-ventures/ibctest => ../ibctest`
71+
72+
Or point it to any local checkout you have.
73+
74+
### Code samples
75+
76+
#### Setup
77+
78+
Every standard test will start with this. This creates two chains and a relayer,
79+
initializes relayer accounts on both chains, establishes a connection and a channel
80+
between the chains.
81+
82+
Both chains have started, but the relayer is not yet started.
83+
84+
The relayer should be started as part of the test if required. See [Starting the Relayer](#starting-the-relayer)
85+
86+
```go
87+
relayer, channelA := s.SetupChainsRelayerAndChannel(ctx, feeMiddlewareChannelOptions())
88+
chainA, chainB := s.GetChains()
89+
```
90+
91+
#### Creating test users
92+
93+
There are helper functions to easily create users on both chains.
94+
95+
```go
96+
chainAWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount)
97+
chainBWallet := s.CreateUserOnChainB(ctx, testvalues.StartingTokenAmount)
98+
```
99+
100+
#### Waiting
101+
102+
We can wait for some number of blocks on the specified chains if required.
103+
104+
```go
105+
chainA, chainB := s.GetChains()
106+
err := test.WaitForBlocks(ctx, 1, chainA, chainB)
107+
s.Require().NoError(err)
108+
```
109+
110+
#### Query wallet balances
111+
112+
We can fetch balances of wallets on specific chains.
113+
114+
```go
115+
chainABalance, err := s.GetChainANativeBalance(ctx, chainAWallet)
116+
s.Require().NoError(err)
117+
```
118+
119+
#### Broadcasting messages
120+
121+
We can broadcast arbitrary messages which are signed on behalf of users created in the test.
122+
123+
This example shows a multi message transaction being broadcast on chainA and signed on behalf of chainAWallet.
124+
125+
```go
126+
relayer, channelA := s.SetupChainsRelayerAndChannel(ctx, feeMiddlewareChannelOptions())
127+
chainA, chainB := s.GetChains()
128+
129+
chainAWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount)
130+
chainBWallet := s.CreateUserOnChainB(ctx, testvalues.StartingTokenAmount)
131+
132+
t.Run("broadcast multi message transaction", func(t *testing.T){
133+
payPacketFeeMsg := feetypes.NewMsgPayPacketFee(testFee, channelA.PortID, channelA.ChannelID, chainAWallet.Bech32Address(chainA.Config().Bech32Prefix), nil)
134+
transferMsg := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, transferAmount, chainAWallet.Bech32Address(chainA.Config().Bech32Prefix), chainBWallet.Bech32Address(chainB.Config().Bech32Prefix), clienttypes.NewHeight(1, 1000), 0)
135+
resp, err := s.BroadcastMessages(ctx, chainA, chainAWallet, payPacketFeeMsg, transferMsg)
136+
137+
s.AssertValidTxResponse(resp)
138+
s.Require().NoError(err)
139+
})
140+
```
141+
142+
#### Starting the relayer
143+
144+
The relayer can be started with the following.
145+
146+
```go
147+
t.Run("start relayer", func(t *testing.T) {
148+
s.StartRelayer(relayer)
149+
})
150+
```
151+
152+
#### Arbitrary commands
153+
154+
Arbitrary commands can be executed on a given chain.
155+
156+
> Note: these commands will be fully configured to run on the chain executed on (home directory, ports configured etc.)
157+
158+
However, it is preferable to [broadcast messages](#broadcasting-messages) or use a gRPC query if possible.
159+
160+
```go
161+
stdout, stderr, err := chainA.Exec(ctx, []string{"tx", "..."}, nil)
162+
```
163+
164+
#### IBC transfer
165+
166+
It is possible to send an IBC transfer in two ways.
167+
168+
Use the ibctest `Chain` interface (this ultimately does a docker exec)
169+
170+
```go
171+
t.Run("send IBC transfer", func(t *testing.T) {
172+
chainATx, err = chainA.SendIBCTransfer(ctx, channelA.ChannelID, chainAWallet.KeyName, walletAmount, nil)
173+
s.Require().NoError(err)
174+
s.Require().NoError(chainATx.Validate(), "chain-a ibc transfer tx is invalid")
175+
})
176+
```
177+
178+
Broadcast a `MsgTransfer`.
179+
180+
```go
181+
t.Run("send IBC transfer", func(t *testing.T){
182+
transferMsg := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, transferAmount, chainAWallet.Bech32Address(chainA.Config().Bech32Prefix), chainBWallet.Bech32Address(chainB.Config().Bech32Prefix), clienttypes.NewHeight(1, 1000), 0)
183+
resp, err := s.BroadcastMessages(ctx, chainA, chainAWallet, transferMsg)
184+
s.AssertValidTxResponse(resp)
185+
s.Require().NoError(err)
186+
})
187+
```
188+
189+
## Test design
190+
191+
192+
#### ibctest
193+
194+
These E2E tests use the [ibctest framework](https://github.com/strangelove-ventures/ibctest). This framework creates chains and relayers in containers and allows for arbitrary commands to be executed in the chain containers,
195+
as well as allowing us to broadcast arbitrary messages which are signed on behalf of a user created in the test.
196+
197+
198+
#### CI configuration
199+
200+
There are two main github actions for e2e tests.
201+
202+
[e2e.yaml](https://github.com/cosmos/ibc-go/blob/main/.github/workflows/e2e.yaml) which runs when collaborators create branches.
203+
204+
[e2e-fork.yaml](https://github.com/cosmos/ibc-go/blob/main/.github/workflows/e2e-fork.yml) which runs when forks are created.
205+
206+
In `e2e.yaml`, the `simd` image is built and pushed to [a registry](https://github.com/cosmos/ibc-go/pkgs/container/ibc-go-simd-e2e) and every test
207+
that is run uses the image that was built.
208+
209+
In `e2e-fork.yaml`, images are not pushed to this registry, but instead remain local to the host runner.
210+
211+
212+
### How tests are run
213+
214+
The tests use the `matrix` feature of Github Actions. The matrix is
215+
dynamically generated using [this command](https://github.com/cosmos/ibc-go/blob/main/cmd/build_test_matrix/main.go).
216+
217+
> Note: there is currently a limitation that all tests belonging to a test suite must be in the same file.
218+
In order to support test functions spread in different files, we would either need to manually maintain a matrix
219+
or update the script to account for this. The script assumes there is a single test suite per test file to avoid an overly complex
220+
generation process.
221+
222+
Which looks under the `e2e` directory, and creates a task for each test suite function.
223+
224+
#### Example
225+
226+
```go
227+
// e2e/file_one_test.go
228+
package e2e
229+
230+
func TestFeeMiddlewareTestSuite(t *testing.T) {
231+
suite.Run(t, new(FeeMiddlewareTestSuite))
232+
}
233+
234+
type FeeMiddlewareTestSuite struct {
235+
testsuite.E2ETestSuite
236+
}
237+
238+
func (s *FeeMiddlewareTestSuite) TestA() {}
239+
func (s *FeeMiddlewareTestSuite) TestB() {}
240+
func (s *FeeMiddlewareTestSuite) TestC() {}
241+
242+
```
243+
244+
```go
245+
// e2e/file_two_test.go
246+
package e2e
247+
248+
func TestTransferTestSuite(t *testing.T) {
249+
suite.Run(t, new(TransferTestSuite))
250+
}
251+
252+
type TransferTestSuite struct {
253+
testsuite.E2ETestSuite
254+
}
255+
256+
func (s *TransferTestSuite) TestD() {}
257+
func (s *TransferTestSuite) TestE() {}
258+
func (s *TransferTestSuite) TestF() {}
259+
260+
```
261+
262+
In the above example, the following would be generated.
263+
264+
```json
265+
{
266+
"include": [
267+
{
268+
"suite": "FeeMiddlewareTestSuite",
269+
"test": "TestA"
270+
},
271+
{
272+
"suite": "FeeMiddlewareTestSuite",
273+
"test": "TestB"
274+
},
275+
{
276+
"suite": "FeeMiddlewareTestSuite",
277+
"test": "TestC"
278+
},
279+
{
280+
"suite": "TransferTestSuite",
281+
"test": "TestD"
282+
},
283+
{
284+
"suite": "TransferTestSuite",
285+
"test": "TestE"
286+
},
287+
{
288+
"suite": "TransferTestSuite",
289+
"test": "TestF"
290+
}
291+
]
292+
}
293+
```
294+
295+
This string is used to generate a test matrix in the Github Action that runs the E2E tests.
296+
297+
All tests will be run on different hosts.
298+
299+
300+
#### Misceleneous:
301+
302+
* Gas fees are set to zero to simply calcuations when asserting account balances.
303+
* When upgrading from e.g. v4 -> v5, in ibc-go, we cannot upgrade the go.mod under `e2e` since v5 will not yet exist. We need to upgrade it in a follow up PR.
304+
305+
### Troubleshooting
306+
307+
* On Mac, after running a lot of tests, it can happen that containers start failing. To fix this, you can try clearing existing containers and restarting the docker daemon.
308+
309+
This generally manifests itself as relayer or simd containers timing out during setup stages of the test. This doesn't happen in CI.
310+
```bash
311+
# delete all images
312+
docker system prune -af
313+
```
314+
This issue doesn't seem to occur on other operating systems.
315+
316+

0 commit comments

Comments
 (0)