You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

143 lines
3.8 KiB

  1. package e2e_test
  2. import (
  3. "context"
  4. "os"
  5. "sort"
  6. "sync"
  7. "testing"
  8. "github.com/stretchr/testify/require"
  9. rpchttp "github.com/tendermint/tendermint/rpc/client/http"
  10. rpctypes "github.com/tendermint/tendermint/rpc/coretypes"
  11. e2e "github.com/tendermint/tendermint/test/e2e/pkg"
  12. "github.com/tendermint/tendermint/types"
  13. )
  14. func init() {
  15. // This can be used to manually specify a testnet manifest and/or node to
  16. // run tests against. The testnet must have been started by the runner first.
  17. // os.Setenv("E2E_MANIFEST", "networks/ci.toml")
  18. // os.Setenv("E2E_NODE", "validator01")
  19. }
  20. var (
  21. testnetCache = map[string]e2e.Testnet{}
  22. testnetCacheMtx = sync.Mutex{}
  23. blocksCache = map[string][]*types.Block{}
  24. blocksCacheMtx = sync.Mutex{}
  25. )
  26. // testNode runs tests for testnet nodes. The callback function is
  27. // given a single stateful node to test, running as a subtest in
  28. // parallel with other subtests.
  29. //
  30. // The testnet manifest must be given as the envvar E2E_MANIFEST. If not set,
  31. // these tests are skipped so that they're not picked up during normal unit
  32. // test runs. If E2E_NODE is also set, only the specified node is tested,
  33. // otherwise all nodes are tested.
  34. func testNode(t *testing.T, testFunc func(context.Context, *testing.T, e2e.Node)) {
  35. t.Helper()
  36. testnet := loadTestnet(t)
  37. nodes := testnet.Nodes
  38. if name := os.Getenv("E2E_NODE"); name != "" {
  39. node := testnet.LookupNode(name)
  40. require.NotNil(t, node, "node %q not found in testnet %q", name, testnet.Name)
  41. nodes = []*e2e.Node{node}
  42. } else {
  43. sort.Slice(nodes, func(i, j int) bool {
  44. return nodes[i].Name < nodes[j].Name
  45. })
  46. }
  47. for _, node := range nodes {
  48. node := *node
  49. if node.Stateless() {
  50. continue
  51. }
  52. t.Run(node.Name, func(t *testing.T) {
  53. ctx, cancel := context.WithCancel(context.Background())
  54. defer cancel()
  55. testFunc(ctx, t, node)
  56. })
  57. }
  58. }
  59. // loadTestnet loads the testnet based on the E2E_MANIFEST envvar.
  60. func loadTestnet(t *testing.T) e2e.Testnet {
  61. t.Helper()
  62. manifest := os.Getenv("E2E_MANIFEST")
  63. if manifest == "" {
  64. t.Skip("E2E_MANIFEST not set, not an end-to-end test run")
  65. }
  66. testnetCacheMtx.Lock()
  67. defer testnetCacheMtx.Unlock()
  68. if testnet, ok := testnetCache[manifest]; ok {
  69. return testnet
  70. }
  71. testnet, err := e2e.LoadTestnet(manifest)
  72. require.NoError(t, err)
  73. testnetCache[manifest] = *testnet
  74. return *testnet
  75. }
  76. // fetchBlockChain fetches a complete, up-to-date block history from
  77. // the freshest testnet archive node.
  78. func fetchBlockChain(ctx context.Context, t *testing.T) []*types.Block {
  79. t.Helper()
  80. testnet := loadTestnet(t)
  81. // Find the freshest archive node
  82. var (
  83. client *rpchttp.HTTP
  84. status *rpctypes.ResultStatus
  85. )
  86. for _, node := range testnet.ArchiveNodes() {
  87. c, err := node.Client()
  88. require.NoError(t, err)
  89. s, err := c.Status(ctx)
  90. require.NoError(t, err)
  91. if status == nil || s.SyncInfo.LatestBlockHeight > status.SyncInfo.LatestBlockHeight {
  92. client = c
  93. status = s
  94. }
  95. }
  96. require.NotNil(t, client, "couldn't find an archive node")
  97. // Fetch blocks. Look for existing block history in the block cache, and
  98. // extend it with any new blocks that have been produced.
  99. blocksCacheMtx.Lock()
  100. defer blocksCacheMtx.Unlock()
  101. from := status.SyncInfo.EarliestBlockHeight
  102. to := status.SyncInfo.LatestBlockHeight
  103. blocks, ok := blocksCache[testnet.Name]
  104. if !ok {
  105. blocks = make([]*types.Block, 0, to-from+1)
  106. }
  107. if len(blocks) > 0 {
  108. from = blocks[len(blocks)-1].Height + 1
  109. }
  110. for h := from; h <= to; h++ {
  111. resp, err := client.Block(ctx, &(h))
  112. require.NoError(t, err)
  113. require.NotNil(t, resp.Block)
  114. require.Equal(t, h, resp.Block.Height, "unexpected block height %v", resp.Block.Height)
  115. blocks = append(blocks, resp.Block)
  116. }
  117. require.NotEmpty(t, blocks, "blockchain does not contain any blocks")
  118. blocksCache[testnet.Name] = blocks
  119. return blocks
  120. }