feat: publish immutable workflow definitions with typed SDK

This commit is contained in:
2026-09-18 00:28:00 +08:00
parent a664ec9370
commit 520e98d9d1
33 changed files with 2603 additions and 11 deletions

View File

@@ -0,0 +1,58 @@
package httpserver
import (
"encoding/json"
"net/http/httptest"
"strings"
"testing"
"git.yuntuo.hk/k2safe/orbit/weave/definition"
)
func TestWorkflowStrictJSONAndNullableLiteral(t *testing.T) {
valid := `{"version":"v1","reason":"release","specification":{"schema_version":1,"input_type":{"kind":"OBJECT","fields":{"number":{"kind":"NUMBER"}}},"timeout_ms":1000,"failure_policy":"REVIEW","body":{"output_type":{"kind":"NULL"},"output":{"kind":"LITERAL","literal":null}}}}`
for _, tc := range []struct {
name, raw string
ok bool
}{
{"explicit null literal", valid, true},
{"map type case alias", strings.Replace(valid, `"number":{"kind"`, `"number":{"Kind"`, 1), false},
{"map unknown property", strings.Replace(valid, `"number":{"kind":"NUMBER"}`, `"number":{"kind":"NUMBER","code":"script"}`, 1), false},
{"null type map", strings.Replace(valid, `"number":{"kind":"NUMBER"}`, `"number":null`, 1), false},
{"null collection", strings.Replace(valid, `"body":{`, `"body":{"steps":null,`, 1), false},
{"duplicate field", strings.Replace(valid, `"schema_version":1`, `"schema_version":1,"schema_version":2`, 1), false},
{"extra top property", strings.Replace(valid, `"reason":"release"`, `"reason":"release","Code":"arbitrary"`, 1), false},
} {
t.Run(tc.name, func(t *testing.T) {
r := httptest.NewRequest("POST", "/", strings.NewReader(tc.raw))
r.Header.Set("Content-Type", "application/json")
var in definition.PublishInput
err := decodeBody(r, &in)
if (err == nil) != tc.ok {
t.Fatalf("decode: %v", err)
}
if tc.ok {
if _, err := definition.Check(in.Specification); err != nil {
t.Fatal(err)
}
}
})
}
// Value.fields 同样递归检查精确字段名;普通任务payload仍不得显式null。
for _, raw := range []string{`{"kind":"OBJECT","fields":{"x":{"Kind":"LITERAL","literal":1}}}`, `{"kind":"OBJECT","fields":{"x":null}}`} {
r := httptest.NewRequest("POST", "/", strings.NewReader(raw))
r.Header.Set("Content-Type", "application/json")
var value definition.Value
if decodeBody(r, &value) == nil {
t.Fatal("invalid value map accepted")
}
}
var ordinary struct {
Payload json.RawMessage `json:"payload"`
}
r := httptest.NewRequest("POST", "/", strings.NewReader(`{"payload":null}`))
r.Header.Set("Content-Type", "application/json")
if decodeBody(r, &ordinary) == nil {
t.Fatal("nullable exception leaked to task payload")
}
}