mirror of
https://gitcode.com/JianFeeeee/ModelRouter.git
synced 2026-11-07 09:47:23 +00:00
产品名早已是 ModelRouter,但仓库标识符仍沿用旧名。这次统一,读写两侧都做兼容, 已部署的机器不会因为顺序问题立刻失效。 - go module `llmsproxy` → `modelrouter`;全仓 import 与 `cmd/modelrouter` 同步。 - `Makefile BINARY=modelrouter`;发行包名、systemd unit、/usr/share 资源、 `/usr/local/bin` 目标全部改为 modelrouter。 - 默认配置目录 `/etc/llmsproxy` → `/etc/modelrouter`。**读取侧回退**:插件与 `storeDir` 仍会检查旧路径,所以"先换二进制、后改 unit"不会立即失效。 - 环境变量 `LLMSPROXY_*`(PLUGIN_DIR / XDISPLAY_BASE / ARCH / LIVE_ZEN / BUILD_DIR)改为 `MODELROUTER_*`;`LLMS_PROXY_MASTER_KEY` → `MODELROUTER_MASTER_KEY`。旧名在读取侧继续接受。 - 桌面端内嵌核心 `bin/llmsproxy` → `bin/modelrouter`,并保留旧文件名回退, 避免升级到一半的 profile 被判成"core binary missing"。 - 新增 `packaging/migrate-to-modelrouter.sh`:**默认 dry-run**,复制而非移动、 旧目录永不删除、支持 `--rollback`;随 release tar 分发并由 core-dist 校验。 - `deploy.sh` 增加改名保护:发现旧 `/etc/llmsproxy` 而新配置不存在时**中止**, 否则会部署出一个"能启动但没有 key、没有源"的空实例。 - 临时目录前缀 `/tmp/llmsproxy-*` → `/tmp/modelrouter-*`;清理逻辑同时回收两代。 兼容别名(`__llmsproxy_*` 全局、`llmsproxy` SDK 别名、旧路径/旧 env)刻意保留, 它们是升级路径而非遗留;docs/plugins.md 已标注为废弃。 本提交未包含:`adapters/opencodezen.lua`、`adapter_opencodezen_test.go`、 `adapter_opencodezen_live_test.go`(OpenCode UA/免费池的既有改动,另批提交)。
70 lines
2.3 KiB
Go
70 lines
2.3 KiB
Go
package core
|
||
|
||
import (
|
||
"testing"
|
||
"time"
|
||
|
||
"modelrouter/internal/lua"
|
||
)
|
||
|
||
// TestNoKernelActionDeadlocksFromLua 对**每个**内核动作做同一条断言:
|
||
// 在插件 Lua 调用(此时持有 p.mu)内执行时不得死锁。
|
||
//
|
||
// 为什么是"每个"而不是"那个出问题的":最初只有 set_plugin_enabled 被发现自死锁
|
||
// (它经 SetEnabled 重入 p.mu),但"是否还有别的动作也会重入"只能靠枚举回答。
|
||
// 这条测试就是那次枚举的固化 —— 将来新增动作时如果也重入插件锁,它会失败。
|
||
//
|
||
// 同时它验证了"超时后副作用仍在幕后执行"这个更隐蔽的变体:那个缺陷的表现是
|
||
// 插件收到 error、但动作其实生效了。断言方式只是"不死锁 + 返回",因为死锁与
|
||
// 迟到副作用是同一个根因(在错误的锁上下文里执行)。
|
||
func TestNoKernelActionDeadlocksFromLua(t *testing.T) {
|
||
for _, a := range lua.KernelActions() {
|
||
a := a
|
||
t.Run(a.Name, func(t *testing.T) {
|
||
c := kernelTestCore(t)
|
||
code := `
|
||
local plugin = { name = "probe_all_actions", version = "1.0" }
|
||
plugin.exports = { "run" }
|
||
function plugin.run(args)
|
||
local r, err = __llmsproxy_kernel.call(args.action, args.arg or {})
|
||
return { ok = r ~= nil, err = err }
|
||
end
|
||
return plugin
|
||
`
|
||
if err := c.Plugins().LoadSource("probe_all_actions", code); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
// 授权所有动作(含破坏性),以便真正执行到
|
||
all := make([]string, 0)
|
||
for _, x := range lua.KernelActions() {
|
||
all = append(all, x.Name)
|
||
}
|
||
if err := c.Plugins().SetPluginKernelPermission("probe_all_actions", all, false); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
arg := map[string]interface{}{}
|
||
switch a.Name {
|
||
case "name", "adapter_owner":
|
||
arg["name"] = "primary"
|
||
}
|
||
if a.Name == "adapter_owner" {
|
||
arg = map[string]interface{}{"name": "openai"}
|
||
}
|
||
done := make(chan struct{})
|
||
go func() {
|
||
defer close(done)
|
||
_, err := c.Plugins().Call("probe_all_actions", "run",
|
||
map[string]interface{}{"action": a.Name, "arg": arg})
|
||
if err != nil {
|
||
t.Logf("%s 返回 err=%v", a.Name, err)
|
||
}
|
||
}()
|
||
select {
|
||
case <-done:
|
||
case <-time.After(8 * time.Second):
|
||
t.Fatalf("动作 %s 在 Lua 调用内死锁(deferred=%v danger=%s)", a.Name, a.Deferred, a.Danger)
|
||
}
|
||
})
|
||
}
|
||
}
|