- package e2e_test
-
- import (
- "context"
- "os"
- "sort"
- "sync"
- "testing"
-
- "github.com/stretchr/testify/require"
-
- rpchttp "github.com/tendermint/tendermint/rpc/client/http"
- rpctypes "github.com/tendermint/tendermint/rpc/coretypes"
- e2e "github.com/tendermint/tendermint/test/e2e/pkg"
- "github.com/tendermint/tendermint/types"
- )
-
- func init() {
- // This can be used to manually specify a testnet manifest and/or node to
- // run tests against. The testnet must have been started by the runner first.
- // os.Setenv("E2E_MANIFEST", "networks/ci.toml")
- // os.Setenv("E2E_NODE", "validator01")
- }
-
- var (
- testnetCache = map[string]e2e.Testnet{}
- testnetCacheMtx = sync.Mutex{}
- blocksCache = map[string][]*types.Block{}
- blocksCacheMtx = sync.Mutex{}
- )
-
- // testNode runs tests for testnet nodes. The callback function is
- // given a single stateful node to test, running as a subtest in
- // parallel with other subtests.
- //
- // The testnet manifest must be given as the envvar E2E_MANIFEST. If not set,
- // these tests are skipped so that they're not picked up during normal unit
- // test runs. If E2E_NODE is also set, only the specified node is tested,
- // otherwise all nodes are tested.
- func testNode(t *testing.T, testFunc func(context.Context, *testing.T, e2e.Node)) {
- t.Helper()
-
- testnet := loadTestnet(t)
- nodes := testnet.Nodes
-
- if name := os.Getenv("E2E_NODE"); name != "" {
- node := testnet.LookupNode(name)
- require.NotNil(t, node, "node %q not found in testnet %q", name, testnet.Name)
- nodes = []*e2e.Node{node}
- } else {
- sort.Slice(nodes, func(i, j int) bool {
- return nodes[i].Name < nodes[j].Name
- })
- }
-
- for _, node := range nodes {
- node := *node
-
- if node.Stateless() {
- continue
- }
-
- t.Run(node.Name, func(t *testing.T) {
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- testFunc(ctx, t, node)
- })
- }
- }
-
- // loadTestnet loads the testnet based on the E2E_MANIFEST envvar.
- func loadTestnet(t *testing.T) e2e.Testnet {
- t.Helper()
-
- manifest := os.Getenv("E2E_MANIFEST")
- if manifest == "" {
- t.Skip("E2E_MANIFEST not set, not an end-to-end test run")
- }
-
- testnetCacheMtx.Lock()
- defer testnetCacheMtx.Unlock()
- if testnet, ok := testnetCache[manifest]; ok {
- return testnet
- }
-
- testnet, err := e2e.LoadTestnet(manifest)
- require.NoError(t, err)
- testnetCache[manifest] = *testnet
- return *testnet
- }
-
- // fetchBlockChain fetches a complete, up-to-date block history from
- // the freshest testnet archive node.
- func fetchBlockChain(ctx context.Context, t *testing.T) []*types.Block {
- t.Helper()
-
- testnet := loadTestnet(t)
-
- // Find the freshest archive node
- var (
- client *rpchttp.HTTP
- status *rpctypes.ResultStatus
- )
- for _, node := range testnet.ArchiveNodes() {
- c, err := node.Client()
- require.NoError(t, err)
- s, err := c.Status(ctx)
- require.NoError(t, err)
- if status == nil || s.SyncInfo.LatestBlockHeight > status.SyncInfo.LatestBlockHeight {
- client = c
- status = s
- }
- }
- require.NotNil(t, client, "couldn't find an archive node")
-
- // Fetch blocks. Look for existing block history in the block cache, and
- // extend it with any new blocks that have been produced.
- blocksCacheMtx.Lock()
- defer blocksCacheMtx.Unlock()
-
- from := status.SyncInfo.EarliestBlockHeight
- to := status.SyncInfo.LatestBlockHeight
- blocks, ok := blocksCache[testnet.Name]
- if !ok {
- blocks = make([]*types.Block, 0, to-from+1)
- }
- if len(blocks) > 0 {
- from = blocks[len(blocks)-1].Height + 1
- }
-
- for h := from; h <= to; h++ {
- resp, err := client.Block(ctx, &(h))
- require.NoError(t, err)
- require.NotNil(t, resp.Block)
- require.Equal(t, h, resp.Block.Height, "unexpected block height %v", resp.Block.Height)
- blocks = append(blocks, resp.Block)
- }
- require.NotEmpty(t, blocks, "blockchain does not contain any blocks")
- blocksCache[testnet.Name] = blocks
-
- return blocks
- }
|