package lua import ( "encoding/json" "path/filepath" "strings" "testing" ) // TestEveryBundledAdapterTwoDirections 逐个验证每个内置适配器在**两个方向**上 // 的声明与能力一致,且都能在真实 VM 上被调用而不报错。这是"重构后两个方向 // 都没坏"的批量断言(用户要求:16 个适配器逐个验证两个方向)。 // // 两个方向: // // 出向(egress):serialize_* 钩子 —— 统一格式 → 客户端协议。 // 一个适配器要么声明了 serialize_*(接管),要么依赖内核 OpenAI 兜底。 // 两种都合法;不合法的是"声明了钩子但调用即报错"。 // // 入向(ingress):adapter.ingress + deserialize_request —— 客户端协议 → 统一格式。 // 声明 ingress 的适配器必须同时实现 deserialize_request,否则内核会让出给 // 一个空解析器(核心里 parseViaIngress 已挡住,此处再在适配器数据面钉一次)。 // // 上游向(upstream):transform_request —— 统一格式 → 上游协议。 // 这是所有适配器的本职,必须存在且可调用。 func TestEveryBundledAdapterTwoDirections(t *testing.T) { vm := NewVM(filepath.Join(t.TempDir(), "adapters")) if err := vm.Start(); err != nil { t.Fatal(err) } defer vm.Stop() adapters := vm.ListAdapters() if len(adapters) == 0 { t.Fatal("no adapters loaded") } // 一个最小、协议中立的统一请求,供上游向 transform_request 使用。 unifiedReq := `{"model":"m","messages":[{"role":"user","content":"hi"}],"max_tokens":16,"stream":false}` for _, a := range adapters { a := a t.Run(a.Name, func(t *testing.T) { // ---- 上游向:transform_request 必须存在且可调用 ---- if !vm.HasFn(a.Name, "transform_request") { t.Errorf("%s: 缺 transform_request(上游向本职)", a.Name) } else if _, err := vm.Transform(a.Name, "transform_request", unifiedReq); err != nil { t.Errorf("%s: transform_request 调用失败: %v", a.Name, err) } // ---- 出向:serialize_* 声明与调用一致性 ---- declaredEgress := false for _, fn := range []string{"serialize_response", "serialize_chunk", "serialize_open_preamble", "serialize_close", "serialize_done_marker"} { if vm.HasFn(a.Name, fn) { declaredEgress = true } } if vm.HasFn(a.Name, "serialize_response") { // 统一结果形状(见 types.UnifiedResult) res := `{"model":"m","id":"x","content":"hello","finish_reason":"stop","token_usage":{"prompt":1,"completion":1,"total":2}}` out, err := vm.Transform(a.Name, "serialize_response", res) if err != nil { t.Errorf("%s: serialize_response 调用失败: %v", a.Name, err) } else if strings.TrimSpace(out) == "" { t.Errorf("%s: serialize_response 返回空", a.Name) } else if !json.Valid([]byte(out)) && !strings.HasPrefix(strings.TrimSpace(out), "event:") { t.Errorf("%s: serialize_response 既非 JSON 也非 SSE: %q", a.Name, out) } } if declaredEgress { t.Logf("%s: 出向由适配器接管", a.Name) } else { t.Logf("%s: 出向走内核 OpenAI 兜底(未声明 serialize_*)", a.Name) } // ---- 入向:声明 ingress 必须配 deserialize_request ---- ingress := vm.AdapterIngress(a.Name) hasDeser := vm.HasFn(a.Name, "deserialize_request") if ingress != "" { if !hasDeser { t.Errorf("%s: 声明 ingress=%q 但没有 deserialize_request —— 内核会让出给空解析器", a.Name, ingress) } else { // 用该适配器自己服务的那个端点的典型 body 调一次,确认不报错。 if _, err := vm.Transform(a.Name, "deserialize_request", `{"model":"m","max_tokens":8,"messages":[{"role":"user","content":"hi"}]}`); err != nil { t.Errorf("%s: deserialize_request 调用失败: %v", a.Name, err) } t.Logf("%s: 入向认领 %s", a.Name, ingress) } } else if hasDeser { t.Errorf("%s: 实现了 deserialize_request 却没声明 ingress —— 内核永远不会调用它", a.Name) } }) } }