| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- package admin
- import (
- "bytes"
- "encoding/json"
- "net/http"
- "net/http/httptest"
- "testing"
- infraerrors "github.com/Wei-Shaw/sub2api/internal/pkg/errors"
- "github.com/Wei-Shaw/sub2api/internal/service"
- "github.com/gin-gonic/gin"
- "github.com/stretchr/testify/require"
- )
- func TestAccountAdminBoundariesRejectMalformedOpenAILongContextBillingValue(t *testing.T) {
- const malformedExtra = `"extra":{"openai_long_context_billing_enabled":"true"}`
- tests := []struct {
- name string
- method string
- path string
- body string
- mount func(*gin.Engine, *AccountHandler)
- setup func(*stubAdminService)
- }{
- {
- name: "create",
- method: http.MethodPost,
- path: "/accounts",
- body: `{"name":"account","platform":"openai","type":"apikey","credentials":{"api_key":"test"},` + malformedExtra + `}`,
- mount: func(router *gin.Engine, handler *AccountHandler) { router.POST("/accounts", handler.Create) },
- },
- {
- name: "update",
- method: http.MethodPut,
- path: "/accounts/1",
- body: `{` + malformedExtra + `}`,
- mount: func(router *gin.Engine, handler *AccountHandler) { router.PUT("/accounts/:id", handler.Update) },
- setup: func(stub *stubAdminService) {
- stub.updateAccountErr = infraerrors.BadRequest("OPENAI_LONG_CONTEXT_BILLING_INVALID", "invalid")
- },
- },
- {
- name: "bulk update",
- method: http.MethodPost,
- path: "/accounts/bulk-update",
- body: `{"account_ids":[1],` + malformedExtra + `}`,
- mount: func(router *gin.Engine, handler *AccountHandler) {
- router.POST("/accounts/bulk-update", handler.BulkUpdate)
- },
- setup: func(stub *stubAdminService) {
- stub.bulkUpdateAccountErr = infraerrors.BadRequest("OPENAI_LONG_CONTEXT_BILLING_INVALID", "invalid")
- },
- },
- {
- name: "batch create",
- method: http.MethodPost,
- path: "/accounts/batch",
- body: `{"accounts":[{"name":"account","platform":"openai","type":"apikey","credentials":{"api_key":"test"},` + malformedExtra + `}]}`,
- mount: func(router *gin.Engine, handler *AccountHandler) { router.POST("/accounts/batch", handler.BatchCreate) },
- },
- {
- name: "Codex session import",
- method: http.MethodPost,
- path: "/accounts/import-codex-session",
- body: `{"content":"token",` + malformedExtra + `}`,
- mount: func(router *gin.Engine, handler *AccountHandler) {
- router.POST("/accounts/import-codex-session", handler.ImportCodexSession)
- },
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- gin.SetMode(gin.TestMode)
- stub := newStubAdminService()
- if tt.setup != nil {
- tt.setup(stub)
- }
- handler := NewAccountHandler(stub, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil)
- router := gin.New()
- tt.mount(router, handler)
- recorder := httptest.NewRecorder()
- request := httptest.NewRequest(tt.method, tt.path, bytes.NewBufferString(tt.body))
- request.Header.Set("Content-Type", "application/json")
- router.ServeHTTP(recorder, request)
- require.Equal(t, http.StatusBadRequest, recorder.Code)
- var responseBody struct {
- Reason string `json:"reason"`
- }
- require.NoError(t, json.Unmarshal(recorder.Body.Bytes(), &responseBody))
- require.Equal(t, "OPENAI_LONG_CONTEXT_BILLING_INVALID", responseBody.Reason)
- })
- }
- }
- func TestAccountCreateBoundaryDoesNotApplyOpenAIValidationToOtherPlatforms(t *testing.T) {
- gin.SetMode(gin.TestMode)
- handler := NewAccountHandler(newStubAdminService(), nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil)
- router := gin.New()
- router.POST("/accounts", handler.Create)
- recorder := httptest.NewRecorder()
- request := httptest.NewRequest(http.MethodPost, "/accounts", bytes.NewBufferString(
- `{"name":"account","platform":"anthropic","type":"apikey","credentials":{"api_key":"test"},"extra":{"openai_long_context_billing_enabled":"provider-owned"}}`,
- ))
- request.Header.Set("Content-Type", "application/json")
- router.ServeHTTP(recorder, request)
- require.Equal(t, http.StatusOK, recorder.Code)
- }
- func TestApplyOAuthCredentialsRejectsMalformedOpenAILongContextBillingBeforeMutation(t *testing.T) {
- gin.SetMode(gin.TestMode)
- stub := newStubAdminService()
- stub.getAccountResult = &service.Account{
- ID: 1,
- Platform: service.PlatformOpenAI,
- Type: service.AccountTypeOAuth,
- }
- handler := NewAccountHandler(stub, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil)
- router := gin.New()
- router.POST("/accounts/:id/apply-oauth-credentials", handler.ApplyOAuthCredentials)
- recorder := httptest.NewRecorder()
- request := httptest.NewRequest(http.MethodPost, "/accounts/1/apply-oauth-credentials", bytes.NewBufferString(
- `{"type":"oauth","credentials":{"access_token":"new-token"},"extra":{"openai_long_context_billing_enabled":"true"}}`,
- ))
- request.Header.Set("Content-Type", "application/json")
- router.ServeHTTP(recorder, request)
- require.Equal(t, http.StatusBadRequest, recorder.Code)
- var responseBody struct {
- Reason string `json:"reason"`
- }
- require.NoError(t, json.Unmarshal(recorder.Body.Bytes(), &responseBody))
- require.Equal(t, "OPENAI_LONG_CONTEXT_BILLING_INVALID", responseBody.Reason)
- require.Zero(t, stub.updateAccountCalls)
- require.Zero(t, stub.updateAccountExtraCalls)
- }
- func TestOpenAIOAuthCodexPATBoundaryRejectsMalformedOpenAILongContextBillingValueBeforeTokenValidation(t *testing.T) {
- gin.SetMode(gin.TestMode)
- handler := NewOpenAIOAuthHandler(nil, newStubAdminService(), nil, nil)
- router := gin.New()
- router.Use(gin.Recovery())
- router.POST("/openai/create-from-codex-pat", handler.CreateAccountFromCodexPAT)
- recorder := httptest.NewRecorder()
- request := httptest.NewRequest(http.MethodPost, "/openai/create-from-codex-pat", bytes.NewBufferString(
- `{"access_token":"token","extra":{"openai_long_context_billing_enabled":1}}`,
- ))
- request.Header.Set("Content-Type", "application/json")
- router.ServeHTTP(recorder, request)
- require.Equal(t, http.StatusBadRequest, recorder.Code)
- var responseBody struct {
- Reason string `json:"reason"`
- }
- require.NoError(t, json.Unmarshal(recorder.Body.Bytes(), &responseBody))
- require.Equal(t, "OPENAI_LONG_CONTEXT_BILLING_INVALID", responseBody.Reason)
- }
|