@@ -5,6 +5,7 @@ package sylveiso
55
66import (
77 "encoding/json"
8+ "errors"
89 "net/http"
910 "net/http/httptest"
1011 "strings"
@@ -172,22 +173,25 @@ func TestEnsureAuth_LogoutError(t *testing.T) {
172173 }
173174}
174175
175- // TestEnsureAuth_SucceedsAfter503Burst verifies the outer login loop: the first
176- // Login exhausts HTTP retries on 503; the second attempt succeeds. Uses a zero
177- // sylveLoginRetryInterval so the sleep path uses the sub-millisecond fallback.
176+ // TestEnsureAuth_SucceedsAfter503Burst verifies the outer ensureAuth retry loop
177+ // plus the microsecond sleep shim when retry interval is zero.
178178func TestEnsureAuth_SucceedsAfter503Burst (t * testing.T ) {
179- orig := sylveLoginRetryInterval
179+ loginTransportErr := errors .New (
180+ `sylve login as "alice": execute request POST /auth/login: dial tcp :0: connect: connection refused` ,
181+ )
182+
183+ origLoginFn := isoEnsureAuthLoginFn
184+ origRetry := sylveLoginRetryInterval
180185 sylveLoginRetryInterval = 0
181- t .Cleanup (func () { sylveLoginRetryInterval = orig })
186+ t .Cleanup (func () {
187+ isoEnsureAuthLoginFn = origLoginFn
188+ sylveLoginRetryInterval = origRetry
189+ })
182190
183- var n int32
191+ var srvCalls int32
184192 srv := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
185193 if r .URL .Path == "/api/auth/login" && r .Method == http .MethodPost {
186- c := atomic .AddInt32 (& n , 1 )
187- if c <= 5 {
188- http .Error (w , "bad" , http .StatusServiceUnavailable )
189- return
190- }
194+ atomic .AddInt32 (& srvCalls , 1 )
191195 w .Header ().Set ("Content-Type" , "application/json" )
192196 _ = json .NewEncoder (w ).Encode (client.APIResponse [client.LoginResponse ]{
193197 Status : "ok" ,
@@ -199,6 +203,15 @@ func TestEnsureAuth_SucceedsAfter503Burst(t *testing.T) {
199203 }))
200204 defer srv .Close ()
201205
206+ var loginAttempts int
207+ isoEnsureAuthLoginFn = func (c * client.Client , u , pw , auth string ) (string , error ) {
208+ loginAttempts ++
209+ if loginAttempts == 1 {
210+ return "" , loginTransportErr
211+ }
212+ return origLoginFn (c , u , pw , auth )
213+ }
214+
202215 b := & Builder {config : Config {
203216 SylveURL : srv .URL ,
204217 SylveUser : "alice" ,
@@ -219,25 +232,34 @@ func TestEnsureAuth_SucceedsAfter503Burst(t *testing.T) {
219232 t .Fatalf ("token = %q" , b .config .SylveToken )
220233 }
221234 cleanup ()
222- if n != 6 {
223- t .Fatalf ("login HTTP requests = %d, want 6" , n )
235+ if loginAttempts != 2 {
236+ t .Fatalf ("outer Login attempts=%d want 2" , loginAttempts )
237+ }
238+ if srvCalls != 1 {
239+ t .Fatalf ("HTTP logins=%d want 1" , srvCalls )
224240 }
225241}
226242
227- // TestEnsureAuth_TimesOutWaitingForAPI covers the deadline branch after a full
228- // Login fails with retriable errors (inner HTTP retries add a few seconds) .
243+ // TestEnsureAuth_TimesOutWaitingForAPI covers the deadline branch when login
244+ // failures are retriable at the ensureAuth layer only .
229245func TestEnsureAuth_TimesOutWaitingForAPI (t * testing.T ) {
230- orig := sylveLoginRetryInterval
246+ loginTransportErr := errors .New (
247+ `sylve login as "alice": execute request POST /auth/login: dial tcp :0: connect: connection refused` ,
248+ )
249+
250+ origLoginFn := isoEnsureAuthLoginFn
251+ origRetry := sylveLoginRetryInterval
231252 sylveLoginRetryInterval = time .Millisecond
232- t .Cleanup (func () { sylveLoginRetryInterval = orig })
253+ t .Cleanup (func () {
254+ isoEnsureAuthLoginFn = origLoginFn
255+ sylveLoginRetryInterval = origRetry
256+ })
233257
234- srv := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
235- if r .URL .Path == "/api/auth/login" && r .Method == http .MethodPost {
236- http .Error (w , "bad" , http .StatusServiceUnavailable )
237- return
238- }
239- http .NotFound (w , r )
240- }))
258+ isoEnsureAuthLoginFn = func (* client.Client , string , string , string ) (string , error ) {
259+ return "" , loginTransportErr
260+ }
261+
262+ srv := httptest .NewServer (http .HandlerFunc (http .NotFound ))
241263 defer srv .Close ()
242264
243265 b := & Builder {config : Config {
@@ -261,18 +283,22 @@ func TestEnsureAuth_TimesOutWaitingForAPI(t *testing.T) {
261283// TestEnsureAuth_TruncatesRetrySleepToDeadline exercises ensureAuth when the
262284// retry interval is larger than the time remaining until the login deadline.
263285func TestEnsureAuth_TruncatesRetrySleepToDeadline (t * testing.T ) {
264- orig := sylveLoginRetryInterval
286+ loginTransportErr := errors .New (
287+ `sylve login as "alice": execute request POST /auth/login: dial tcp :0: connect: connection refused` ,
288+ )
289+
290+ origLoginFn := isoEnsureAuthLoginFn
291+ origRetry := sylveLoginRetryInterval
265292 sylveLoginRetryInterval = time .Minute
266- t .Cleanup (func () { sylveLoginRetryInterval = orig })
293+ t .Cleanup (func () {
294+ isoEnsureAuthLoginFn = origLoginFn
295+ sylveLoginRetryInterval = origRetry
296+ })
267297
268- var n int32
298+ var srvCalls int32
269299 srv := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
270300 if r .URL .Path == "/api/auth/login" && r .Method == http .MethodPost {
271- c := atomic .AddInt32 (& n , 1 )
272- if c == 1 {
273- http .Error (w , "bad" , http .StatusServiceUnavailable )
274- return
275- }
301+ atomic .AddInt32 (& srvCalls , 1 )
276302 w .Header ().Set ("Content-Type" , "application/json" )
277303 _ = json .NewEncoder (w ).Encode (client.APIResponse [client.LoginResponse ]{
278304 Status : "ok" ,
@@ -284,6 +310,15 @@ func TestEnsureAuth_TruncatesRetrySleepToDeadline(t *testing.T) {
284310 }))
285311 defer srv .Close ()
286312
313+ var loginAttempts int
314+ isoEnsureAuthLoginFn = func (c * client.Client , u , pw , auth string ) (string , error ) {
315+ loginAttempts ++
316+ if loginAttempts == 1 {
317+ return "" , loginTransportErr
318+ }
319+ return origLoginFn (c , u , pw , auth )
320+ }
321+
287322 b := & Builder {config : Config {
288323 SylveURL : srv .URL ,
289324 SylveUser : "alice" ,
@@ -299,10 +334,13 @@ func TestEnsureAuth_TruncatesRetrySleepToDeadline(t *testing.T) {
299334 t .Fatalf ("ensureAuth: %v" , err )
300335 }
301336 cleanup ()
302- if n != 2 {
303- t .Fatalf ("login attempts = %d, want 2" , n )
337+ if loginAttempts != 2 {
338+ t .Fatalf ("outer Login attempts=%d want 2" , loginAttempts )
339+ }
340+ if srvCalls != 1 {
341+ t .Fatalf ("HTTP logins=%d want 1" , srvCalls )
304342 }
305- if time .Since (start ) > 3 * time .Second {
343+ if time .Since (start ) > 4 * time .Second {
306344 t .Fatalf ("expected truncated sleep (deadline ~1.5s), took %v" , time .Since (start ))
307345 }
308346}
0 commit comments