package backgroundtask import ( "context" "log/slog" "sync/atomic" "testing" "time" ) // TestSlowWorkFunc tests the slow work function func TestSlowWorkFunc(t *testing.T) { t.Run("NormalExecution", func(t *testing.T) { config := NewTestConfigMap() testConfig, _ := GetTestConfig(config) testConfig.WorkDuration = 100 * time.Millisecond start := time.Now() err := SlowWorkFunc(t.Context(), slog.Default(), config) elapsed := time.Since(start) if err != nil { t.Errorf("Expected no error, got: %v", err) } if elapsed < testConfig.WorkDuration/2 { t.Errorf("Work completed too quickly: %v (expected ~%v)", elapsed, testConfig.WorkDuration) } if testConfig.Counter.Load() != 1 { t.Errorf("Expected counter to be 1, got %d", testConfig.Counter.Load()) } }) t.Run("ContextCancellation", func(t *testing.T) { config := NewTestConfigMap() testConfig, _ := GetTestConfig(config) testConfig.WorkDuration = 1 * time.Second // Long duration ctx, cancel := context.WithTimeout(t.Context(), 50*time.Millisecond) defer cancel() start := time.Now() err := SlowWorkFunc(ctx, slog.Default(), config) elapsed := time.Since(start) if err == nil { t.Error("Expected context cancellation error") } if elapsed > 200*time.Millisecond { t.Errorf("Work took too long after cancellation: %v", elapsed) } if testConfig.Counter.Load() != 1 { t.Errorf("Expected counter to be 1, got %d", testConfig.Counter.Load()) } }) t.Run("InvalidConfig", func(t *testing.T) { config := map[string]any{"invalid": "config"} err := SlowWorkFunc(t.Context(), slog.Default(), config) if err == nil { t.Error("Expected error for invalid config") } }) } // TestBlockingWorkFunc tests the blocking work function func TestBlockingWorkFunc(t *testing.T) { t.Run("BlocksUntilCancellation", func(t *testing.T) { config := NewTestConfigMap() testConfig, _ := GetTestConfig(config) ctx, cancel := context.WithTimeout(t.Context(), 50*time.Millisecond) defer cancel() start := time.Now() err := BlockingWorkFunc(ctx, slog.Default(), config) elapsed := time.Since(start) if err == nil { t.Error("Expected context cancellation error") } // Should block for approximately the timeout duration if elapsed < 40*time.Millisecond || elapsed > 100*time.Millisecond { t.Errorf("Unexpected blocking duration: %v", elapsed) } if testConfig.Counter.Load() != 1 { t.Errorf("Expected counter to be 1, got %d", testConfig.Counter.Load()) } }) t.Run("InvalidConfig", func(t *testing.T) { config := map[string]any{"invalid": "config"} err := BlockingWorkFunc(t.Context(), slog.Default(), config) if err == nil { t.Error("Expected error for invalid config") } }) } // TestWaitForCondition tests the wait for condition helper func TestWaitForCondition(t *testing.T) { t.Run("ConditionMet", func(t *testing.T) { var conditionMet atomic.Bool // Start a goroutine that will set the condition after a delay go func() { time.Sleep(50 * time.Millisecond) conditionMet.Store(true) }() start := time.Now() result := WaitForCondition(func() bool { return conditionMet.Load() }, 200*time.Millisecond) elapsed := time.Since(start) if !result { t.Error("Expected condition to be met") } if elapsed > 100*time.Millisecond { t.Errorf("Condition took too long to be met: %v", elapsed) } }) t.Run("ConditionTimeout", func(t *testing.T) { start := time.Now() result := WaitForCondition(func() bool { return false // Never true }, 50*time.Millisecond) elapsed := time.Since(start) if result { t.Error("Expected condition to timeout") } if elapsed < 40*time.Millisecond { t.Errorf("Timeout too short: %v", elapsed) } }) t.Run("ImmediateCondition", func(t *testing.T) { start := time.Now() result := WaitForCondition(func() bool { return true // Always true }, 100*time.Millisecond) elapsed := time.Since(start) if !result { t.Error("Expected immediate condition to be met") } if elapsed > 50*time.Millisecond { t.Errorf("Immediate condition took too long: %v", elapsed) } }) } // TestHelperFunctions tests additional helper functions for coverage func TestHelperFunctions(t *testing.T) { t.Run("NewTestConfigMap", func(t *testing.T) { config := NewTestConfigMap() if config == nil { t.Fatal("Expected config map to be created") } testConfig, ok := GetTestConfig(config) if !ok { t.Fatal("Expected test config to be in map") } if testConfig.Counter == nil { t.Error("Expected counter to be initialized") } if testConfig.WorkDuration != 1*time.Millisecond { t.Errorf("Expected default work duration to be 1ms, got %v", testConfig.WorkDuration) } }) t.Run("GetTestConfigInvalid", func(t *testing.T) { config := map[string]any{"invalid": "config"} _, ok := GetTestConfig(config) if ok { t.Error("Expected GetTestConfig to return false for invalid config") } }) t.Run("GetTestConfigMissing", func(t *testing.T) { config := map[string]any{} _, ok := GetTestConfig(config) if ok { t.Error("Expected GetTestConfig to return false for missing config") } }) t.Run("GetTestConfigWrongType", func(t *testing.T) { config := map[string]any{"testConfig": "not a TestConfig"} _, ok := GetTestConfig(config) if ok { t.Error("Expected GetTestConfig to return false for wrong type") } }) } // TestErrorWorkFuncVariations tests error work function with different configurations func TestErrorWorkFuncVariations(t *testing.T) { t.Run("CustomErrorMessage", func(t *testing.T) { config := NewTestConfigMap() testConfig, _ := GetTestConfig(config) testConfig.ErrorMessage = "custom error message" err := ErrorWorkFunc(t.Context(), slog.Default(), config) if err == nil { t.Error("Expected error") } if err.Error() != "custom error message" { t.Errorf("Expected 'custom error message', got: %v", err.Error()) } if testConfig.Counter.Load() != 1 { t.Errorf("Expected counter to be 1, got %d", testConfig.Counter.Load()) } }) t.Run("EmptyErrorMessage", func(t *testing.T) { config := NewTestConfigMap() testConfig, _ := GetTestConfig(config) testConfig.ErrorMessage = "" err := ErrorWorkFunc(t.Context(), slog.Default(), config) if err == nil { t.Error("Expected error") } if err.Error() != "error work function failed" { t.Errorf("Expected default error message, got: %v", err.Error()) } }) } // TestTestWorkFuncVariations tests the test work function with different configurations func TestTestWorkFuncVariations(t *testing.T) { t.Run("MaxExecutionsLimit", func(t *testing.T) { config := NewTestConfigMap() testConfig, _ := GetTestConfig(config) testConfig.MaxExecutions = 2 // First execution should work err := TestWorkFunc(t.Context(), slog.Default(), config) if err != nil { t.Errorf("First execution failed: %v", err) } // Second execution should work err = TestWorkFunc(t.Context(), slog.Default(), config) if err != nil { t.Errorf("Second execution failed: %v", err) } // Third execution should be skipped err = TestWorkFunc(t.Context(), slog.Default(), config) if err != nil { t.Errorf("Third execution failed: %v", err) } // Counter should be 2 (third execution was skipped) if testConfig.Counter.Load() != 2 { t.Errorf("Expected counter to be 2, got %d", testConfig.Counter.Load()) } }) t.Run("ErrorConfigured", func(t *testing.T) { config := NewTestConfigMap() testConfig, _ := GetTestConfig(config) testConfig.ShouldError = true testConfig.ErrorMessage = "configured error" err := TestWorkFunc(t.Context(), slog.Default(), config) if err == nil { t.Error("Expected error") } if err.Error() != "configured error" { t.Errorf("Expected 'configured error', got: %v", err.Error()) } }) t.Run("ContextDisrespected", func(t *testing.T) { config := NewTestConfigMap() testConfig, _ := GetTestConfig(config) testConfig.WorkDuration = 100 * time.Millisecond testConfig.RespectContext = false ctx, cancel := context.WithTimeout(t.Context(), 10*time.Millisecond) defer cancel() start := time.Now() err := TestWorkFunc(ctx, slog.Default(), config) elapsed := time.Since(start) // Should complete despite context cancellation if err != nil { t.Errorf("Expected no error when context is disrespected, got: %v", err) } // Should take approximately the full work duration if elapsed < testConfig.WorkDuration/2 { t.Errorf("Work completed too quickly: %v", elapsed) } }) }