Files
ModelRouter/internal/provider/registry_pinned_name_test.go
JianFeeeee 8f2c5572e7 chore!: 移除厂商私有协议适配器与渠道业务插件(合规清理)
G-Star 合规要求下,把"模拟官方客户端、复刻私有协议、自动领取平台额度"这一类
能力整体移出仓库。这些实现依赖各平台未公开的端点、签名算法与官方 client id,
属于绕过客户端校验获取额度,风险高于普通协议适配。

移除(93 个文件):
- 适配器:opencodezen(伪装 UA 取免费池)、trae、buddy、kimicode
- 插件:channels.lua(12 个平台登录/领额度/签到)、quota.lua(厂商额度探针)
- 随之删除的 78 个渠道/额度专用测试与 3 份渠道文档

同时修掉的既有问题:
- **硬编码第三方 OAuth client_secret**(Google Cloud Code 的 GOCSPX-…,两处)
  随 channels.lua 一起消失。
- `deploy.sh` 的 `sync_plugins` 整段删除:它仍按"内置插件是发行物"的旧前提
  把插件复制/覆盖进 plugin_dir,与"插件属运维资产、网关不安装不覆盖"的契约
  冲突。现在部署脚本只同步适配器与二进制/配置。
- 适配器清单去掉已移除项;e2e 配置改用显式 `auto:` 链(`models.priority` 早已
  移除,该测试此前已失效)。

保留(公开协议):openai / anthropic / gemini / deepseek / github / groq /
mistral / ollama / qwen38 / sensenova = 10 个适配器;插件示例 billing / usage。

验证:go build -tags luajit ./... OK;internal/lua 21.4s、provider、core 51s、
gateway 122.8s、e2e 9.0s 全绿。
2026-10-27 09:25:58 +08:00

99 lines
3.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package provider
import "testing"
// ★ `源名:模型名` 这种限定写法,源名本身**含 `-`** 时必须仍能解开。
//
// 真实缺陷(用户报「无法使用 channel 注册的模型」,2026-10-17):
//
// WebUI 的模型下拉框用 `源名:模型名` 作为 option value —— 这是**有意**的:
// 本实例有 44 个模型被多个源同时提供(glm-5.2 被 6 个源提供),
// 用户必须能指定「从哪个源调用」。
//
// 但 ResolvePinned 用 `IndexAny(model, "-:/")` 找**第一个**分隔符,
// 而渠道源名形如 `channels-trae-b8dd6b3df30e`(含 `-`)⇒ 被切成
//
// src="channels"、model="trae-b8dd6b3df30e:Doubao-Seed-2.1-Pro"
//
// ⇒ 源名永不匹配 ⇒ Resolve() 返回 nil
// ⇒ 客户端看到 `model "channels-trae-xxx:..." is not configured`。
func TestResolvePinnedWithHyphenatedSourceName(t *testing.T) {
cases := []struct {
name string
sources map[string][]string // 源名 → 模型
input string
wantSrc string
wantMdl string
wantOK bool
}{
{
name: "渠道源名含两个 -(真实形态)",
sources: map[string][]string{
"channels-trae-b8dd6b3df30e": {"Doubao-Seed-2.1-Pro", "glm-5.2"},
"vendor-x-acct-1": {"hy4-preview", "glm-5.2"},
},
input: "channels-trae-b8dd6b3df30e:Doubao-Seed-2.1-Pro",
wantSrc: "channels-trae-b8dd6b3df30e",
wantMdl: "Doubao-Seed-2.1-Pro",
wantOK: true,
},
{
name: "同名模型跨源:必须能选中第二个源",
sources: map[string][]string{
"channels-trae-b8dd6b3df30e": {"glm-5.2"},
"vendor-x-acct-1": {"glm-5.2"},
},
input: "vendor-x-acct-1:glm-5.2",
wantSrc: "vendor-x-acct-1",
wantMdl: "glm-5.2",
wantOK: true,
},
{
name: "斜杠写法仍要支持",
sources: map[string][]string{
"channels-trae-b8dd6b3df30e": {"glm-5.2"},
},
input: "channels-trae-b8dd6b3df30e/glm-5.2",
wantSrc: "channels-trae-b8dd6b3df30e",
wantMdl: "glm-5.2",
wantOK: true,
},
{
// 自带 ":" 的第三方模型名,且**没有**任何源名与之匹配 ⇒ 走旧兜底。
// ⚠️ 不能拿 "our-free-model_cohere/..." 当例子:本实例真有一个叫
// `our-free-model_cohere` 的源,而仓库里还有叫 `our` 的源 ——
// 最长前缀匹配会正确命中 `our`,那个例子的预期是我写错了。
name: "无源名匹配时走旧兜底",
sources: map[string][]string{
"channels-trae-b8dd6b3df30e": {"glm-5.2"},
},
input: "vendor-lib/thing:free",
wantSrc: "vendor",
wantMdl: "lib/thing:free",
wantOK: true,
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
var ps []*Provider
for name, models := range c.sources {
ps = append(ps, newTestProvider(t, src(name, "http://127.0.0.1:1", "openai", models...)))
}
src, m, ok := splitPinned(c.input, ps)
if ok != c.wantOK {
t.Fatalf("ok 应为 %v,实得 %v(输入 %q)", c.wantOK, ok, c.input)
}
if !ok {
return
}
if src != c.wantSrc {
t.Fatalf("★ 源名解析错:期望 %q,实得 %q\n"+
" 输入 %q —— 源名含 `-` 时不能按第一个分隔符切", c.wantSrc, src, c.input)
}
if m != c.wantMdl {
t.Fatalf("模型名解析错:期望 %q,实得 %q", c.wantMdl, m)
}
})
}
}