46 lines
1.4 KiB
Go
46 lines
1.4 KiB
Go
package notification
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// TestRouteBackoffMonotonic locks the documented schedule:
|
|
// attempt 1 == ~backoffBase, each subsequent attempt grows by
|
|
// backoffFactor up to backoffMax. The check uses the lower bound of
|
|
// the jitter window so the assertion is robust under random output.
|
|
func TestRouteBackoffMonotonic(t *testing.T) {
|
|
t.Parallel()
|
|
lower := func(d time.Duration) time.Duration {
|
|
return time.Duration(float64(d) * (1 - backoffJitter))
|
|
}
|
|
upper := func(d time.Duration) time.Duration {
|
|
return time.Duration(float64(d) * (1 + backoffJitter))
|
|
}
|
|
|
|
cases := []struct {
|
|
attempt int32
|
|
want time.Duration
|
|
}{
|
|
{attempt: 1, want: backoffBase},
|
|
{attempt: 2, want: time.Duration(float64(backoffBase) * backoffFactor)},
|
|
{attempt: 3, want: time.Duration(float64(backoffBase) * backoffFactor * backoffFactor)},
|
|
}
|
|
for _, tc := range cases {
|
|
got := routeBackoff(tc.attempt)
|
|
if got < lower(tc.want) || got > upper(tc.want) {
|
|
t.Fatalf("attempt=%d got=%s want ~%s (±%.0f%%)", tc.attempt, got, tc.want, backoffJitter*100)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestRouteBackoffCap asserts the schedule clamps at backoffMax.
|
|
func TestRouteBackoffCap(t *testing.T) {
|
|
t.Parallel()
|
|
upper := time.Duration(float64(backoffMax) * (1 + backoffJitter))
|
|
got := routeBackoff(50)
|
|
if got > upper {
|
|
t.Fatalf("attempt=50 got=%s exceeds cap (max=%s)", got, backoffMax)
|
|
}
|
|
}
|