| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394 |
- 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)
- }
- }
|