Skip to content

Commit 751f6fb

Browse files
authored
Merge pull request #2 from codeGROOVE-dev/merge_128
Merge avast#128 (FullJitterBackoffDe…
2 parents 1eb3dfc + d09461f commit 751f6fb

File tree

1 file changed

+69
-0
lines changed

1 file changed

+69
-0
lines changed

retry_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
"math"
78
"os"
89
"testing"
910
"time"
@@ -664,3 +665,71 @@ func TestIsRecoverable(t *testing.T) {
664665
err = fmt.Errorf("wrapping: %w", err)
665666
assert.False(t, IsRecoverable(err))
666667
}
668+
669+
func TestFullJitterBackoffDelay(t *testing.T) {
670+
// Seed for predictable randomness in tests
671+
// In real usage, math/rand is auto-seeded in Go 1.20+ or should be seeded once at program start.
672+
// For library test predictability, local seeding is fine.
673+
// However, retry-go's RandomDelay uses global math/rand without explicit seeding in tests.
674+
// Let's follow the existing pattern of not explicitly seeding in each test for now,
675+
// assuming test runs are isolated enough or that exact delay values aren't asserted,
676+
// but rather ranges or properties.
677+
678+
baseDelay := 50 * time.Millisecond
679+
maxDelay := 500 * time.Millisecond
680+
681+
config := &Config{
682+
delay: baseDelay,
683+
maxDelay: maxDelay,
684+
// other fields can be zero/default for this test
685+
}
686+
687+
attempts := []uint{0, 1, 2, 3, 4, 5, 6, 10}
688+
689+
for _, n := range attempts {
690+
delay := FullJitterBackoffDelay(n, errors.New("test error"), config)
691+
692+
expectedMaxCeiling := float64(baseDelay) * math.Pow(2, float64(n))
693+
if expectedMaxCeiling > float64(maxDelay) {
694+
expectedMaxCeiling = float64(maxDelay)
695+
}
696+
697+
assert.True(t, delay >= 0, "Delay should be non-negative. Got: %v for attempt %d", delay, n)
698+
assert.True(t, delay <= time.Duration(expectedMaxCeiling),
699+
"Delay %v should be less than or equal to current backoff ceiling %v for attempt %d", delay, time.Duration(expectedMaxCeiling), n)
700+
701+
t.Logf("Attempt %d: BaseDelay=%v, MaxDelay=%v, Calculated Ceiling=~%v, Actual Delay=%v",
702+
n, baseDelay, maxDelay, time.Duration(expectedMaxCeiling), delay)
703+
704+
// Test with MaxDelay disabled (0)
705+
configNoMax := &Config{delay: baseDelay, maxDelay: 0}
706+
delayNoMax := FullJitterBackoffDelay(n, errors.New("test error"), configNoMax)
707+
expectedCeilingNoMax := float64(baseDelay) * math.Pow(2, float64(n))
708+
if expectedCeilingNoMax > float64(10*time.Minute) { // Avoid overflow for very large N
709+
expectedCeilingNoMax = float64(10 * time.Minute)
710+
}
711+
assert.True(t, delayNoMax >= 0, "Delay (no max) should be non-negative. Got: %v for attempt %d", delayNoMax, n)
712+
assert.True(t, delayNoMax <= time.Duration(expectedCeilingNoMax),
713+
"Delay (no max) %v should be less than or equal to current backoff ceiling %v for attempt %d", delayNoMax, time.Duration(expectedCeilingNoMax), n)
714+
}
715+
716+
// Test case where baseDelay might be zero
717+
configZeroBase := &Config{delay: 0, maxDelay: maxDelay}
718+
delayZeroBase := FullJitterBackoffDelay(0, errors.New("test error"), configZeroBase)
719+
assert.Equal(t, time.Duration(0), delayZeroBase, "Delay with zero base delay should be 0")
720+
721+
delayZeroBaseAttempt1 := FullJitterBackoffDelay(1, errors.New("test error"), configZeroBase)
722+
assert.Equal(t, time.Duration(0), delayZeroBaseAttempt1, "Delay with zero base delay (attempt > 0) should be 0")
723+
724+
// Test with very small base delay
725+
smallBaseDelay := 1 * time.Nanosecond
726+
configSmallBase := &Config{delay: smallBaseDelay, maxDelay: 100 * time.Nanosecond}
727+
for i := uint(0); i < 5; i++ {
728+
d := FullJitterBackoffDelay(i, errors.New("test"), configSmallBase)
729+
ceil := float64(smallBaseDelay) * math.Pow(2, float64(i))
730+
if ceil > 100 {
731+
ceil = 100
732+
}
733+
assert.True(t, d <= time.Duration(ceil))
734+
}
735+
}

0 commit comments

Comments
 (0)