mirror of
https://github.com/cloudflare/cloudflared.git
synced 2025-05-22 14:16:34 +00:00

A clock structure was used to help support unit testing timetravel but it is a globally shared object and is likely unsafe to share across tests. Reordering of the tests seemed to have intermittent failures for the TestWaitForBackoffFallback specifically on windows builds. Adjusting this to be a shim inside the BackoffHandler struct should resolve shared object overrides in unit testing. Additionally, added the reset retries functionality to be inline with the ResetNow function of the BackoffHandler to align better with expected functionality of the method. Removes unused reconnectCredentialManager.
143 lines
5.0 KiB
Go
143 lines
5.0 KiB
Go
package retry
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func immediateTimeAfter(time.Duration) <-chan time.Time {
|
|
c := make(chan time.Time, 1)
|
|
c <- time.Now()
|
|
return c
|
|
}
|
|
|
|
func TestBackoffRetries(t *testing.T) {
|
|
ctx := context.Background()
|
|
// make backoff return immediately
|
|
backoff := BackoffHandler{maxRetries: 3, Clock: Clock{time.Now, immediateTimeAfter}}
|
|
if !backoff.Backoff(ctx) {
|
|
t.Fatalf("backoff failed immediately")
|
|
}
|
|
if !backoff.Backoff(ctx) {
|
|
t.Fatalf("backoff failed after 1 retry")
|
|
}
|
|
if !backoff.Backoff(ctx) {
|
|
t.Fatalf("backoff failed after 2 retry")
|
|
}
|
|
if backoff.Backoff(ctx) {
|
|
t.Fatalf("backoff allowed after 3 (max) retries")
|
|
}
|
|
}
|
|
|
|
func TestBackoffCancel(t *testing.T) {
|
|
ctx, cancelFunc := context.WithCancel(context.Background())
|
|
// prevent backoff from returning normally
|
|
after := func(time.Duration) <-chan time.Time { return make(chan time.Time) }
|
|
backoff := BackoffHandler{maxRetries: 3, Clock: Clock{time.Now, after}}
|
|
cancelFunc()
|
|
if backoff.Backoff(ctx) {
|
|
t.Fatalf("backoff allowed after cancel")
|
|
}
|
|
if _, ok := backoff.GetMaxBackoffDuration(ctx); ok {
|
|
t.Fatalf("backoff allowed after cancel")
|
|
}
|
|
}
|
|
|
|
func TestBackoffGracePeriod(t *testing.T) {
|
|
ctx := context.Background()
|
|
currentTime := time.Now()
|
|
// make Clock.Now return whatever we like
|
|
now := func() time.Time { return currentTime }
|
|
// make backoff return immediately
|
|
backoff := BackoffHandler{maxRetries: 1, Clock: Clock{now, immediateTimeAfter}}
|
|
if !backoff.Backoff(ctx) {
|
|
t.Fatalf("backoff failed immediately")
|
|
}
|
|
// the next call to Backoff would fail unless it's after the grace period
|
|
gracePeriod := backoff.SetGracePeriod()
|
|
// advance time to after the grace period, which at most will be 8 seconds, but we will advance +1 second.
|
|
currentTime = currentTime.Add(gracePeriod + time.Second)
|
|
if !backoff.Backoff(ctx) {
|
|
t.Fatalf("backoff failed after the grace period expired")
|
|
}
|
|
// confirm we ignore grace period after backoff
|
|
if backoff.Backoff(ctx) {
|
|
t.Fatalf("backoff allowed after 1 (max) retry")
|
|
}
|
|
}
|
|
|
|
func TestGetMaxBackoffDurationRetries(t *testing.T) {
|
|
ctx := context.Background()
|
|
// make backoff return immediately
|
|
backoff := BackoffHandler{maxRetries: 3, Clock: Clock{time.Now, immediateTimeAfter}}
|
|
if _, ok := backoff.GetMaxBackoffDuration(ctx); !ok {
|
|
t.Fatalf("backoff failed immediately")
|
|
}
|
|
backoff.Backoff(ctx) // noop
|
|
if _, ok := backoff.GetMaxBackoffDuration(ctx); !ok {
|
|
t.Fatalf("backoff failed after 1 retry")
|
|
}
|
|
backoff.Backoff(ctx) // noop
|
|
if _, ok := backoff.GetMaxBackoffDuration(ctx); !ok {
|
|
t.Fatalf("backoff failed after 2 retry")
|
|
}
|
|
backoff.Backoff(ctx) // noop
|
|
if _, ok := backoff.GetMaxBackoffDuration(ctx); ok {
|
|
t.Fatalf("backoff allowed after 3 (max) retries")
|
|
}
|
|
if backoff.Backoff(ctx) {
|
|
t.Fatalf("backoff allowed after 3 (max) retries")
|
|
}
|
|
}
|
|
|
|
func TestGetMaxBackoffDuration(t *testing.T) {
|
|
ctx := context.Background()
|
|
// make backoff return immediately
|
|
backoff := BackoffHandler{maxRetries: 3, Clock: Clock{time.Now, immediateTimeAfter}}
|
|
if duration, ok := backoff.GetMaxBackoffDuration(ctx); !ok || duration > time.Second*2 {
|
|
t.Fatalf("backoff (%s) didn't return < 2 seconds on first retry", duration)
|
|
}
|
|
backoff.Backoff(ctx) // noop
|
|
if duration, ok := backoff.GetMaxBackoffDuration(ctx); !ok || duration > time.Second*4 {
|
|
t.Fatalf("backoff (%s) didn't return < 4 seconds on second retry", duration)
|
|
}
|
|
backoff.Backoff(ctx) // noop
|
|
if duration, ok := backoff.GetMaxBackoffDuration(ctx); !ok || duration > time.Second*8 {
|
|
t.Fatalf("backoff (%s) didn't return < 8 seconds on third retry", duration)
|
|
}
|
|
backoff.Backoff(ctx) // noop
|
|
if duration, ok := backoff.GetMaxBackoffDuration(ctx); ok || duration != 0 {
|
|
t.Fatalf("backoff (%s) didn't return 0 seconds on fourth retry (exceeding limit)", duration)
|
|
}
|
|
}
|
|
|
|
func TestBackoffRetryForever(t *testing.T) {
|
|
ctx := context.Background()
|
|
// make backoff return immediately
|
|
backoff := BackoffHandler{maxRetries: 3, retryForever: true, Clock: Clock{time.Now, immediateTimeAfter}}
|
|
if duration, ok := backoff.GetMaxBackoffDuration(ctx); !ok || duration > time.Second*2 {
|
|
t.Fatalf("backoff (%s) didn't return < 2 seconds on first retry", duration)
|
|
}
|
|
backoff.Backoff(ctx) // noop
|
|
if duration, ok := backoff.GetMaxBackoffDuration(ctx); !ok || duration > time.Second*4 {
|
|
t.Fatalf("backoff (%s) didn't return < 4 seconds on second retry", duration)
|
|
}
|
|
backoff.Backoff(ctx) // noop
|
|
if duration, ok := backoff.GetMaxBackoffDuration(ctx); !ok || duration > time.Second*8 {
|
|
t.Fatalf("backoff (%s) didn't return < 8 seconds on third retry", duration)
|
|
}
|
|
if !backoff.Backoff(ctx) {
|
|
t.Fatalf("backoff refused on fourth retry despire RetryForever")
|
|
}
|
|
if duration, ok := backoff.GetMaxBackoffDuration(ctx); !ok || duration > time.Second*16 {
|
|
t.Fatalf("backoff returned %v instead of 8 seconds on fourth retry", duration)
|
|
}
|
|
if !backoff.Backoff(ctx) {
|
|
t.Fatalf("backoff refused on fifth retry despire RetryForever")
|
|
}
|
|
if duration, ok := backoff.GetMaxBackoffDuration(ctx); !ok || duration > time.Second*16 {
|
|
t.Fatalf("backoff returned %v instead of 8 seconds on fifth retry", duration)
|
|
}
|
|
}
|