MCPcopy Create free account
hub / github.com/ddev/ddev / TestDownloadFileRetryLogic

Function TestDownloadFileRetryLogic

pkg/util/network_test.go:72–251  ·  view source on GitHub ↗

TestDownloadFileRetryLogic tests the retry logic structure of DownloadFile

(t *testing.T)

Source from the content-addressed store, hash-verified

70
71// TestDownloadFileRetryLogic tests the retry logic structure of DownloadFile
72func TestDownloadFileRetryLogic(t *testing.T) {
73 testData := "hello world\n"
74 fileName := "testfile.txt"
75 attempts := 0
76
77 // Simulate server that fails first few times then succeeds
78 handlerThatFailsThenSucceeds := func(w http.ResponseWriter, r *http.Request) {
79 attempts++
80 if attempts <= 2 { // First 2 attempts fail
81 t.Logf("simulating server error (attempt %d)", attempts)
82 http.Error(w, "server temporarily unavailable", http.StatusInternalServerError)
83 return
84 }
85 t.Logf("responding 200 OK (attempt %d)", attempts)
86 _, _ = io.WriteString(w, testData)
87 }
88
89 tmpDir := t.TempDir()
90
91 t.Run("server errors then success with retries", func(t *testing.T) {
92 attempts = 0
93 ts := httptest.NewServer(http.HandlerFunc(handlerThatFailsThenSucceeds))
94 defer ts.Close()
95
96 dest := filepath.Join(tmpDir, "retry-success.txt")
97 err := util.DownloadFile(dest, ts.URL+"/"+fileName, false, "")
98 require.NoError(t, err)
99 require.Equal(t, 3, attempts, "expected exactly 3 attempts (2 failures + 1 success)")
100
101 content, err := os.ReadFile(dest)
102 require.NoError(t, err)
103 require.Equal(t, testData, string(content))
104 })
105
106 t.Run("server errors exhaust all retries", func(t *testing.T) {
107 attempts = 0
108 // Server always returns error
109 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
110 attempts++
111 t.Logf("simulating server error (attempt %d)", attempts)
112 http.Error(w, "server permanently unavailable", http.StatusInternalServerError)
113 }))
114 defer ts.Close()
115
116 dest := filepath.Join(tmpDir, "retry-fail.txt")
117 // Set DdevDebug directly since the package variable is cached at init time
118 origDebug := globalconfig.DdevDebug
119 globalconfig.DdevDebug = true
120 t.Cleanup(func() { globalconfig.DdevDebug = origDebug })
121 // Also set log level since UserOut is initialized at package load time
122 origLevel := output.UserOut.GetLevel()
123 output.UserOut.SetLevel(log.DebugLevel)
124 t.Cleanup(func() { output.UserOut.SetLevel(origLevel) })
125
126 restoreOutput := util.CaptureUserOut()
127 err := util.DownloadFile(dest, ts.URL+"/"+fileName, false, "")
128 out := restoreOutput()
129

Callers

nothing calls this directly

Calls 9

DownloadFileFunction · 0.92
CaptureUserOutFunction · 0.92
DownloadFileExtendedFunction · 0.92
ErrorMethod · 0.80
CleanupMethod · 0.80
StopMethod · 0.80
FlushMethod · 0.80
SetMethod · 0.65
WriteMethod · 0.65

Tested by

no test coverage detected