Skip to content

Commit 43cd435

Browse files
committed
add tests
1 parent b25338c commit 43cd435

File tree

5 files changed

+185
-67
lines changed

5 files changed

+185
-67
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func EchoErrorHandler(error error, c echo.Context) {
5454

5555
// resolve problem details error from response in echo
5656
if !c.Response().Committed {
57-
if err := problem.ResolveProblemDetails(c.Response(), c.Request(), error); err != nil {
57+
if _, err := problem.ResolveProblemDetails(c.Response(), c.Request(), error); err != nil {
5858
log.Error(err)
5959
}
6060
}
@@ -110,7 +110,7 @@ func GinErrorHandler() gin.HandlerFunc {
110110

111111
// add custom map problem details here...
112112

113-
if err := problem.ResolveProblemDetails(c.Writer, c.Request, err); err != nil {
113+
if _, err := problem.ResolveProblemDetails(c.Writer, c.Request, err); err != nil {
114114
log.Error(err)
115115
}
116116
}

problem_details.go

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ func Map[T error](funcProblem func() ProblemDetailErr) {
134134
}
135135

136136
// ResolveProblemDetails retrieve and resolve error with format problem details error
137-
func ResolveProblemDetails(w http.ResponseWriter, r *http.Request, err error) error {
137+
func ResolveProblemDetails(w http.ResponseWriter, r *http.Request, err error) (ProblemDetailErr, error) {
138138

139139
var statusCode int = http.StatusInternalServerError
140140
var echoError *echo.HTTPError
@@ -150,25 +150,31 @@ func ResolveProblemDetails(w http.ResponseWriter, r *http.Request, err error) er
150150
}
151151
if gin.Mode() == gin.TestMode {
152152
var rw = w.(*httptest.ResponseRecorder)
153-
statusCode = rw.Code
153+
if rw.Code != http.StatusOK {
154+
statusCode = rw.Code
155+
}
154156
}
155157
err = err.(*gin.Error).Err.(error)
156158
}
157159

158-
var mapCustomTypeErr, mapCustomType = setMapCustomType(w, r, err)
159-
if mapCustomType {
160-
return mapCustomTypeErr
160+
var mapCustomType, mapCustomTypeErr = setMapCustomType(w, r, err)
161+
if mapCustomType != nil {
162+
return mapCustomType, mapCustomTypeErr
161163
}
162164

163-
var mapStatusErr, mapStatus = setMapStatusCode(w, r, err, statusCode)
164-
if mapStatus {
165-
return mapStatusErr
165+
var mapStatus, mapStatusErr = setMapStatusCode(w, r, err, statusCode)
166+
if mapStatus != nil {
167+
return mapStatus, mapStatusErr
166168
}
167169

168-
return setDefaultProblemDetails(w, r, err, statusCode)
170+
var p, errr = setDefaultProblemDetails(w, r, err, statusCode)
171+
if errr != nil {
172+
return nil, err
173+
}
174+
return p, errr
169175
}
170176

171-
func setMapCustomType(w http.ResponseWriter, r *http.Request, err error) (error, bool) {
177+
func setMapCustomType(w http.ResponseWriter, r *http.Request, err error) (ProblemDetailErr, error) {
172178

173179
problemCustomType := mappers[reflect.TypeOf(err)]
174180
if problemCustomType != nil {
@@ -180,36 +186,36 @@ func setMapCustomType(w http.ResponseWriter, r *http.Request, err error) (error,
180186
if k == prob.GetStatus() {
181187
_, err = writeTo(w, v())
182188
if err != nil {
183-
return err, false
189+
return nil, err
184190
}
185-
return err, true
191+
return prob, err
186192
}
187193
}
188194

189195
_, err = writeTo(w, prob)
190196
if err != nil {
191-
return err, false
197+
return nil, err
192198
}
193-
return err, true
199+
return prob, err
194200
}
195-
return err, false
201+
return nil, err
196202
}
197203

198-
func setMapStatusCode(w http.ResponseWriter, r *http.Request, err error, statusCode int) (error, bool) {
204+
func setMapStatusCode(w http.ResponseWriter, r *http.Request, err error, statusCode int) (ProblemDetailErr, error) {
199205
problemStatus := mapperStatus[statusCode]
200206
if problemStatus != nil {
201207
prob := problemStatus()
202208
validationProblems(prob, err, r)
203209
_, err = writeTo(w, prob)
204210
if err != nil {
205-
return err, false
211+
return nil, err
206212
}
207-
return err, true
213+
return prob, err
208214
}
209-
return err, false
215+
return nil, err
210216
}
211217

212-
func setDefaultProblemDetails(w http.ResponseWriter, r *http.Request, err error, statusCode int) error {
218+
func setDefaultProblemDetails(w http.ResponseWriter, r *http.Request, err error, statusCode int) (ProblemDetailErr, error) {
213219
defaultProblem := func() ProblemDetailErr {
214220
return &problemDetail{
215221
Type: getDefaultType(statusCode),
@@ -219,11 +225,12 @@ func setDefaultProblemDetails(w http.ResponseWriter, r *http.Request, err error,
219225
Instance: r.URL.RequestURI(),
220226
}
221227
}
222-
_, err = writeTo(w, defaultProblem())
228+
prob := defaultProblem()
229+
_, err = writeTo(w, prob)
223230
if err != nil {
224-
return err
231+
return nil, err
225232
}
226-
return err
233+
return prob, err
227234
}
228235

229236
func validationProblems(problem ProblemDetailErr, err error, r *http.Request) {

problem_details_test.go

Lines changed: 151 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,46 @@ func TestMap_CustomType_Echo(t *testing.T) {
2929

3030
err := echo_endpoint1(c)
3131

32-
var problemErr ProblemDetailErr
33-
3432
Map[custom_errors.BadRequestError](func() ProblemDetailErr {
35-
problemErr = New(http.StatusBadRequest, "bad-request", err.Error())
36-
return problemErr
33+
return New(http.StatusBadRequest, "bad-request", err.Error())
3734
})
3835

39-
_ = ResolveProblemDetails(c.Response(), c.Request(), err)
36+
p, _ := ResolveProblemDetails(c.Response(), c.Request(), err)
4037

4138
assert.Equal(t, c.Response().Status, http.StatusBadRequest)
42-
assert.Equal(t, err.Error(), problemErr.GetDetails())
43-
assert.Equal(t, "bad-request", problemErr.GetTitle())
44-
assert.Equal(t, "https://httpstatuses.io/400", problemErr.GetType())
45-
assert.Equal(t, http.StatusBadRequest, problemErr.GetStatus())
39+
assert.Equal(t, err.Error(), p.GetDetails())
40+
assert.Equal(t, "bad-request", p.GetTitle())
41+
assert.Equal(t, "https://httpstatuses.io/400", p.GetType())
42+
assert.Equal(t, http.StatusBadRequest, p.GetStatus())
43+
}
44+
45+
func TestMap_Custom_Problem_Err_Echo(t *testing.T) {
46+
47+
e := echo.New()
48+
req := httptest.NewRequest(http.MethodGet, "http://echo_endpoint4", nil)
49+
rec := httptest.NewRecorder()
50+
c := e.NewContext(req, rec)
51+
52+
err := echo_endpoint4(c)
53+
54+
Map[custom_errors.ConflictError](func() ProblemDetailErr {
55+
return &CustomProblemDetailTest{
56+
ProblemDetailErr: New(http.StatusConflict, "conflict", err.Error()),
57+
AdditionalInfo: "some additional info...",
58+
Description: "some description...",
59+
}
60+
})
61+
62+
p, _ := ResolveProblemDetails(c.Response(), c.Request(), err)
63+
cp := p.(*CustomProblemDetailTest)
64+
65+
assert.Equal(t, c.Response().Status, http.StatusConflict)
66+
assert.Equal(t, err.Error(), cp.GetDetails())
67+
assert.Equal(t, "conflict", cp.GetTitle())
68+
assert.Equal(t, "https://httpstatuses.io/409", cp.GetType())
69+
assert.Equal(t, http.StatusConflict, cp.GetStatus())
70+
assert.Equal(t, "some description...", cp.Description)
71+
assert.Equal(t, "some additional info...", cp.AdditionalInfo)
4672
}
4773

4874
func TestMap_Status_Echo(t *testing.T) {
@@ -54,21 +80,35 @@ func TestMap_Status_Echo(t *testing.T) {
5480

5581
err := echo_endpoint2(c)
5682

57-
var problemErr ProblemDetailErr
58-
59-
// map status code to problem details error
6083
MapStatus(http.StatusBadGateway, func() ProblemDetailErr {
61-
problemErr = New(http.StatusUnauthorized, "unauthorized", err.Error())
62-
return problemErr
84+
return New(http.StatusUnauthorized, "unauthorized", err.Error())
6385
})
6486

65-
_ = ResolveProblemDetails(c.Response(), c.Request(), err)
87+
p, _ := ResolveProblemDetails(c.Response(), c.Request(), err)
6688

6789
assert.Equal(t, c.Response().Status, http.StatusUnauthorized)
68-
assert.Equal(t, err.(*echo.HTTPError).Message.(error).Error(), problemErr.GetDetails())
69-
assert.Equal(t, "unauthorized", problemErr.GetTitle())
70-
assert.Equal(t, "https://httpstatuses.io/401", problemErr.GetType())
71-
assert.Equal(t, http.StatusUnauthorized, problemErr.GetStatus())
90+
assert.Equal(t, err.(*echo.HTTPError).Message.(error).Error(), p.GetDetails())
91+
assert.Equal(t, "unauthorized", p.GetTitle())
92+
assert.Equal(t, "https://httpstatuses.io/401", p.GetType())
93+
assert.Equal(t, http.StatusUnauthorized, p.GetStatus())
94+
}
95+
96+
func TestMap_Unhandled_Err_Echo(t *testing.T) {
97+
98+
e := echo.New()
99+
req := httptest.NewRequest(http.MethodGet, "http://echo_endpoint3", nil)
100+
rec := httptest.NewRecorder()
101+
c := e.NewContext(req, rec)
102+
103+
err := echo_endpoint3(c)
104+
105+
p, _ := ResolveProblemDetails(c.Response(), c.Request(), err)
106+
107+
assert.Equal(t, c.Response().Status, http.StatusInternalServerError)
108+
assert.Equal(t, err.Error(), p.GetDetails())
109+
assert.Equal(t, "Internal Server Error", p.GetTitle())
110+
assert.Equal(t, "https://httpstatuses.io/500", p.GetType())
111+
assert.Equal(t, http.StatusInternalServerError, p.GetStatus())
72112
}
73113

74114
func TestMap_CustomType_Gin(t *testing.T) {
@@ -89,19 +129,54 @@ func TestMap_CustomType_Gin(t *testing.T) {
89129

90130
for _, err := range c.Errors {
91131

92-
var problemErr ProblemDetailErr
93-
94132
Map[custom_errors.BadRequestError](func() ProblemDetailErr {
95-
problemErr = New(http.StatusBadRequest, "bad-request", err.Error())
96-
return problemErr
133+
return New(http.StatusBadRequest, "bad-request", err.Error())
134+
})
135+
136+
p, _ := ResolveProblemDetails(w, req, err)
137+
138+
assert.Equal(t, http.StatusBadRequest, p.GetStatus())
139+
assert.Equal(t, err.Error(), p.GetDetails())
140+
assert.Equal(t, "bad-request", p.GetTitle())
141+
assert.Equal(t, "https://httpstatuses.io/400", p.GetType())
142+
}
143+
}
144+
145+
func TestMap_Custom_Problem_Err_Gin(t *testing.T) {
146+
147+
gin.SetMode(gin.TestMode)
148+
w := httptest.NewRecorder()
149+
c, _ := gin.CreateTestContext(w)
150+
r := gin.Default()
151+
152+
r.GET("/gin_endpoint4", func(ctx *gin.Context) {
153+
err := errors.New("We have a custom error with custom problem details error in our endpoint")
154+
customConflictError := custom_errors.ConflictError{InternalError: err}
155+
_ = c.Error(customConflictError)
156+
})
157+
158+
req, _ := http.NewRequest(http.MethodGet, "/gin_endpoint4", nil)
159+
r.ServeHTTP(w, req)
160+
161+
for _, err := range c.Errors {
162+
163+
Map[custom_errors.ConflictError](func() ProblemDetailErr {
164+
return &CustomProblemDetailTest{
165+
ProblemDetailErr: New(http.StatusConflict, "conflict", err.Error()),
166+
AdditionalInfo: "some additional info...",
167+
Description: "some description...",
168+
}
97169
})
98170

99-
_ = ResolveProblemDetails(w, req, err)
171+
p, _ := ResolveProblemDetails(w, req, err)
172+
cp := p.(*CustomProblemDetailTest)
100173

101-
assert.Equal(t, http.StatusBadRequest, problemErr.GetStatus())
102-
assert.Equal(t, err.Error(), problemErr.GetDetails())
103-
assert.Equal(t, "bad-request", problemErr.GetTitle())
104-
assert.Equal(t, "https://httpstatuses.io/400", problemErr.GetType())
174+
assert.Equal(t, http.StatusConflict, cp.GetStatus())
175+
assert.Equal(t, err.Error(), cp.GetDetails())
176+
assert.Equal(t, "conflict", cp.GetTitle())
177+
assert.Equal(t, "https://httpstatuses.io/409", cp.GetType())
178+
assert.Equal(t, "some description...", cp.Description)
179+
assert.Equal(t, "some additional info...", cp.AdditionalInfo)
105180
}
106181
}
107182

@@ -114,7 +189,6 @@ func TestMap_Status_Gin(t *testing.T) {
114189

115190
r.GET("/gin_endpoint2", func(ctx *gin.Context) {
116191
err := errors.New("We have a specific status code error in our endpoint")
117-
// change status code 'StatusBadGateway' to 'StatusUnauthorized' base on handler config
118192
_ = c.AbortWithError(http.StatusBadGateway, err)
119193
})
120194

@@ -123,20 +197,42 @@ func TestMap_Status_Gin(t *testing.T) {
123197

124198
for _, err := range c.Errors {
125199

126-
var problemErr ProblemDetailErr
127-
128-
// map status code to problem details error
129200
MapStatus(http.StatusBadGateway, func() ProblemDetailErr {
130-
problemErr = New(http.StatusUnauthorized, "unauthorized", err.Error())
131-
return problemErr
201+
return New(http.StatusUnauthorized, "unauthorized", err.Error())
132202
})
133203

134-
_ = ResolveProblemDetails(w, req, err)
204+
p, _ := ResolveProblemDetails(w, req, err)
205+
206+
assert.Equal(t, http.StatusUnauthorized, p.GetStatus())
207+
assert.Equal(t, err.Error(), p.GetDetails())
208+
assert.Equal(t, "unauthorized", p.GetTitle())
209+
assert.Equal(t, "https://httpstatuses.io/401", p.GetType())
210+
}
211+
}
212+
213+
func TestMap_Unhandled_Err_Gin(t *testing.T) {
214+
215+
gin.SetMode(gin.TestMode)
216+
w := httptest.NewRecorder()
217+
c, _ := gin.CreateTestContext(w)
218+
r := gin.Default()
219+
220+
r.GET("/gin_endpoint3", func(ctx *gin.Context) {
221+
err := errors.New("We have a unhandeled error in our endpoint")
222+
_ = c.Error(err)
223+
})
224+
225+
req, _ := http.NewRequest(http.MethodGet, "/gin_endpoint3", nil)
226+
r.ServeHTTP(w, req)
227+
228+
for _, err := range c.Errors {
229+
230+
p, _ := ResolveProblemDetails(w, req, err)
135231

136-
assert.Equal(t, http.StatusUnauthorized, problemErr.GetStatus())
137-
assert.Equal(t, err.Error(), problemErr.GetDetails())
138-
assert.Equal(t, "unauthorized", problemErr.GetTitle())
139-
assert.Equal(t, "https://httpstatuses.io/401", problemErr.GetType())
232+
assert.Equal(t, http.StatusInternalServerError, p.GetStatus())
233+
assert.Equal(t, err.Error(), p.GetDetails())
234+
assert.Equal(t, "Internal Server Error", p.GetTitle())
235+
assert.Equal(t, "https://httpstatuses.io/500", p.GetType())
140236
}
141237
}
142238

@@ -147,6 +243,21 @@ func echo_endpoint1(c echo.Context) error {
147243

148244
func echo_endpoint2(c echo.Context) error {
149245
err := errors.New("We have a specific status code error in our endpoint")
150-
// change status code 'StatusBadGateway' to 'StatusUnauthorized' base on handler config
151246
return echo.NewHTTPError(http.StatusBadGateway, err)
152247
}
248+
249+
func echo_endpoint3(c echo.Context) error {
250+
err := errors.New("We have a unhandeled error in our endpoint")
251+
return err
252+
}
253+
254+
func echo_endpoint4(c echo.Context) error {
255+
err := errors.New("We have a custom error with custom problem details error in our endpoint")
256+
return custom_errors.ConflictError{InternalError: err}
257+
}
258+
259+
type CustomProblemDetailTest struct {
260+
ProblemDetailErr
261+
Description string `json:"description,omitempty"`
262+
AdditionalInfo string `json:"additionalInfo,omitempty"`
263+
}

samples/cmd/echo/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ func EchoErrorHandler(error error, c echo.Context) {
6565

6666
// resolve problem details error from response in echo
6767
if !c.Response().Committed {
68-
if err := problem.ResolveProblemDetails(c.Response(), c.Request(), error); err != nil {
68+
if _, err := problem.ResolveProblemDetails(c.Response(), c.Request(), error); err != nil {
6969
log.Error(err)
7070
}
7171
}

samples/cmd/gin/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ func GinErrorHandler() gin.HandlerFunc {
7272
return problem.New(http.StatusUnauthorized, "unauthorized", err.Error())
7373
})
7474

75-
if err := problem.ResolveProblemDetails(c.Writer, c.Request, err); err != nil {
75+
if _, err := problem.ResolveProblemDetails(c.Writer, c.Request, err); err != nil {
7676
log.Error(err)
7777
}
7878
}

0 commit comments

Comments
 (0)