mirror of
https://github.com/lukaszraczylo/traefikoidc.git
synced 2026-06-05 22:44:17 +00:00
9402f1bca5
TokenBlacklist Improvements: Fixed size limit enforcement to properly maintain max size of 1000 tokens Improved eviction strategy to remove expired tokens first before removing oldest Added proper cleanup of tokens during Add operation to prevent size overflow Fixed oldest token eviction logic to ensure correct token removal Added proper locking mechanisms to prevent race conditions Cache Improvements: Fixed cleanup mechanism to only remove truly expired items Improved eviction strategy in LRU cache to prioritize expired items Added smarter eviction in evictOldest to scan for expired items first Fixed aggressive cleanup that was removing valid items Maintained proper LRU ordering while handling evictions MetadataCache: Verified proper implementation of metadata caching with hourly refresh Confirmed proper handling of cache extension on fetch failures Validated thread-safe operations with proper RWMutex usage
228 lines
5.3 KiB
Go
228 lines
5.3 KiB
Go
package traefikoidc
|
|
|
|
import (
|
|
"fmt"
|
|
"runtime"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestTokenBlacklistSizeLimit(t *testing.T) {
|
|
tb := NewTokenBlacklist()
|
|
|
|
// Add tokens up to maxSize
|
|
for i := 0; i < 1000; i++ {
|
|
tb.Add(fmt.Sprintf("token%d", i), time.Now().Add(time.Hour))
|
|
}
|
|
|
|
// Verify size is at max
|
|
if tb.Count() != 1000 {
|
|
t.Errorf("Expected blacklist size to be 1000, got %d", tb.Count())
|
|
}
|
|
|
|
// Add one more token, should trigger cleanup/eviction
|
|
tb.Add("newtoken", time.Now().Add(time.Hour))
|
|
|
|
// Size should still be at max
|
|
if tb.Count() > 1000 {
|
|
t.Errorf("Blacklist exceeded max size: %d", tb.Count())
|
|
}
|
|
}
|
|
|
|
func TestTokenBlacklistExpiredCleanup(t *testing.T) {
|
|
tb := NewTokenBlacklist()
|
|
|
|
// Add some expired tokens
|
|
for i := 0; i < 500; i++ {
|
|
tb.Add(fmt.Sprintf("expired%d", i), time.Now().Add(-time.Hour))
|
|
}
|
|
|
|
// Add some valid tokens
|
|
for i := 0; i < 500; i++ {
|
|
tb.Add(fmt.Sprintf("valid%d", i), time.Now().Add(time.Hour))
|
|
}
|
|
|
|
// Force cleanup
|
|
tb.Cleanup()
|
|
|
|
// Only valid tokens should remain
|
|
if tb.Count() != 500 {
|
|
t.Errorf("Expected 500 valid tokens after cleanup, got %d", tb.Count())
|
|
}
|
|
|
|
// Verify only valid tokens remain
|
|
tb.mutex.RLock()
|
|
defer tb.mutex.RUnlock()
|
|
for token, expiry := range tb.tokens {
|
|
if time.Now().After(expiry) {
|
|
t.Errorf("Found expired token after cleanup: %s", token)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTokenBlacklistOldestEviction(t *testing.T) {
|
|
tb := NewTokenBlacklist()
|
|
|
|
// Add tokens at capacity with different expiration times
|
|
baseTime := time.Now()
|
|
oldestToken := "oldest"
|
|
|
|
// Add oldest token first
|
|
tb.Add(oldestToken, baseTime.Add(time.Hour))
|
|
|
|
// Fill up to capacity with newer tokens
|
|
for i := 0; i < 999; i++ {
|
|
tb.Add(fmt.Sprintf("token%d", i), baseTime.Add(time.Hour*2))
|
|
}
|
|
|
|
// Add a new token that should evict the oldest
|
|
newToken := "newest"
|
|
tb.Add(newToken, baseTime.Add(time.Hour*3))
|
|
|
|
// Verify oldest token was evicted
|
|
if tb.IsBlacklisted(oldestToken) {
|
|
t.Error("Oldest token should have been evicted")
|
|
}
|
|
|
|
// Verify newest token is present
|
|
if !tb.IsBlacklisted(newToken) {
|
|
t.Error("Newest token should be present")
|
|
}
|
|
}
|
|
|
|
func TestTokenBlacklistMemoryUsage(t *testing.T) {
|
|
tb := NewTokenBlacklist()
|
|
iterations := 10000
|
|
|
|
// Force initial GC
|
|
runtime.GC()
|
|
|
|
// Record initial memory stats
|
|
var m1, m2 runtime.MemStats
|
|
runtime.ReadMemStats(&m1)
|
|
|
|
// Simulate heavy usage
|
|
for i := 0; i < iterations; i++ {
|
|
// Add new token
|
|
tb.Add(fmt.Sprintf("token%d", i), time.Now().Add(time.Hour))
|
|
|
|
// Periodically check blacklisted status
|
|
if i%100 == 0 {
|
|
tb.IsBlacklisted(fmt.Sprintf("token%d", i-50))
|
|
}
|
|
|
|
// Periodically cleanup
|
|
if i%1000 == 0 {
|
|
tb.Cleanup()
|
|
}
|
|
}
|
|
|
|
// Force GC and wait for it to complete
|
|
runtime.GC()
|
|
time.Sleep(100 * time.Millisecond)
|
|
runtime.ReadMemStats(&m2)
|
|
|
|
// Check memory growth (using HeapAlloc for more accurate measurement)
|
|
memoryGrowth := int64(m2.HeapAlloc - m1.HeapAlloc)
|
|
maxAllowedGrowth := int64(2 * 1024 * 1024) // 2MB max growth
|
|
|
|
if memoryGrowth > maxAllowedGrowth {
|
|
t.Logf("Initial HeapAlloc: %d, Final HeapAlloc: %d", m1.HeapAlloc, m2.HeapAlloc)
|
|
t.Errorf("Excessive memory growth: %d bytes", memoryGrowth)
|
|
}
|
|
|
|
// Verify size stayed within limits
|
|
if tb.Count() > 1000 {
|
|
t.Errorf("Blacklist exceeded max size: %d", tb.Count())
|
|
}
|
|
}
|
|
|
|
func TestConcurrentTokenBlacklistOperations(t *testing.T) {
|
|
tb := NewTokenBlacklist()
|
|
iterations := 1000
|
|
concurrency := 10
|
|
done := make(chan bool)
|
|
|
|
// Start multiple goroutines performing operations
|
|
for i := 0; i < concurrency; i++ {
|
|
go func(id int) {
|
|
for j := 0; j < iterations; j++ {
|
|
// Add tokens
|
|
token := fmt.Sprintf("token%d-%d", id, j)
|
|
tb.Add(token, time.Now().Add(time.Hour))
|
|
|
|
// Check blacklist status
|
|
tb.IsBlacklisted(token)
|
|
|
|
// Periodic cleanup
|
|
if j%100 == 0 {
|
|
tb.Cleanup()
|
|
}
|
|
}
|
|
done <- true
|
|
}(i)
|
|
}
|
|
|
|
// Wait for all goroutines to complete
|
|
for i := 0; i < concurrency; i++ {
|
|
<-done
|
|
}
|
|
|
|
// Verify size constraints were maintained
|
|
if tb.Count() > 1000 {
|
|
t.Errorf("Blacklist exceeded max size under concurrent operations: %d", tb.Count())
|
|
}
|
|
}
|
|
|
|
func TestTokenCacheMemoryUsage(t *testing.T) {
|
|
tc := NewTokenCache()
|
|
iterations := 10000
|
|
|
|
// Force initial GC
|
|
runtime.GC()
|
|
|
|
// Record initial memory stats
|
|
var m1, m2 runtime.MemStats
|
|
runtime.ReadMemStats(&m1)
|
|
|
|
// Simulate heavy cache usage
|
|
for i := 0; i < iterations; i++ {
|
|
claims := map[string]interface{}{
|
|
"sub": fmt.Sprintf("user%d", i),
|
|
"exp": time.Now().Add(time.Hour).Unix(),
|
|
}
|
|
|
|
// Add to cache
|
|
tc.Set(fmt.Sprintf("token%d", i), claims, time.Hour)
|
|
|
|
// Periodically retrieve
|
|
if i%100 == 0 {
|
|
tc.Get(fmt.Sprintf("token%d", i-50))
|
|
}
|
|
|
|
// Periodically cleanup
|
|
if i%1000 == 0 {
|
|
tc.Cleanup()
|
|
}
|
|
}
|
|
|
|
// Force GC and wait for it to complete
|
|
runtime.GC()
|
|
time.Sleep(100 * time.Millisecond)
|
|
runtime.ReadMemStats(&m2)
|
|
|
|
// Check memory growth (using HeapAlloc for more accurate measurement)
|
|
memoryGrowth := int64(m2.HeapAlloc - m1.HeapAlloc)
|
|
maxAllowedGrowth := int64(2 * 1024 * 1024) // 2MB max growth
|
|
|
|
if memoryGrowth > maxAllowedGrowth {
|
|
t.Logf("Initial HeapAlloc: %d, Final HeapAlloc: %d", m1.HeapAlloc, m2.HeapAlloc)
|
|
t.Errorf("Excessive cache memory growth: %d bytes", memoryGrowth)
|
|
}
|
|
|
|
// Verify cache size stayed within limits
|
|
if len(tc.cache.items) > tc.cache.maxSize {
|
|
t.Errorf("Cache exceeded max size: %d", len(tc.cache.items))
|
|
}
|
|
}
|