package workerpool import ( "testing" "time" ) // resetCircuitBreakerForTesting clears all failed domain state for testing purposes. // This function provides test isolation by resetting the global circuit breaker state. func resetCircuitBreakerForTesting() { failedDomainsMutex.Lock() defer failedDomainsMutex.Unlock() failedDomains = make(map[string]*domainFailure) } func TestCircuitBreaker(t *testing.T) { // Ensure clean state before test resetCircuitBreakerForTesting() defer resetCircuitBreakerForTesting() // Clean up after test testDomain := "failing.example.com" // Initially, domain should not be skipped if ShouldSkipDomain(testDomain) { t.Error("Domain should not be skipped initially") } // Record failures recordDomainFailure(testDomain) recordDomainFailure(testDomain) recordDomainFailure(testDomain) // Domain should now be skipped if !ShouldSkipDomain(testDomain) { t.Error("Domain should be skipped after failures") } // After successful delivery, domain should be reset resetDomainFailure(testDomain) if ShouldSkipDomain(testDomain) { t.Error("Domain should not be skipped after reset") } } func TestHTTPTimeouts(t *testing.T) { // Ensure clean state before test resetCircuitBreakerForTesting() defer resetCircuitBreakerForTesting() // Clean up after test // Initialize HTTP client InitOutboundWorkerPool(1) if httpClient == nil { t.Error("HTTP client should be initialized") } if httpClient.Timeout != 8*time.Second { t.Errorf("HTTP client should have 8 second timeout, got %v", httpClient.Timeout) } } func TestWorkerPoolSizing(t *testing.T) { // Ensure clean state before test resetCircuitBreakerForTesting() defer resetCircuitBreakerForTesting() // Clean up after test // Test that queue buffer is at least the minimum (500) even for small worker pools InitOutboundWorkerPool(5) if cap(queue) < 500 { t.Errorf("Queue capacity should be at least 500, got %d", cap(queue)) } // Test that larger worker pools get proportionally larger buffers InitOutboundWorkerPool(100) if cap(queue) != 1000 { t.Errorf("Queue capacity should be 1000 for 100 workers, got %d", cap(queue)) } } func TestBackoffDurations(t *testing.T) { // Test that backoff durations are properly configured expectedDurations := []time.Duration{ 1 * time.Minute, 5 * time.Minute, 15 * time.Minute, 30 * time.Minute, 60 * time.Minute, } if len(circuitBreakerBackoffDurations) != len(expectedDurations) { t.Errorf("Expected %d backoff durations, got %d", len(expectedDurations), len(circuitBreakerBackoffDurations)) } for i, expected := range expectedDurations { if circuitBreakerBackoffDurations[i] != expected { t.Errorf("Backoff duration at index %d: expected %v, got %v", i, expected, circuitBreakerBackoffDurations[i]) } } } func TestCircuitBreakerIsolation(t *testing.T) { // Test that multiple tests don't interfere with each other resetCircuitBreakerForTesting() defer resetCircuitBreakerForTesting() domain1 := "test1.example.com" domain2 := "test2.example.com" // Neither domain should be blocked initially if ShouldSkipDomain(domain1) || ShouldSkipDomain(domain2) { t.Error("Domains should not be blocked initially") } // Record failures for domain1 only recordDomainFailure(domain1) recordDomainFailure(domain1) recordDomainFailure(domain1) // Only domain1 should be blocked if !ShouldSkipDomain(domain1) { t.Error("Domain1 should be blocked after failures") } if ShouldSkipDomain(domain2) { t.Error("Domain2 should not be blocked") } // Reset and verify clean state resetCircuitBreakerForTesting() if ShouldSkipDomain(domain1) || ShouldSkipDomain(domain2) { t.Error("Both domains should be unblocked after reset") } }