| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- package handler
- import (
- "bytes"
- "encoding/json"
- "mime/multipart"
- "net/http"
- "net/http/httptest"
- "testing"
- "github.com/Wei-Shaw/sub2api/internal/service"
- "github.com/gin-gonic/gin"
- "github.com/stretchr/testify/require"
- )
- func TestParseLiveCallRequestMultipartPreservesSession(t *testing.T) {
- gin.SetMode(gin.TestMode)
- session := `{"model":"gpt-live-test","delegation":{"type":"client"},"instructions":"你好"}`
- var body bytes.Buffer
- writer := multipart.NewWriter(&body)
- require.NoError(t, writer.WriteField("sdp", "v=0\r\n"))
- require.NoError(t, writer.WriteField("session", session))
- require.NoError(t, writer.Close())
- request := httptest.NewRequest("POST", "/v1/live", &body)
- request.Header.Set("Content-Type", writer.FormDataContentType())
- context, _ := gin.CreateTestContext(httptest.NewRecorder())
- context.Request = request
- parsed, err := parseLiveCallRequest(context)
- require.NoError(t, err)
- require.Equal(t, "v=0\r\n", parsed.SDP)
- require.JSONEq(t, session, string(parsed.Session))
- require.Equal(t, "client", jsonPathString(t, parsed.Session, "delegation", "type"))
- }
- func TestParseLiveCallRequestJSONPreservesSessionWithoutDelegation(t *testing.T) {
- gin.SetMode(gin.TestMode)
- body := `{"sdp":"v=0\\r\\n","session":{"model":"gpt-live-test","instructions":"standalone"}}`
- request := httptest.NewRequest("POST", "/backend-api/codex/realtime/calls", bytes.NewBufferString(body))
- request.Header.Set("Content-Type", "application/json")
- context, _ := gin.CreateTestContext(httptest.NewRecorder())
- context.Request = request
- parsed, err := parseLiveCallRequest(context)
- require.NoError(t, err)
- require.NotContains(t, string(parsed.Session), "delegation")
- require.Equal(t, "standalone", jsonPathString(t, parsed.Session, "instructions"))
- }
- func TestParseLiveCallRequestRejectsInvalidJSONShape(t *testing.T) {
- gin.SetMode(gin.TestMode)
- testCases := []string{
- `{"session":{"type":"quicksilver"}}`,
- `{"sdp":"v=0\\r\\n","session":[]}`,
- `{"sdp":"v=0\\r\\n","session":null}`,
- `{"sdp":"v=0\\r\\n","session":{"type":"quicksilver"}} {}`,
- }
- for _, body := range testCases {
- request := httptest.NewRequest("POST", "/backend-api/codex/realtime/calls", bytes.NewBufferString(body))
- request.Header.Set("Content-Type", "application/json")
- context, _ := gin.CreateTestContext(httptest.NewRecorder())
- context.Request = request
- _, err := parseLiveCallRequest(context)
- require.Error(t, err)
- }
- }
- func TestLiveSidebandLocationMatchesCreateRoute(t *testing.T) {
- require.Equal(t, "/v1/live/call_123", liveSidebandLocation("/v1/live", "call_123"))
- require.Equal(
- t,
- "/backend-api/codex/call_123",
- liveSidebandLocation("/backend-api/codex/realtime/calls", "call_123"),
- )
- }
- func TestLiveEnabledForAPIKey(t *testing.T) {
- require.False(t, liveEnabledForAPIKey(nil))
- require.False(t, liveEnabledForAPIKey(&service.APIKey{}))
- require.False(t, liveEnabledForAPIKey(&service.APIKey{
- Group: &service.Group{Platform: service.PlatformOpenAI},
- }))
- require.False(t, liveEnabledForAPIKey(&service.APIKey{
- Group: &service.Group{Platform: service.PlatformAnthropic, AllowLive: true},
- }))
- require.True(t, liveEnabledForAPIKey(&service.APIKey{
- Group: &service.Group{Platform: service.PlatformOpenAI, AllowLive: true},
- }))
- require.True(t, liveEnabledForAPIKey(&service.APIKey{
- Group: &service.Group{Platform: service.PlatformComposite, AllowLive: true},
- }))
- }
- func TestLiveAttestationErrorIsExplicit(t *testing.T) {
- gin.SetMode(gin.TestMode)
- recorder := httptest.NewRecorder()
- context, _ := gin.CreateTestContext(recorder)
- (&OpenAIGatewayHandler{}).writeLiveCreateError(context, &service.LiveAttestationUnavailableError{
- Reason: "Live attestation is only supported when Sub2API runs on macOS",
- })
- require.Equal(t, http.StatusServiceUnavailable, recorder.Code)
- require.Contains(t, recorder.Body.String(), "Sub2API runs on macOS")
- }
- func jsonPathString(t *testing.T, raw json.RawMessage, keys ...string) string {
- t.Helper()
- var value any
- require.NoError(t, json.Unmarshal(raw, &value))
- current := value
- for _, key := range keys {
- object, ok := current.(map[string]any)
- require.True(t, ok)
- current = object[key]
- }
- result, ok := current.(string)
- require.True(t, ok)
- return result
- }
|