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:
2025-10-01 12:13:10 +01:00
committed by GitHub
parent 3bbc6a1608
commit c3f23cb99b
93 changed files with 26767 additions and 4230 deletions
+224
View File
@@ -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
}