mirror of
https://github.com/lukaszraczylo/traefikoidc.git
synced 2026-10-14 04:07:46 +00:00
325 lines
8.9 KiB
Go
325 lines
8.9 KiB
Go
package traefikoidc
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestPerformanceMetrics(t *testing.T) {
|
|
logger := NewLogger("debug")
|
|
metrics := NewPerformanceMetrics(logger)
|
|
|
|
t.Run("Record cache operations", func(t *testing.T) {
|
|
metrics.RecordCacheHit()
|
|
metrics.RecordCacheMiss()
|
|
metrics.RecordCacheEviction()
|
|
metrics.UpdateCacheSize(100)
|
|
|
|
result := metrics.GetMetrics()
|
|
|
|
if result["cache_hits"].(int64) != 1 {
|
|
t.Errorf("Expected 1 cache hit, got %v", result["cache_hits"])
|
|
}
|
|
if result["cache_misses"].(int64) != 1 {
|
|
t.Errorf("Expected 1 cache miss, got %v", result["cache_misses"])
|
|
}
|
|
if result["cache_evictions"].(int64) != 1 {
|
|
t.Errorf("Expected 1 cache eviction, got %v", result["cache_evictions"])
|
|
}
|
|
if result["cache_size"].(int64) != 100 {
|
|
t.Errorf("Expected cache size 100, got %v", result["cache_size"])
|
|
}
|
|
})
|
|
|
|
t.Run("Record token operations", func(t *testing.T) {
|
|
start := time.Now()
|
|
time.Sleep(10 * time.Millisecond)
|
|
metrics.RecordTokenVerification(time.Since(start), true)
|
|
|
|
start = time.Now()
|
|
time.Sleep(5 * time.Millisecond)
|
|
metrics.RecordTokenValidation(time.Since(start), false)
|
|
|
|
start = time.Now()
|
|
time.Sleep(15 * time.Millisecond)
|
|
metrics.RecordTokenRefresh(time.Since(start), true)
|
|
|
|
result := metrics.GetMetrics()
|
|
|
|
if result["token_verifications"].(int64) != 1 {
|
|
t.Errorf("Expected 1 token verification, got %v", result["token_verifications"])
|
|
}
|
|
if result["token_validations"].(int64) != 1 {
|
|
t.Errorf("Expected 1 token validation, got %v", result["token_validations"])
|
|
}
|
|
if result["token_refreshes"].(int64) != 1 {
|
|
t.Errorf("Expected 1 token refresh, got %v", result["token_refreshes"])
|
|
}
|
|
if result["successful_verifications"].(int64) != 1 {
|
|
t.Errorf("Expected 1 successful verification, got %v", result["successful_verifications"])
|
|
}
|
|
if result["failed_validations"].(int64) != 1 {
|
|
t.Errorf("Expected 1 failed validation, got %v", result["failed_validations"])
|
|
}
|
|
})
|
|
|
|
t.Run("Record rate limiting and sessions", func(t *testing.T) {
|
|
metrics.RecordRateLimitedRequest()
|
|
metrics.RecordSessionCreation()
|
|
metrics.RecordSessionDeletion()
|
|
|
|
result := metrics.GetMetrics()
|
|
|
|
if result["rate_limited_requests"].(int64) != 1 {
|
|
t.Errorf("Expected 1 rate limited request, got %v", result["rate_limited_requests"])
|
|
}
|
|
if result["sessions_created"].(int64) != 1 {
|
|
t.Errorf("Expected 1 session created, got %v", result["sessions_created"])
|
|
}
|
|
if result["sessions_deleted"].(int64) != 1 {
|
|
t.Errorf("Expected 1 session deleted, got %v", result["sessions_deleted"])
|
|
}
|
|
})
|
|
|
|
t.Run("Get detailed timing metrics", func(t *testing.T) {
|
|
// Add more timing data
|
|
for i := range 5 {
|
|
metrics.RecordTokenVerification(time.Duration(i+1)*time.Millisecond, true)
|
|
}
|
|
|
|
detailed := metrics.GetDetailedTimingMetrics()
|
|
|
|
if detailed["verification_stats"] == nil {
|
|
t.Error("Expected verification stats to be present")
|
|
}
|
|
|
|
verificationStats := detailed["verification_stats"].(map[string]any)
|
|
if verificationStats["count"].(int) != 6 { // 1 from previous test + 5 new
|
|
t.Errorf("Expected 6 verifications, got %v", verificationStats["count"])
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestResourceMonitor(t *testing.T) {
|
|
logger := NewLogger("debug")
|
|
metrics := NewPerformanceMetrics(logger)
|
|
monitor := NewResourceMonitor(metrics, logger)
|
|
|
|
t.Run("Set limits", func(t *testing.T) {
|
|
monitor.SetMemoryLimit(100 * 1024 * 1024) // 100MB
|
|
monitor.SetCacheLimit(1000)
|
|
monitor.SetSessionLimit(500)
|
|
|
|
// Should not panic
|
|
})
|
|
|
|
t.Run("Get resource status", func(t *testing.T) {
|
|
status := monitor.GetResourceStatus()
|
|
|
|
if status["memory_limit"] == nil {
|
|
t.Error("Expected memory limit to be set")
|
|
}
|
|
if status["cache_limit"] == nil {
|
|
t.Error("Expected cache limit to be set")
|
|
}
|
|
if status["session_limit"] == nil {
|
|
t.Error("Expected session limit to be set")
|
|
}
|
|
})
|
|
|
|
t.Run("Get alerts", func(t *testing.T) {
|
|
alerts := monitor.GetAlerts()
|
|
|
|
// Should return empty slice initially
|
|
if alerts == nil {
|
|
t.Error("Expected alerts slice to be initialized")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestPerformanceMetricsCalculations(t *testing.T) {
|
|
logger := NewLogger("debug")
|
|
metrics := NewPerformanceMetrics(logger)
|
|
|
|
t.Run("Average calculation", func(t *testing.T) {
|
|
// Record multiple operations with known durations
|
|
durations := []time.Duration{
|
|
10 * time.Millisecond,
|
|
20 * time.Millisecond,
|
|
30 * time.Millisecond,
|
|
}
|
|
|
|
for _, d := range durations {
|
|
metrics.RecordTokenVerification(d, true)
|
|
}
|
|
|
|
detailed := metrics.GetDetailedTimingMetrics()
|
|
verificationStats := detailed["verification_stats"].(map[string]any)
|
|
|
|
// Average should be 20ms
|
|
avgMs := verificationStats["average_ms"].(float64)
|
|
if avgMs < 19 || avgMs > 21 { // Allow small variance
|
|
t.Errorf("Expected average around 20ms, got %f", avgMs)
|
|
}
|
|
})
|
|
|
|
t.Run("Min/Max calculation", func(t *testing.T) {
|
|
logger := NewLogger("debug")
|
|
metrics := NewPerformanceMetrics(logger) // Fresh instance
|
|
|
|
durations := []time.Duration{
|
|
5 * time.Millisecond,
|
|
50 * time.Millisecond,
|
|
25 * time.Millisecond,
|
|
}
|
|
|
|
for _, d := range durations {
|
|
metrics.RecordTokenVerification(d, true)
|
|
}
|
|
|
|
detailed := metrics.GetDetailedTimingMetrics()
|
|
verificationStats := detailed["verification_stats"].(map[string]any)
|
|
|
|
minMs := verificationStats["min_ms"].(float64)
|
|
maxMs := verificationStats["max_ms"].(float64)
|
|
|
|
if minMs < 4 || minMs > 6 {
|
|
t.Errorf("Expected min around 5ms, got %f", minMs)
|
|
}
|
|
if maxMs < 49 || maxMs > 51 {
|
|
t.Errorf("Expected max around 50ms, got %f", maxMs)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestPerformanceMetricsReset(t *testing.T) {
|
|
logger := NewLogger("debug")
|
|
metrics := NewPerformanceMetrics(logger)
|
|
|
|
// Record some data
|
|
metrics.RecordCacheHit()
|
|
metrics.RecordTokenVerification(10*time.Millisecond, true)
|
|
|
|
// Verify data is there
|
|
result := metrics.GetMetrics()
|
|
if result["cache_hits"].(int64) != 1 {
|
|
t.Error("Expected cache hit to be recorded")
|
|
}
|
|
|
|
// Note: The current implementation doesn't have a reset method,
|
|
// but we can test that metrics accumulate correctly
|
|
metrics.RecordCacheHit()
|
|
result = metrics.GetMetrics()
|
|
if result["cache_hits"].(int64) != 2 {
|
|
t.Error("Expected cache hits to accumulate")
|
|
}
|
|
}
|
|
|
|
func TestPerformanceMetricsConcurrency(t *testing.T) {
|
|
logger := NewLogger("debug")
|
|
metrics := NewPerformanceMetrics(logger)
|
|
|
|
// Test concurrent access
|
|
done := make(chan bool, 10)
|
|
|
|
for range 10 {
|
|
go func() {
|
|
defer func() { done <- true }()
|
|
|
|
for range 100 {
|
|
metrics.RecordCacheHit()
|
|
metrics.RecordTokenVerification(time.Millisecond, true)
|
|
}
|
|
}()
|
|
}
|
|
|
|
// Wait for all goroutines to complete
|
|
for range 10 {
|
|
<-done
|
|
}
|
|
|
|
result := metrics.GetMetrics()
|
|
|
|
// Should have 1000 cache hits (10 goroutines * 100 operations)
|
|
if result["cache_hits"].(int64) != 1000 {
|
|
t.Errorf("Expected 1000 cache hits, got %v", result["cache_hits"])
|
|
}
|
|
|
|
// Should have 1000 token verifications
|
|
if result["token_verifications"].(int64) != 1000 {
|
|
t.Errorf("Expected 1000 token verifications, got %v", result["token_verifications"])
|
|
}
|
|
}
|
|
|
|
func TestResourceMonitorLimits(t *testing.T) {
|
|
logger := NewLogger("debug")
|
|
metrics := NewPerformanceMetrics(logger)
|
|
monitor := NewResourceMonitor(metrics, logger)
|
|
|
|
t.Run("Memory limit validation", func(t *testing.T) {
|
|
// Set a reasonable memory limit
|
|
monitor.SetMemoryLimit(50 * 1024 * 1024) // 50MB
|
|
|
|
status := monitor.GetResourceStatus()
|
|
if status["memory_limit"].(uint64) != 50*1024*1024 {
|
|
t.Error("Memory limit not set correctly")
|
|
}
|
|
})
|
|
|
|
t.Run("Cache limit validation", func(t *testing.T) {
|
|
monitor.SetCacheLimit(2000)
|
|
|
|
status := monitor.GetResourceStatus()
|
|
if status["cache_limit"].(int) != 2000 {
|
|
t.Error("Cache limit not set correctly")
|
|
}
|
|
})
|
|
|
|
t.Run("Session limit validation", func(t *testing.T) {
|
|
monitor.SetSessionLimit(1000)
|
|
|
|
status := monitor.GetResourceStatus()
|
|
if status["session_limit"].(int) != 1000 {
|
|
t.Error("Session limit not set correctly")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestPerformanceMetricsEdgeCases(t *testing.T) {
|
|
logger := NewLogger("debug")
|
|
metrics := NewPerformanceMetrics(logger)
|
|
|
|
t.Run("Zero duration handling", func(t *testing.T) {
|
|
metrics.RecordTokenVerification(0, true)
|
|
|
|
result := metrics.GetMetrics()
|
|
if result["token_verifications"].(int64) != 1 {
|
|
t.Error("Should record verification even with zero duration")
|
|
}
|
|
})
|
|
|
|
t.Run("Very large duration handling", func(t *testing.T) {
|
|
largeDuration := time.Hour
|
|
metrics.RecordTokenVerification(largeDuration, true)
|
|
|
|
detailed := metrics.GetDetailedTimingMetrics()
|
|
verificationStats := detailed["verification_stats"].(map[string]any)
|
|
|
|
// Should handle large durations without overflow
|
|
if verificationStats["max_ms"].(float64) <= 0 {
|
|
t.Error("Should handle large durations correctly")
|
|
}
|
|
})
|
|
|
|
t.Run("Negative cache size handling", func(t *testing.T) {
|
|
// This shouldn't happen in practice, but test robustness
|
|
metrics.UpdateCacheSize(-1)
|
|
|
|
result := metrics.GetMetrics()
|
|
// Implementation should handle this gracefully
|
|
if result["cache_size"] == nil {
|
|
t.Error("Cache size should be present even if negative")
|
|
}
|
|
})
|
|
}
|