Implements retry middleware as a RoundTripper wrapper: - Exponential and constant backoff strategies with jitter - RFC 7231 Retry-After header parsing (seconds and HTTP-date) - Default policy retries idempotent methods on 429/5xx and network errors - Body restoration via GetBody, context cancellation, response body cleanup
59 lines
1.1 KiB
Go
59 lines
1.1 KiB
Go
package retry
|
|
|
|
import (
|
|
"net/http"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestParseRetryAfter(t *testing.T) {
|
|
t.Run("seconds format", func(t *testing.T) {
|
|
resp := &http.Response{
|
|
Header: http.Header{"Retry-After": []string{"120"}},
|
|
}
|
|
d, ok := ParseRetryAfter(resp)
|
|
if !ok {
|
|
t.Fatal("expected ok=true")
|
|
}
|
|
if d != 120*time.Second {
|
|
t.Fatalf("expected 120s, got %v", d)
|
|
}
|
|
})
|
|
|
|
t.Run("empty header", func(t *testing.T) {
|
|
resp := &http.Response{
|
|
Header: make(http.Header),
|
|
}
|
|
d, ok := ParseRetryAfter(resp)
|
|
if ok {
|
|
t.Fatal("expected ok=false for empty header")
|
|
}
|
|
if d != 0 {
|
|
t.Fatalf("expected 0, got %v", d)
|
|
}
|
|
})
|
|
|
|
t.Run("nil response", func(t *testing.T) {
|
|
d, ok := ParseRetryAfter(nil)
|
|
if ok {
|
|
t.Fatal("expected ok=false for nil response")
|
|
}
|
|
if d != 0 {
|
|
t.Fatalf("expected 0, got %v", d)
|
|
}
|
|
})
|
|
|
|
t.Run("negative value", func(t *testing.T) {
|
|
resp := &http.Response{
|
|
Header: http.Header{"Retry-After": []string{"-5"}},
|
|
}
|
|
d, ok := ParseRetryAfter(resp)
|
|
if ok {
|
|
t.Fatal("expected ok=false for negative value")
|
|
}
|
|
if d != 0 {
|
|
t.Fatalf("expected 0, got %v", d)
|
|
}
|
|
})
|
|
}
|