openai_gateway_cn_dispatch_test.go 3.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. package handler
  2. // CN 分组 /v1/messages 调度闸门回归(修复:正常途径创建的 CN 分组曾恒 403):
  3. // sanitizeGroupMessagesDispatchFields 对非 openai/composite 平台强制 AllowMessagesDispatch
  4. // =false,故 CN 分组必须与 grok 一样在闸门处豁免,否则原生 Anthropic 直通
  5. //(Claude Code 主用例)永远不可达。composite 分组解析到 grok/CN 目标时按
  6. // 目标平台豁免,解析到 openai 目标仍受其可配置开关控制。
  7. import (
  8. "net/http/httptest"
  9. "testing"
  10. "github.com/Wei-Shaw/sub2api/internal/service"
  11. "github.com/gin-gonic/gin"
  12. "github.com/stretchr/testify/require"
  13. )
  14. func TestAllowOpenAICompatibleMessagesDispatch_CNProvidersExempt(t *testing.T) {
  15. require.True(t, allowOpenAICompatibleMessagesDispatch(nil, nil), "无 key 保持放行")
  16. for _, platform := range []string{service.PlatformKimi, service.PlatformZhipu, service.PlatformDeepseek, service.PlatformMiniMax, service.PlatformGrok} {
  17. apiKey := &service.APIKey{Group: &service.Group{Platform: platform, AllowMessagesDispatch: false}}
  18. require.True(t, allowOpenAICompatibleMessagesDispatch(nil, apiKey),
  19. "%s 分组必须豁免 allow_messages_dispatch 闸门", platform)
  20. }
  21. // 非回归:openai 分组仍受开关控制。
  22. openaiOff := &service.APIKey{Group: &service.Group{Platform: service.PlatformOpenAI, AllowMessagesDispatch: false}}
  23. require.False(t, allowOpenAICompatibleMessagesDispatch(nil, openaiOff))
  24. openaiOn := &service.APIKey{Group: &service.Group{Platform: service.PlatformOpenAI, AllowMessagesDispatch: true}}
  25. require.True(t, allowOpenAICompatibleMessagesDispatch(nil, openaiOn))
  26. }
  27. func TestAllowOpenAICompatibleMessagesDispatch_CompositeResolvedTargets(t *testing.T) {
  28. gin.SetMode(gin.TestMode)
  29. newCompositeCtx := func(model string, allow bool) (*gin.Context, *service.APIKey) {
  30. c, _ := gin.CreateTestContext(httptest.NewRecorder())
  31. c.Request = httptest.NewRequest("POST", "/v1/messages", nil)
  32. apiKey := &service.APIKey{Group: &service.Group{Platform: service.PlatformComposite, AllowMessagesDispatch: allow}}
  33. ensureCompositeTargetPlatform(c, apiKey, model)
  34. return c, apiKey
  35. }
  36. // 解析到 grok/CN 目标:与对应独立分组同语义豁免。
  37. for _, model := range []string{"grok-4.3", "kimi-k2-thinking", "glm-5.2", "deepseek-v3.2"} {
  38. c, apiKey := newCompositeCtx(model, false)
  39. require.True(t, allowOpenAICompatibleMessagesDispatch(c, apiKey), "model=%s", model)
  40. }
  41. // 解析到 openai 目标:受 composite 分组自身开关控制。
  42. c, apiKey := newCompositeCtx("gpt-5.5", false)
  43. require.False(t, allowOpenAICompatibleMessagesDispatch(c, apiKey))
  44. c, apiKey = newCompositeCtx("gpt-5.5", true)
  45. require.True(t, allowOpenAICompatibleMessagesDispatch(c, apiKey))
  46. // 未解析出目标平台:保持拒绝,不放宽。
  47. cNone, _ := gin.CreateTestContext(httptest.NewRecorder())
  48. cNone.Request = httptest.NewRequest("POST", "/v1/messages", nil)
  49. require.False(t, allowOpenAICompatibleMessagesDispatch(cNone,
  50. &service.APIKey{Group: &service.Group{Platform: service.PlatformComposite, AllowMessagesDispatch: false}}))
  51. }
  52. // composite 解析到 grok/CN 目标时,Group 级调度映射(gpt-5.x 默认值为 openai
  53. // 专属)不得注入,模型改写完全交给账号级 model_mapping。
  54. func TestResolveOpenAIMessagesDispatchMappedModel_CompositeCNTargetsSkipGroupMapping(t *testing.T) {
  55. gin.SetMode(gin.TestMode)
  56. for _, model := range []string{"kimi-k2-thinking", "glm-5.2", "deepseek-v3.2", "grok-4.3"} {
  57. c, _ := gin.CreateTestContext(httptest.NewRecorder())
  58. c.Request = httptest.NewRequest("POST", "/v1/messages", nil)
  59. apiKey := &service.APIKey{Group: &service.Group{Platform: service.PlatformComposite}}
  60. ensureCompositeTargetPlatform(c, apiKey, model)
  61. require.Empty(t, resolveOpenAIMessagesDispatchMappedModel(c, apiKey, "claude-sonnet-4-5-20250929"), "model=%s", model)
  62. }
  63. }