mirror of
https://github.com/lukaszraczylo/traefikoidc.git
synced 2026-10-14 04:07:46 +00:00
315 lines
8.6 KiB
Go
315 lines
8.6 KiB
Go
package traefikoidc
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// SimpleMemoryTestSuite provides focused memory verification tests using unified infrastructure
|
|
type SimpleMemoryTestSuite struct {
|
|
runner *TestSuiteRunner
|
|
factory *TestDataFactory
|
|
edgeGen *EdgeCaseGenerator
|
|
perfTest *PerformanceTestHelper
|
|
logger *Logger
|
|
}
|
|
|
|
// NewSimpleMemoryTestSuite creates a new test suite for simple memory verification
|
|
func NewSimpleMemoryTestSuite() *SimpleMemoryTestSuite {
|
|
return &SimpleMemoryTestSuite{
|
|
runner: NewTestSuiteRunner(),
|
|
factory: NewTestDataFactory(),
|
|
edgeGen: NewEdgeCaseGenerator(),
|
|
perfTest: NewPerformanceTestHelper(),
|
|
logger: GetSingletonNoOpLogger(),
|
|
}
|
|
}
|
|
|
|
// TestSimpleCacheOperations verifies basic cache operations using table-driven tests
|
|
func TestSimpleCacheOperations(t *testing.T) {
|
|
config := GetTestConfig()
|
|
if config.ShouldSkipTest(t, TestTypeQuick) {
|
|
return
|
|
}
|
|
|
|
suite := NewSimpleMemoryTestSuite()
|
|
|
|
tests := []MemoryLeakTestCase{
|
|
{
|
|
Name: "Basic cache creation and cleanup",
|
|
Description: "Verify cache can be created, used briefly, and cleaned up without leaks",
|
|
Operation: func() error {
|
|
cache := NewOptimizedCache()
|
|
if cache == nil {
|
|
return fmt.Errorf("cache creation failed")
|
|
}
|
|
|
|
// Use the cache briefly
|
|
cache.Set("test", "value", time.Minute)
|
|
val, found := cache.Get("test")
|
|
if !found {
|
|
return fmt.Errorf("cache get failed: key not found")
|
|
}
|
|
if val != "value" {
|
|
return fmt.Errorf("cache get failed: expected 'value', got %v", val)
|
|
}
|
|
|
|
// Close immediately
|
|
cache.Close()
|
|
|
|
// Brief wait for cleanup
|
|
time.Sleep(50 * time.Millisecond)
|
|
return nil
|
|
},
|
|
Iterations: 3,
|
|
MaxGoroutineGrowth: 2, // Allow minimal framework overhead
|
|
MaxMemoryGrowthMB: 0.5, // Very strict for simple operations
|
|
GCBetweenRuns: true,
|
|
Timeout: 5 * time.Second,
|
|
},
|
|
{
|
|
Name: "Cache with multiple quick operations",
|
|
Description: "Test cache with rapid set/get operations",
|
|
Operation: func() error {
|
|
cache := NewOptimizedCache()
|
|
defer cache.Close()
|
|
|
|
// Perform multiple quick operations
|
|
for i := 0; i < 10; i++ {
|
|
key := fmt.Sprintf("key-%d", i)
|
|
value := fmt.Sprintf("value-%d", i)
|
|
cache.Set(key, value, time.Minute)
|
|
|
|
val, found := cache.Get(key)
|
|
if !found {
|
|
return fmt.Errorf("cache get failed for key %s", key)
|
|
}
|
|
if val != value {
|
|
return fmt.Errorf("cache value mismatch for key %s: expected %s, got %v", key, value, val)
|
|
}
|
|
}
|
|
return nil
|
|
},
|
|
Iterations: 5,
|
|
MaxGoroutineGrowth: 2,
|
|
MaxMemoryGrowthMB: 1.0,
|
|
GCBetweenRuns: true,
|
|
Timeout: 8 * time.Second,
|
|
},
|
|
{
|
|
Name: "Cache with edge case values",
|
|
Description: "Test cache with edge case string values",
|
|
Operation: func() error {
|
|
cache := NewOptimizedCache()
|
|
defer cache.Close()
|
|
|
|
// Test with edge case strings from the generator
|
|
edgeCases := suite.edgeGen.GenerateStringEdgeCases()
|
|
for i, value := range edgeCases[:5] { // Limit to first 5 for simplicity
|
|
key := fmt.Sprintf("edge-key-%d", i)
|
|
cache.Set(key, value, time.Minute)
|
|
|
|
val, found := cache.Get(key)
|
|
if !found {
|
|
return fmt.Errorf("cache get failed for edge case key %s", key)
|
|
}
|
|
if val != value {
|
|
return fmt.Errorf("cache value mismatch for edge case key %s", key)
|
|
}
|
|
}
|
|
return nil
|
|
},
|
|
Iterations: 3,
|
|
MaxGoroutineGrowth: 2,
|
|
MaxMemoryGrowthMB: 1.0,
|
|
GCBetweenRuns: true,
|
|
Timeout: 10 * time.Second,
|
|
},
|
|
}
|
|
|
|
suite.runner.RunMemoryLeakTests(t, tests)
|
|
}
|
|
|
|
// TestChunkManagerInitialization verifies chunk manager initialization using table-driven tests
|
|
func TestChunkManagerInitialization(t *testing.T) {
|
|
suite := NewSimpleMemoryTestSuite()
|
|
|
|
tests := []TableTestCase{
|
|
{
|
|
Name: "Basic chunk manager creation",
|
|
Description: "Verify chunk manager can be created with proper defaults",
|
|
Input: nil, // No specific input needed
|
|
Expected: map[string]interface{}{
|
|
"maxSessions": 1000,
|
|
"sessionTTL": 24 * time.Hour,
|
|
"notNil": true,
|
|
},
|
|
Timeout: 5 * time.Second,
|
|
Setup: func(t *testing.T) error {
|
|
// No setup needed
|
|
return nil
|
|
},
|
|
Teardown: func(t *testing.T) error {
|
|
// No teardown needed
|
|
return nil
|
|
},
|
|
},
|
|
{
|
|
Name: "Chunk manager with logger verification",
|
|
Description: "Verify chunk manager works correctly with singleton logger",
|
|
Input: "singleton_logger",
|
|
Expected: map[string]interface{}{
|
|
"hasLogger": true,
|
|
"maxSessions": 1000,
|
|
"sessionTTL": 24 * time.Hour,
|
|
},
|
|
Timeout: 5 * time.Second,
|
|
},
|
|
}
|
|
|
|
// Custom test execution since TableTestCase doesn't have built-in logic
|
|
for _, test := range tests {
|
|
test := test // Capture loop variable
|
|
|
|
t.Run(test.Name, func(t *testing.T) {
|
|
if test.Setup != nil {
|
|
require.NoError(t, test.Setup(t))
|
|
}
|
|
|
|
if test.Teardown != nil {
|
|
defer func() {
|
|
require.NoError(t, test.Teardown(t))
|
|
}()
|
|
}
|
|
|
|
// Execute the actual test logic
|
|
logger := suite.logger
|
|
cm := NewChunkManager(logger)
|
|
|
|
// Verify basic properties
|
|
assert.NotNil(t, cm, "Chunk manager should not be nil")
|
|
assert.NotNil(t, cm.sessionMap, "Session map should not be nil")
|
|
|
|
// Verify expected values from test case
|
|
expected := test.Expected.(map[string]interface{})
|
|
assert.Equal(t, expected["maxSessions"], cm.maxSessions, "Max sessions should match expected value")
|
|
assert.Equal(t, expected["sessionTTL"], cm.sessionTTL, "Session TTL should match expected value")
|
|
|
|
if hasLogger, exists := expected["hasLogger"]; exists && hasLogger.(bool) {
|
|
assert.NotNil(t, logger, "Logger should not be nil when expected")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestSimpleMemoryLeakDetection provides memory leak detection using the infrastructure
|
|
func TestSimpleMemoryLeakDetection(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("Skipping simple memory leak detection in short mode")
|
|
}
|
|
|
|
suite := NewSimpleMemoryTestSuite()
|
|
|
|
tests := []MemoryLeakTestCase{
|
|
{
|
|
Name: "Repeated cache creation and destruction",
|
|
Description: "Verify no leaks from repeated cache lifecycle",
|
|
Operation: func() error {
|
|
cache := NewOptimizedCache()
|
|
cache.Set("test", "value", 100*time.Millisecond)
|
|
_, _ = cache.Get("test")
|
|
cache.Close()
|
|
|
|
// Small delay to allow cleanup
|
|
time.Sleep(20 * time.Millisecond)
|
|
return nil
|
|
},
|
|
Iterations: 20,
|
|
MaxGoroutineGrowth: 3, // Slightly more tolerance for repeated operations
|
|
MaxMemoryGrowthMB: 2.0, // Allow for some accumulation over iterations
|
|
GCBetweenRuns: true,
|
|
Timeout: 15 * time.Second,
|
|
},
|
|
{
|
|
Name: "Chunk manager creation cycles",
|
|
Description: "Verify no leaks from chunk manager creation",
|
|
Operation: func() error {
|
|
logger := suite.logger
|
|
cm := NewChunkManager(logger)
|
|
|
|
// Verify it was created properly
|
|
if cm == nil {
|
|
return fmt.Errorf("chunk manager creation failed")
|
|
}
|
|
|
|
if cm.sessionMap == nil {
|
|
return fmt.Errorf("chunk manager session map not initialized")
|
|
}
|
|
|
|
return nil
|
|
},
|
|
Iterations: 15,
|
|
MaxGoroutineGrowth: 2,
|
|
MaxMemoryGrowthMB: 1.0,
|
|
GCBetweenRuns: true,
|
|
Timeout: 10 * time.Second,
|
|
},
|
|
}
|
|
|
|
suite.runner.RunMemoryLeakTests(t, tests)
|
|
}
|
|
|
|
// BenchmarkSimpleCacheOperations provides basic performance benchmarks
|
|
func BenchmarkSimpleCacheOperations(b *testing.B) {
|
|
cache := NewOptimizedCache()
|
|
defer cache.Close()
|
|
|
|
b.Run("Set operations", func(b *testing.B) {
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
key := fmt.Sprintf("bench-key-%d", i)
|
|
cache.Set(key, "benchmark-value", time.Minute)
|
|
}
|
|
})
|
|
|
|
b.Run("Get operations", func(b *testing.B) {
|
|
// Pre-populate cache
|
|
for i := 0; i < 1000; i++ {
|
|
key := fmt.Sprintf("bench-key-%d", i)
|
|
cache.Set(key, "benchmark-value", time.Minute)
|
|
}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
key := fmt.Sprintf("bench-key-%d", i%1000)
|
|
cache.Get(key)
|
|
}
|
|
})
|
|
|
|
b.Run("Set and Get combined", func(b *testing.B) {
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
key := fmt.Sprintf("bench-key-%d", i)
|
|
cache.Set(key, "benchmark-value", time.Minute)
|
|
cache.Get(key)
|
|
}
|
|
})
|
|
}
|
|
|
|
// BenchmarkChunkManagerCreation provides benchmarks for chunk manager operations
|
|
func BenchmarkChunkManagerCreation(b *testing.B) {
|
|
logger := GetSingletonNoOpLogger()
|
|
|
|
b.Run("Chunk manager creation", func(b *testing.B) {
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
cm := NewChunkManager(logger)
|
|
_ = cm // Avoid compiler optimization
|
|
}
|
|
})
|
|
}
|