Skip to content

Commit

Permalink
chore(tests/stress): refactor compareBlocksByNumber
Browse files Browse the repository at this point in the history
- Takes in context
- Retry as long as context is not canceled
- Assert errors and common values
  • Loading branch information
qdm12 committed Mar 11, 2022
1 parent 8840bb5 commit 4a59c01
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 75 deletions.
4 changes: 0 additions & 4 deletions tests/stress/empty.go

This file was deleted.

2 changes: 0 additions & 2 deletions tests/stress/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,5 @@ import (
var (
errFinalizedBlockMismatch = errors.New("node finalised head hashes don't match")
errNoFinalizedBlock = errors.New("did not finalise block for round")
errNoBlockAtNumber = errors.New("no blocks found for given number")
errBlocksAtNumberMismatch = errors.New("different blocks found for given number")
errChainHeadMismatch = errors.New("node chain head hashes don't match")
)
94 changes: 40 additions & 54 deletions tests/stress/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
package stress

import (
"context"
"errors"
"fmt"
"sync"
"testing"
"time"

Expand Down Expand Up @@ -65,74 +65,60 @@ func compareChainHeadsWithRetry(t *testing.T, nodes []*utils.Node) error {

// compareBlocksByNumber calls getBlockByNumber for each node in the array
// it returns a map of block hashes to node key names, and an error if the hashes don't all match
func compareBlocksByNumber(t *testing.T, nodes []*utils.Node, num string) (map[common.Hash][]string, error) {
hashes := make(map[common.Hash][]string)
var errs []error
var mapMu sync.Mutex
var wg sync.WaitGroup
wg.Add(len(nodes))
func compareBlocksByNumber(ctx context.Context, t *testing.T, nodes []*utils.Node,
num string) (hashToKeys map[common.Hash][]string) {
type resultContainer struct {
hash common.Hash
nodeKey string
err error
}
results := make(chan resultContainer)

for _, node := range nodes {
go func(node *utils.Node) {
logger.Debugf("calling chain_getBlockHash for node index %d", node.Idx)
hash, err := utils.GetBlockHash(t, node, num)
mapMu.Lock()
defer func() {
mapMu.Unlock()
wg.Done()
}()
if err != nil {
errs = append(errs, err)
return
result := resultContainer{
nodeKey: node.Key,
}
logger.Debugf("got hash %s from node with key %s", hash, node.Key)

hashes[hash] = append(hashes[hash], node.Key)
}(node)
}
for { // retry until context gets canceled
result.hash, result.err = utils.GetBlockHash(t, node, num)

wg.Wait()

var err error
if len(errs) != 0 {
err = fmt.Errorf("%v", errs)
}
if err := ctx.Err(); err != nil {
result.err = err
break
}

if len(hashes) == 0 {
err = errNoBlockAtNumber
}
if result.err == nil {
break
}
}

if len(hashes) > 1 {
err = errBlocksAtNumberMismatch
results <- result
}(node)
}

return hashes, err
}

// compareBlocksByNumberWithRetry calls compareChainHeads, retrying up to maxRetries times if it errors.
func compareBlocksByNumberWithRetry(t *testing.T, nodes []*utils.Node, num string) (map[common.Hash][]string, error) {
var hashes map[common.Hash][]string
var err error
hashToKeys = make(map[common.Hash][]string, len(nodes))
for range nodes {
result := <-results
if err != nil {
continue // one failed, we don't care anymore
}

timeout := time.After(120 * time.Second)
doneBlockProduction:
for {
time.Sleep(time.Second)
select {
case <-timeout:
break doneBlockProduction
default:
hashes, err = compareBlocksByNumber(t, nodes, num)
if err == nil {
break doneBlockProduction
}
if result.err != nil {
err = result.err
continue
}
}

if err != nil {
err = fmt.Errorf("%w: hashes=%v", err, hashes)
hashToKeys[result.hash] = append(hashToKeys[result.hash], result.nodeKey)
}
return hashes, err

require.NoError(t, err)
require.Lenf(t, hashToKeys, 1,
"expected 1 block found for number %s but got %d block(s)",
num, len(hashToKeys))

return hashToKeys
}

// compareFinalizedHeads calls getFinalizedHeadByRound for each node in the array
Expand Down
71 changes: 56 additions & 15 deletions tests/stress/stress_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package stress

import (
"context"
"fmt"
"math/big"
"math/rand"
Expand Down Expand Up @@ -111,14 +112,18 @@ func TestSync_SingleBlockProducer(t *testing.T) {
}()

numCmps := 10
ctx := context.Background()

for i := 0; i < numCmps; i++ {
time.Sleep(3 * time.Second)
t.Log("comparing...", i)
hashes, err := compareBlocksByNumberWithRetry(t, nodes, strconv.Itoa(i))
if len(hashes) > 1 || len(hashes) == 0 {
require.NoError(t, err, i)
continue
}

const comparisonTimeout = 5 * time.Second
compareCtx, cancel := context.WithTimeout(ctx, comparisonTimeout)

hashes := compareBlocksByNumber(compareCtx, t, nodes, strconv.Itoa(i))

cancel()

// there will only be one key in the mapping
for _, nodesWithHash := range hashes {
Expand Down Expand Up @@ -163,13 +168,20 @@ func TestSync_MultipleEpoch(t *testing.T) {
// Wait for epoch to pass
time.Sleep(time.Duration(uint64(slotDuration.Nanoseconds()) * epochLength))

ctx := context.Background()

// Just checking that everythings operating as expected
header := utils.GetChainHead(t, nodes[0])
currentHeight := header.Number
for i := uint(0); i < currentHeight; i++ {
t.Log("comparing...", i)
_, err = compareBlocksByNumberWithRetry(t, nodes, strconv.Itoa(int(i)))
require.NoError(t, err, i)

const compareTimeout = 5 * time.Second
compareCtx, cancel := context.WithTimeout(ctx, compareTimeout)

_ = compareBlocksByNumber(compareCtx, t, nodes, strconv.Itoa(int(i)))

cancel()
}
}

Expand Down Expand Up @@ -197,11 +209,18 @@ func TestSync_SingleSyncingNode(t *testing.T) {
require.Len(t, errList, 0)
}()

ctx := context.Background()

numCmps := 100
for i := 0; i < numCmps; i++ {
t.Log("comparing...", i)
_, err = compareBlocksByNumberWithRetry(t, nodes, strconv.Itoa(i))
require.NoError(t, err, i)

const compareTimeout = 5 * time.Second
compareCtx, cancel := context.WithTimeout(ctx, compareTimeout)

_ = compareBlocksByNumber(compareCtx, t, nodes, strconv.Itoa(i))

cancel()
}
}

Expand Down Expand Up @@ -277,8 +296,16 @@ func TestSync_Bench(t *testing.T) {

// assert block is correct
t.Log("comparing block...", numBlocks)
_, err = compareBlocksByNumberWithRetry(t, nodes, fmt.Sprint(numBlocks))
require.NoError(t, err, numBlocks)

ctx := context.Background()

const compareTimeout = 5 * time.Second
compareCtx, cancel := context.WithTimeout(ctx, compareTimeout)

_ = compareBlocksByNumber(compareCtx, t, nodes, fmt.Sprint(numBlocks))

cancel()

time.Sleep(time.Second * 3)
}

Expand Down Expand Up @@ -328,11 +355,19 @@ func TestSync_Restart(t *testing.T) {
}
}()

ctx := context.Background()

numCmps := 12
for i := 0; i < numCmps; i++ {
t.Log("comparing...", i)
_, err = compareBlocksByNumberWithRetry(t, nodes, strconv.Itoa(i))
require.NoError(t, err, i)

const compareTimeout = 5 * time.Second
compareCtx, cancel := context.WithTimeout(ctx, compareTimeout)

_ = compareBlocksByNumber(compareCtx, t, nodes, strconv.Itoa(i))

cancel()

time.Sleep(time.Second * 5)
}
close(done)
Expand Down Expand Up @@ -476,8 +511,14 @@ func TestSync_SubmitExtrinsic(t *testing.T) {

require.True(t, included)

hashes, err := compareBlocksByNumberWithRetry(t, nodes, fmt.Sprint(extInBlock))
require.NoError(t, err, hashes)
ctx := context.Background()

const compareTimeout = 5 * time.Second
compareCtx, cancel := context.WithTimeout(ctx, compareTimeout)

_ = compareBlocksByNumber(compareCtx, t, nodes, fmt.Sprint(extInBlock))

cancel()
}

func Test_SubmitAndWatchExtrinsic(t *testing.T) {
Expand Down

0 comments on commit 4a59c01

Please sign in to comment.