From 8914726e82743fa0f395782c98398a6619dc5bee Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Fri, 28 Jun 2024 15:04:29 +0200 Subject: [PATCH 1/5] Start system test tutorial --- tests/systemtests/bank_test.go | 16 ++++++ tests/systemtests/getting_started.md | 82 ++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 tests/systemtests/bank_test.go create mode 100644 tests/systemtests/getting_started.md diff --git a/tests/systemtests/bank_test.go b/tests/systemtests/bank_test.go new file mode 100644 index 000000000000..531f49a64b6d --- /dev/null +++ b/tests/systemtests/bank_test.go @@ -0,0 +1,16 @@ +//go:build system_test + +package systemtests + +import ( + "testing" +) + +func TestQueryTotalSupply(t *testing.T) { + sut.ResetChain(t) + sut.StartChain(t) + + cli := NewCLIWrapper(t, sut, verbose) + raw := cli.CustomQuery("q", "bank", "total-supply") + t.Log("### got: " + raw) +} diff --git a/tests/systemtests/getting_started.md b/tests/systemtests/getting_started.md new file mode 100644 index 000000000000..65987182f9d5 --- /dev/null +++ b/tests/systemtests/getting_started.md @@ -0,0 +1,82 @@ +# Getting started with a new system test + +## Preparation + +Build a new binary from current branch and copy it to the `tests/systemtests/binaries` folder by running system tests. +In project root: +```shell +make test-system +``` +Or via manual steps +```shell +make build +mkdir -p ./tests/systemtests/binaries +cp ./build/simd ./tests/systemtests/binaries/ +``` + +## Writing the first system test + +Switch to the `tests/systemtests` folder to work from here. + +If there is no test file matching your use case, start a new test file here. +for example `bank_test.go` to begin with: + +```go +//go:build system_test + +package systemtests + +import ( + "testing" +) + +func TestQueryTotalSupply(t *testing.T) { + sut.ResetChain(t) + sut.StartChain(t) + + cli := NewCLIWrapper(t, sut, verbose) + raw := cli.CustomQuery("q", "bank", "total-supply") + t.Log("### got: " + raw) +} +``` +The file begins with a Go build tag to exclude it from regular go test runs. +All tests in the `systemtests` folder build upon the *test runner* initialized in `main_test.go`. +This gives you a multi node chain started on your box. +It is a good practice to reset state in the beginning so that you have a stable base. + +The system tests framework comes with a CLI wrapper that makes it easier to interact or parse results. +In this example we want to execute `simd q bank total-supply --output json --node tcp://localhost:26657` which queries the bank module. +Then print the result to for the next steps + +### Run the test + +```shell +go test -mod=readonly -tags='system_test' -v ./... --run TestQueryTotalSupply --verbose +``` + +This give very verbose output. You would see all simd CLI commands used for starting the server or by the client to interact. +In the example code, we just log the output. Watch out for +```shell + bank_test.go:15: ### got: { + "supply": [ + { + "denom": "stake", + "amount": "2000000190" + }, + { + "denom": "testtoken", + "amount": "4000000000" + } + ], + "pagination": { + "total": "2" + } + } +``` + +At the end is a tail from the server log printed. This can sometimes be handy when debugging issues. + + +### Tips + +* Passing `--nodes-count=1` overwrites the default node count and can speed up your test for local runs \ No newline at end of file From a3e8d668b8fb0643f084d7d8661455ea93c8868a Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Fri, 28 Jun 2024 15:07:22 +0200 Subject: [PATCH 2/5] Working with json --- tests/systemtests/bank_test.go | 17 ++++++++++- tests/systemtests/getting_started.md | 43 ++++++++++++++++++++++++++-- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/tests/systemtests/bank_test.go b/tests/systemtests/bank_test.go index 531f49a64b6d..a82bb703a38a 100644 --- a/tests/systemtests/bank_test.go +++ b/tests/systemtests/bank_test.go @@ -3,7 +3,12 @@ package systemtests import ( + "fmt" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tidwall/gjson" ) func TestQueryTotalSupply(t *testing.T) { @@ -12,5 +17,15 @@ func TestQueryTotalSupply(t *testing.T) { cli := NewCLIWrapper(t, sut, verbose) raw := cli.CustomQuery("q", "bank", "total-supply") - t.Log("### got: " + raw) + + exp := map[string]int64{ + "stake": 2000000190, + "testtoken": 4000000000, + } + require.Len(t, gjson.Get(raw, "supply").Array(), len(exp), raw) + + for k, v := range exp { + got := gjson.Get(raw, fmt.Sprintf("supply.#(denom==%q).amount", k)).Int() + assert.Equal(t, v, got, raw) + } } diff --git a/tests/systemtests/getting_started.md b/tests/systemtests/getting_started.md index 65987182f9d5..cb0d46f9bfdd 100644 --- a/tests/systemtests/getting_started.md +++ b/tests/systemtests/getting_started.md @@ -14,7 +14,7 @@ mkdir -p ./tests/systemtests/binaries cp ./build/simd ./tests/systemtests/binaries/ ``` -## Writing the first system test +## Part 1: Writing the first system test Switch to the `tests/systemtests` folder to work from here. @@ -45,7 +45,8 @@ This gives you a multi node chain started on your box. It is a good practice to reset state in the beginning so that you have a stable base. The system tests framework comes with a CLI wrapper that makes it easier to interact or parse results. -In this example we want to execute `simd q bank total-supply --output json --node tcp://localhost:26657` which queries the bank module. +In this example we want to execute `simd q bank total-supply --output json --node tcp://localhost:26657` which queries +the bank module. Then print the result to for the next steps ### Run the test @@ -79,4 +80,40 @@ At the end is a tail from the server log printed. This can sometimes be handy wh ### Tips -* Passing `--nodes-count=1` overwrites the default node count and can speed up your test for local runs \ No newline at end of file +* Passing `--nodes-count=1` overwrites the default node count and can speed up your test for local runs + +## Part 2: Working with json + +When we have a json response, the [gjson](https://github.com/tidwall/gjson) lib can shine. It comes with jquery like +syntax that makes it easy to navigation within the document. + +For example `gjson.Get(raw, "supply").Array()` gives us all the childs to `supply` as an array. +Or `gjson.Get("supply.#(denom==stake).amount").Int()` for the amount of the stake token as int64 type. + +In order to test our assumptions in the system test, we modify the code to use `gjson` to fetch the data: + +```go + raw := cli.CustomQuery("q", "bank", "total-supply") + + exp := map[string]int64{ + "stake": 2000000190, + "testtoken": 4000000000, + } + require.Len(t, gjson.Get(raw, "supply").Array(), len(exp), raw) + + for k, v := range exp { + got := gjson.Get(raw, fmt.Sprintf("supply.#(denom==%q).amount", k)).Int() + assert.Equal(t, v, got, raw) + } +``` + +### Run the test + +```shell +go test -mod=readonly -tags='system_test' -v ./... --run TestQueryTotalSupply --verbose +``` + +### Tips + +* Putting the `raw` json response to the assert/require statements helps with debugging on failures. You are usually lacking + context when you look at the values only. From d1fa94b9a81cb6adf44fcea7d5efd81bfad2027e Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Fri, 28 Jun 2024 16:00:38 +0200 Subject: [PATCH 3/5] Set state via genesis --- tests/systemtests/bank_test.go | 36 +++++++++++++++-- tests/systemtests/getting_started.md | 58 +++++++++++++++++++++++++++- 2 files changed, 89 insertions(+), 5 deletions(-) diff --git a/tests/systemtests/bank_test.go b/tests/systemtests/bank_test.go index a82bb703a38a..8d190927a89a 100644 --- a/tests/systemtests/bank_test.go +++ b/tests/systemtests/bank_test.go @@ -3,7 +3,10 @@ package systemtests import ( + "encoding/json" "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/tidwall/sjson" "testing" "github.com/stretchr/testify/assert" @@ -13,14 +16,41 @@ import ( func TestQueryTotalSupply(t *testing.T) { sut.ResetChain(t) + cli := NewCLIWrapper(t, sut, verbose) + + sut.ModifyGenesisJSON(t, func(genesis []byte) []byte { + // disable inflation + genesis, err := sjson.SetRawBytes(genesis, "app_state.mint.minter.inflation", []byte(`"0.000000000000000000"`)) + require.NoError(t, err) + + // add new token to supply + var supply []json.RawMessage + rawSupply := gjson.Get(string(genesis), "app_state.bank.supply").String() + require.NoError(t, json.Unmarshal([]byte(rawSupply), &supply)) + supply = append(supply, json.RawMessage(`{"denom": "mytoken","amount": "1000000"}`)) + newSupply, err := json.Marshal(supply) + require.NoError(t, err) + genesis, err = sjson.SetRawBytes(genesis, "app_state.bank.supply", newSupply) + require.NoError(t, err) + + // add amount to any balance + anyAddr := cli.GetKeyAddr("node0") + newBalances := GetGenesisBalance(genesis, anyAddr).Add(sdk.NewInt64Coin("mytoken", 1000000)) + newBalancesBz, err := newBalances.MarshalJSON() + require.NoError(t, err) + newState, err := sjson.SetRawBytes(genesis, fmt.Sprintf("app_state.bank.balances.#[address==%q]#.coins", anyAddr), newBalancesBz) + require.NoError(t, err) + return newState + }) + sut.StartChain(t) - cli := NewCLIWrapper(t, sut, verbose) raw := cli.CustomQuery("q", "bank", "total-supply") exp := map[string]int64{ - "stake": 2000000190, - "testtoken": 4000000000, + "stake": int64(500000000 * sut.nodesCount), + "testtoken": int64(1000000000 * sut.nodesCount), + "mytoken": 1000000, } require.Len(t, gjson.Get(raw, "supply").Array(), len(exp), raw) diff --git a/tests/systemtests/getting_started.md b/tests/systemtests/getting_started.md index cb0d46f9bfdd..d5da44730f2e 100644 --- a/tests/systemtests/getting_started.md +++ b/tests/systemtests/getting_started.md @@ -96,8 +96,8 @@ In order to test our assumptions in the system test, we modify the code to use ` raw := cli.CustomQuery("q", "bank", "total-supply") exp := map[string]int64{ - "stake": 2000000190, - "testtoken": 4000000000, + "stake": int64(500000000 * sut.nodesCount), + "testtoken": int64(1000000000 * sut.nodesCount), } require.Len(t, gjson.Get(raw, "supply").Array(), len(exp), raw) @@ -106,6 +106,7 @@ In order to test our assumptions in the system test, we modify the code to use ` assert.Equal(t, v, got, raw) } ``` +The assumption on the staking token usually fails due to inflation minted on the staking token. Let's fix this in the next step ### Run the test @@ -117,3 +118,56 @@ go test -mod=readonly -tags='system_test' -v ./... --run TestQueryTotalSupply - * Putting the `raw` json response to the assert/require statements helps with debugging on failures. You are usually lacking context when you look at the values only. + + +## Part 3: Setting state via genesis + +First step is to disable inflation. This can be done via the `ModifyGenesisJSON` helper. But to add some complexity, +we also introduce a new token and update the balance of the account for key `node0`. +The setup code looks quite big and unreadable now. Usually a good time to think about extracting helper functions for +common operations. The `genesis_io.go` file contains some examples already. I would skip this and take this to showcase the mix +of `gjson`, `sjson` and stdlib json operations. + +```go + sut.ResetChain(t) + cli := NewCLIWrapper(t, sut, verbose) + + sut.ModifyGenesisJSON(t, func(genesis []byte) []byte { + // disable inflation + genesis, err := sjson.SetRawBytes(genesis, "app_state.mint.minter.inflation", []byte(`"0.000000000000000000"`)) + require.NoError(t, err) + + // add new token to supply + var supply []json.RawMessage + rawSupply := gjson.Get(string(genesis), "app_state.bank.supply").String() + require.NoError(t, json.Unmarshal([]byte(rawSupply), &supply)) + supply = append(supply, json.RawMessage(`{"denom": "mytoken","amount": "1000000"}`)) + newSupply, err := json.Marshal(supply) + require.NoError(t, err) + genesis, err = sjson.SetRawBytes(genesis, "app_state.bank.supply", newSupply) + require.NoError(t, err) + + // add amount to any balance + anyAddr := cli.GetKeyAddr("node0") + newBalances := GetGenesisBalance(genesis, anyAddr).Add(sdk.NewInt64Coin("mytoken", 1000000)) + newBalancesBz, err := newBalances.MarshalJSON() + require.NoError(t, err) + newState, err := sjson.SetRawBytes(genesis, fmt.Sprintf("app_state.bank.balances.#[address==%q]#.coins", anyAddr), newBalancesBz) + require.NoError(t, err) + return newState + }) + sut.StartChain(t) +``` +Next step is to add the new token to the assert map. But we can also make it more resilient to different node counts. + +```go + exp := map[string]int64{ + "stake": int64(500000000 * sut.nodesCount), + "testtoken": int64(1000000000 * sut.nodesCount), + "mytoken": 1000000, + } +``` + +```shell +go test -mod=readonly -tags='system_test' -v ./... --run TestQueryTotalSupply --verbose --nodes-count=1 +``` From 0377891ab3fbb5ee4fddb274307f9b0762d4ac6a Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Fri, 28 Jun 2024 16:20:39 +0200 Subject: [PATCH 4/5] Set state via TX --- tests/systemtests/bank_test.go | 53 +++++++++++++++++++--------- tests/systemtests/getting_started.md | 32 +++++++++++++++++ 2 files changed, 68 insertions(+), 17 deletions(-) diff --git a/tests/systemtests/bank_test.go b/tests/systemtests/bank_test.go index 8d190927a89a..5df4953114b0 100644 --- a/tests/systemtests/bank_test.go +++ b/tests/systemtests/bank_test.go @@ -15,10 +15,45 @@ import ( ) func TestQueryTotalSupply(t *testing.T) { + // scenario: + // given a chain with a custom token on genesis + // when an amount is burned + // then this is reflected in the total supply + sut.ResetChain(t) cli := NewCLIWrapper(t, sut, verbose) + sut.ModifyGenesisJSON(t, setupGenesis(t, cli)) + sut.StartChain(t) + + raw := cli.CustomQuery("q", "bank", "total-supply") + + exp := map[string]int64{ + "stake": int64(500000000 * sut.nodesCount), + "testtoken": int64(1000000000 * sut.nodesCount), + "mytoken": 1_000_000, + } + require.Len(t, gjson.Get(raw, "supply").Array(), len(exp), raw) - sut.ModifyGenesisJSON(t, func(genesis []byte) []byte { + for k, v := range exp { + got := gjson.Get(raw, fmt.Sprintf("supply.#(denom==%q).amount", k)).Int() + assert.Equal(t, v, got, raw) + } + + // and when + txHash := cli.Run("tx", "bank", "burn", "node0", "400000mytoken") + RequireTxSuccess(t, txHash) + // then + exp["mytoken"] = 600_000 // update expected state + raw = cli.CustomQuery("q", "bank", "total-supply") + for k, v := range exp { + got := gjson.Get(raw, fmt.Sprintf("supply.#(denom==%q).amount", k)).Int() + assert.Equal(t, v, got, raw) + } + assert.Equal(t, int64(600_000), cli.QueryBalance(cli.GetKeyAddr("node0"), "mytoken")) +} + +func setupGenesis(t *testing.T, cli *CLIWrapper) func(genesis []byte) []byte { + return func(genesis []byte) []byte { // disable inflation genesis, err := sjson.SetRawBytes(genesis, "app_state.mint.minter.inflation", []byte(`"0.000000000000000000"`)) require.NoError(t, err) @@ -41,21 +76,5 @@ func TestQueryTotalSupply(t *testing.T) { newState, err := sjson.SetRawBytes(genesis, fmt.Sprintf("app_state.bank.balances.#[address==%q]#.coins", anyAddr), newBalancesBz) require.NoError(t, err) return newState - }) - - sut.StartChain(t) - - raw := cli.CustomQuery("q", "bank", "total-supply") - - exp := map[string]int64{ - "stake": int64(500000000 * sut.nodesCount), - "testtoken": int64(1000000000 * sut.nodesCount), - "mytoken": 1000000, - } - require.Len(t, gjson.Get(raw, "supply").Array(), len(exp), raw) - - for k, v := range exp { - got := gjson.Get(raw, fmt.Sprintf("supply.#(denom==%q).amount", k)).Int() - assert.Equal(t, v, got, raw) } } diff --git a/tests/systemtests/getting_started.md b/tests/systemtests/getting_started.md index d5da44730f2e..3d38fdfc19a0 100644 --- a/tests/systemtests/getting_started.md +++ b/tests/systemtests/getting_started.md @@ -171,3 +171,35 @@ Next step is to add the new token to the assert map. But we can also make it mor ```shell go test -mod=readonly -tags='system_test' -v ./... --run TestQueryTotalSupply --verbose --nodes-count=1 ``` + +## Part 4: Set state via TX + +Complexer workflows and tests require modifying state on a running chain. This works only with builtin logic and operations. +If we want to burn some our new tokens, we need to submit a bank burn message to do this. +The CLI wrapper works similar to the query. Just pass the parameters. It uses the `node0` key as *default*: + +```go + // and when + txHash := cli.Run("tx", "bank", "burn", "node0", "400000mytoken") + RequireTxSuccess(t, txHash) +``` +`RequireTxSuccess` or `RequireTxFailure` can be used to ensure the expected result of the operation. +Next, check that the changes are applied. +```go + exp["mytoken"] = 600_000 // update expected state + raw = cli.CustomQuery("q", "bank", "total-supply") + for k, v := range exp { + got := gjson.Get(raw, fmt.Sprintf("supply.#(denom==%q).amount", k)).Int() + assert.Equal(t, v, got, raw) + } + assert.Equal(t, int64(600_000), cli.QueryBalance(cli.GetKeyAddr("node0"), "mytoken")) +``` + +While tests are still more or less readable, it can gets harder the longer they are. I found it helpful to add +some comments at the beginning to describe what the intention is. For example: +```go + // scenario: + // given a chain with a custom token on genesis + // when an amount is burned + // then this is reflected in the total supply +``` \ No newline at end of file From a1fab68fb070f41040d3394b078ca36b48876b0c Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Wed, 4 Sep 2024 17:17:50 +0200 Subject: [PATCH 5/5] docs --- tests/systemtests/README.md | 15 +++++- tests/systemtests/bank_test.go | 80 ---------------------------- tests/systemtests/getting_started.md | 12 ++++- 3 files changed, 24 insertions(+), 83 deletions(-) delete mode 100644 tests/systemtests/bank_test.go diff --git a/tests/systemtests/README.md b/tests/systemtests/README.md index ab20d155f08f..ac9fcb49cdc9 100644 --- a/tests/systemtests/README.md +++ b/tests/systemtests/README.md @@ -3,23 +3,32 @@ Test framework for system tests. Starts and interacts with a (multi node) blockchain in Go. Supports + * CLI * Servers * Events * RPC Uses: + * testify * gjson * sjson -Server and client side are executed on the host machine + +Server and client side are executed on the host machine. ## Developer + ### Test strategy + System tests cover the full stack via cli and a running (multi node) network. They are more expensive (in terms of time/ cpu) to run compared to unit or integration tests. Therefore, we focus on the **critical path** and do not cover every condition. +## How to use + +Read the [getting_started.md](getting_started.md) guide to get started. + ### Execute a single test ```sh @@ -33,7 +42,9 @@ Test cli parameters * `-nodes-count` int - number of nodes in the cluster (default 4) # Port ranges + With *n* nodes: + * `26657` - `26657+n` - RPC * `1317` - `1317+n` - API * `9090` - `9090+n` - GRPC @@ -47,4 +58,4 @@ For example Node *3* listens on `26660` for RPC calls ## Disclaimer -This is based on the system test framework in [wasmd](https://github.com/CosmWasm/wasmd) built by Confio. \ No newline at end of file +This is based on the system test framework in [wasmd](https://github.com/CosmWasm/wasmd) built by Confio. diff --git a/tests/systemtests/bank_test.go b/tests/systemtests/bank_test.go deleted file mode 100644 index 5df4953114b0..000000000000 --- a/tests/systemtests/bank_test.go +++ /dev/null @@ -1,80 +0,0 @@ -//go:build system_test - -package systemtests - -import ( - "encoding/json" - "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/tidwall/sjson" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/tidwall/gjson" -) - -func TestQueryTotalSupply(t *testing.T) { - // scenario: - // given a chain with a custom token on genesis - // when an amount is burned - // then this is reflected in the total supply - - sut.ResetChain(t) - cli := NewCLIWrapper(t, sut, verbose) - sut.ModifyGenesisJSON(t, setupGenesis(t, cli)) - sut.StartChain(t) - - raw := cli.CustomQuery("q", "bank", "total-supply") - - exp := map[string]int64{ - "stake": int64(500000000 * sut.nodesCount), - "testtoken": int64(1000000000 * sut.nodesCount), - "mytoken": 1_000_000, - } - require.Len(t, gjson.Get(raw, "supply").Array(), len(exp), raw) - - for k, v := range exp { - got := gjson.Get(raw, fmt.Sprintf("supply.#(denom==%q).amount", k)).Int() - assert.Equal(t, v, got, raw) - } - - // and when - txHash := cli.Run("tx", "bank", "burn", "node0", "400000mytoken") - RequireTxSuccess(t, txHash) - // then - exp["mytoken"] = 600_000 // update expected state - raw = cli.CustomQuery("q", "bank", "total-supply") - for k, v := range exp { - got := gjson.Get(raw, fmt.Sprintf("supply.#(denom==%q).amount", k)).Int() - assert.Equal(t, v, got, raw) - } - assert.Equal(t, int64(600_000), cli.QueryBalance(cli.GetKeyAddr("node0"), "mytoken")) -} - -func setupGenesis(t *testing.T, cli *CLIWrapper) func(genesis []byte) []byte { - return func(genesis []byte) []byte { - // disable inflation - genesis, err := sjson.SetRawBytes(genesis, "app_state.mint.minter.inflation", []byte(`"0.000000000000000000"`)) - require.NoError(t, err) - - // add new token to supply - var supply []json.RawMessage - rawSupply := gjson.Get(string(genesis), "app_state.bank.supply").String() - require.NoError(t, json.Unmarshal([]byte(rawSupply), &supply)) - supply = append(supply, json.RawMessage(`{"denom": "mytoken","amount": "1000000"}`)) - newSupply, err := json.Marshal(supply) - require.NoError(t, err) - genesis, err = sjson.SetRawBytes(genesis, "app_state.bank.supply", newSupply) - require.NoError(t, err) - - // add amount to any balance - anyAddr := cli.GetKeyAddr("node0") - newBalances := GetGenesisBalance(genesis, anyAddr).Add(sdk.NewInt64Coin("mytoken", 1000000)) - newBalancesBz, err := newBalances.MarshalJSON() - require.NoError(t, err) - newState, err := sjson.SetRawBytes(genesis, fmt.Sprintf("app_state.bank.balances.#[address==%q]#.coins", anyAddr), newBalancesBz) - require.NoError(t, err) - return newState - } -} diff --git a/tests/systemtests/getting_started.md b/tests/systemtests/getting_started.md index 3d38fdfc19a0..47bee4dafa5f 100644 --- a/tests/systemtests/getting_started.md +++ b/tests/systemtests/getting_started.md @@ -4,10 +4,13 @@ Build a new binary from current branch and copy it to the `tests/systemtests/binaries` folder by running system tests. In project root: + ```shell make test-system ``` + Or via manual steps + ```shell make build mkdir -p ./tests/systemtests/binaries @@ -39,6 +42,7 @@ func TestQueryTotalSupply(t *testing.T) { t.Log("### got: " + raw) } ``` + The file begins with a Go build tag to exclude it from regular go test runs. All tests in the `systemtests` folder build upon the *test runner* initialized in `main_test.go`. This gives you a multi node chain started on your box. @@ -57,6 +61,7 @@ go test -mod=readonly -tags='system_test' -v ./... --run TestQueryTotalSupply - This give very verbose output. You would see all simd CLI commands used for starting the server or by the client to interact. In the example code, we just log the output. Watch out for + ```shell bank_test.go:15: ### got: { "supply": [ @@ -106,6 +111,7 @@ In order to test our assumptions in the system test, we modify the code to use ` assert.Equal(t, v, got, raw) } ``` + The assumption on the staking token usually fails due to inflation minted on the staking token. Let's fix this in the next step ### Run the test @@ -158,6 +164,7 @@ of `gjson`, `sjson` and stdlib json operations. }) sut.StartChain(t) ``` + Next step is to add the new token to the assert map. But we can also make it more resilient to different node counts. ```go @@ -183,8 +190,10 @@ The CLI wrapper works similar to the query. Just pass the parameters. It uses th txHash := cli.Run("tx", "bank", "burn", "node0", "400000mytoken") RequireTxSuccess(t, txHash) ``` + `RequireTxSuccess` or `RequireTxFailure` can be used to ensure the expected result of the operation. Next, check that the changes are applied. + ```go exp["mytoken"] = 600_000 // update expected state raw = cli.CustomQuery("q", "bank", "total-supply") @@ -197,9 +206,10 @@ Next, check that the changes are applied. While tests are still more or less readable, it can gets harder the longer they are. I found it helpful to add some comments at the beginning to describe what the intention is. For example: + ```go // scenario: // given a chain with a custom token on genesis // when an amount is burned // then this is reflected in the total supply -``` \ No newline at end of file +```