mirror of
https://github.com/lukaszraczylo/kportal.git
synced 2026-06-09 23:59:45 +00:00
7df161aee0
* Fix enter misbehaving. * Cleanup after previous tui implementation. * Fix race condition and improve logging * Add filtering of the namespaces by text input in the wizard UI
170 lines
4.4 KiB
Go
170 lines
4.4 KiB
Go
package retry
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestBackoff_Next(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
attempt int
|
|
minDelay time.Duration
|
|
maxDelay time.Duration
|
|
}{
|
|
{
|
|
name: "first attempt returns ~1s",
|
|
attempt: 0,
|
|
minDelay: 900 * time.Millisecond, // 1s - 10% jitter
|
|
maxDelay: 1100 * time.Millisecond, // 1s + 10% jitter
|
|
},
|
|
{
|
|
name: "second attempt returns ~2s",
|
|
attempt: 1,
|
|
minDelay: 1800 * time.Millisecond, // 2s - 10% jitter
|
|
maxDelay: 2200 * time.Millisecond, // 2s + 10% jitter
|
|
},
|
|
{
|
|
name: "third attempt returns ~4s",
|
|
attempt: 2,
|
|
minDelay: 3600 * time.Millisecond, // 4s - 10% jitter
|
|
maxDelay: 4400 * time.Millisecond, // 4s + 10% jitter
|
|
},
|
|
{
|
|
name: "fourth attempt returns ~8s",
|
|
attempt: 3,
|
|
minDelay: 7200 * time.Millisecond, // 8s - 10% jitter
|
|
maxDelay: 8800 * time.Millisecond, // 8s + 10% jitter
|
|
},
|
|
{
|
|
name: "fifth attempt returns ~10s (max)",
|
|
attempt: 4,
|
|
minDelay: 9000 * time.Millisecond, // 10s - 10% jitter
|
|
maxDelay: 11000 * time.Millisecond, // 10s + 10% jitter
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
b := NewBackoff()
|
|
|
|
// Advance to the desired attempt
|
|
for i := 0; i < tt.attempt; i++ {
|
|
b.Next()
|
|
}
|
|
|
|
delay := b.Next()
|
|
|
|
assert.GreaterOrEqual(t, delay, tt.minDelay, "delay should be >= min with jitter")
|
|
assert.LessOrEqual(t, delay, tt.maxDelay, "delay should be <= max with jitter")
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestBackoff_Next_StaysAtMax(t *testing.T) {
|
|
b := NewBackoff()
|
|
|
|
// Go through several attempts past the max
|
|
for i := 0; i < 10; i++ {
|
|
delay := b.Next()
|
|
|
|
// After the 5th attempt (index 4), should always be at max (10s ± jitter)
|
|
if i >= 4 {
|
|
assert.GreaterOrEqual(t, delay, 9*time.Second, "should stay at max delay")
|
|
assert.LessOrEqual(t, delay, 11*time.Second, "should stay at max delay with jitter")
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestBackoff_Reset(t *testing.T) {
|
|
b := NewBackoff()
|
|
|
|
// Advance through several attempts
|
|
for i := 0; i < 5; i++ {
|
|
b.Next()
|
|
}
|
|
|
|
// Should be at attempt 5
|
|
assert.Equal(t, 5, b.Attempt(), "should be at attempt 5")
|
|
|
|
// Reset
|
|
b.Reset()
|
|
|
|
// Should be back to attempt 0
|
|
assert.Equal(t, 0, b.Attempt(), "should be reset to attempt 0")
|
|
|
|
// Next call should return ~1s (first attempt)
|
|
delay := b.Next()
|
|
assert.GreaterOrEqual(t, delay, 900*time.Millisecond, "after reset should return ~1s")
|
|
assert.LessOrEqual(t, delay, 1100*time.Millisecond, "after reset should return ~1s with jitter")
|
|
}
|
|
|
|
func TestBackoff_Jitter_IsWithinExpectedRange(t *testing.T) {
|
|
b := NewBackoff()
|
|
|
|
// Test multiple times to ensure jitter varies
|
|
delays := make([]time.Duration, 20)
|
|
for i := 0; i < 20; i++ {
|
|
b.Reset()
|
|
delays[i] = b.Next()
|
|
}
|
|
|
|
// All delays should be within the jitter range for 1s
|
|
for _, delay := range delays {
|
|
assert.GreaterOrEqual(t, delay, 900*time.Millisecond, "jitter should not go below 10%")
|
|
assert.LessOrEqual(t, delay, 1100*time.Millisecond, "jitter should not go above 10%")
|
|
}
|
|
|
|
// Check that not all delays are identical (jitter is working)
|
|
allSame := true
|
|
first := delays[0]
|
|
for _, d := range delays[1:] {
|
|
if d != first {
|
|
allSame = false
|
|
break
|
|
}
|
|
}
|
|
|
|
assert.False(t, allSame, "jitter should produce varying delays")
|
|
}
|
|
|
|
func TestBackoff_Attempt(t *testing.T) {
|
|
b := NewBackoff()
|
|
|
|
assert.Equal(t, 0, b.Attempt(), "initial attempt should be 0")
|
|
|
|
b.Next()
|
|
assert.Equal(t, 1, b.Attempt(), "attempt should increment after Next()")
|
|
|
|
b.Next()
|
|
assert.Equal(t, 2, b.Attempt(), "attempt should increment after Next()")
|
|
|
|
b.Reset()
|
|
assert.Equal(t, 0, b.Attempt(), "attempt should reset to 0")
|
|
}
|
|
|
|
func TestBackoff_ExponentialProgression(t *testing.T) {
|
|
b := NewBackoff()
|
|
|
|
// Track the progression
|
|
var delays []time.Duration
|
|
for i := 0; i < 5; i++ {
|
|
delays = append(delays, b.Next())
|
|
}
|
|
|
|
// Verify exponential growth (each should be roughly 2x the previous)
|
|
// We allow for jitter by checking a range
|
|
for i := 1; i < len(delays)-1; i++ {
|
|
// Each delay should be roughly double the previous (accounting for jitter)
|
|
// With 10% jitter on each value:
|
|
// Lower bound: (2.0 * 0.9) / 1.1 ≈ 1.636
|
|
// Upper bound: (2.0 * 1.1) / 0.9 ≈ 2.444
|
|
// We use 1.6x to 2.5x as a reasonable range to account for jitter variance
|
|
ratio := float64(delays[i]) / float64(delays[i-1])
|
|
assert.GreaterOrEqual(t, ratio, 1.6, "exponential growth should be ~2x")
|
|
assert.LessOrEqual(t, ratio, 2.5, "exponential growth should be ~2x")
|
|
}
|
|
}
|