network/pkg/errors/helpers_test.go
2026-01-20 10:03:55 +02:00

618 lines
12 KiB
Go

package errors
import (
"errors"
"testing"
)
func TestIsNotFound(t *testing.T) {
tests := []struct {
name string
err error
expected bool
}{
{
name: "nil error",
err: nil,
expected: false,
},
{
name: "NotFoundError",
err: NewNotFoundError("user", "123"),
expected: true,
},
{
name: "sentinel ErrNotFound",
err: ErrNotFound,
expected: true,
},
{
name: "wrapped NotFoundError",
err: Wrap(NewNotFoundError("user", "123"), "context"),
expected: true,
},
{
name: "wrapped sentinel",
err: Wrap(ErrNotFound, "context"),
expected: true,
},
{
name: "other error",
err: NewInternalError("internal", nil),
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := IsNotFound(tt.err)
if result != tt.expected {
t.Errorf("Expected %v, got %v", tt.expected, result)
}
})
}
}
func TestIsValidation(t *testing.T) {
tests := []struct {
name string
err error
expected bool
}{
{
name: "nil error",
err: nil,
expected: false,
},
{
name: "ValidationError",
err: NewValidationError("field", "invalid", nil),
expected: true,
},
{
name: "wrapped ValidationError",
err: Wrap(NewValidationError("field", "invalid", nil), "context"),
expected: true,
},
{
name: "other error",
err: NewNotFoundError("user", "123"),
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := IsValidation(tt.err)
if result != tt.expected {
t.Errorf("Expected %v, got %v", tt.expected, result)
}
})
}
}
func TestIsUnauthorized(t *testing.T) {
tests := []struct {
name string
err error
expected bool
}{
{
name: "nil error",
err: nil,
expected: false,
},
{
name: "UnauthorizedError",
err: NewUnauthorizedError("invalid token"),
expected: true,
},
{
name: "sentinel ErrUnauthorized",
err: ErrUnauthorized,
expected: true,
},
{
name: "wrapped UnauthorizedError",
err: Wrap(NewUnauthorizedError("invalid token"), "context"),
expected: true,
},
{
name: "other error",
err: NewForbiddenError("resource", "action"),
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := IsUnauthorized(tt.err)
if result != tt.expected {
t.Errorf("Expected %v, got %v", tt.expected, result)
}
})
}
}
func TestIsForbidden(t *testing.T) {
tests := []struct {
name string
err error
expected bool
}{
{
name: "nil error",
err: nil,
expected: false,
},
{
name: "ForbiddenError",
err: NewForbiddenError("resource", "action"),
expected: true,
},
{
name: "sentinel ErrForbidden",
err: ErrForbidden,
expected: true,
},
{
name: "wrapped ForbiddenError",
err: Wrap(NewForbiddenError("resource", "action"), "context"),
expected: true,
},
{
name: "other error",
err: NewUnauthorizedError("invalid token"),
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := IsForbidden(tt.err)
if result != tt.expected {
t.Errorf("Expected %v, got %v", tt.expected, result)
}
})
}
}
func TestIsConflict(t *testing.T) {
tests := []struct {
name string
err error
expected bool
}{
{
name: "nil error",
err: nil,
expected: false,
},
{
name: "ConflictError",
err: NewConflictError("user", "email", "test@example.com"),
expected: true,
},
{
name: "sentinel ErrConflict",
err: ErrConflict,
expected: true,
},
{
name: "wrapped ConflictError",
err: Wrap(NewConflictError("user", "email", "test@example.com"), "context"),
expected: true,
},
{
name: "other error",
err: NewNotFoundError("user", "123"),
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := IsConflict(tt.err)
if result != tt.expected {
t.Errorf("Expected %v, got %v", tt.expected, result)
}
})
}
}
func TestIsTimeout(t *testing.T) {
tests := []struct {
name string
err error
expected bool
}{
{
name: "nil error",
err: nil,
expected: false,
},
{
name: "TimeoutError",
err: NewTimeoutError("operation", "30s"),
expected: true,
},
{
name: "sentinel ErrTimeout",
err: ErrTimeout,
expected: true,
},
{
name: "wrapped TimeoutError",
err: Wrap(NewTimeoutError("operation", "30s"), "context"),
expected: true,
},
{
name: "other error",
err: NewInternalError("internal", nil),
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := IsTimeout(tt.err)
if result != tt.expected {
t.Errorf("Expected %v, got %v", tt.expected, result)
}
})
}
}
func TestIsRateLimit(t *testing.T) {
tests := []struct {
name string
err error
expected bool
}{
{
name: "nil error",
err: nil,
expected: false,
},
{
name: "RateLimitError",
err: NewRateLimitError(100, 60),
expected: true,
},
{
name: "sentinel ErrTooManyRequests",
err: ErrTooManyRequests,
expected: true,
},
{
name: "wrapped RateLimitError",
err: Wrap(NewRateLimitError(100, 60), "context"),
expected: true,
},
{
name: "other error",
err: NewTimeoutError("operation", "30s"),
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := IsRateLimit(tt.err)
if result != tt.expected {
t.Errorf("Expected %v, got %v", tt.expected, result)
}
})
}
}
func TestIsServiceUnavailable(t *testing.T) {
tests := []struct {
name string
err error
expected bool
}{
{
name: "nil error",
err: nil,
expected: false,
},
{
name: "ServiceError",
err: NewServiceError("rqlite", "unavailable", 503, nil),
expected: true,
},
{
name: "sentinel ErrServiceUnavailable",
err: ErrServiceUnavailable,
expected: true,
},
{
name: "wrapped ServiceError",
err: Wrap(NewServiceError("rqlite", "unavailable", 503, nil), "context"),
expected: true,
},
{
name: "other error",
err: NewTimeoutError("operation", "30s"),
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := IsServiceUnavailable(tt.err)
if result != tt.expected {
t.Errorf("Expected %v, got %v", tt.expected, result)
}
})
}
}
func TestIsInternal(t *testing.T) {
tests := []struct {
name string
err error
expected bool
}{
{
name: "nil error",
err: nil,
expected: false,
},
{
name: "InternalError",
err: NewInternalError("internal error", nil),
expected: true,
},
{
name: "sentinel ErrInternal",
err: ErrInternal,
expected: true,
},
{
name: "wrapped InternalError",
err: Wrap(NewInternalError("internal error", nil), "context"),
expected: true,
},
{
name: "other error",
err: NewNotFoundError("user", "123"),
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := IsInternal(tt.err)
if result != tt.expected {
t.Errorf("Expected %v, got %v", tt.expected, result)
}
})
}
}
func TestShouldRetry(t *testing.T) {
tests := []struct {
name string
err error
expected bool
}{
{
name: "nil error",
err: nil,
expected: false,
},
{
name: "timeout error",
err: NewTimeoutError("operation", "30s"),
expected: true,
},
{
name: "service unavailable error",
err: NewServiceError("rqlite", "unavailable", 503, nil),
expected: true,
},
{
name: "not found error",
err: NewNotFoundError("user", "123"),
expected: false,
},
{
name: "validation error",
err: NewValidationError("field", "invalid", nil),
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := ShouldRetry(tt.err)
if result != tt.expected {
t.Errorf("Expected %v, got %v", tt.expected, result)
}
})
}
}
func TestGetErrorCode(t *testing.T) {
tests := []struct {
name string
err error
expectedCode string
}{
{
name: "nil error",
err: nil,
expectedCode: CodeOK,
},
{
name: "validation error",
err: NewValidationError("field", "invalid", nil),
expectedCode: CodeValidation,
},
{
name: "not found error",
err: NewNotFoundError("user", "123"),
expectedCode: CodeNotFound,
},
{
name: "unauthorized error",
err: NewUnauthorizedError("invalid token"),
expectedCode: CodeUnauthorized,
},
{
name: "forbidden error",
err: NewForbiddenError("resource", "action"),
expectedCode: CodeForbidden,
},
{
name: "conflict error",
err: NewConflictError("user", "email", "test@example.com"),
expectedCode: CodeConflict,
},
{
name: "timeout error",
err: NewTimeoutError("operation", "30s"),
expectedCode: CodeTimeout,
},
{
name: "rate limit error",
err: NewRateLimitError(100, 60),
expectedCode: CodeRateLimit,
},
{
name: "service error",
err: NewServiceError("rqlite", "unavailable", 503, nil),
expectedCode: CodeServiceUnavailable,
},
{
name: "internal error",
err: NewInternalError("internal", nil),
expectedCode: CodeInternal,
},
{
name: "sentinel ErrNotFound",
err: ErrNotFound,
expectedCode: CodeNotFound,
},
{
name: "standard error",
err: errors.New("generic error"),
expectedCode: CodeInternal,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
code := GetErrorCode(tt.err)
if code != tt.expectedCode {
t.Errorf("Expected code %s, got %s", tt.expectedCode, code)
}
})
}
}
func TestGetErrorMessage(t *testing.T) {
tests := []struct {
name string
err error
expectedMessage string
}{
{
name: "nil error",
err: nil,
expectedMessage: "",
},
{
name: "validation error",
err: NewValidationError("field", "invalid format", nil),
expectedMessage: "invalid format",
},
{
name: "not found error",
err: NewNotFoundError("user", "123"),
expectedMessage: "user not found",
},
{
name: "standard error",
err: errors.New("generic error"),
expectedMessage: "generic error",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
message := GetErrorMessage(tt.err)
if message != tt.expectedMessage {
t.Errorf("Expected message %q, got %q", tt.expectedMessage, message)
}
})
}
}
func TestCause(t *testing.T) {
t.Run("unwrap error chain", func(t *testing.T) {
root := errors.New("root cause")
level1 := Wrap(root, "level 1")
level2 := Wrap(level1, "level 2")
level3 := Wrap(level2, "level 3")
cause := Cause(level3)
if cause != root {
t.Errorf("Expected to find root cause, got %v", cause)
}
})
t.Run("error without cause", func(t *testing.T) {
err := errors.New("standalone error")
cause := Cause(err)
if cause != err {
t.Errorf("Expected to return same error, got %v", cause)
}
})
t.Run("custom error with cause", func(t *testing.T) {
root := errors.New("database error")
wrapped := NewInternalError("failed to save", root)
cause := Cause(wrapped)
if cause != root {
t.Errorf("Expected to find root cause, got %v", cause)
}
})
}
func BenchmarkIsNotFound(b *testing.B) {
err := NewNotFoundError("user", "123")
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = IsNotFound(err)
}
}
func BenchmarkShouldRetry(b *testing.B) {
err := NewTimeoutError("operation", "30s")
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = ShouldRetry(err)
}
}
func BenchmarkGetErrorCode(b *testing.B) {
err := NewValidationError("field", "invalid", nil)
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = GetErrorCode(err)
}
}
func BenchmarkCause(b *testing.B) {
root := errors.New("root")
wrapped := Wrap(Wrap(Wrap(root, "l1"), "l2"), "l3")
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = Cause(wrapped)
}
}