package auth import ( "testing" "time" ) func TestGetServiceToken_NotCached(t *testing.T) { // Clear cache first globalServiceTokensMu.Lock() globalServiceTokens = make(map[string]*serviceTokenEntry) globalServiceTokensMu.Unlock() did := "did:plc:test123" holdDID := "did:web:hold.example.com" token, expiresAt := GetServiceToken(did, holdDID) if token != "" { t.Errorf("Expected empty token for uncached entry, got %q", token) } if !expiresAt.IsZero() { t.Error("Expected zero time for uncached entry") } } func TestSetServiceToken_ManualExpiry(t *testing.T) { // Clear cache first globalServiceTokensMu.Lock() globalServiceTokens = make(map[string]*serviceTokenEntry) globalServiceTokensMu.Unlock() did := "did:plc:test123" holdDID := "did:web:hold.example.com" token := "invalid_jwt_token" // Will fall back to 50s default // This should succeed with default 50s TTL since JWT parsing will fail err := SetServiceToken(did, holdDID, token) if err != nil { t.Fatalf("SetServiceToken() error = %v", err) } // Verify token was cached cachedToken, expiresAt := GetServiceToken(did, holdDID) if cachedToken != token { t.Errorf("Expected token %q, got %q", token, cachedToken) } if expiresAt.IsZero() { t.Error("Expected non-zero expiry time") } // Expiry should be approximately 50s from now (with 10s margin subtracted in some cases) expectedExpiry := time.Now().Add(50 * time.Second) diff := expiresAt.Sub(expectedExpiry) if diff < -5*time.Second || diff > 5*time.Second { t.Errorf("Expiry time off by %v (expected ~50s from now)", diff) } } func TestGetServiceToken_Expired(t *testing.T) { // Manually insert an expired token did := "did:plc:test123" holdDID := "did:web:hold.example.com" cacheKey := did + ":" + holdDID globalServiceTokensMu.Lock() globalServiceTokens[cacheKey] = &serviceTokenEntry{ token: "expired_token", expiresAt: time.Now().Add(-1 * time.Hour), // 1 hour ago } globalServiceTokensMu.Unlock() // Try to get - should return empty since expired token, expiresAt := GetServiceToken(did, holdDID) if token != "" { t.Errorf("Expected empty token for expired entry, got %q", token) } if !expiresAt.IsZero() { t.Error("Expected zero time for expired entry") } // Verify token was removed from cache globalServiceTokensMu.RLock() _, exists := globalServiceTokens[cacheKey] globalServiceTokensMu.RUnlock() if exists { t.Error("Expected expired token to be removed from cache") } } func TestInvalidateServiceToken(t *testing.T) { // Set a token did := "did:plc:test123" holdDID := "did:web:hold.example.com" token := "test_token" err := SetServiceToken(did, holdDID, token) if err != nil { t.Fatalf("SetServiceToken() error = %v", err) } // Verify it's cached cachedToken, _ := GetServiceToken(did, holdDID) if cachedToken != token { t.Fatal("Token should be cached") } // Invalidate InvalidateServiceToken(did, holdDID) // Verify it's gone cachedToken, _ = GetServiceToken(did, holdDID) if cachedToken != "" { t.Error("Expected token to be invalidated") } } func TestCleanExpiredTokens(t *testing.T) { // Clear cache first globalServiceTokensMu.Lock() globalServiceTokens = make(map[string]*serviceTokenEntry) globalServiceTokensMu.Unlock() // Add expired and valid tokens globalServiceTokensMu.Lock() globalServiceTokens["expired:hold1"] = &serviceTokenEntry{ token: "expired1", expiresAt: time.Now().Add(-1 * time.Hour), } globalServiceTokens["valid:hold2"] = &serviceTokenEntry{ token: "valid1", expiresAt: time.Now().Add(1 * time.Hour), } globalServiceTokensMu.Unlock() // Clean expired CleanExpiredTokens() // Verify only valid token remains globalServiceTokensMu.RLock() _, expiredExists := globalServiceTokens["expired:hold1"] _, validExists := globalServiceTokens["valid:hold2"] globalServiceTokensMu.RUnlock() if expiredExists { t.Error("Expected expired token to be removed") } if !validExists { t.Error("Expected valid token to remain") } } func TestGetCacheStats(t *testing.T) { // Clear cache first globalServiceTokensMu.Lock() globalServiceTokens = make(map[string]*serviceTokenEntry) globalServiceTokensMu.Unlock() // Add some tokens globalServiceTokensMu.Lock() globalServiceTokens["did1:hold1"] = &serviceTokenEntry{ token: "token1", expiresAt: time.Now().Add(1 * time.Hour), } globalServiceTokens["did2:hold2"] = &serviceTokenEntry{ token: "token2", expiresAt: time.Now().Add(1 * time.Hour), } globalServiceTokensMu.Unlock() stats := GetCacheStats() if stats == nil { t.Fatal("Expected non-nil stats") } // GetCacheStats returns map[string]any with "total_entries" key totalEntries, ok := stats["total_entries"].(int) if !ok { t.Fatalf("Expected total_entries in stats map, got: %v", stats) } if totalEntries != 2 { t.Errorf("Expected 2 entries, got %d", totalEntries) } // Also check valid_tokens validTokens, ok := stats["valid_tokens"].(int) if !ok { t.Fatal("Expected valid_tokens in stats map") } if validTokens != 2 { t.Errorf("Expected 2 valid tokens, got %d", validTokens) } }