1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
package logic

import (
	"net/http"
	"testing"
	"time"
)

func TestParseRetryAfter(t *testing.T) {
	now := time.Date(2026, 10, 28, 12, 0, 0, 0, time.UTC)
	cases := []struct {
		in   string
		want time.Duration
	}{
		{"", 0},
		{"120", 2 * time.Minute},
		{" 3600 ", time.Hour},
		{"0", 0},
		{"-5", 0},
		{"soon", 0},
		{now.Add(90 * time.Minute).Format(http.TimeFormat), 90 * time.Minute},
		{now.Add(-time.Hour).Format(http.TimeFormat), 0},
	}
	for _, c := range cases {
		if got := parseRetryAfter(c.in, now); got != c.want {
			t.Errorf("parseRetryAfter(%q) = %s, want %s", c.in, got, c.want)
		}
	}
}

func TestBackoffDelay(t *testing.T) {
	h := time.Hour
	day := 24 * h
	cases := []struct {
		name       string
		interval   time.Duration
		failures   int
		retryAfter time.Duration
		maxDelay   time.Duration
		want       time.Duration
	}{
		{"first failure doubles", h, 1, 0, day, 2 * h},
		{"third failure", h, 3, 0, day, 8 * h},
		{"zero failures treated as one", h, 0, 0, day, 2 * h},
		{"doubling stops at the cap", h, 20, 0, day, day},
		{"Retry-After longer than backoff wins", h, 1, 10 * h, day, 10 * h},
		{"Retry-After shorter than backoff is ignored", h, 3, h, day, 8 * h},
		{"Retry-After of five weeks is capped at a day", h, 1, 5 * 7 * day, day, day},
		{"a custom cap", h, 1, 5 * 7 * day, 6 * h, 6 * h},
		{"slow feeds keep their normal interval", 7 * day, 1, 0, day, 7 * day},
		{"slow feeds ignore a longer Retry-After too", 7 * day, 1, 5 * 7 * day, day, 7 * day},
	}
	for _, c := range cases {
		if got := backoffDelay(c.interval, c.failures, c.retryAfter, c.maxDelay); got != c.want {
			t.Errorf("%s: backoffDelay(%s, %d, %s, %s) = %s, want %s",
				c.name, c.interval, c.failures, c.retryAfter, c.maxDelay, got, c.want)
		}
	}
}

func TestMaxRetryDelay(t *testing.T) {
	if got := maxRetryDelay(0); got != 24*time.Hour {
		t.Errorf("maxRetryDelay(0) = %s, want the 24h default", got)
	}
	if got := maxRetryDelay(6); got != 6*time.Hour {
		t.Errorf("maxRetryDelay(6) = %s, want 6h", got)
	}
}