Files
sub2api/backend/internal/handler/openai_gateway_cn_dispatch_test.go
T
刘佳林 efcc2252e5 fix(opencode): address review on dispatch, billing, session, and 402
Skip OpenAI messages-dispatch gpt-5.x defaults for OpenCode groups and
composite OpenCode targets. Filter unpriced claude-* billing candidates,
estimate count_tokens locally, sanitize body session IDs before setting
X-OpenCode-Session, and treat Zen 402 as recoverable payg cooldown.

Stop rewriting the inbound body before protocol routing so account
model_mapping applies once and usage_logs.model stays the client name.
2026-09-11 15:39:13 +08:00

85 lines
4.3 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 handler
// CN 分组 /v1/messages 调度闸门回归(修复:正常途径创建的 CN 分组曾恒 403):
// sanitizeGroupMessagesDispatchFields 对非 openai/composite 平台强制 AllowMessagesDispatch
// =false,故 CN 分组必须与 grok 一样在闸门处豁免,否则原生 Anthropic 直通
//(Claude Code 主用例)永远不可达。composite 分组解析到 grok/CN 目标时按
// 目标平台豁免,解析到 openai 目标仍受其可配置开关控制。
import (
"net/http/httptest"
"testing"
"github.com/Wei-Shaw/sub2api/internal/service"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/require"
)
func TestAllowOpenAICompatibleMessagesDispatch_CNProvidersExempt(t *testing.T) {
require.True(t, allowOpenAICompatibleMessagesDispatch(nil, nil), "无 key 保持放行")
for _, platform := range []string{service.PlatformKimi, service.PlatformZhipu, service.PlatformDeepseek, service.PlatformMiniMax, service.PlatformOpenCodeGo, service.PlatformGrok} {
apiKey := &service.APIKey{Group: &service.Group{Platform: platform, AllowMessagesDispatch: false}}
require.True(t, allowOpenAICompatibleMessagesDispatch(nil, apiKey),
"%s 分组必须豁免 allow_messages_dispatch 闸门", platform)
}
// 非回归:openai 分组仍受开关控制。
openaiOff := &service.APIKey{Group: &service.Group{Platform: service.PlatformOpenAI, AllowMessagesDispatch: false}}
require.False(t, allowOpenAICompatibleMessagesDispatch(nil, openaiOff))
openaiOn := &service.APIKey{Group: &service.Group{Platform: service.PlatformOpenAI, AllowMessagesDispatch: true}}
require.True(t, allowOpenAICompatibleMessagesDispatch(nil, openaiOn))
}
func TestAllowOpenAICompatibleMessagesDispatch_CompositeResolvedTargets(t *testing.T) {
gin.SetMode(gin.TestMode)
newCompositeCtx := func(model string, allow bool) (*gin.Context, *service.APIKey) {
c, _ := gin.CreateTestContext(httptest.NewRecorder())
c.Request = httptest.NewRequest("POST", "/v1/messages", nil)
apiKey := &service.APIKey{Group: &service.Group{Platform: service.PlatformComposite, AllowMessagesDispatch: allow}}
ensureCompositeTargetPlatform(c, apiKey, model)
return c, apiKey
}
// 解析到 grok/CN 目标:与对应独立分组同语义豁免。
for _, model := range []string{"grok-4.3", "kimi-k2-thinking", "glm-5.2", "deepseek-v3.2"} {
c, apiKey := newCompositeCtx(model, false)
require.True(t, allowOpenAICompatibleMessagesDispatch(c, apiKey), "model=%s", model)
}
// 解析到 openai 目标:受 composite 分组自身开关控制。
c, apiKey := newCompositeCtx("gpt-5.5", false)
require.False(t, allowOpenAICompatibleMessagesDispatch(c, apiKey))
c, apiKey = newCompositeCtx("gpt-5.5", true)
require.True(t, allowOpenAICompatibleMessagesDispatch(c, apiKey))
// 未解析出目标平台:保持拒绝,不放宽。
cNone, _ := gin.CreateTestContext(httptest.NewRecorder())
cNone.Request = httptest.NewRequest("POST", "/v1/messages", nil)
require.False(t, allowOpenAICompatibleMessagesDispatch(cNone,
&service.APIKey{Group: &service.Group{Platform: service.PlatformComposite, AllowMessagesDispatch: false}}))
}
// composite 解析到 grok/CN 目标时,Group 级调度映射(gpt-5.x 默认值为 openai
// 专属)不得注入,模型改写完全交给账号级 model_mapping。
func TestResolveOpenAIMessagesDispatchMappedModel_CompositeCNTargetsSkipGroupMapping(t *testing.T) {
gin.SetMode(gin.TestMode)
for _, model := range []string{"kimi-k2-thinking", "glm-5.2", "deepseek-v3.2", "grok-4.3"} {
c, _ := gin.CreateTestContext(httptest.NewRecorder())
c.Request = httptest.NewRequest("POST", "/v1/messages", nil)
apiKey := &service.APIKey{Group: &service.Group{Platform: service.PlatformComposite}}
ensureCompositeTargetPlatform(c, apiKey, model)
require.Empty(t, resolveOpenAIMessagesDispatchMappedModel(c, apiKey, "claude-sonnet-4-5-20250929"), "model=%s", model)
}
c, _ := gin.CreateTestContext(httptest.NewRecorder())
c.Request = httptest.NewRequest("POST", "/v1/messages", nil)
c.Request = c.Request.WithContext(service.WithResolvedTargetPlatform(c.Request.Context(), service.PlatformOpenCodeGo))
apiKey := &service.APIKey{Group: &service.Group{Platform: service.PlatformComposite}}
require.Empty(t, resolveOpenAIMessagesDispatchMappedModel(c, apiKey, "claude-sonnet-4-5-20250929"),
"composite → opencode_go 不得注入 openai 默认 gpt-5.x 映射")
}