Files
traefikoidc/memory_monitor_singleton_test.go
T

158 lines
3.9 KiB
Go

package traefikoidc
import (
"context"
"runtime"
"sync"
"testing"
"time"
)
func TestMemoryMonitorSingleton(t *testing.T) {
// Reset global state
globalMonitoringMutex.Lock()
globalMonitoringStarted = false
globalMonitoringMutex.Unlock()
// Clear task registry for clean test
registry := GetGlobalTaskRegistry()
registry.StopAllTasks()
// Test that multiple StartMonitoring calls don't create multiple monitors
monitor := GetGlobalMemoryMonitor()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
goroutinesBefore := runtime.NumGoroutine()
// Call StartMonitoring multiple times (simulating multiple middleware instances)
var wg sync.WaitGroup
numCalls := 10
for i := 0; i < numCalls; i++ {
wg.Add(1)
go func() {
defer wg.Done()
monitor.StartMonitoring(ctx, 100*time.Millisecond)
}()
}
wg.Wait()
// Give some time for goroutines to start
time.Sleep(50 * time.Millisecond)
goroutinesAfter := runtime.NumGoroutine()
// Should only create one additional goroutine for the singleton task
goroutineDiff := goroutinesAfter - goroutinesBefore
if goroutineDiff > 2 { // Allow some tolerance for test runner goroutines
t.Errorf("Expected at most 2 additional goroutines, got %d", goroutineDiff)
}
// Check that monitoring is active
if !monitor.IsMonitoringActive() {
t.Error("Memory monitoring should be active")
}
// Verify only one task is registered
taskCount := registry.GetTaskCount()
if taskCount != 1 {
t.Errorf("Expected 1 task, got %d", taskCount)
}
// Check that the task is specifically memory-monitor
if task, exists := registry.GetTask("memory-monitor"); !exists {
t.Error("memory-monitor task should exist")
} else if task == nil {
t.Error("memory-monitor task should not be nil")
}
// Stop monitoring
monitor.StopMonitoring()
// Verify monitoring is no longer active
if monitor.IsMonitoringActive() {
t.Error("Memory monitoring should be inactive after stopping")
}
// Clean up
registry.StopAllTasks()
}
func TestMemoryMonitorSingletonTaskCreation(t *testing.T) {
// Reset global state
globalMonitoringMutex.Lock()
globalMonitoringStarted = false
globalMonitoringMutex.Unlock()
registry := GetGlobalTaskRegistry()
registry.StopAllTasks()
monitor1 := GetGlobalMemoryMonitor()
monitor2 := GetGlobalMemoryMonitor()
// Should be the same instance
if monitor1 != monitor2 {
t.Error("GetGlobalMemoryMonitor should return the same instance")
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// First start should succeed
monitor1.StartMonitoring(ctx, 50*time.Millisecond)
if !monitor1.IsMonitoringActive() {
t.Error("First StartMonitoring should activate monitoring")
}
// Second start should be skipped
monitor2.StartMonitoring(ctx, 50*time.Millisecond)
// Should still only have one task
taskCount := registry.GetTaskCount()
if taskCount != 1 {
t.Errorf("Expected 1 task after duplicate start, got %d", taskCount)
}
// Clean up
monitor1.StopMonitoring()
registry.StopAllTasks()
}
func TestMemoryMonitorTaskRegistryEnforcement(t *testing.T) {
// Reset global state
globalMonitoringMutex.Lock()
globalMonitoringStarted = false
globalMonitoringMutex.Unlock()
registry := GetGlobalTaskRegistry()
registry.StopAllTasks()
// Try to create memory-monitor task directly through registry
task1, err1 := registry.CreateSingletonTask("memory-monitor", 50*time.Millisecond,
func() {}, GetSingletonNoOpLogger(), nil)
if err1 != nil {
t.Fatalf("First memory-monitor task creation should succeed: %v", err1)
}
// Try to create another memory-monitor task - should fail
task2, err2 := registry.CreateSingletonTask("memory-monitor-2", 50*time.Millisecond,
func() {}, GetSingletonNoOpLogger(), nil)
if err2 == nil {
t.Error("Second memory-monitor task creation should fail due to singleton enforcement")
if task2 != nil {
task2.Stop()
}
}
// Clean up
if task1 != nil {
task1.Stop()
}
registry.StopAllTasks()
}