fixup! Further pursue of perfection.

This commit is contained in:
2025-09-04 22:43:39 +01:00
parent 29ec26cbaa
commit f291dcca26
43 changed files with 3995 additions and 2916 deletions
+495
View File
@@ -0,0 +1,495 @@
package traefikoidc
import (
"encoding/base64"
"encoding/json"
"fmt"
"strings"
"sync"
"testing"
"time"
)
// Test the core OptimizedCache functionality that's not covered
func TestOptimizedCacheBasic(t *testing.T) {
cache := NewOptimizedCache()
if cache == nil {
t.Fatal("NewOptimizedCache returned nil")
}
// Basic set and get
cache.Set("test_key", "test_value", 5*time.Minute)
if val, found := cache.Get("test_key"); !found || val != "test_value" {
t.Errorf("Failed to get cached value: %v, %v", val, found)
}
// Delete
cache.Delete("test_key")
if _, found := cache.Get("test_key"); found {
t.Error("Value should be deleted")
}
// Test with config
logger := NewLogger("debug")
cache2 := NewOptimizedCacheWithConfig(50, 10, logger)
if cache2 == nil {
t.Fatal("NewOptimizedCacheWithConfig returned nil")
}
// Test cleanup
cache2.Set("expire", "value", 100*time.Millisecond)
time.Sleep(150 * time.Millisecond)
cache2.Cleanup()
if _, found := cache2.Get("expire"); found {
t.Error("Expired item should be cleaned up")
}
// Test close
cache2.Close()
}
// Test UnifiedCache basic functionality
func TestUnifiedCacheBasic(t *testing.T) {
config := DefaultUnifiedCacheConfig()
if config.MaxSize <= 0 {
t.Error("Default config should have positive MaxSize")
}
cache := NewUnifiedCache(config)
if cache == nil {
t.Fatal("NewUnifiedCache returned nil")
}
// Basic operations
cache.Set("key1", "value1", 5*time.Minute)
if val, found := cache.Get("key1"); !found || val != "value1" {
t.Errorf("Failed to get cached value: %v", val)
}
cache.Delete("key1")
if _, found := cache.Get("key1"); found {
t.Error("Value should be deleted")
}
// Cleanup
cache.Set("expired", "value", 1*time.Nanosecond)
time.Sleep(10 * time.Millisecond)
cache.Cleanup()
// GetMetrics
metrics := cache.GetMetrics()
if metrics == nil {
t.Error("GetMetrics should not return nil")
}
cache.Close()
}
// Test memory pool functionality
func TestMemoryPoolBasic(t *testing.T) {
manager := NewMemoryPoolManager()
if manager == nil {
t.Fatal("NewMemoryPoolManager returned nil")
}
// Test compression buffer
buf := manager.GetCompressionBuffer()
if buf == nil {
t.Fatal("GetCompressionBuffer returned nil")
}
buf.WriteString("test")
manager.PutCompressionBuffer(buf)
// Test JWT parsing buffer
jwtBuf := manager.GetJWTParsingBuffer()
if jwtBuf == nil {
t.Fatal("GetJWTParsingBuffer returned nil")
}
manager.PutJWTParsingBuffer(jwtBuf)
// Test HTTP response buffer
httpBuf := manager.GetHTTPResponseBuffer()
if httpBuf == nil {
t.Fatal("GetHTTPResponseBuffer returned nil")
}
manager.PutHTTPResponseBuffer(httpBuf)
// Test string builder
sb := manager.GetStringBuilder()
if sb == nil {
t.Fatal("GetStringBuilder returned nil")
}
manager.PutStringBuilder(sb)
}
// Test global memory pools
func TestGlobalPools(t *testing.T) {
pools := GetGlobalMemoryPools()
if pools == nil {
t.Fatal("GetGlobalMemoryPools returned nil")
}
// Should be singleton
pools2 := GetGlobalMemoryPools()
if pools != pools2 {
t.Error("GetGlobalMemoryPools should return singleton")
}
// Cleanup should not panic
CleanupGlobalMemoryPools()
}
// Test TokenCompressionPool
func TestTokenCompression(t *testing.T) {
pool := NewTokenCompressionPool()
if pool == nil {
t.Fatal("NewTokenCompressionPool returned nil")
}
compBuf := pool.GetCompressionBuffer()
if compBuf == nil {
t.Fatal("GetCompressionBuffer returned nil")
}
pool.PutCompressionBuffer(compBuf)
decompBuf := pool.GetDecompressionBuffer()
if decompBuf == nil {
t.Fatal("GetDecompressionBuffer returned nil")
}
pool.PutDecompressionBuffer(decompBuf)
}
// Test error recovery base functionality
func TestErrorRecoveryBasic(t *testing.T) {
logger := NewLogger("debug")
// Test BaseRecoveryMechanism
base := NewBaseRecoveryMechanism("test", logger)
base.RecordRequest()
base.RecordSuccess()
base.RecordFailure()
metrics := base.GetBaseMetrics()
if metrics == nil {
t.Fatal("GetBaseMetrics returned nil")
}
// Test CircuitBreaker
cbConfig := CircuitBreakerConfig{
MaxFailures: 3,
ResetTimeout: 100 * time.Millisecond,
}
cb := NewCircuitBreaker(cbConfig, logger)
if cb.GetState() != CircuitBreakerClosed {
t.Error("Initial state should be closed")
}
// Trip the circuit
for i := 0; i < 3; i++ {
cb.Execute(func() error {
return fmt.Errorf("error")
})
}
if cb.GetState() != CircuitBreakerOpen {
t.Error("Circuit should be open after max failures")
}
cb.Reset()
if cb.GetState() != CircuitBreakerClosed {
t.Error("Circuit should be closed after reset")
}
// Test RetryExecutor
retryConfig := RetryConfig{
MaxAttempts: 3,
InitialDelay: 10 * time.Millisecond,
}
re := NewRetryExecutor(retryConfig, logger)
if re != nil && !re.IsAvailable() {
t.Error("RetryExecutor should be available")
}
}
// Test profiling components
func TestProfilingBasic(t *testing.T) {
logger := NewLogger("debug")
// Test ProfilingManager
pm := NewProfilingManager(logger)
if pm == nil {
t.Fatal("NewProfilingManager returned nil")
}
// Take snapshot - may fail if profiling is disabled
snapshot, _ := pm.TakeSnapshot()
if snapshot != nil {
t.Log("Snapshot taken successfully")
}
// Test global singletons
globalPM := GetGlobalProfilingManager()
if globalPM == nil {
t.Fatal("GetGlobalProfilingManager returned nil")
}
globalMTO := GetGlobalTestOrchestrator()
if globalMTO == nil {
t.Fatal("GetGlobalTestOrchestrator returned nil")
}
}
// Test cache strategies
func TestCacheStrategies(t *testing.T) {
// Test LRU strategy
lru := NewLRUStrategy(10)
if lru.Name() != "LRU" {
t.Errorf("Expected LRU name, got %s", lru.Name())
}
// Test doubly linked list
list := NewDoublyLinkedList()
node1 := list.PushBack("key1")
if node1 == nil || node1.Key != "key1" {
t.Error("PushBack failed")
}
list.PushBack("key2")
list.PushBack("key3")
list.MoveToBack(node1)
popped := list.PopFront()
if popped == nil || popped.Key != "key2" {
t.Errorf("Expected key2, got %v", popped)
}
}
// Test CacheAdapter
func TestCacheAdapterBasic(t *testing.T) {
config := DefaultUnifiedCacheConfig()
unified := NewUnifiedCache(config)
adapter := NewCacheAdapter(unified)
adapter.Set("key", "value", 5*time.Minute)
if val, found := adapter.Get("key"); !found || val != "value" {
t.Errorf("CacheAdapter get failed: %v", val)
}
adapter.Delete("key")
adapter.Cleanup()
adapter.Close()
}
// Test JWT validation edge cases
func TestJWTValidationCases(t *testing.T) {
validator := NewTokenValidator(NewLogger("debug"))
// Test valid JWT
header := base64.RawURLEncoding.EncodeToString([]byte(`{"alg":"RS256","typ":"JWT"}`))
claims := map[string]interface{}{
"sub": "user123",
"exp": time.Now().Add(1 * time.Hour).Unix(),
"iat": time.Now().Unix(),
}
claimsJSON, _ := json.Marshal(claims)
payload := base64.RawURLEncoding.EncodeToString(claimsJSON)
signature := base64.RawURLEncoding.EncodeToString([]byte("fake-signature"))
token := header + "." + payload + "." + signature
result := validator.ValidateToken(token, true)
if !result.Valid {
t.Errorf("Expected valid token, got error: %v", result.Error)
}
// Test expired JWT
expiredClaims := map[string]interface{}{
"sub": "user123",
"exp": time.Now().Add(-1 * time.Hour).Unix(),
}
expiredJSON, _ := json.Marshal(expiredClaims)
expiredPayload := base64.RawURLEncoding.EncodeToString(expiredJSON)
expiredToken := header + "." + expiredPayload + "." + signature
expiredResult := validator.ValidateToken(expiredToken, true)
if expiredResult.Valid {
t.Error("Expired token should be invalid")
}
// Test opaque token
opaqueToken := "abcdefghijklmnopqrstuvwxyz1234567890"
opaqueResult := validator.ValidateToken(opaqueToken, false)
if !opaqueResult.Valid {
t.Errorf("Valid opaque token rejected: %v", opaqueResult.Error)
}
// Test ExtractClaims
extractedClaims, err := validator.ExtractClaims(token)
if err != nil || extractedClaims["sub"] != "user123" {
t.Errorf("ExtractClaims failed: %v", err)
}
// Test CompareTokens
if !validator.CompareTokens("token123", "token123") {
t.Error("Identical tokens should match")
}
if validator.CompareTokens("token123", "token456") {
t.Error("Different tokens should not match")
}
// Test ValidateTokenSize
if err := validator.ValidateTokenSize("small", 100); err != nil {
t.Errorf("Small token should be valid: %v", err)
}
if err := validator.ValidateTokenSize(strings.Repeat("a", 200), 100); err == nil {
t.Error("Large token should be invalid")
}
}
// Test replay cache
func TestReplayCacheBasic(t *testing.T) {
// Test getReplayCacheStats
size, maxSize := getReplayCacheStats()
if size < 0 || maxSize <= 0 {
t.Errorf("Invalid replay cache stats: size=%d, maxSize=%d", size, maxSize)
}
// Test cleanupReplayCache (should not panic)
cleanupReplayCache()
}
// Test audience verification
func TestAudienceVerify(t *testing.T) {
// Exact match
claims1 := map[string]interface{}{
"aud": "my-client",
}
if err := verifyAudience(claims1, "my-client"); err != nil {
t.Errorf("Exact match should succeed: %v", err)
}
// Array contains
claims2 := map[string]interface{}{
"aud": []interface{}{"client1", "my-client", "client2"},
}
if err := verifyAudience(claims2, "my-client"); err != nil {
t.Errorf("Array contains should succeed: %v", err)
}
// Mismatch
claims3 := map[string]interface{}{
"aud": "other-client",
}
if err := verifyAudience(claims3, "my-client"); err == nil {
t.Error("Mismatch should fail")
}
// Missing
claims4 := map[string]interface{}{}
if err := verifyAudience(claims4, "my-client"); err == nil {
t.Error("Missing aud should fail")
}
}
// Test helper functions
func TestHelpers(t *testing.T) {
// Test nonce generation
nonce1, err := generateNonce()
if err != nil {
t.Fatalf("generateNonce failed: %v", err)
}
if len(nonce1) == 0 {
t.Error("Nonce should not be empty")
}
nonce2, _ := generateNonce()
if nonce1 == nonce2 {
t.Error("Nonces should be unique")
}
// Test code verifier generation
verifier1, err := generateCodeVerifier()
if err != nil {
t.Fatalf("generateCodeVerifier failed: %v", err)
}
if len(verifier1) == 0 {
t.Error("Code verifier should not be empty")
}
verifier2, _ := generateCodeVerifier()
if verifier1 == verifier2 {
t.Error("Code verifiers should be unique")
}
}
// Test HTTP client factory
func TestHTTPClientCreation(t *testing.T) {
// Default client
client1 := CreateDefaultHTTPClient()
if client1 == nil {
t.Fatal("CreateDefaultHTTPClient returned nil")
}
if client1.Timeout != 30*time.Second {
t.Errorf("Expected 30s timeout, got %v", client1.Timeout)
}
// Token client
client2 := CreateTokenHTTPClient()
if client2 == nil {
t.Fatal("CreateTokenHTTPClient returned nil")
}
if client2.Timeout != 10*time.Second {
t.Errorf("Expected 10s timeout, got %v", client2.Timeout)
}
// Custom config client
config := HTTPClientConfig{
Timeout: 5 * time.Second,
DisableCompression: true,
DisableKeepAlives: true,
}
client3 := CreateHTTPClientWithConfig(config)
if client3 == nil {
t.Fatal("CreateHTTPClientWithConfig returned nil")
}
if client3.Timeout != 5*time.Second {
t.Errorf("Expected 5s timeout, got %v", client3.Timeout)
}
}
// Test metadata cache
func TestMetadataCaching(t *testing.T) {
var wg sync.WaitGroup
logger := NewLogger("debug")
cache := NewMetadataCacheWithLogger(&wg, logger)
if cache == nil {
t.Fatal("NewMetadataCache returned nil")
}
// Basic test that cache was created
}
// Test JWT parsing
func TestJWTParsing(t *testing.T) {
header := base64.RawURLEncoding.EncodeToString([]byte(`{"alg":"RS256","typ":"JWT"}`))
claims := map[string]interface{}{
"sub": "user123",
"exp": time.Now().Add(1 * time.Hour).Unix(),
}
claimsJSON, _ := json.Marshal(claims)
payload := base64.RawURLEncoding.EncodeToString(claimsJSON)
signature := base64.RawURLEncoding.EncodeToString([]byte("signature"))
token := header + "." + payload + "." + signature
parsedJWT, err := parseJWT(token)
if err != nil {
t.Fatalf("Failed to parse JWT: %v", err)
}
if parsedJWT.Claims["sub"] != "user123" {
t.Errorf("Expected sub=user123, got %v", parsedJWT.Claims["sub"])
}
}