@@ -20,6 +20,9 @@ import (
20
20
"github.com/treeverse/lakefs/pkg/logging"
21
21
)
22
22
23
+ func TestMain (m * testing.M ) {
24
+ os .Exit (m .Run ())
25
+ }
23
26
func TestGetTokenCacheOnce (t * testing.T ) {
24
27
t .Run ("creates cache on first call ONLY" , func (t * testing.T ) {
25
28
resetGlobalState ()
@@ -195,20 +198,6 @@ func TestTokenExpiredWrite(t *testing.T) {
195
198
require .Nil (t , token )
196
199
})
197
200
}
198
- func resetGlobalState () {
199
- tokenLoadOnce = sync.Once {}
200
- tokenCacheOnce = sync.Once {}
201
- tokenSaveOnce = sync.Once {}
202
- cachedToken = nil
203
- tokenCache = nil
204
-
205
- homeDir := os .Getenv ("HOME" )
206
- if homeDir != "" {
207
- cacheDir := filepath .Join (homeDir , ".lakectl" , "cache" )
208
- os .RemoveAll (cacheDir )
209
- }
210
- }
211
-
212
201
func setupTestHomeDir (t * testing.T ) (cleanup func ()) {
213
202
tempDir := t .TempDir ()
214
203
originalHome := os .Getenv ("HOME" )
@@ -310,12 +299,9 @@ func createSecurityProvider(mockClient *mockExternalLoginClient, initialToken *a
310
299
)
311
300
}
312
301
313
- var testMutex sync.Mutex
314
-
315
302
func TestLoginOnlyOnce (t * testing.T ) {
316
303
t .Run ("login called only once across multiple requests" , func (t * testing.T ) {
317
- testMutex .Lock ()
318
- defer testMutex .Unlock ()
304
+ // Remove testMutex.Lock()/Unlock() since TestMain handles sequencing
319
305
resetGlobalState ()
320
306
cleanup := setupTestHomeDir (t )
321
307
defer cleanup ()
@@ -329,26 +315,18 @@ func TestLoginOnlyOnce(t *testing.T) {
329
315
provider := createSecurityProvider (mockClient , nil , & callbackCount )
330
316
require .Nil (t , provider .AuthenticationToken )
331
317
332
- // Add debug logging
333
- t .Logf ("Before Intercept - Token: %v" , provider .AuthenticationToken )
334
- t .Logf ("Before Intercept - Login count: %d" , mockClient .getLoginCount ())
335
-
336
318
req1 := httptest .NewRequest ("GET" , "http://example.com/api/v1/repositories" , nil )
337
319
err := provider .Intercept (context .Background (), req1 )
338
320
339
- t .Logf ("After Intercept - Token: %v" , provider .AuthenticationToken )
340
- t .Logf ("After Intercept - Login count: %d" , mockClient .getLoginCount ())
341
- t .Logf ("Authorization header: %s" , req1 .Header .Get ("Authorization" ))
342
-
343
321
require .NoError (t , err )
344
322
require .Equal (t , "Bearer cached-token" , req1 .Header .Get ("Authorization" ))
345
323
require .Equal (t , int64 (1 ), mockClient .getLoginCount ())
324
+
325
+ // Keep a short sleep to let callback complete
326
+ time .Sleep (100 * time .Millisecond )
346
327
})
347
- // }
348
- // func TestNoLoginWhenTokenIsGiven(t *testing.T) {
328
+
349
329
t .Run ("no login performed when valid token provided initially" , func (t * testing.T ) {
350
- testMutex .Lock ()
351
- defer testMutex .Unlock ()
352
330
resetGlobalState ()
353
331
cleanup := setupTestHomeDir (t )
354
332
defer cleanup ()
@@ -367,20 +345,17 @@ func TestLoginOnlyOnce(t *testing.T) {
367
345
var callbackCount int64
368
346
provider := createSecurityProvider (mockClient , existingToken , & callbackCount )
369
347
370
- // Request should use existing token, no login
371
348
req := httptest .NewRequest ("GET" , "http://example.com/api/v1/repositories" , nil )
372
349
err := provider .Intercept (context .Background (), req )
373
350
require .NoError (t , err )
374
351
require .Equal (t , "Bearer pre-existing-token" , req .Header .Get ("Authorization" ))
375
- require .Equal (t , int64 (0 ), mockClient .getLoginCount ()) // No login called
376
- time .Sleep (time .Second )
377
- require .Equal (t , int64 (0 ), atomic .LoadInt64 (& callbackCount )) // No callback called
352
+ require .Equal (t , int64 (0 ), mockClient .getLoginCount ())
353
+
354
+ time .Sleep (100 * time .Millisecond )
355
+ require .Equal (t , int64 (0 ), atomic .LoadInt64 (& callbackCount ))
378
356
})
379
- // }
380
- // func TestRealInterceptWithGlobalCache2(t *testing.T) {
357
+
381
358
t .Run ("handles login failure gracefully" , func (t * testing.T ) {
382
- testMutex .Lock ()
383
- defer testMutex .Unlock ()
384
359
resetGlobalState ()
385
360
cleanup := setupTestHomeDir (t )
386
361
defer cleanup ()
@@ -393,20 +368,17 @@ func TestLoginOnlyOnce(t *testing.T) {
393
368
var callbackCount int64
394
369
provider := createSecurityProvider (mockClient , nil , & callbackCount )
395
370
396
- // Request should fail due to login failure
397
371
req := httptest .NewRequest ("GET" , "http://example.com/api/v1/repositories" , nil )
398
372
err := provider .Intercept (context .Background (), req )
399
373
require .ErrorIs (t , err , errMockLoginFailed )
400
374
require .Empty (t , req .Header .Get ("Authorization" ))
401
- require .Equal (t , int64 (1 ), mockClient .getLoginCount ()) // Login attempted once
402
- time .Sleep (time .Second )
403
- require .Equal (t , int64 (0 ), atomic .LoadInt64 (& callbackCount )) // No callback on failure
375
+ require .Equal (t , int64 (1 ), mockClient .getLoginCount ())
376
+
377
+ time .Sleep (100 * time .Millisecond )
378
+ require .Equal (t , int64 (0 ), atomic .LoadInt64 (& callbackCount ))
404
379
})
405
- // }
406
- // func TestRealInterceptWithGlobalCache5(t *testing.T) {
380
+
407
381
t .Run ("token cached via callback and reused after provider recreation" , func (t * testing.T ) {
408
- testMutex .Lock ()
409
- defer testMutex .Unlock ()
410
382
resetGlobalState ()
411
383
cleanup := setupTestHomeDir (t )
412
384
defer cleanup ()
@@ -419,34 +391,48 @@ func TestLoginOnlyOnce(t *testing.T) {
419
391
var callbackCount int64
420
392
provider1 := createSecurityProvider (mockClient , nil , & callbackCount )
421
393
422
- // First request - should trigger login and cache via callback
423
394
req1 := httptest .NewRequest ("GET" , "http://example.com/api/v1/repositories" , nil )
424
395
err := provider1 .Intercept (context .Background (), req1 )
425
396
require .NoError (t , err )
426
397
require .Equal (t , "Bearer callback-cached-token" , req1 .Header .Get ("Authorization" ))
427
398
require .Equal (t , int64 (1 ), mockClient .getLoginCount ())
428
- time .Sleep (time .Second )
399
+
400
+ time .Sleep (100 * time .Millisecond )
429
401
require .Equal (t , int64 (1 ), atomic .LoadInt64 (& callbackCount ))
430
402
431
- // Verify token was saved to global cache
432
403
require .NotNil (t , cachedToken )
433
404
require .Equal (t , "callback-cached-token" , cachedToken .Token )
434
405
435
- // Create new provider instance (simulating new command execution)
436
406
mockClient .resetLoginCount ()
437
407
callbackCount = 0
438
408
439
- // Get token from cache using global function
440
409
cachedTokenFromFile := getTokenOnce ()
441
410
provider2 := createSecurityProvider (mockClient , cachedTokenFromFile , & callbackCount )
442
411
443
- // Second request with new provider should use cached token from file
444
412
req2 := httptest .NewRequest ("GET" , "http://example.com/api/v1/repositories" , nil )
445
413
err = provider2 .Intercept (context .Background (), req2 )
446
414
require .NoError (t , err )
447
415
require .Equal (t , "Bearer callback-cached-token" , req2 .Header .Get ("Authorization" ))
448
- require .Equal (t , int64 (0 ), mockClient .getLoginCount ()) // No new login, used cache
449
- time .Sleep (time .Second )
450
- require .Equal (t , int64 (0 ), atomic .LoadInt64 (& callbackCount )) // No new callback
416
+ require .Equal (t , int64 (0 ), mockClient .getLoginCount ())
417
+
418
+ time .Sleep (100 * time .Millisecond )
419
+ require .Equal (t , int64 (0 ), atomic .LoadInt64 (& callbackCount ))
451
420
})
452
421
}
422
+
423
+ func resetGlobalState () {
424
+ // Brief sleep to let any callback goroutines finish
425
+ time .Sleep (50 * time .Millisecond )
426
+
427
+ tokenLoadOnce = sync.Once {}
428
+ tokenCacheOnce = sync.Once {}
429
+ tokenSaveOnce = sync.Once {}
430
+ cachedToken = nil
431
+ tokenCache = nil
432
+
433
+ homeDir := os .Getenv ("HOME" )
434
+ if homeDir != "" {
435
+ cacheDir := filepath .Join (homeDir , ".lakectl" , "cache" )
436
+ os .RemoveAll (cacheDir )
437
+ }
438
+ }
0 commit comments