feat: add project-owned error catalogs and HTTP 200 failure contracts
This commit is contained in:
92
cmd/go-omni/apigen/testdata/errorCatalog/consumer_test.go
vendored
Normal file
92
cmd/go-omni/apigen/testdata/errorCatalog/consumer_test.go
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
package consumer_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"example.com/errorCatalog/internal/apierrors"
|
||||
"example.com/errorCatalog/internal/handler"
|
||||
"example.com/errorCatalog/internal/servicecontext"
|
||||
omni "git.yuntuo.hk/k2safe/go-omni"
|
||||
omnierrors "git.yuntuo.hk/k2safe/go-omni/errors"
|
||||
"git.yuntuo.hk/k2safe/go-omni/httpx"
|
||||
"git.yuntuo.hk/k2safe/go-omni/logx"
|
||||
)
|
||||
|
||||
func TestGeneratedCatalog(t *testing.T) {
|
||||
first := apierrors.UsernameInvalid().WithCause(errors.New("private"))
|
||||
second := apierrors.UsernameInvalid()
|
||||
if first == second || second.Cause != nil || second.Status != 200 || second.BusinessCode != int64(400002) {
|
||||
t.Fatal("shared or incomplete generated error")
|
||||
}
|
||||
copy := apierrors.Catalog()
|
||||
delete(copy.Definitions, apierrors.CodeUsernameInvalid)
|
||||
if len(apierrors.Catalog().Definitions) != 3 {
|
||||
t.Fatal("shared catalog")
|
||||
}
|
||||
cfg := logx.Default()
|
||||
cfg.Writer = io.Discard
|
||||
logger, err := logx.New(cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer logger.Close()
|
||||
deps, err := servicecontext.New(context.Background(), logger)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer deps.Close()
|
||||
app := omni.New()
|
||||
defer app.Close()
|
||||
// Global middleware exits early: generated route policy must already be active.
|
||||
app.Use(func(next httpx.Handler) httpx.Handler {
|
||||
return func(c *httpx.Context) error {
|
||||
switch c.Header("X-Fixture") {
|
||||
case "username":
|
||||
return omnierrors.ByCode(apierrors.CodeUsernameInvalid).WithCause(errors.New("private"))
|
||||
case "password":
|
||||
return apierrors.PasswordInvalid()
|
||||
case "denied":
|
||||
return apierrors.PermissionDenied()
|
||||
case "unknown":
|
||||
return omnierrors.ByCode("MISSING")
|
||||
default:
|
||||
return c.OK(map[string]string{"token": "ok"})
|
||||
}
|
||||
}
|
||||
})
|
||||
if err := handler.RegisterRoutes(app, deps); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, path := range []string{"/token", "/raw"} {
|
||||
for _, test := range []struct {
|
||||
kind string
|
||||
status int
|
||||
want string
|
||||
}{{"username", 200, "用户名格式不正确"}, {"password", 200, "密码格式不正确"}, {"denied", 403, "没有权限"}, {"unknown", 500, "internal server error"}, {"", 200, `"token":"ok"`}} {
|
||||
method := "POST"
|
||||
if path == "/raw" {
|
||||
method = "GET"
|
||||
}
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest(method, path, nil)
|
||||
r.Header.Set("X-Fixture", test.kind)
|
||||
app.ServeHTTP(w, r)
|
||||
if w.Code != test.status || !strings.Contains(w.Body.String(), test.want) || strings.Contains(w.Body.String(), "private") {
|
||||
t.Fatal(path, test.kind, w.Code, w.Body.String())
|
||||
}
|
||||
if test.kind == "username" || test.kind == "password" {
|
||||
if !strings.Contains(w.Body.String(), `"code":400002`) || !strings.Contains(w.Body.String(), `"ok":false`) {
|
||||
t.Fatal(w.Body.String())
|
||||
}
|
||||
}
|
||||
if path == "/raw" && test.kind == "" && strings.Contains(w.Body.String(), "code") {
|
||||
t.Fatal("raw success wrapped")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user