Skip to content

Commit c3b09f5

Browse files
committed
sequential
1 parent cd3888e commit c3b09f5

File tree

1 file changed

+41
-55
lines changed

1 file changed

+41
-55
lines changed

cmd/lakectl/cmd/token_cacing_test.go

Lines changed: 41 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ import (
2020
"github.com/treeverse/lakefs/pkg/logging"
2121
)
2222

23+
func TestMain(m *testing.M) {
24+
os.Exit(m.Run())
25+
}
2326
func TestGetTokenCacheOnce(t *testing.T) {
2427
t.Run("creates cache on first call ONLY", func(t *testing.T) {
2528
resetGlobalState()
@@ -195,20 +198,6 @@ func TestTokenExpiredWrite(t *testing.T) {
195198
require.Nil(t, token)
196199
})
197200
}
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-
212201
func setupTestHomeDir(t *testing.T) (cleanup func()) {
213202
tempDir := t.TempDir()
214203
originalHome := os.Getenv("HOME")
@@ -310,12 +299,9 @@ func createSecurityProvider(mockClient *mockExternalLoginClient, initialToken *a
310299
)
311300
}
312301

313-
var testMutex sync.Mutex
314-
315302
func TestLoginOnlyOnce(t *testing.T) {
316303
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
319305
resetGlobalState()
320306
cleanup := setupTestHomeDir(t)
321307
defer cleanup()
@@ -329,26 +315,18 @@ func TestLoginOnlyOnce(t *testing.T) {
329315
provider := createSecurityProvider(mockClient, nil, &callbackCount)
330316
require.Nil(t, provider.AuthenticationToken)
331317

332-
// Add debug logging
333-
t.Logf("Before Intercept - Token: %v", provider.AuthenticationToken)
334-
t.Logf("Before Intercept - Login count: %d", mockClient.getLoginCount())
335-
336318
req1 := httptest.NewRequest("GET", "http://example.com/api/v1/repositories", nil)
337319
err := provider.Intercept(context.Background(), req1)
338320

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-
343321
require.NoError(t, err)
344322
require.Equal(t, "Bearer cached-token", req1.Header.Get("Authorization"))
345323
require.Equal(t, int64(1), mockClient.getLoginCount())
324+
325+
// Keep a short sleep to let callback complete
326+
time.Sleep(100 * time.Millisecond)
346327
})
347-
// }
348-
// func TestNoLoginWhenTokenIsGiven(t *testing.T) {
328+
349329
t.Run("no login performed when valid token provided initially", func(t *testing.T) {
350-
testMutex.Lock()
351-
defer testMutex.Unlock()
352330
resetGlobalState()
353331
cleanup := setupTestHomeDir(t)
354332
defer cleanup()
@@ -367,20 +345,17 @@ func TestLoginOnlyOnce(t *testing.T) {
367345
var callbackCount int64
368346
provider := createSecurityProvider(mockClient, existingToken, &callbackCount)
369347

370-
// Request should use existing token, no login
371348
req := httptest.NewRequest("GET", "http://example.com/api/v1/repositories", nil)
372349
err := provider.Intercept(context.Background(), req)
373350
require.NoError(t, err)
374351
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))
378356
})
379-
// }
380-
// func TestRealInterceptWithGlobalCache2(t *testing.T) {
357+
381358
t.Run("handles login failure gracefully", func(t *testing.T) {
382-
testMutex.Lock()
383-
defer testMutex.Unlock()
384359
resetGlobalState()
385360
cleanup := setupTestHomeDir(t)
386361
defer cleanup()
@@ -393,20 +368,17 @@ func TestLoginOnlyOnce(t *testing.T) {
393368
var callbackCount int64
394369
provider := createSecurityProvider(mockClient, nil, &callbackCount)
395370

396-
// Request should fail due to login failure
397371
req := httptest.NewRequest("GET", "http://example.com/api/v1/repositories", nil)
398372
err := provider.Intercept(context.Background(), req)
399373
require.ErrorIs(t, err, errMockLoginFailed)
400374
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))
404379
})
405-
// }
406-
// func TestRealInterceptWithGlobalCache5(t *testing.T) {
380+
407381
t.Run("token cached via callback and reused after provider recreation", func(t *testing.T) {
408-
testMutex.Lock()
409-
defer testMutex.Unlock()
410382
resetGlobalState()
411383
cleanup := setupTestHomeDir(t)
412384
defer cleanup()
@@ -419,34 +391,48 @@ func TestLoginOnlyOnce(t *testing.T) {
419391
var callbackCount int64
420392
provider1 := createSecurityProvider(mockClient, nil, &callbackCount)
421393

422-
// First request - should trigger login and cache via callback
423394
req1 := httptest.NewRequest("GET", "http://example.com/api/v1/repositories", nil)
424395
err := provider1.Intercept(context.Background(), req1)
425396
require.NoError(t, err)
426397
require.Equal(t, "Bearer callback-cached-token", req1.Header.Get("Authorization"))
427398
require.Equal(t, int64(1), mockClient.getLoginCount())
428-
time.Sleep(time.Second)
399+
400+
time.Sleep(100 * time.Millisecond)
429401
require.Equal(t, int64(1), atomic.LoadInt64(&callbackCount))
430402

431-
// Verify token was saved to global cache
432403
require.NotNil(t, cachedToken)
433404
require.Equal(t, "callback-cached-token", cachedToken.Token)
434405

435-
// Create new provider instance (simulating new command execution)
436406
mockClient.resetLoginCount()
437407
callbackCount = 0
438408

439-
// Get token from cache using global function
440409
cachedTokenFromFile := getTokenOnce()
441410
provider2 := createSecurityProvider(mockClient, cachedTokenFromFile, &callbackCount)
442411

443-
// Second request with new provider should use cached token from file
444412
req2 := httptest.NewRequest("GET", "http://example.com/api/v1/repositories", nil)
445413
err = provider2.Intercept(context.Background(), req2)
446414
require.NoError(t, err)
447415
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))
451420
})
452421
}
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

Comments
 (0)