130 lines
4.6 KiB
Go
130 lines
4.6 KiB
Go
package main_test
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"io"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"example.com/errorCatalog/internal/handler"
|
|
"example.com/errorCatalog/internal/svc"
|
|
omni "git.yuntuo.hk/k2safe/go-omni"
|
|
apierrors "git.yuntuo.hk/k2safe/go-omni/errors"
|
|
"git.yuntuo.hk/k2safe/go-omni/httpx"
|
|
"git.yuntuo.hk/k2safe/go-omni/logx"
|
|
"git.yuntuo.hk/k2safe/go-omni/response"
|
|
)
|
|
|
|
func TestGoOwnedCatalogOnGeneratedRoutes(t *testing.T) {
|
|
catalog := apierrors.Catalog{DefaultStatus: 400, Definitions: map[string]apierrors.Definition{
|
|
"USERNAME_INVALID": {Code: 400002, Message: "用户名格式不正确"},
|
|
"TEXT_TOO_LONG": {Status: 200, Code: 400003, Message: "{label}不能超过{max}个字符", Params: []apierrors.Parameter{{Name: "label", Type: "string"}, {Name: "max", Type: "int"}}},
|
|
"INTERNAL_ERROR": {Status: 500, Code: 9999, Message: "系统错误"},
|
|
"BODY_TOO_LARGE": {Status: 413, Code: 413001, Message: "请求体超限"},
|
|
}}
|
|
lc := logx.Default()
|
|
lc.Writer = io.Discard
|
|
logger, err := logx.New(lc)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer logger.Close()
|
|
deps, err := svc.New(context.Background(), logger)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer deps.Close()
|
|
format := response.Config{CodeType: "int32", SuccessCode: 0, ErrorCode: 9999, MessageField: "msg", DataMode: "always", RequestIDField: "-"}
|
|
app := omni.New(omni.WithErrors(catalog), omni.WithResponse(format))
|
|
defer app.Close()
|
|
resolve := func(c *httpx.Context) error {
|
|
switch c.Request().URL.Query().Get("kind") {
|
|
case "long":
|
|
return apierrors.ByCode("TEXT_TOO_LONG").WithParams(map[string]any{"label": "企业名称", "max": 100})
|
|
case "unknown":
|
|
return apierrors.ByCode("NOT_REGISTERED")
|
|
default:
|
|
return apierrors.ByCode("USERNAME_INVALID")
|
|
}
|
|
}
|
|
app.Use(func(next httpx.Handler) httpx.Handler {
|
|
return func(c *httpx.Context) error {
|
|
if c.Header("X-Early") == "true" {
|
|
return resolve(c)
|
|
}
|
|
return next(c)
|
|
}
|
|
})
|
|
app.GET("/ordinary", resolve)
|
|
if err := handler.RegisterRoutes(app, deps); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// Explicit route policy stays independent of App errors and response fields.
|
|
local := apierrors.Catalog{Definitions: map[string]apierrors.Definition{"USERNAME_INVALID": {Status: 409, Code: 409001, Message: "路由提示"}}}
|
|
localFormat := format
|
|
localFormat.MessageField = "detail"
|
|
app.HandleWithResponse("GET", "/independent", response.MustWithErrors(local, response.MustNew(localFormat)), resolve)
|
|
for _, early := range []string{"false", "true"} {
|
|
for _, test := range []struct {
|
|
kind string
|
|
status, code int
|
|
message string
|
|
}{
|
|
{"invalid", 400, 400002, "用户名格式不正确"}, {"long", 200, 400003, "企业名称不能超过100个字符"}, {"unknown", 500, 9999, "系统错误"},
|
|
} {
|
|
var ordinary string
|
|
for _, path := range []string{"/ordinary", "/plain", "/raw", "/cleared"} {
|
|
r := httptest.NewRequest("GET", path+"?kind="+test.kind, nil)
|
|
r.Header.Set("X-Early", early)
|
|
w := httptest.NewRecorder()
|
|
app.ServeHTTP(w, r)
|
|
var body map[string]any
|
|
if err := json.Unmarshal(w.Body.Bytes(), &body); err != nil {
|
|
t.Fatal(err, w.Body.String())
|
|
}
|
|
if w.Code != test.status || body["code"] != float64(test.code) || body["msg"] != test.message {
|
|
t.Fatal(path, early, w.Code, body)
|
|
}
|
|
if value, ok := body["data"]; !ok || value != nil {
|
|
t.Fatal("data:null missing", body)
|
|
}
|
|
if path == "/ordinary" {
|
|
ordinary = w.Body.String()
|
|
} else if w.Body.String() != ordinary {
|
|
t.Fatal("generated response differs", ordinary, w.Body.String())
|
|
}
|
|
}
|
|
}
|
|
r := httptest.NewRequest("GET", "/independent", nil)
|
|
r.Header.Set("X-Early", early)
|
|
w := httptest.NewRecorder()
|
|
app.ServeHTTP(w, r)
|
|
if w.Code != 409 || !strings.Contains(w.Body.String(), `"detail":"路由提示"`) || !strings.Contains(w.Body.String(), `"code":409001`) {
|
|
t.Fatal(w.Code, w.Body.String())
|
|
}
|
|
}
|
|
for _, path := range []string{"/plain", "/raw"} {
|
|
w := httptest.NewRecorder()
|
|
app.ServeHTTP(w, httptest.NewRequest("GET", path+"?kind=success", nil))
|
|
if w.Code != 200 || !strings.Contains(w.Body.String(), `"ok":true`) {
|
|
t.Fatal(w.Code, w.Body.String())
|
|
}
|
|
if path == "/raw" && strings.Contains(w.Body.String(), "code") {
|
|
t.Fatal("raw success wrapped")
|
|
}
|
|
}
|
|
for _, size := range []int{8, 65} {
|
|
w := httptest.NewRecorder()
|
|
app.ServeHTTP(w, httptest.NewRequest("POST", "/bounded", strings.NewReader(strings.Repeat("x", size))))
|
|
if size == 8 {
|
|
if w.Code != 200 || w.Body.String() != "ACK" {
|
|
t.Fatal(w.Code, w.Body.String())
|
|
}
|
|
} else if w.Code != 413 || !strings.Contains(w.Body.String(), "请求体超限") {
|
|
t.Fatal(w.Code, w.Body.String())
|
|
}
|
|
}
|
|
}
|