fix(depot): retry transient probe responses like curl --retry
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -120,6 +120,81 @@ func hostPort(srv *httptest.Server) string {
|
||||
return srv.URL
|
||||
}
|
||||
|
||||
// stubProbeSleep replaces probeRetrySleep for the test, recording durations.
|
||||
func stubProbeSleep(t *testing.T) *[]time.Duration {
|
||||
t.Helper()
|
||||
var slept []time.Duration
|
||||
old := probeRetrySleep
|
||||
probeRetrySleep = func(d time.Duration) { slept = append(slept, d) }
|
||||
t.Cleanup(func() { probeRetrySleep = old })
|
||||
return &slept
|
||||
}
|
||||
|
||||
func TestProbeRetriesTransientThenPresent(t *testing.T) {
|
||||
slept := stubProbeSleep(t)
|
||||
sha := shaOf("throttled-blob")
|
||||
|
||||
var calls int
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
calls++
|
||||
if calls == 1 {
|
||||
w.WriteHeader(428)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(206)
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
cfg := testCfg(hostPort(srv), "readkey", "writekey")
|
||||
b, err := NewBackend("bunny", "", cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("NewBackend: %v", err)
|
||||
}
|
||||
|
||||
state, transient, err := b.Probe(context.Background(), sha)
|
||||
if err != nil {
|
||||
t.Fatalf("Probe: %v", err)
|
||||
}
|
||||
if state != Present || transient {
|
||||
t.Fatalf("expected Present/non-transient after retry, got %v/%v", state, transient)
|
||||
}
|
||||
if calls != 2 {
|
||||
t.Fatalf("expected 2 requests (428 then 206), got %d", calls)
|
||||
}
|
||||
if len(*slept) != 1 || (*slept)[0] != time.Second {
|
||||
t.Fatalf("expected one 1s backoff, got %v", *slept)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProbe404NoRetry(t *testing.T) {
|
||||
slept := stubProbeSleep(t)
|
||||
sha := shaOf("gone-blob")
|
||||
|
||||
f := newFakeBunny()
|
||||
srv := httptest.NewServer(f.handler())
|
||||
defer srv.Close()
|
||||
|
||||
cfg := testCfg(hostPort(srv), "readkey", "writekey")
|
||||
b, err := NewBackend("bunny", "", cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("NewBackend: %v", err)
|
||||
}
|
||||
|
||||
state, transient, err := b.Probe(context.Background(), sha)
|
||||
if err != nil {
|
||||
t.Fatalf("Probe: %v", err)
|
||||
}
|
||||
if state != Absent || transient {
|
||||
t.Fatalf("expected Absent/non-transient, got %v/%v", state, transient)
|
||||
}
|
||||
if got := len(f.requestsSnapshot()); got != 1 {
|
||||
t.Fatalf("expected exactly 1 request for 404, got %d", got)
|
||||
}
|
||||
if len(*slept) != 0 {
|
||||
t.Fatalf("expected zero backoffs for 404, got %v", *slept)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProbeUsesRangeGetNotHead(t *testing.T) {
|
||||
sha := shaOf("present-blob")
|
||||
f := newFakeBunny()
|
||||
@@ -157,6 +232,7 @@ func TestProbeUsesRangeGetNotHead(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestProbeStates(t *testing.T) {
|
||||
stubProbeSleep(t)
|
||||
cases := []struct {
|
||||
status int
|
||||
wantState ProbeState
|
||||
|
||||
Reference in New Issue
Block a user