Repository navigation
Expand file tree
/
Copy patherrors_test.go
More file actions
146 lines (135 loc) · 3.92 KB
/
Copy patherrors_test.go
File metadata and controls
146 lines (135 loc) · 3.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package devicebase
import (
"strings"
"testing"
)
func TestHTTPErrorMessages(t *testing.T) {
tests := []struct {
name string
status int
body string
want string
wantTyp any
}{
{
name: "unauthorized",
status: 401,
body: `{"code":401,"message":"API Key 不存在或已停用"}`,
want: `API error (HTTP 401): {"code":401,"message":"API Key 不存在或已停用"}`,
wantTyp: &AuthenticationError{},
},
{
name: "not found",
status: 404,
body: `{"code":404,"message":"设备不存在"}`,
want: `API error (HTTP 404): {"code":404,"message":"设备不存在"}`,
wantTyp: &DeviceNotFoundError{},
},
{
// The gateway reports validation failures as 400.
name: "bad request is a validation error",
status: 400,
body: `{"detail":"body.username: Field required"}`,
want: `API error (HTTP 400): {"detail":"body.username: Field required"}`,
wantTyp: &ValidationError{},
},
{
name: "unprocessable entity is also a validation error",
status: 422,
body: "invalid input",
want: `API error (HTTP 422): invalid input`,
wantTyp: &ValidationError{},
},
{
name: "server error",
status: 500,
body: "internal",
want: `API error (HTTP 500): internal`,
wantTyp: &Error{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := newHTTPError(tt.status, []byte(tt.body))
if err.Error() != tt.want {
t.Errorf("Error() = %q, want %q", err.Error(), tt.want)
}
if !sameType(err, tt.wantTyp) {
t.Errorf("error type = %T, want %T", err, tt.wantTyp)
}
})
}
}
func TestHTTPErrorStatusCode(t *testing.T) {
err := newHTTPError(404, []byte("nope"))
notFound, ok := err.(*DeviceNotFoundError)
if !ok {
t.Fatalf("error type = %T, want *DeviceNotFoundError", err)
}
if notFound.StatusCode != 404 {
t.Errorf("StatusCode = %d, want 404", notFound.StatusCode)
}
}
// A business failure carries the envelope's code, not an HTTP status — the
// transport itself succeeded.
func TestBusinessErrorMessage(t *testing.T) {
body := `{"code":502,"message":"-32602: Invalid parameters"}`
err := newBusinessError(502, []byte(body))
if err.Code != 502 {
t.Errorf("Code = %d, want 502", err.Code)
}
if err.Body != body {
t.Errorf("Body = %q, want %q", err.Body, body)
}
want := `API error (code 502): {"code":502,"message":"-32602: Invalid parameters"}`
if err.Error() != want {
t.Errorf("Error() = %q, want %q", err.Error(), want)
}
}
func TestBusinessErrorTruncatesALongBody(t *testing.T) {
long := strings.Repeat("x", maxErrorBodyChars+100)
err := newBusinessError(500, []byte(long))
if !strings.HasSuffix(err.Error(), "… (truncated)") {
t.Error("a body over the cap should be marked as truncated")
}
if err.Body != long {
t.Error("Body should keep the untruncated payload")
}
}
func TestErrorTypeDistinction(t *testing.T) {
err := error(&AuthenticationError{Message: "auth", StatusCode: 401})
if _, ok := err.(*DeviceNotFoundError); ok {
t.Error("AuthenticationError should not match DeviceNotFoundError")
}
if _, ok := err.(*ValidationError); ok {
t.Error("AuthenticationError should not match ValidationError")
}
if _, ok := err.(*BusinessError); ok {
t.Error("AuthenticationError should not match BusinessError")
}
if _, ok := err.(*AuthenticationError); !ok {
t.Error("AuthenticationError should match itself")
}
}
// sameType reports whether err has the same concrete type as want, without
// relying on errors.As pointer-target plumbing in a table test.
func sameType(err error, want any) bool {
switch want.(type) {
case *AuthenticationError:
_, ok := err.(*AuthenticationError)
return ok
case *DeviceNotFoundError:
_, ok := err.(*DeviceNotFoundError)
return ok
case *ValidationError:
_, ok := err.(*ValidationError)
return ok
case *BusinessError:
_, ok := err.(*BusinessError)
return ok
case *Error:
_, ok := err.(*Error)
return ok
}
return false
}