refactor(api): enforce protocol-neutral service boundaries
- refactor: move HTTP status and DTO concerns out of model and service layers into API and handler code. - feat: add admin service boundary and route auth through services instead of direct repository access. - test: add architecture and error tests covering package boundaries, redaction, and service behavior. - docs: record the protocol-neutral boundary decision and update architecture and roadmap notes.
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAppErrorConstructors(t *testing.T) {
|
||||
cause := errors.New("database offline")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
err *AppError
|
||||
kind ErrorKind
|
||||
message string
|
||||
cause error
|
||||
}{
|
||||
{
|
||||
name: "invalid argument",
|
||||
err: NewInvalidArgumentError("bad input"),
|
||||
kind: KindInvalidArgument,
|
||||
message: "bad input",
|
||||
},
|
||||
{
|
||||
name: "unauthenticated",
|
||||
err: NewUnauthenticatedError("invalid token"),
|
||||
kind: KindUnauthenticated,
|
||||
message: "invalid token",
|
||||
},
|
||||
{
|
||||
name: "permission denied",
|
||||
err: NewPermissionDeniedError("access denied", ErrForbidden),
|
||||
kind: KindPermissionDenied,
|
||||
message: "access denied",
|
||||
cause: ErrForbidden,
|
||||
},
|
||||
{
|
||||
name: "not found",
|
||||
err: NewNotFoundError("missing", ErrNotFound),
|
||||
kind: KindNotFound,
|
||||
message: "missing",
|
||||
cause: ErrNotFound,
|
||||
},
|
||||
{
|
||||
name: "conflict",
|
||||
err: NewConflictError("duplicate"),
|
||||
kind: KindConflict,
|
||||
message: "duplicate",
|
||||
},
|
||||
{
|
||||
name: "payload too large",
|
||||
err: NewPayloadTooLargeError("too large", ErrUploadTooLarge),
|
||||
kind: KindPayloadTooLarge,
|
||||
message: "too large",
|
||||
cause: ErrUploadTooLarge,
|
||||
},
|
||||
{
|
||||
name: "internal",
|
||||
err: NewInternalError("load record", cause),
|
||||
kind: KindInternal,
|
||||
message: "internal server error",
|
||||
cause: cause,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.err.Kind != tt.kind {
|
||||
t.Fatalf("Kind = %q, want %q", tt.err.Kind, tt.kind)
|
||||
}
|
||||
if tt.err.Message != tt.message {
|
||||
t.Fatalf("Message = %q, want %q", tt.err.Message, tt.message)
|
||||
}
|
||||
if tt.cause != nil && !errors.Is(tt.err, tt.cause) {
|
||||
t.Fatalf("errors.Is(%v, %v) = false", tt.err, tt.cause)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user