errors_paths_test.mx raw
1 package errors
2
3 import (
4 "fmt"
5 "testing"
6 )
7
8 // The constructors and the helpers' non-domain paths. The suite above covers
9 // the common errors; these are the builder methods and the plain-error answers
10 // a caller gets when the error in hand is not a DomainError.
11
12 func TestBaseStringAndWithMessage(t *testing.T) {
13 e := ErrInvalidJSON
14 if e.String() == "" || e.String() != e.Error() {
15 t.Fatal("String must mirror Error")
16 }
17 m := e.WithMessage([]byte("custom"))
18 if string(m.message) != "custom" {
19 t.Fatal("WithMessage")
20 }
21 if string(m.Code()) != "INVALID_JSON" || string(m.Category()) != "validation" {
22 t.Fatal("WithMessage must keep the code and category")
23 }
24 if m.IsRetryable() {
25 t.Fatal("WithMessage must keep the retryable flag")
26 }
27 if string(e.message) != "malformed JSON" {
28 t.Fatal("WithMessage must not mutate the original")
29 }
30 // No cause: the message stands alone.
31 if e.Error() != "malformed JSON" {
32 t.Fatalf("Error without a cause = %s", e.Error())
33 }
34 }
35
36 func TestWithFieldAndConstructors(t *testing.T) {
37 v := ErrInvalidEventID.WithField([]byte("other"))
38 if string(v.Field) != "other" || string(v.Code()) != "INVALID_ID" {
39 t.Fatal("WithField")
40 }
41 if string(v.Category()) != "validation" {
42 t.Fatal("WithField must keep the category")
43 }
44
45 a := NewAccessDenied([]byte("write"), []byte("nope"))
46 if string(a.Code()) != "ACCESS_DENIED" || string(a.AccessLevel) != "write" || a.NeedsAuth() {
47 t.Fatal("NewAccessDenied")
48 }
49 if a.Category()[0] != 'a' {
50 t.Fatal("NewAccessDenied category")
51 }
52
53 p := NewProcessingError([]byte("X"), []byte("x"), true).WithEventID([]byte("abc"))
54 if string(p.EventID) != "abc" || !p.IsRetryable() {
55 t.Fatal("WithEventID")
56 }
57 p2 := p.WithKind(7)
58 if p2.Kind != 7 || string(p2.EventID) != "abc" {
59 t.Fatal("WithKind")
60 }
61
62 pb := NewPolicyBlocked([]byte("rule"), []byte("no"))
63 if string(pb.RuleName) != "rule" || string(pb.Action) != "block" {
64 t.Fatal("NewPolicyBlocked")
65 }
66 pr := NewPolicyRejected([]byte("rule"), []byte("no"))
67 if string(pr.Action) != "reject" || string(pr.Code()) != "POLICY_REJECTED" {
68 t.Fatal("NewPolicyRejected")
69 }
70 if !NeedsAuth(NewAuthRequired([]byte("because"))) {
71 t.Fatal("NewAuthRequired")
72 }
73
74 ap := ErrBanned.WithPubkey([]byte("pk"))
75 if string(ap.Pubkey) != "pk" || string(ap.Code()) != "BANNED" {
76 t.Fatal("WithPubkey")
77 }
78 }
79
80 func TestCodeCategoryAndIsOnPlainErrors(t *testing.T) {
81 plain := fmt.Errorf("plain")
82 if Code(plain) != nil {
83 t.Fatal("a plain error has no code")
84 }
85 if string(Category(plain)) != "unknown" {
86 t.Fatal("a plain error's category is unknown")
87 }
88 if Is(plain, ErrDuplicate) {
89 t.Fatal("Is on a plain error is false")
90 }
91 if IsRetryable(plain) {
92 t.Fatal("a plain error is not retryable")
93 }
94 if NeedsAuth(plain) {
95 t.Fatal("a plain error does not need auth")
96 }
97
98 if string(Code(ErrAuthRequired)) != "AUTH_REQUIRED" {
99 t.Fatal("code")
100 }
101 if string(Category(ErrRateLimited)) != "processing" {
102 t.Fatal("rate limit category")
103 }
104 if string(Category(ErrKindBlocked)) != "policy" {
105 t.Fatal("policy category")
106 }
107 if string(Category(ErrServiceUnavailable)) != "service" || !IsRetryable(ErrServiceUnavailable) {
108 t.Fatal("service error")
109 }
110 if string(Category(ErrStorageFull)) != "storage" {
111 t.Fatal("storage category")
112 }
113 if !Is(ErrAuthRequired, ErrAuthRequired) {
114 t.Fatal("Is matches on the code, not the pointer")
115 }
116 }
117