package resilience import ( "context" "errors" "io" "log/slog" "testing" "time" "github.com/aws/smithy-go" "wucher/internal/config" ) func TestExecutor_ExcludedErrorsDoNotTrip(t *testing.T) { executor := NewExecutor("ses", config.CircuitBreakerPolicy{ Enabled: true, Timeout: time.Second, MinRequests: 2, FailureRatio: 0.5, ConsecutiveFailures: 2, }, slog.New(slog.NewJSONHandler(io.Discard, nil)), func(error) Classification { return ClassificationExcluded }) for range 2 { err := executor.Execute(context.Background(), func(context.Context) error { return errors.New("validation error") }) if err == nil { t.Fatalf("expected original error") } } counts := executor.Counts() if counts.TotalExclusions != 2 { t.Fatalf("expected 2 exclusions, got %+v", counts) } if counts.TotalFailures != 0 { t.Fatalf("expected 0 failures, got %+v", counts) } } func TestExecutor_FailuresTripBreaker(t *testing.T) { executor := NewExecutor("sqs", config.CircuitBreakerPolicy{ Enabled: true, Timeout: time.Second, MinRequests: 1, FailureRatio: 0.5, ConsecutiveFailures: 2, }, slog.New(slog.NewJSONHandler(io.Discard, nil)), nil) for range 2 { err := executor.Execute(context.Background(), func(context.Context) error { return errors.New("dependency down") }) if err == nil { t.Fatalf("expected dependency error") } } err := executor.Execute(context.Background(), func(context.Context) error { return nil }) var openErr *OpenError if !errors.As(err, &openErr) { t.Fatalf("expected breaker open error, got %v", err) } } func TestClassifySQSError(t *testing.T) { if got := ClassifySQSError(apiError{code: "AccessDenied", fault: smithy.FaultClient}); got != ClassificationExcluded { t.Fatalf("expected client fault excluded, got %v", got) } if got := ClassifySQSError(apiError{code: "InternalError", fault: smithy.FaultServer}); got != ClassificationFailure { t.Fatalf("expected server fault failure, got %v", got) } if got := ClassifySQSError(apiError{code: "ThrottlingException", fault: smithy.FaultClient}); got != ClassificationFailure { t.Fatalf("expected throttling failure, got %v", got) } } type apiError struct { code string fault smithy.ErrorFault } func (e apiError) Error() string { return e.code } func (e apiError) ErrorCode() string { return e.code } func (e apiError) ErrorMessage() string { return e.code } func (e apiError) ErrorFault() smithy.ErrorFault { return e.fault }