mirror of
https://github.com/lukaszraczylo/traefikoidc.git
synced 2026-06-05 22:44:17 +00:00
c3f23cb99b
* Resolve issue with opaque tokens not being parsed correctly * Increase test coverage * Further improvements to test coverage and code quality * Add new providers. * fixup! Add new providers. * Cleanup. * fixup! Cleanup. * fixup! fixup! Cleanup. * fixup! fixup! fixup! Cleanup. * fixup! fixup! fixup! fixup! Cleanup. * Memory management optimisation 24 bytes per Put < 256-4096 bytes per buffer allocation avoided (10-170x difference) * Pooling cleanup.
225 lines
6.4 KiB
Go
225 lines
6.4 KiB
Go
package traefikoidc
|
|
|
|
import (
|
|
"errors"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// globalRegistryMutex protects only the global registry operations
|
|
var globalRegistryMutex sync.Mutex
|
|
|
|
// TestTaskCircuitBreakerOnTaskFailure tests the OnTaskFailure method
|
|
func TestTaskCircuitBreakerOnTaskFailure(t *testing.T) {
|
|
logger := NewLogger("debug") // Create a real logger
|
|
cb := NewTaskCircuitBreaker(3, time.Minute, logger)
|
|
|
|
// Test failure doesn't trigger open state before threshold
|
|
cb.OnTaskFailure("test-task", errors.New("test error"))
|
|
if err := cb.CanCreateTask("test-task"); err != nil {
|
|
t.Error("Circuit breaker should allow task creation after 1 failure (threshold: 3)")
|
|
}
|
|
|
|
// Test failure count reaches threshold and opens circuit
|
|
cb.OnTaskFailure("test-task", errors.New("test error 2"))
|
|
cb.OnTaskFailure("test-task", errors.New("test error 3"))
|
|
|
|
if err := cb.CanCreateTask("test-task"); err == nil {
|
|
t.Error("Circuit breaker should prevent task creation after reaching failure threshold")
|
|
}
|
|
}
|
|
|
|
// TestResetGlobalTaskRegistry tests the reset functionality
|
|
func TestResetGlobalTaskRegistry(t *testing.T) {
|
|
globalRegistryMutex.Lock()
|
|
defer globalRegistryMutex.Unlock()
|
|
|
|
// Get the global registry first
|
|
registry := GetGlobalTaskRegistry()
|
|
|
|
// Create and register a dummy task
|
|
logger := NewLogger("debug")
|
|
task := NewBackgroundTask("test-task", time.Second, func() {
|
|
// Do nothing
|
|
}, logger)
|
|
|
|
registry.RegisterTask("test-task", task)
|
|
|
|
// Verify task is registered
|
|
if registry.GetTaskCount() == 0 {
|
|
t.Error("Expected task to be registered")
|
|
}
|
|
|
|
// Reset the registry
|
|
ResetGlobalTaskRegistry()
|
|
|
|
// Get registry again and verify it's empty
|
|
newRegistry := GetGlobalTaskRegistry()
|
|
if newRegistry.GetTaskCount() != 0 {
|
|
t.Error("Expected registry to be empty after reset")
|
|
}
|
|
}
|
|
|
|
// TestGetTask tests the GetTask method
|
|
func TestGetTask(t *testing.T) {
|
|
globalRegistryMutex.Lock()
|
|
defer globalRegistryMutex.Unlock()
|
|
|
|
// Reset registry to ensure clean state
|
|
ResetGlobalTaskRegistry()
|
|
registry := GetGlobalTaskRegistry()
|
|
|
|
// Test getting non-existent task
|
|
task, exists := registry.GetTask("non-existent")
|
|
if task != nil || exists {
|
|
t.Error("Expected nil and false for non-existent task")
|
|
}
|
|
|
|
// Create and register a task
|
|
logger := NewLogger("debug")
|
|
newTask := NewBackgroundTask("test-task", time.Second, func() {
|
|
// Do nothing
|
|
}, logger)
|
|
|
|
registry.RegisterTask("test-task", newTask)
|
|
|
|
// Test getting existing task
|
|
retrievedTask, exists := registry.GetTask("test-task")
|
|
if retrievedTask == nil || !exists {
|
|
t.Error("Expected to retrieve registered task")
|
|
return
|
|
}
|
|
|
|
if retrievedTask.name != "test-task" {
|
|
t.Errorf("Expected task name 'test-task', got '%s'", retrievedTask.name)
|
|
}
|
|
}
|
|
|
|
// TestNewTaskMemoryMonitor tests the NewTaskMemoryMonitor function
|
|
func TestNewTaskMemoryMonitor(t *testing.T) {
|
|
// No mutex needed - this doesn't modify global state
|
|
logger := NewLogger("debug")
|
|
registry := GetGlobalTaskRegistry()
|
|
monitor := NewTaskMemoryMonitor(logger, registry)
|
|
|
|
if monitor == nil {
|
|
t.Error("Expected NewTaskMemoryMonitor to return non-nil monitor")
|
|
}
|
|
}
|
|
|
|
// TestGetCurrentStats tests the GetCurrentStats method
|
|
func TestGetCurrentStats(t *testing.T) {
|
|
// Don't hold mutex during background task execution to avoid deadlocks
|
|
logger := NewLogger("debug")
|
|
registry := GetGlobalTaskRegistry()
|
|
monitor := NewTaskMemoryMonitor(logger, registry)
|
|
|
|
// Start the monitor and let it collect at least one statistic
|
|
err := monitor.Start(50 * time.Millisecond)
|
|
if err != nil {
|
|
t.Fatalf("Failed to start monitor: %v", err)
|
|
}
|
|
|
|
// Ensure monitor is stopped even if test fails
|
|
defer func() {
|
|
monitor.Stop()
|
|
// Give extra time for cleanup
|
|
time.Sleep(50 * time.Millisecond)
|
|
}()
|
|
|
|
// Wait a bit for the monitor to collect stats
|
|
time.Sleep(150 * time.Millisecond)
|
|
|
|
stats, err := monitor.GetCurrentStats()
|
|
if err != nil {
|
|
// If no stats are available yet, that's acceptable for this test
|
|
t.Logf("No memory statistics available yet: %v", err)
|
|
return
|
|
}
|
|
|
|
// TaskMemoryStats is a struct, not a pointer, so it can't be nil
|
|
if stats.Timestamp.IsZero() {
|
|
t.Error("Expected GetCurrentStats to return valid timestamp")
|
|
}
|
|
}
|
|
|
|
// TestGetStatsHistory tests the GetStatsHistory method
|
|
func TestGetStatsHistory(t *testing.T) {
|
|
// No mutex needed - this just creates a monitor and checks its initial state
|
|
logger := NewLogger("debug")
|
|
registry := GetGlobalTaskRegistry()
|
|
monitor := NewTaskMemoryMonitor(logger, registry)
|
|
|
|
history := monitor.GetStatsHistory()
|
|
if history == nil {
|
|
t.Error("Expected GetStatsHistory to return non-nil history")
|
|
}
|
|
|
|
// A fresh monitor should have empty history
|
|
if len(history) != 0 {
|
|
t.Logf("History length: %d (may be non-empty due to shared global state)", len(history))
|
|
}
|
|
}
|
|
|
|
// TestForceGC tests the ForceGC method
|
|
func TestForceGC(t *testing.T) {
|
|
// No mutex needed - this doesn't modify global state
|
|
logger := NewLogger("debug")
|
|
registry := GetGlobalTaskRegistry()
|
|
monitor := NewTaskMemoryMonitor(logger, registry)
|
|
|
|
// This should not panic and should work
|
|
monitor.ForceGC()
|
|
// No specific verification needed, just ensuring it doesn't crash
|
|
}
|
|
|
|
// TestShutdownAllTasks tests the ShutdownAllTasks function
|
|
func TestShutdownAllTasks(t *testing.T) {
|
|
// Use a unique task name prefix to avoid conflicts with other tests
|
|
taskPrefix := "shutdown-test-"
|
|
|
|
// Create a temporary clean registry state
|
|
func() {
|
|
globalRegistryMutex.Lock()
|
|
defer globalRegistryMutex.Unlock()
|
|
ResetGlobalTaskRegistry()
|
|
}()
|
|
|
|
registry := GetGlobalTaskRegistry()
|
|
logger := NewLogger("debug")
|
|
|
|
// Create some test tasks with unique names
|
|
task1 := NewBackgroundTask(taskPrefix+"task1", time.Millisecond, func() {
|
|
time.Sleep(100 * time.Millisecond) // Simulate work
|
|
}, logger)
|
|
|
|
task2 := NewBackgroundTask(taskPrefix+"task2", time.Millisecond, func() {
|
|
time.Sleep(100 * time.Millisecond) // Simulate work
|
|
}, logger)
|
|
|
|
// Register tasks under mutex protection
|
|
func() {
|
|
globalRegistryMutex.Lock()
|
|
defer globalRegistryMutex.Unlock()
|
|
registry.RegisterTask(taskPrefix+"task1", task1)
|
|
registry.RegisterTask(taskPrefix+"task2", task2)
|
|
}()
|
|
|
|
// Start the tasks (outside mutex to avoid deadlock)
|
|
task1.Start()
|
|
task2.Start()
|
|
|
|
// Give tasks time to start
|
|
time.Sleep(50 * time.Millisecond)
|
|
|
|
// Shutdown all tasks
|
|
ShutdownAllTasks()
|
|
|
|
// Give shutdown time to complete
|
|
time.Sleep(200 * time.Millisecond)
|
|
|
|
// Note: We can't reliably verify task count due to other tests
|
|
// Just ensure shutdown doesn't panic
|
|
}
|