1 package apperror_test
2
3 import (
4 "bytes"
5 "encoding/json"
6 "errors"
7 "fmt"
8 "testing"
9
10 "github.com/gin-gonic/gin"
11 "github.com/go-logr/logr"
12 "github.com/stretchr/testify/assert"
13
14 "edge-infra.dev/pkg/edge/iam/apperror"
15 "edge-infra.dev/pkg/lib/fog"
16 )
17
18 func TestJSONError(t *testing.T) {
19 dbErr := errors.New("SQL_ERR::NO_ROWS")
20 handlerErr := apperror.NewJSONError(dbErr, 401, "user not found", gin.H{"k1": "v1", "k2": 2})
21
22 assert.Equal(t, map[string]interface{}{"k1": "v1", "k2": 2}, handlerErr.JSONDetails())
23 assert.Equal(t, "user not found. SQL_ERR::NO_ROWS", handlerErr.Error())
24 }
25
26 func TestJSONErrorWithNilErr(t *testing.T) {
27 err := apperror.NewJSONError(nil, 401, "subject's profile could not be found", gin.H{"error": "invalid_user"})
28
29 assert.Equal(t, "subject's profile could not be found", err.Error())
30 assert.Equal(t, "[401]: subject's profile could not be found", apperror.ErrorChain(err))
31 }
32
33 func TestJSONErrorLogEntry(t *testing.T) {
34 dbErr := errors.New("SQL_ERR::NO_ROWS")
35 handlerErr := apperror.NewJSONError(dbErr, 401, "user not found", gin.H{"k1": "v1", "k2": "v2"})
36
37 l, buf := testLogger()
38 code, responseBody := handlerErr.JSONResponse()
39 msg := fmt.Sprintf("(%d) aborting with json", code)
40 l.Error(handlerErr, msg, "details", handlerErr.JSONDetails(), "body", responseBody)
41
42 out := getLogEntry(buf)
43
44 assert.Equal(t, "(401) aborting with json", out["message"])
45 assert.Equal(t, "user not found. SQL_ERR::NO_ROWS", out["error"])
46 assert.Equal(t, map[string]interface{}{"k1": "v1", "k2": "v2"}, out["details"])
47 assert.Equal(t, map[string]interface{}{"k1": "v1", "k2": "v2", "message": "user not found"}, out["body"])
48 }
49
50 func TestErrorChainWithJSONError(t *testing.T) {
51
52 err := errors.New("SQL_ERR::NO_ROWS")
53 dbErr := apperror.New(err, "not_found", "user not found in db")
54
55 svcErr := fmt.Errorf("(user service) -> %w", dbErr)
56
57 handlerErr := apperror.NewJSONError(svcErr, 401, "user not found", gin.H{"error": "invalid_user"})
58
59 code, responseBody := handlerErr.JSONResponse()
60 assert.Equal(t, 401, code)
61 assert.Equal(t, map[string]interface{}{"error": "invalid_user", "message": "user not found"}, responseBody)
62
63 errChain := apperror.ErrorChain(handlerErr)
64 assert.Equal(t, "[401]: user not found. (user service) -> user not found in db <not_found>. SQL_ERR::NO_ROWS", errChain)
65 assert.Equal(t, "user not found. (user service) -> user not found in db <not_found>. SQL_ERR::NO_ROWS", handlerErr.Error())
66 assert.Equal(t, map[string]interface{}{"error": "invalid_user"}, handlerErr.JSONDetails())
67 }
68
69 func TestWithCaller(t *testing.T) {
70 dbErr := errors.New("SQL_ERR::NO_ROWS")
71
72 handlerErr := apperror.NewJSONError(dbErr, 401, "user not found", nil)
73
74 l, buf := testLogger()
75
76 loc := handlerErr.SourceLocation()
77 l.Error(handlerErr, "testing caller information", "file", loc.File, "line", loc.Line)
78
79 out := getLogEntry(buf)
80 assert.Equal(t, "testing caller information", out["message"])
81 }
82
83 func TestSourceLocationToMap(t *testing.T) {
84 loc := apperror.SourceLocation{
85 File: "f1",
86 Line: 53,
87 }
88
89 m := loc.ToMap()
90
91 assert.Equal(t, m["file"], "f1")
92 assert.Equal(t, m["line"], float64(53))
93 assert.Nil(t, m["func"])
94 }
95
96 func testLogger() (logr.Logger, *bytes.Buffer) {
97 buf := new(bytes.Buffer)
98 l := fog.New(fog.To(buf))
99 return l, buf
100 }
101
102 func getLogEntry(buf *bytes.Buffer) map[string]interface{} {
103 var out map[string]interface{}
104 err := json.Unmarshal(buf.Bytes(), &out)
105 if err != nil {
106 return nil
107 }
108 return out
109 }
110
View as plain text