mirror of
https://github.com/lukaszraczylo/traefikoidc.git
synced 2026-06-05 22:44:17 +00:00
Release 0.7.5 (#70)
* 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.
This commit is contained in:
@@ -0,0 +1,224 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user