go-zero/rest/httpx/responses_test.go

217 lines
4.7 KiB
Go
Raw Normal View History

2020-07-26 17:09:05 +08:00
package httpx
import (
2020-08-21 23:09:35 +08:00
"errors"
2020-07-26 17:09:05 +08:00
"net/http"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/logx"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
2020-07-26 17:09:05 +08:00
)
type message struct {
Name string `json:"name"`
}
func init() {
logx.Disable()
}
2020-08-21 23:09:35 +08:00
func TestError(t *testing.T) {
2020-11-17 18:04:48 +08:00
const (
body = "foo"
wrappedBody = `"foo"`
)
tests := []struct {
2021-09-01 19:52:56 +08:00
name string
input string
errorHandler func(error) (int, interface{})
expectHasBody bool
expectBody string
expectCode int
2020-11-17 18:04:48 +08:00
}{
{
2021-09-01 19:52:56 +08:00
name: "default error handler",
input: body,
expectHasBody: true,
expectBody: body,
expectCode: http.StatusBadRequest,
2020-11-17 18:04:48 +08:00
},
{
name: "customized error handler return string",
input: body,
errorHandler: func(err error) (int, interface{}) {
return http.StatusForbidden, err.Error()
},
2021-09-01 19:52:56 +08:00
expectHasBody: true,
expectBody: wrappedBody,
expectCode: http.StatusForbidden,
2020-11-17 18:04:48 +08:00
},
{
name: "customized error handler return error",
input: body,
errorHandler: func(err error) (int, interface{}) {
return http.StatusForbidden, err
},
2021-09-01 19:52:56 +08:00
expectHasBody: true,
expectBody: body,
expectCode: http.StatusForbidden,
},
{
name: "customized error handler return nil",
input: body,
errorHandler: func(err error) (int, interface{}) {
return http.StatusForbidden, nil
},
2021-09-01 19:52:56 +08:00
expectHasBody: false,
expectBody: "",
expectCode: http.StatusForbidden,
2020-11-17 18:04:48 +08:00
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
w := tracedResponseWriter{
headers: make(map[string][]string),
}
if test.errorHandler != nil {
lock.RLock()
prev := errorHandler
lock.RUnlock()
SetErrorHandler(test.errorHandler)
defer func() {
lock.Lock()
errorHandler = prev
lock.Unlock()
}()
}
Error(&w, errors.New(test.input))
assert.Equal(t, test.expectCode, w.code)
2021-09-01 19:52:56 +08:00
assert.Equal(t, test.expectHasBody, w.hasBody)
2020-11-17 18:04:48 +08:00
assert.Equal(t, test.expectBody, strings.TrimSpace(w.builder.String()))
})
2020-08-21 23:09:35 +08:00
}
}
func TestErrorWithGrpcError(t *testing.T) {
w := tracedResponseWriter{
headers: make(map[string][]string),
}
Error(&w, status.Error(codes.Unavailable, "foo"))
assert.Equal(t, http.StatusServiceUnavailable, w.code)
assert.True(t, w.hasBody)
assert.True(t, strings.Contains(w.builder.String(), "foo"))
}
func TestErrorWithHandler(t *testing.T) {
w := tracedResponseWriter{
headers: make(map[string][]string),
}
Error(&w, errors.New("foo"), func(w http.ResponseWriter, err error) {
http.Error(w, err.Error(), 499)
})
assert.Equal(t, 499, w.code)
assert.True(t, w.hasBody)
assert.Equal(t, "foo", strings.TrimSpace(w.builder.String()))
}
2020-08-21 23:09:35 +08:00
func TestOk(t *testing.T) {
w := tracedResponseWriter{
headers: make(map[string][]string),
}
Ok(&w)
assert.Equal(t, http.StatusOK, w.code)
}
2020-07-26 17:09:05 +08:00
func TestOkJson(t *testing.T) {
w := tracedResponseWriter{
headers: make(map[string][]string),
}
msg := message{Name: "anyone"}
OkJson(&w, msg)
assert.Equal(t, http.StatusOK, w.code)
assert.Equal(t, "{\"name\":\"anyone\"}", w.builder.String())
}
func TestWriteJsonTimeout(t *testing.T) {
// only log it and ignore
w := tracedResponseWriter{
headers: make(map[string][]string),
2022-05-02 21:24:20 +08:00
err: http.ErrHandlerTimeout,
}
msg := message{Name: "anyone"}
WriteJson(&w, http.StatusOK, msg)
assert.Equal(t, http.StatusOK, w.code)
}
func TestWriteJsonError(t *testing.T) {
// only log it and ignore
w := tracedResponseWriter{
headers: make(map[string][]string),
err: errors.New("foo"),
2020-07-26 17:09:05 +08:00
}
msg := message{Name: "anyone"}
WriteJson(&w, http.StatusOK, msg)
assert.Equal(t, http.StatusOK, w.code)
}
func TestWriteJsonLessWritten(t *testing.T) {
w := tracedResponseWriter{
headers: make(map[string][]string),
lessWritten: true,
}
msg := message{Name: "anyone"}
WriteJson(&w, http.StatusOK, msg)
assert.Equal(t, http.StatusOK, w.code)
}
func TestWriteJsonMarshalFailed(t *testing.T) {
w := tracedResponseWriter{
headers: make(map[string][]string),
}
WriteJson(&w, http.StatusOK, map[string]interface{}{
"Data": complex(0, 0),
})
assert.Equal(t, http.StatusInternalServerError, w.code)
}
2020-07-26 17:09:05 +08:00
type tracedResponseWriter struct {
headers map[string][]string
builder strings.Builder
2021-09-01 19:52:56 +08:00
hasBody bool
2020-07-26 17:09:05 +08:00
code int
lessWritten bool
wroteHeader bool
2022-05-02 21:24:20 +08:00
err error
2020-07-26 17:09:05 +08:00
}
func (w *tracedResponseWriter) Header() http.Header {
return w.headers
}
func (w *tracedResponseWriter) Write(bytes []byte) (n int, err error) {
2022-05-02 21:24:20 +08:00
if w.err != nil {
return 0, w.err
2020-07-26 17:09:05 +08:00
}
n, err = w.builder.Write(bytes)
if w.lessWritten {
n -= 1
}
2021-09-01 19:52:56 +08:00
w.hasBody = true
2020-07-26 17:09:05 +08:00
return
}
func (w *tracedResponseWriter) WriteHeader(code int) {
if w.wroteHeader {
return
}
w.wroteHeader = true
2020-07-26 17:09:05 +08:00
w.code = code
}