Files
sub2api/backend/internal/handler/openai_service_tier_validation_test.go
T
刘佳林 126ac24c8c feat(codex): support ultrafast service tier
Accept service_tier=ultrafast on the OpenAI/Codex gateway, advertise it
on GPT-5.6 Sol in the Codex model catalog, and include it in ChatGPT
OAuth routing hints so Codex clients can select Ultrafast.
2026-09-04 10:14:29 +08:00

95 lines
3.8 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
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/Wei-Shaw/sub2api/internal/config"
middleware2 "github.com/Wei-Shaw/sub2api/internal/server/middleware"
"github.com/Wei-Shaw/sub2api/internal/service"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/require"
)
// 非法 service_tier 必须在两个 OpenAI 端点(/v1/responses、/v1/chat/completions)
// 上以 OpenAI 兼容错误结构返回 HTTP 400。这些用例在 handler 的 service_tier
// 校验处短路,不会进入账号选择/重试。
//
// 合法值(fast/priority/flex/auto/default/scale/ultrafast)与省略/null 的接受语义由
// service 层纯校验函数 TestValidateOpenAIServiceTierField 覆盖,避免 handler
// 测试走入真实账号选择/重试路径。
func newServiceTierHandlerTest(t *testing.T) *OpenAIGatewayHandler {
t.Helper()
return &OpenAIGatewayHandler{
gatewayService: &service.OpenAIGatewayService{},
billingCacheService: service.NewBillingCacheService(nil, nil, nil, nil, nil, nil, &config.Config{RunMode: config.RunModeSimple}, nil),
apiKeyService: &service.APIKeyService{},
concurrencyHelper: &ConcurrencyHelper{concurrencyService: service.NewConcurrencyService(
&helperConcurrencyCacheStub{userSeq: []bool{true}},
)},
cfg: &config.Config{},
imageLimiter: &imageConcurrencyLimiter{},
}
}
func runOpenAIHandlerServiceTierTest(t *testing.T, path, body string, handler func(h *OpenAIGatewayHandler, c *gin.Context)) *httptest.ResponseRecorder {
t.Helper()
gin.SetMode(gin.TestMode)
rec := httptest.NewRecorder()
c, _ := gin.CreateTestContext(rec)
c.Request = httptest.NewRequest(http.MethodPost, path, strings.NewReader(body))
c.Request.Header.Set("Content-Type", "application/json")
groupID := int64(6401)
userID := int64(6402)
c.Set(string(middleware2.ContextKeyAPIKey), &service.APIKey{
ID: 6403,
GroupID: &groupID,
Group: &service.Group{
ID: groupID,
Platform: service.PlatformOpenAI,
},
User: &service.User{ID: userID, Status: service.StatusActive},
})
c.Set(string(middleware2.ContextKeyUser), middleware2.AuthSubject{UserID: userID, Concurrency: 1})
handler(newServiceTierHandlerTest(t), c)
return rec
}
func TestOpenAIGatewayHandlerResponses_InvalidServiceTierRejected400(t *testing.T) {
for _, body := range []string{
`{"model":"gpt-5.5","input":"hi","service_tier":"turbo"}`,
`{"model":"gpt-5.5","input":"hi","service_tier":"SPEED"}`,
`{"model":"gpt-5.5","input":"hi","service_tier":""}`,
`{"model":"gpt-5.5","input":"hi","service_tier":123}`,
`{"model":"gpt-5.5","input":"hi","service_tier":{}}`,
} {
rec := runOpenAIHandlerServiceTierTest(t, "/v1/responses", body, func(h *OpenAIGatewayHandler, c *gin.Context) {
h.Responses(c)
})
require.Equal(t, http.StatusBadRequest, rec.Code, "body=%s", body)
require.Contains(t, rec.Body.String(), "invalid_request_error", "body=%s", body)
require.Contains(t, rec.Body.String(), "invalid service_tier", "body=%s", body)
}
}
func TestOpenAIGatewayHandlerChatCompletions_InvalidServiceTierRejected400(t *testing.T) {
for _, body := range []string{
`{"model":"gpt-5.5","messages":[{"role":"user","content":"hi"}],"service_tier":"turbo"}`,
`{"model":"gpt-5.5","messages":[{"role":"user","content":"hi"}],"service_tier":"ultra"}`,
`{"model":"gpt-5.5","messages":[{"role":"user","content":"hi"}],"service_tier":""}`,
`{"model":"gpt-5.5","messages":[{"role":"user","content":"hi"}],"service_tier":["priority"]}`,
} {
rec := runOpenAIHandlerServiceTierTest(t, "/v1/chat/completions", body, func(h *OpenAIGatewayHandler, c *gin.Context) {
h.ChatCompletions(c)
})
require.Equal(t, http.StatusBadRequest, rec.Code, "body=%s", body)
require.Contains(t, rec.Body.String(), "invalid_request_error", "body=%s", body)
require.Contains(t, rec.Body.String(), "invalid service_tier", "body=%s", body)
}
}