-
Notifications
You must be signed in to change notification settings - Fork 0
/
recovery_test.go
110 lines (95 loc) · 2.84 KB
/
recovery_test.go
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
package fox
import (
"bytes"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tigerwill90/fox/internal/slogpretty"
"log/slog"
"net"
"net/http"
"net/http/httptest"
"os"
"syscall"
"testing"
)
func TestAbortHandler(t *testing.T) {
m := CustomRecovery(func(c Context, err any) {
c.Writer().WriteHeader(http.StatusInternalServerError)
_, _ = c.Writer().Write([]byte(err.(error).Error()))
})
f := New(WithMiddleware(m))
h := func(c Context) {
func() { panic(http.ErrAbortHandler) }()
_ = c.String(200, "foo")
}
require.NoError(t, onlyError(f.Handle(http.MethodPost, "/{foo}", h)))
req := httptest.NewRequest(http.MethodPost, "/foo", nil)
req.Header.Set(HeaderAuthorization, "foobar")
w := httptest.NewRecorder()
defer func() {
val := recover()
require.NotNil(t, val)
err := val.(error)
require.NotNil(t, err)
assert.ErrorIs(t, err, http.ErrAbortHandler)
}()
f.ServeHTTP(w, req)
}
func TestRecoveryMiddleware(t *testing.T) {
woBuf := bytes.NewBuffer(nil)
weBuf := bytes.NewBuffer(nil)
m := CustomRecoveryWithLogHandler(&slogpretty.Handler{
We: weBuf,
Wo: woBuf,
Lvl: slog.LevelDebug,
}, func(c Context, err any) {
c.Writer().WriteHeader(http.StatusInternalServerError)
_, _ = c.Writer().Write([]byte(err.(string)))
})
f := New(WithMiddleware(m))
const errMsg = "unexpected error"
h := func(c Context) {
func() { panic(errMsg) }()
_ = c.String(200, "foo")
}
require.NoError(t, onlyError(f.Handle(http.MethodPost, "/", h)))
req := httptest.NewRequest(http.MethodPost, "/", nil)
req.Header.Set(HeaderAuthorization, "foobar")
w := httptest.NewRecorder()
f.ServeHTTP(w, req)
require.Equal(t, http.StatusInternalServerError, w.Code)
assert.Equal(t, errMsg, w.Body.String())
assert.Equal(t, woBuf.Len(), 0)
assert.NotEqual(t, weBuf.Len(), 0)
}
func TestRecoveryMiddlewareWithBrokenPipe(t *testing.T) {
woBuf := bytes.NewBuffer(nil)
weBuf := bytes.NewBuffer(nil)
expectMsgs := map[syscall.Errno]string{
syscall.EPIPE: "broken pipe",
syscall.ECONNRESET: "connection reset by peer",
}
for errno, expectMsg := range expectMsgs {
t.Run(expectMsg, func(t *testing.T) {
f := New(WithMiddleware(CustomRecoveryWithLogHandler(&slogpretty.Handler{
We: weBuf,
Wo: woBuf,
Lvl: slog.LevelDebug,
}, func(c Context, err any) {
if !connIsBroken(err) {
http.Error(c.Writer(), http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
}
})))
require.NoError(t, onlyError(f.Handle(http.MethodGet, "/foo", func(c Context) {
e := &net.OpError{Err: &os.SyscallError{Err: errno}}
panic(e)
})))
req := httptest.NewRequest(http.MethodGet, "/foo", nil)
w := httptest.NewRecorder()
f.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, woBuf.Len(), 0)
assert.NotEqual(t, weBuf.Len(), 0)
})
}
}