Files
go-omni/cmd/go-omni/apigen/testdata/errorInheritance/consumer_test.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())
}
}
}