- package e2e_test
-
- import (
- "bytes"
- "context"
- "fmt"
- "math/rand"
- "testing"
- "time"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-
- "github.com/tendermint/tendermint/rpc/client/http"
- e2e "github.com/tendermint/tendermint/test/e2e/pkg"
- "github.com/tendermint/tendermint/types"
- )
-
- // Tests that any initial state given in genesis has made it into the app.
- func TestApp_InitialState(t *testing.T) {
- testNode(t, func(t *testing.T, node e2e.Node) {
- if len(node.Testnet.InitialState) == 0 {
- return
- }
-
- client, err := node.Client()
- require.NoError(t, err)
- for k, v := range node.Testnet.InitialState {
- resp, err := client.ABCIQuery(ctx, "", []byte(k))
- require.NoError(t, err)
- assert.Equal(t, k, string(resp.Response.Key))
- assert.Equal(t, v, string(resp.Response.Value))
- }
- })
- }
-
- // Tests that the app hash (as reported by the app) matches the last
- // block and the node sync status.
- func TestApp_Hash(t *testing.T) {
- testNode(t, func(t *testing.T, node e2e.Node) {
- client, err := node.Client()
- require.NoError(t, err)
- info, err := client.ABCIInfo(ctx)
- require.NoError(t, err)
- require.NotEmpty(t, info.Response.LastBlockAppHash, "expected app to return app hash")
-
- status, err := client.Status(ctx)
- require.NoError(t, err)
- require.NotZero(t, status.SyncInfo.LatestBlockHeight)
-
- block, err := client.Block(ctx, &info.Response.LastBlockHeight)
- require.NoError(t, err)
-
- if info.Response.LastBlockHeight == block.Block.Height {
- require.Equal(t,
- fmt.Sprintf("%x", info.Response.LastBlockAppHash),
- fmt.Sprintf("%x", block.Block.AppHash.Bytes()),
- "app hash does not match last block's app hash")
- }
-
- require.True(t, status.SyncInfo.LatestBlockHeight >= info.Response.LastBlockHeight,
- "status out of sync with application")
- })
- }
-
- // Tests that the app and blockstore have and report the same height.
- func TestApp_Height(t *testing.T) {
- testNode(t, func(t *testing.T, node e2e.Node) {
- client, err := node.Client()
- require.NoError(t, err)
- info, err := client.ABCIInfo(ctx)
- require.NoError(t, err)
- require.NotZero(t, info.Response.LastBlockHeight)
-
- status, err := client.Status(ctx)
- require.NoError(t, err)
- require.NotZero(t, status.SyncInfo.LatestBlockHeight)
-
- block, err := client.Block(ctx, &info.Response.LastBlockHeight)
- require.NoError(t, err)
-
- require.Equal(t, info.Response.LastBlockHeight, block.Block.Height)
-
- require.True(t, status.SyncInfo.LatestBlockHeight >= info.Response.LastBlockHeight,
- "status out of sync with application")
- })
- }
-
- // Tests that we can set a value and retrieve it.
- func TestApp_Tx(t *testing.T) {
- type broadcastFunc func(context.Context, types.Tx) error
-
- testCases := []struct {
- Name string
- WaitTime time.Duration
- BroadcastTx func(client *http.HTTP) broadcastFunc
- ShouldSkip bool
- }{
- {
- Name: "Sync",
- WaitTime: time.Minute,
- BroadcastTx: func(client *http.HTTP) broadcastFunc {
- return func(ctx context.Context, tx types.Tx) error {
- _, err := client.BroadcastTxSync(ctx, tx)
- return err
- }
- },
- },
- {
- Name: "Commit",
- WaitTime: 15 * time.Second,
- // TODO: turn this check back on if it can
- // return reliably. Currently these calls have
- // a hard timeout of 10s (server side
- // configured). The Sync check is probably
- // safe.
- ShouldSkip: true,
- BroadcastTx: func(client *http.HTTP) broadcastFunc {
- return func(ctx context.Context, tx types.Tx) error {
- _, err := client.BroadcastTxCommit(ctx, tx)
- return err
- }
- },
- },
- {
- Name: "Async",
- WaitTime: 90 * time.Second,
- // TODO: turn this check back on if there's a
- // way to avoid failures in the case that the
- // transaction doesn't make it into the
- // mempool. (retries?)
- ShouldSkip: true,
- BroadcastTx: func(client *http.HTTP) broadcastFunc {
- return func(ctx context.Context, tx types.Tx) error {
- _, err := client.BroadcastTxAsync(ctx, tx)
- return err
- }
- },
- },
- }
-
- for idx, test := range testCases {
- if test.ShouldSkip {
- continue
- }
- t.Run(test.Name, func(t *testing.T) {
- // testNode calls t.Parallel as well, so we should
- // have a copy of the
- test := testCases[idx]
- testNode(t, func(t *testing.T, node e2e.Node) {
- client, err := node.Client()
- require.NoError(t, err)
-
- // Generate a random value, to prevent duplicate tx errors when
- // manually running the test multiple times for a testnet.
- bz := make([]byte, 32)
- _, err = rand.Read(bz)
- require.NoError(t, err)
-
- key := fmt.Sprintf("testapp-tx-%v", node.Name)
- value := fmt.Sprintf("%x", bz)
- tx := types.Tx(fmt.Sprintf("%v=%v", key, value))
-
- require.NoError(t, test.BroadcastTx(client)(ctx, tx))
-
- hash := tx.Hash()
-
- require.Eventuallyf(t, func() bool {
- txResp, err := client.Tx(ctx, hash, false)
- return err == nil && bytes.Equal(txResp.Tx, tx)
- },
- test.WaitTime, // timeout
- time.Second, // interval
- "submitted tx %X wasn't committed after %v",
- hash, test.WaitTime,
- )
-
- abciResp, err := client.ABCIQuery(ctx, "", []byte(key))
- require.NoError(t, err)
- assert.Equal(t, key, string(abciResp.Response.Key))
- assert.Equal(t, value, string(abciResp.Response.Value))
- })
-
- })
-
- }
-
- }
|