93 lines
2.5 KiB
Go
93 lines
2.5 KiB
Go
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 }
|