Files
go-omni/response/config_test.go
k2safe 7670b222ac feat: release configurable API response contracts
Define reusable response bodies in .api with typed code mappings, per-route overrides and matching OpenAPI schemas. Add application and callback encoders, early response policy selection, and isolated remote-consumer release verification.

Release v0.8.0-preview after full race, vet, build and local MySQL workflow acceptance.
2026-09-23 20:42:38 +08:00

76 lines
3.0 KiB
Go

package response_test
import (
"encoding/json"
"errors"
"os"
"path/filepath"
"reflect"
"testing"
"git.yuntuo.hk/k2safe/go-omni/config"
"git.yuntuo.hk/k2safe/go-omni/response"
)
func TestConfigurableWireContract(t *testing.T) {
cfg := response.Config{CodeType: "integer", SuccessCode: 0, ErrorCode: 9999, MessageField: "msg", RequestIDField: "-", DataMode: "always", SuccessMessage: "操作成功", Codes: map[string]any{"EMAIL_TAKEN": 409001}, Messages: map[string]string{"EMAIL_TAKEN": "邮箱已存在"}}
f, err := response.New(cfg)
if err != nil {
t.Fatal(err)
}
cfg.Codes["EMAIL_TAKEN"] = 123
cfg.Messages["EMAIL_TAKEN"] = "changed"
f.Config().Codes["EMAIL_TAKEN"] = 456
for _, tc := range []struct {
result response.Result
code int64
message string
data any
}{
{response.Result{Status: 200, Code: "OK", Message: "success"}, 0, "操作成功", nil},
{response.Result{Status: 409, Code: "EMAIL_TAKEN", Message: "email taken", RequestID: "request", Err: errors.New("private")}, 409001, "邮箱已存在", nil},
{response.Result{Status: 200, Code: "OK", Data: []string{}}, 0, "操作成功", []string{}},
} {
value := f.Value(tc.result)
if !reflect.DeepEqual(value, map[string]any{"code": tc.code, "msg": tc.message, "data": tc.data}) {
t.Fatalf("unexpected envelope: %#v", value)
}
}
for _, bad := range []response.Config{
{CodeType: "integer"}, {CodeType: "bool"}, {MessageField: "code"}, {DataMode: "sometimes"},
{CodeType: "integer", SuccessCode: 200, ErrorCode: 9.5},
{CodeType: "integer", SuccessCode: json.Number("9007199254740992"), ErrorCode: 9999},
{Codes: map[string]any{"ERROR": 42}},
} {
if _, err := response.New(bad); err == nil {
t.Fatalf("invalid config accepted: %+v", bad)
}
}
}
func TestResponseConfigLoadsFromJSONAndYAML(t *testing.T) {
for filename, body := range map[string]string{
"flat.json": `{"response":{"codeType":"integer","successCode":0,"errorCode":9999,"messageField":"msg","requestIdField":"-","dataMode":"always","codes":{"DENIED":403001}}}`,
"flat.yaml": "response:\n codeType: integer\n successCode: 0\n errorCode: 9999\n messageField: msg\n requestIdField: '-'\n dataMode: always\n codes:\n DENIED: 403001\n",
"body.json": `{"response":{"body":{"code":"${code}","msg":"${message}","data":"${data}"},"codeType":"integer","successCode":0,"errorCode":9999,"dataMode":"always","codes":{"DENIED":403001}}}`,
"body.yaml": "response:\n body:\n code: '${code}'\n msg: '${message}'\n data: '${data}'\n codeType: integer\n successCode: 0\n errorCode: 9999\n dataMode: always\n codes:\n DENIED: 403001\n",
} {
path := filepath.Join(t.TempDir(), filename)
if err := os.WriteFile(path, []byte(body), 0600); err != nil {
t.Fatal(err)
}
cfg, err := config.LoadFile(path, "RESPONSE_TEST_")
if err != nil {
t.Fatal(err)
}
f, err := response.New(cfg.Response)
if err != nil {
t.Fatal(err)
}
value := f.Value(response.Result{Status: 403, Code: "DENIED"})
if value["code"] != int64(403001) || len(value) != 3 {
t.Fatalf("%s: %v", filename, value)
}
}
}