2023-02-22 13:06:55 +01:00
|
|
|
package backoff
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
2024-08-03 19:12:48 +02:00
|
|
|
"strings"
|
2023-02-22 13:06:55 +01:00
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
2024-07-12 08:59:31 +02:00
|
|
|
func TestBackoffRetry_Failure(t *testing.T) {
|
|
|
|
f := func(backoffFactor float64, backoffRetries int, cancelTimeout time.Duration, retryFunc func() error, resultExpected int) {
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
r := &Backoff{
|
|
|
|
retries: backoffRetries,
|
|
|
|
factor: backoffFactor,
|
|
|
|
minDuration: time.Millisecond * 10,
|
|
|
|
}
|
|
|
|
ctx := context.Background()
|
|
|
|
if cancelTimeout != 0 {
|
|
|
|
newCtx, cancelFn := context.WithTimeout(context.Background(), cancelTimeout)
|
|
|
|
ctx = newCtx
|
|
|
|
defer cancelFn()
|
|
|
|
}
|
|
|
|
|
|
|
|
result, err := r.Retry(ctx, retryFunc)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatalf("expecting non-nil error")
|
|
|
|
}
|
|
|
|
if result != uint64(resultExpected) {
|
|
|
|
t.Fatalf("unexpected result: got %d; want %d", result, resultExpected)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// return bad request
|
|
|
|
retryFunc := func() error {
|
|
|
|
return ErrBadRequest
|
|
|
|
}
|
|
|
|
f(0, 0, 0, retryFunc, 0)
|
|
|
|
|
|
|
|
// empty retries values
|
|
|
|
retryFunc = func() error {
|
|
|
|
time.Sleep(time.Millisecond * 100)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
f(0, 0, 0, retryFunc, 0)
|
|
|
|
|
|
|
|
// all retries failed test
|
|
|
|
backoffFactor := 0.1
|
|
|
|
backoffRetries := 5
|
|
|
|
cancelTimeout := time.Second * 0
|
|
|
|
retryFunc = func() error {
|
|
|
|
t := time.NewTicker(time.Millisecond * 5)
|
|
|
|
defer t.Stop()
|
|
|
|
for range t.C {
|
|
|
|
return fmt.Errorf("got some error")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
resultExpected := 5
|
|
|
|
f(backoffFactor, backoffRetries, cancelTimeout, retryFunc, resultExpected)
|
|
|
|
|
|
|
|
// cancel context
|
|
|
|
backoffFactor = 1.7
|
|
|
|
backoffRetries = 5
|
|
|
|
cancelTimeout = time.Millisecond * 40
|
|
|
|
retryFunc = func() error {
|
|
|
|
return fmt.Errorf("got some error")
|
|
|
|
}
|
|
|
|
resultExpected = 3
|
|
|
|
f(backoffFactor, backoffRetries, cancelTimeout, retryFunc, resultExpected)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestBackoffRetry_Success(t *testing.T) {
|
|
|
|
f := func(retryFunc func() error, resultExpected int) {
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
r := &Backoff{
|
|
|
|
retries: 5,
|
|
|
|
factor: 1.7,
|
|
|
|
minDuration: time.Millisecond * 10,
|
|
|
|
}
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
result, err := r.Retry(ctx, retryFunc)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Retry() error: %s", err)
|
|
|
|
}
|
|
|
|
if result != uint64(resultExpected) {
|
|
|
|
t.Fatalf("unexpected result: got %d; want %d", result, resultExpected)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// only one retry test
|
2023-02-22 13:06:55 +01:00
|
|
|
counter := 0
|
2024-07-12 08:59:31 +02:00
|
|
|
retryFunc := func() error {
|
|
|
|
t := time.NewTicker(time.Millisecond * 5)
|
|
|
|
defer t.Stop()
|
|
|
|
for range t.C {
|
|
|
|
counter++
|
|
|
|
if counter%2 == 0 {
|
2024-01-22 12:21:14 +01:00
|
|
|
return fmt.Errorf("got some error")
|
2023-06-13 13:54:24 +02:00
|
|
|
}
|
2024-07-12 08:59:31 +02:00
|
|
|
if counter%3 == 0 {
|
|
|
|
return nil
|
2023-02-22 13:06:55 +01:00
|
|
|
}
|
2024-07-12 08:59:31 +02:00
|
|
|
}
|
|
|
|
return nil
|
2023-02-22 13:06:55 +01:00
|
|
|
}
|
2024-07-12 08:59:31 +02:00
|
|
|
resultExpected := 1
|
|
|
|
f(retryFunc, resultExpected)
|
2023-02-22 13:06:55 +01:00
|
|
|
}
|
2024-08-03 19:12:48 +02:00
|
|
|
|
|
|
|
func TestBackoff_New(t *testing.T) {
|
|
|
|
f := func(retries int, factor float64, minDuration time.Duration, errExpected string) {
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
_, err := New(retries, factor, minDuration)
|
|
|
|
if err == nil {
|
|
|
|
if errExpected != "" {
|
|
|
|
t.Fatalf("expecting non-nil error")
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if !strings.Contains(err.Error(), errExpected) {
|
|
|
|
t.Fatalf("unexpected error: got %q; want %q", err.Error(), errExpected)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// empty retries
|
|
|
|
f(0, 1.1, time.Millisecond*10, "retries must be greater than 0")
|
|
|
|
|
|
|
|
// empty factor
|
|
|
|
f(1, 0, time.Millisecond*10, "factor must be greater than 1")
|
|
|
|
|
|
|
|
// empty minDuration
|
|
|
|
f(1, 1.1, 0, "minimum duration must be greater than 0")
|
|
|
|
|
|
|
|
// no errors
|
|
|
|
f(1, 1.1, time.Millisecond*10, "")
|
|
|
|
}
|