Files
go-sip/contracts/v1_bundle_test.go
T

258 lines
8.6 KiB
Go

package contracts_test
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"
"testing"
"github.com/santhosh-tekuri/jsonschema/v6"
"git.ipao.vip/rogee/go-sip/internal/tenant"
)
const v1Dir = "upstream/v1"
const v1Base = "https://go-sip.local/contracts/v1/"
type offlineLoader struct{}
func (offlineLoader) Load(url string) (any, error) {
return nil, fmt.Errorf("schema is not in the immutable local bundle: %s", url)
}
func compileV1(t *testing.T, name string) *jsonschema.Schema {
t.Helper()
compiler := jsonschema.NewCompiler()
compiler.AssertFormat()
compiler.UseLoader(offlineLoader{})
paths, err := filepath.Glob(filepath.Join(v1Dir, "*.schema.json"))
if err != nil || len(paths) == 0 {
t.Fatalf("contract bundle missing: %v", err)
}
for _, path := range paths {
var schema any
if err := json.Unmarshal(readV1(t, path), &schema); err != nil {
t.Fatal(err)
}
if err := compiler.AddResource(v1Base+filepath.Base(path), schema); err != nil {
t.Fatal(err)
}
}
schema, err := compiler.Compile(v1Base + name)
if err != nil {
t.Fatal(err)
}
return schema
}
func readV1(t *testing.T, path string) []byte {
t.Helper()
raw, err := os.ReadFile(path)
if err != nil {
t.Fatal(err)
}
return raw
}
func objectV1(t *testing.T, path string) map[string]any {
t.Helper()
var value map[string]any
if err := json.Unmarshal(readV1(t, path), &value); err != nil {
t.Fatal(err)
}
return value
}
func TestV1BundleFixtures(t *testing.T) {
for _, name := range []string{"mq.schema.json", "event-payloads.schema.json", "dispatcher-config.schema.json"} {
t.Run(name, func(t *testing.T) { compileV1(t, name) })
}
var cases []struct {
File string `json:"file"`
Schema string `json:"schema"`
Valid bool `json:"valid"`
}
if err := json.Unmarshal(readV1(t, filepath.Join(v1Dir, "fixtures.json")), &cases); err != nil {
t.Fatal(err)
}
if len(cases) < 16 {
t.Fatal("missing bounded positive and negative message/config fixtures")
}
for _, tc := range cases {
t.Run(tc.File, func(t *testing.T) {
schema := compileV1(t, tc.Schema)
value := objectV1(t, filepath.Join(v1Dir, tc.File))
err := schema.Validate(value)
if (err == nil) != tc.Valid {
t.Fatalf("valid=%v, validation=%v", tc.Valid, err)
}
})
}
}
func TestV1ExecuteIdentityAndTenantConstraints(t *testing.T) {
schema := compileV1(t, "mq.schema.json")
for _, tc := range []struct {
name string
edit func(map[string]any)
}{
{"missing dispatcher", func(m map[string]any) { delete(m, "dispatcher_id") }},
{"non UUID dispatcher", func(m map[string]any) { m["dispatcher_id"] = "dispatcher-a" }},
{"uppercase dispatcher", func(m map[string]any) { m["dispatcher_id"] = strings.ToUpper(m["dispatcher_id"].(string)) }},
{"wildcard tenant", func(m map[string]any) { m["tenant_key"] = "tenant.#" }},
{"old version", func(m map[string]any) { m["schema_version"] = "1.0" }},
{"extra root", func(m map[string]any) { m["metadata"] = map[string]any{} }},
{"extra payload", func(m map[string]any) { m["payload"].(map[string]any)["mode"] = "full_ai" }},
} {
t.Run(tc.name, func(t *testing.T) {
value := objectV1(t, filepath.Join(v1Dir, "examples/call-execute.json"))
tc.edit(value)
if err := schema.Validate(value); err == nil {
t.Fatal("invalid envelope accepted")
}
})
}
}
func TestV1ResponseCorrelationAndResultBranches(t *testing.T) {
schema := compileV1(t, "mq.schema.json")
for _, tc := range []struct {
name string
edit func(map[string]any)
}{
{"missing correlation", func(m map[string]any) { delete(m, "correlation_id") }},
{"wrong result", func(m map[string]any) { m["status"] = "rejected"; m["reason_code"] = "ok" }},
{"response deadline", func(m map[string]any) { m["not_after"] = "2026-09-21T00:00:30Z" }},
{"missing command ID", func(m map[string]any) { delete(m["payload"].(map[string]any), "command_id") }},
{"extra result", func(m map[string]any) { m["payload"].(map[string]any)["raw"] = map[string]any{} }},
} {
t.Run(tc.name, func(t *testing.T) {
value := objectV1(t, filepath.Join(v1Dir, "examples/command-query-result.json"))
tc.edit(value)
if err := schema.Validate(value); err == nil {
t.Fatal("invalid query response accepted")
}
})
}
}
func TestV1UploadIsAFactNotASaaSHandshake(t *testing.T) {
schema := compileV1(t, "mq.schema.json")
for _, field := range []string{"oss_id", "verified", "token", "upload_url", "access_key_secret"} {
t.Run(field, func(t *testing.T) {
value := objectV1(t, filepath.Join(v1Dir, "examples/event-recording-uploaded.json"))
value["payload"].(map[string]any)[field] = "not-a-real-value"
if err := schema.Validate(value); err == nil {
t.Fatal("uploaded fact accepted a credential or SaaS processing claim")
}
})
}
for _, kind := range []string{"recording.upload-session.request", "recording.upload-session.result", "recording.complete", "recording.verified"} {
if strings.Contains(string(readV1(t, filepath.Join(v1Dir, "mq.schema.json"))), `"`+kind+`"`) {
t.Errorf("removed upload handshake is still in the published schema: %s", kind)
}
}
}
func TestV1DispatcherConfigDoesNotAcceptSecretsOrTTLOverride(t *testing.T) {
schema := compileV1(t, "dispatcher-config.schema.json")
for _, field := range []string{"access_key_id", "access_key_secret", "grant_ttl_seconds", "token"} {
t.Run(field, func(t *testing.T) {
value := objectV1(t, filepath.Join(v1Dir, "examples/dispatcher-config.json"))
value["oss"].(map[string]any)[field] = "not-a-real-value"
if err := schema.Validate(value); err == nil {
t.Fatal("unexpected secret/override field accepted")
}
})
}
}
func TestV1TopologyMatchesDispatcherRoutes(t *testing.T) {
var topology struct {
Exchanges map[string]struct {
Type string `json:"type"`
Durable bool `json:"durable"`
} `json:"exchanges"`
Inbox string `json:"inbox_queue"`
Dead string `json:"dead_letter_queue"`
Inbound string `json:"inbound_key"`
Outbound string `json:"outbound_key"`
Durable bool `json:"business_queues_durable"`
Persistent bool `json:"message_persistent"`
Mandatory bool `json:"publish_mandatory"`
Confirm bool `json:"publisher_confirms"`
TenantBytes int `json:"tenant_key_max_utf8_bytes"`
TokenSeconds int `json:"upload_token_seconds"`
}
if err := json.Unmarshal(readV1(t, filepath.Join(v1Dir, "mq-topology.json")), &topology); err != nil {
t.Fatal(err)
}
if !topology.Durable || !topology.Persistent || !topology.Mandatory || !topology.Confirm || topology.TenantBytes != 196 || topology.TokenSeconds != 900 {
t.Fatal("topology weakens the approved queue/token boundary")
}
if len(topology.Exchanges) != 3 {
t.Fatal("unexpected exchange topology")
}
for _, name := range []string{"agent-call.dispatchers.v2", "agent-call.saas.v2", "agent-call.dead-letter.v2"} {
x, ok := topology.Exchanges[name]
if !ok || x.Type != "topic" || !x.Durable {
t.Fatalf("wrong exchange contract: %s", name)
}
}
id := "c046b893-8628-4589-ae50-619d049248a6"
for _, key := range []string{"tenant-a", "租户.甲", strings.Repeat("a", 196)} {
route, err := tenant.NewDispatcherRoute(id, key)
if err != nil {
t.Fatal(err)
}
r := strings.NewReplacer("<dispatcher_id>", id, "<tenant_key>", key)
if route.InboxQueue != r.Replace(topology.Inbox) || route.DeadLetterQueue != r.Replace(topology.Dead) || route.InboundKey != r.Replace(topology.Inbound) || route.OutboundKey != r.Replace(topology.Outbound) {
t.Fatal("implementation differs from the published route templates")
}
}
}
func TestV1ManifestPinsEveryBundleFile(t *testing.T) {
var manifest struct {
Version string `json:"version"`
Source string `json:"source"`
Files map[string]string `json:"files"`
}
if err := json.Unmarshal(readV1(t, filepath.Join(v1Dir, "manifest.json")), &manifest); err != nil {
t.Fatal(err)
}
if manifest.Version != "v1" || manifest.Source != "project-development-v1" || len(manifest.Files) == 0 {
t.Fatal("invalid project-local provenance")
}
err := filepath.WalkDir(v1Dir, func(path string, entry os.DirEntry, err error) error {
if err != nil || entry.IsDir() {
return err
}
rel, err := filepath.Rel(v1Dir, path)
if err != nil || rel == "manifest.json" {
return err
}
actual := sha256.Sum256(readV1(t, path))
if manifest.Files[filepath.ToSlash(rel)] != hex.EncodeToString(actual[:]) {
t.Errorf("missing/incorrect manifest hash: %s", rel)
}
return nil
})
if err != nil {
t.Fatal(err)
}
for rel := range manifest.Files {
if !filepath.IsLocal(rel) {
t.Errorf("non-local manifest entry: %s", rel)
continue
}
if _, err := os.Stat(filepath.Join(v1Dir, rel)); err != nil {
t.Error(err)
}
}
}