@@ -7,8 +7,10 @@ import (
77 "net/http/httptest"
88 "net/url"
99 "testing"
10+ "time"
1011
1112 "github.com/actions/scaleset/internal/testserver"
13+ "github.com/hashicorp/go-retryablehttp"
1214 "github.com/stretchr/testify/assert"
1315 "github.com/stretchr/testify/require"
1416 "golang.org/x/net/http/httpproxy"
@@ -153,3 +155,88 @@ func TestUserAgent(t *testing.T) {
153155
154156 assert .Equal (t , want , got )
155157}
158+
159+ // TestWithRetryableHTTPClient verifies that a custom retryable HTTP client
160+ // provided via WithRetryableHTTPClient is actually used instead of the built-in one
161+ func TestWithRetryableHTTPClient (t * testing.T ) {
162+ t .Run ("uses custom retryable client instead of built-in" , func (t * testing.T ) {
163+ attemptCount := 0
164+ server := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
165+ attemptCount ++
166+ if attemptCount == 1 {
167+ w .WriteHeader (http .StatusServiceUnavailable )
168+ return
169+ }
170+ w .WriteHeader (http .StatusOK )
171+ w .Write ([]byte (`{"result": "success"}` ))
172+ }))
173+ defer server .Close ()
174+
175+ // Create a custom retryable HTTP client with specific retry configuration
176+ customRetryClient := retryablehttp .NewClient ()
177+ customRetryClient .RetryMax = 3
178+ customRetryClient .RetryWaitMax = 10 * time .Millisecond
179+
180+ // Create options with the custom retryable client
181+ opts := defaultHTTPClientOption ()
182+ WithRetryableHTTPClint (customRetryClient )(& opts )
183+
184+ // Verify that the custom client is set in options
185+ assert .NotNil (t , opts .retryableHTTPClient )
186+ assert .Equal (t , customRetryClient , opts .retryableHTTPClient )
187+
188+ // Create the common client with custom retryable client
189+ client := newCommonClient (testSystemInfo , opts )
190+
191+ // Make a request that will trigger a retry
192+ req , err := http .NewRequest ("GET" , server .URL , nil )
193+ require .NoError (t , err )
194+
195+ resp , err := client .do (req )
196+ require .NoError (t , err )
197+
198+ // Should succeed after retry
199+ assert .Equal (t , http .StatusOK , resp .StatusCode )
200+ assert .Equal (t , 2 , attemptCount )
201+
202+ // Verify that the client used is the custom one by checking newRetryableHTTPClient
203+ retrievedRetryClient , err := client .newRetryableHTTPClient ()
204+ require .NoError (t , err )
205+ assert .Equal (t , customRetryClient , retrievedRetryClient , "should return the custom retryable client" )
206+ })
207+
208+ t .Run ("respects custom client's retry configuration over built-in defaults" , func (t * testing.T ) {
209+ attemptCount := 0
210+ server := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
211+ attemptCount ++
212+ w .WriteHeader (http .StatusServiceUnavailable )
213+ }))
214+ defer server .Close ()
215+
216+ // Create custom client with limited retries
217+ customRetryClient := retryablehttp .NewClient ()
218+ customRetryClient .RetryMax = 1 // Only 1 retry (2 total attempts)
219+ customRetryClient .RetryWaitMax = 5 * time .Millisecond
220+
221+ opts := defaultHTTPClientOption ()
222+ WithRetryableHTTPClint (customRetryClient )(& opts )
223+
224+ client := newCommonClient (testSystemInfo , opts )
225+
226+ req , err := http .NewRequest ("GET" , server .URL , nil )
227+ require .NoError (t , err )
228+
229+ resp , err := client .do (req )
230+ // When all retries are exhausted with a retryable error, the client gives up
231+ // and an error is returned
232+ if err != nil {
233+ // Expected: request failed after exhausting retries
234+ assert .Contains (t , err .Error (), "giving up after 2 attempt(s)" )
235+ } else {
236+ // Or the final response is returned
237+ assert .Equal (t , http .StatusServiceUnavailable , resp .StatusCode )
238+ }
239+ // Should have tried 1 initial + 1 retry = 2 times total
240+ assert .Equal (t , 2 , attemptCount )
241+ })
242+ }
0 commit comments