package lua import ( "fmt" "os" "path/filepath" "testing" ) // zcodeHarness 是与 runtimePlugins 等价的测试台,唯一差别是 **adapters 与 // plugins 目录互为兄弟**(`/adapters` + `/plugins`)。 // // 为什么必须这样:installZcodeAdapter 要从「插件目录的父目录/adapters」读 // anthropic.lua 的源码,再把基座**内联**进适配器脚本(适配器沙箱没有 fs)。 // runtimePlugins 给 adapters/plugins 各用一个独立的 t.TempDir(),两个目录 // 不是兄弟 ⇒ zcode 安装期就报「读不到 anthropic.lua」而被跳过,适配器根本 // 不会出现(探针会如实报 ok:false,这本身是好事 —— 说明失败可见)。 // // 生产里这两个目录是兄弟(config.PluginDir 与 config.AdapterDir 同级), // 所以这个测试台更贴近真实布局。 func zcodeHarness(t *testing.T) (*VM, *Plugins) { t.Helper() root := t.TempDir() adir := filepath.Join(root, "adapters") vm := NewVM(adir) if err := vm.Start(); err != nil { t.Fatalf("vm: %v", err) } t.Cleanup(vm.Stop) pdir := filepath.Join(root, "plugins") if os.Getenv("LLMSPROXY_PLUGIN_DIR") == "" { t.Setenv("LLMSPROXY_PLUGIN_DIR", pdir) } ps := NewPlugins(vm, pdir) ps.SetOutboundHosts([]string{"127.0.0.1"}) // 同 runtimePlugins:关掉状态持久化,避免后台调度器写进生产 store。 ps.DisableStatePersistence() src, err := bundledAdapters.ReadFile("plugins/channels.lua") if err != nil { t.Fatal(err) } if err := ps.LoadSource("channels", string(src)); err != nil { t.Fatal(err) } // zcode 装不上时必须**响亮失败**,不能静默跳过 —— 否则判据会在 // 「适配器根本不存在」的情况下误判为通过(那正是 plan §3 第 1 条 // 说的假绿形态)。 res, err := ps.Call("channels", "__adapter_install_probe", map[string]interface{}{}) if err != nil { t.Fatalf("__adapter_install_probe: %v", err) } j := probeJSON(t, res) zc, ok := j["zcode"].(map[string]interface{}) if !ok { t.Fatalf("探针未报告 zcode 装载结果: %v", j) } if zc["ok"] != true { t.Fatalf("★ zcode 适配器装载失败: %v\n"+ " 注意 luac -p 对长字符串内的适配器代码无效(plan §3 第 1 条),"+ "必须以本探针为准", zc["err"]) } if !vm.HasFn("channels-zcode", "build_headers") { t.Fatal("zcode 装载后仍然没有 build_headers") } _ = fmt.Sprint() return vm, ps }