Files
sub2api/backend/internal/handler/openai_service_tier_validation_test.go
T
alfadb c0c3e1cb47 fix(openai): wire local observer service tier in WS ingress; bound handler tests
- openai_ws_forwarder_ingress: resolve billing tier from the local
  upstreamResponseModelObserver (upstream echo first) instead of the raw
  request payload, matching the HTTP->WS bridge and WS v2 forwarder.
- openai_ws_http_bridge_test: add fast-alias + upstream default case
  proving the local observer's echoed tier wins.
- handler tests: keep only invalid service_tier -> 400 (short-circuits at
  validation); valid/omitted semantics covered by the pure service-level
  validation tests, avoiding real account selection in tests.
2026-08-24 11:52:48 +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)与省略/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)
}
}