Files
go-omni/response/codeTypes_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

124 lines
4.1 KiB
Go

package response_test
import (
"bytes"
"encoding/json"
"math"
"os"
"path/filepath"
"strconv"
"testing"
"git.yuntuo.hk/k2safe/go-omni/config"
"git.yuntuo.hk/k2safe/go-omni/response"
)
func TestCodeTypeWidthsAndWireValues(t *testing.T) {
for _, tc := range []struct {
kind string
min, max int64
}{
{"int32", math.MinInt32, math.MaxInt32}, {"int64", math.MinInt64, math.MaxInt64},
{"integer", -9007199254740991, 9007199254740991},
} {
t.Run(tc.kind, func(t *testing.T) {
cfg := response.Config{CodeType: tc.kind, SuccessCode: tc.max, ErrorCode: tc.min, Codes: map[string]any{"ZERO": 0}}
formatter, err := response.New(cfg)
if err != nil {
t.Fatal(err)
}
for _, sample := range []struct {
result response.Result
want int64
}{
{response.Result{Status: 200, Code: "OK"}, tc.max},
{response.Result{Status: 500, Code: "INTERNAL"}, tc.min},
{response.Result{Status: 409, Code: "ZERO"}, 0},
} {
payload, err := formatter.Encode(sample.result)
if err != nil {
t.Fatal(err)
}
decoder := json.NewDecoder(bytes.NewReader(payload.Body))
decoder.UseNumber()
var body map[string]any
if err = decoder.Decode(&body); err != nil {
t.Fatal(err)
}
code, ok := body["code"].(json.Number)
if !ok || code.String() != strconv.FormatInt(sample.want, 10) {
t.Fatalf("precision/type lost: %s", payload.Body)
}
}
})
}
for _, tc := range []struct {
kind string
value any
}{
{"int32", int64(math.MaxInt32) + 1}, {"int32", int64(math.MinInt32) - 1},
{"int64", json.Number("9223372036854775808")}, {"int64", json.Number("-9223372036854775809")},
{"int64", uint64(math.MaxUint64)}, {"int64", float64(math.MaxInt64)},
{"int32", 1.5}, {"int64", json.Number("1.5")}, {"int64", "200"},
{"string", 200},
} {
for _, field := range []string{"successCode", "errorCode", "codes"} {
cfg := response.Config{CodeType: tc.kind, SuccessCode: 0, ErrorCode: 1}
if tc.kind == "string" {
cfg.SuccessCode = "OK"
cfg.ErrorCode = "ERROR"
}
switch field {
case "successCode":
cfg.SuccessCode = tc.value
case "errorCode":
cfg.ErrorCode = tc.value
case "codes":
cfg.Codes = map[string]any{"MAPPED": tc.value}
}
if _, err := response.New(cfg); err == nil {
t.Fatalf("%s %s accepted %#v", tc.kind, field, tc.value)
}
}
}
for _, kind := range []string{"int32", "int64"} {
if _, err := response.New(response.Config{CodeType: kind}); err == nil {
t.Fatalf("%s accepted missing numeric fallbacks", kind)
}
}
f := response.MustNew(response.Config{CodeType: "string", SuccessCode: "SUCCESS", ErrorCode: "ERROR", Codes: map[string]any{"DENIED": "403"}})
if got := f.Value(response.Result{Status: 403, Code: "DENIED"})["code"]; got != "403" {
t.Fatal(got)
}
}
func TestInt64CodesFromConfigurationKeepPrecision(t *testing.T) {
for ext, body := range map[string]string{
"json": `{"response":{"codeType":"int64","successCode":9223372036854775807,"errorCode":-9223372036854775808,"codes":{"EXACT":9007199254740993}}}`,
"yaml": "response:\n codeType: int64\n successCode: 9223372036854775807\n errorCode: -9223372036854775808\n codes:\n EXACT: 9007199254740993\n",
} {
path := filepath.Join(t.TempDir(), "config."+ext)
if err := os.WriteFile(path, []byte(body), 0600); err != nil {
t.Fatal(err)
}
cfg, err := config.LoadFile(path, "RESPONSE_TEST_")
if err != nil {
t.Fatalf("%s: %v", ext, err)
}
f := response.MustNew(cfg.Response)
if f.Config().SuccessCode != int64(math.MaxInt64) || f.Config().ErrorCode != int64(math.MinInt64) || f.Config().Codes["EXACT"] != int64(9007199254740993) {
t.Fatalf("%s: precision lost: %#v", ext, f.Config())
}
}
var cfg response.Config
if err := json.Unmarshal([]byte(`{"codeType":"int64","successCode":9223372036854775807,"errorCode":0}`), &cfg); err != nil {
t.Fatal(err)
}
if response.MustNew(cfg).Config().SuccessCode != int64(math.MaxInt64) {
t.Fatal("json.Unmarshal lost precision")
}
if err := json.Unmarshal([]byte(`{"unknownOption":1}`), &cfg); err == nil {
t.Fatal("custom decoder bypassed unknown-field validation")
}
}