Files
traefikoidc/performance_monitoring_test.go
T
2025-06-20 08:02:26 +01:00

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")
}
})
}