package retry import ( "testing" "time" ) func TestExponentialBackoff(t *testing.T) { t.Run("doubles each attempt", func(t *testing.T) { b := ExponentialBackoff(100*time.Millisecond, 10*time.Second, false) want := []time.Duration{ 100 * time.Millisecond, // attempt 0: base 200 * time.Millisecond, // attempt 1: base*2 400 * time.Millisecond, // attempt 2: base*4 800 * time.Millisecond, // attempt 3: base*8 1600 * time.Millisecond, // attempt 4: base*16 } for i, expected := range want { got := b.Delay(i) if got != expected { t.Errorf("attempt %d: expected %v, got %v", i, expected, got) } } }) t.Run("caps at max", func(t *testing.T) { b := ExponentialBackoff(100*time.Millisecond, 500*time.Millisecond, false) // attempt 0: 100ms, 1: 200ms, 2: 400ms, 3: 500ms (capped), 4: 500ms for _, attempt := range []int{3, 4, 10} { got := b.Delay(attempt) if got != 500*time.Millisecond { t.Errorf("attempt %d: expected cap at 500ms, got %v", attempt, got) } } }) t.Run("with jitter adds randomness", func(t *testing.T) { base := 100 * time.Millisecond b := ExponentialBackoff(base, 10*time.Second, true) // Run multiple times; with jitter, delay >= base for attempt 0. // Also verify not all values are identical (randomness). seen := make(map[time.Duration]bool) for range 20 { d := b.Delay(0) if d < base { t.Fatalf("delay %v is less than base %v", d, base) } // With jitter: delay = base + rand in [0, base/2), so max is base*1.5 maxExpected := base + base/2 if d > maxExpected { t.Fatalf("delay %v exceeds expected max %v", d, maxExpected) } seen[d] = true } if len(seen) < 2 { t.Errorf("expected jitter to produce varying delays, got %d unique values", len(seen)) } }) } func TestConstantBackoff(t *testing.T) { t.Run("always returns same value", func(t *testing.T) { d := 250 * time.Millisecond b := ConstantBackoff(d) for _, attempt := range []int{0, 1, 2, 5, 100} { got := b.Delay(attempt) if got != d { t.Errorf("attempt %d: expected %v, got %v", attempt, d, got) } } }) }