From b18f6631c96a793e87b9a8274e3f4f4a0a07bb31 Mon Sep 17 00:00:00 2001 From: Quentin McGaw Date: Mon, 4 Apr 2022 14:33:41 +0000 Subject: [PATCH] chore(tests): `retry.UntilNoError` function - Use in `compareBlocksByNumber` - Use in `waitForNode` - Change `GetBlockHash` to not retry RPC - Remove `PostWithRetry` --- tests/stress/helpers.go | 18 ++++++---------- tests/utils/node/waitnode.go | 29 ++++++++----------------- tests/utils/retry/untilnoerror.go | 36 +++++++++++++++++++++++++++++++ tests/utils/rpc/chain.go | 4 +--- tests/utils/rpc/request.go | 36 ------------------------------- 5 files changed, 52 insertions(+), 71 deletions(-) create mode 100644 tests/utils/retry/untilnoerror.go diff --git a/tests/stress/helpers.go b/tests/stress/helpers.go index d1cf35a00e7..4dc7ed2f597 100644 --- a/tests/stress/helpers.go +++ b/tests/stress/helpers.go @@ -14,6 +14,7 @@ import ( "github.com/ChainSafe/gossamer/internal/log" "github.com/ChainSafe/gossamer/lib/common" "github.com/ChainSafe/gossamer/tests/utils/node" + "github.com/ChainSafe/gossamer/tests/utils/retry" "github.com/ChainSafe/gossamer/tests/utils/rpc" "github.com/stretchr/testify/require" @@ -86,18 +87,11 @@ func compareBlocksByNumber(ctx context.Context, t *testing.T, nodes node.Nodes, nodeKey: node.GetKey(), } - for { // retry until context gets canceled - result.hash, result.err = rpc.GetBlockHash(ctx, node.GetRPCPort(), num) - - if err := ctx.Err(); err != nil { - result.err = err - break - } - - if result.err == nil { - break - } - } + const retryWait = 200 * time.Millisecond + result.err = retry.UntilNoError(ctx, retryWait, func() (err error) { + result.hash, err = rpc.GetBlockHash(ctx, node.GetRPCPort(), num) + return err + }) results <- result }(n) diff --git a/tests/utils/node/waitnode.go b/tests/utils/node/waitnode.go index 96de01d2f49..fd4662eb5cb 100644 --- a/tests/utils/node/waitnode.go +++ b/tests/utils/node/waitnode.go @@ -6,39 +6,28 @@ import ( "fmt" "time" + "github.com/ChainSafe/gossamer/tests/utils/retry" "github.com/ChainSafe/gossamer/tests/utils/rpc" ) func waitForNode(ctx context.Context, rpcPort string) (err error) { - tries := 0 - const checkNodeStartedTimeout = time.Second const retryWait = time.Second - for ctx.Err() == nil { - tries++ - + err = retry.UntilNoError(ctx, retryWait, func() (err error) { + const checkNodeStartedTimeout = time.Second checkNodeCtx, checkNodeCancel := context.WithTimeout(ctx, checkNodeStartedTimeout) - err = checkNodeStarted(checkNodeCtx, "http://localhost:"+rpcPort) checkNodeCancel() - if err == nil { - return nil - } + return err + }) - retryWaitCtx, retryWaitCancel := context.WithTimeout(ctx, retryWait) - <-retryWaitCtx.Done() - retryWaitCancel() + if err != nil { + return fmt.Errorf("node did not start: %w", err) } - totalTryTime := time.Duration(tries) * checkNodeStartedTimeout - tryWord := "try" - if tries > 1 { - tryWord = "tries" - } - return fmt.Errorf("node did not start after %d %s during %s: %w", - tries, tryWord, totalTryTime, err) + return nil } -var errNodeNotExpectingPeers = errors.New("node shoult expect to have peers") +var errNodeNotExpectingPeers = errors.New("node should expect to have peers") // checkNodeStarted check if gossamer node is started func checkNodeStarted(ctx context.Context, gossamerHost string) error { diff --git a/tests/utils/retry/untilnoerror.go b/tests/utils/retry/untilnoerror.go new file mode 100644 index 00000000000..f266f2f5e76 --- /dev/null +++ b/tests/utils/retry/untilnoerror.go @@ -0,0 +1,36 @@ +package retry + +import ( + "context" + "fmt" + "time" +) + +// UntilNoError retries the function `f` until it returns a nil error. +// It waits `retryWait` after each failed call to `f`. +// If the context `ctx` is canceled, the function returns +// immediately an error stating the number of failed tries, +// for how long it retried and the last error returned by `f`. +func UntilNoError(ctx context.Context, retryWait time.Duration, + f func() (err error)) (err error) { + failedTries := 0 + for ctx.Err() == nil { + err = f() + if err == nil { + return nil + } + + failedTries++ + waitCtx, waitCancel := context.WithTimeout(ctx, retryWait) + <-waitCtx.Done() + waitCancel() + } + + totalRetryTime := time.Duration(failedTries) * retryWait + tryWord := "try" + if failedTries > 1 { + tryWord = "tries" + } + return fmt.Errorf("failed after %d %s during %s: %w (%s)", + failedTries, tryWord, totalRetryTime, err, ctx.Err()) +} diff --git a/tests/utils/rpc/chain.go b/tests/utils/rpc/chain.go index f8b0582290d..d1b4b1ec881 100644 --- a/tests/utils/rpc/chain.go +++ b/tests/utils/rpc/chain.go @@ -7,7 +7,6 @@ import ( "context" "fmt" "strconv" - "time" "github.com/ChainSafe/gossamer/dot/rpc/modules" "github.com/ChainSafe/gossamer/dot/types" @@ -44,8 +43,7 @@ func GetBlockHash(ctx context.Context, rpcPort, num string) (hash common.Hash, e endpoint := NewEndpoint(rpcPort) const method = "chain_getBlockHash" params := "[" + num + "]" - const requestWait = time.Second - respBody, err := PostWithRetry(ctx, endpoint, method, params, requestWait) + respBody, err := Post(ctx, endpoint, method, params) if err != nil { return hash, fmt.Errorf("cannot post RPC: %w", err) } diff --git a/tests/utils/rpc/request.go b/tests/utils/rpc/request.go index 5de5246fb25..f89e5cf49aa 100644 --- a/tests/utils/rpc/request.go +++ b/tests/utils/rpc/request.go @@ -11,7 +11,6 @@ import ( "fmt" "io" "net/http" - "time" "github.com/ChainSafe/gossamer/dot/types" "github.com/ChainSafe/gossamer/lib/common" @@ -52,41 +51,6 @@ func Post(ctx context.Context, endpoint, method, params string) (data []byte, er return data, nil } -// PostWithRetry repeatitively calls `Post` repeatitively -// until it succeeds within the requestWait duration or returns -// the last error if the context is canceled. -func PostWithRetry(ctx context.Context, endpoint, method, params string, - requestWait time.Duration) (data []byte, err error) { - try := 0 - for { - try++ - - postRPCCtx, postRPCCancel := context.WithTimeout(ctx, requestWait) - - data, err = Post(postRPCCtx, endpoint, method, params) - - if err == nil { - postRPCCancel() - return data, nil - } - - // wait for full requestWait duration or main context cancelation - <-postRPCCtx.Done() - postRPCCancel() - - if ctx.Err() != nil { - break - } - } - - totalTime := time.Duration(try) * requestWait - tryWord := "try" - if try > 1 { - tryWord = "tries" - } - return nil, fmt.Errorf("after %d %s totalling %s: %w", try, tryWord, totalTime, err) -} - var ( ErrResponseVersion = errors.New("unexpected response version received") ErrResponseError = errors.New("response error received")