Files
CLIProxyAPI/internal/logging/gin_logger_test.go
Luis Pater 7de9757c82 feat: add OpenAI video support with improved error handling and response normalization
- Introduced `/openai/v1/videos` endpoint to support OpenAI-specific video generation.
- Added error normalization and handling for OpenAI video resources, including detailed error propagation.
- Enhanced response structure to include OpenAI-specific fields for status, progress, and model mappings.
- Implemented new handlers for video content retrieval and error scenarios.
- Expanded test coverage to validate OpenAI video support, error handling, and backend compatibility.
2026-06-15 01:53:52 +08:00

126 lines
3.4 KiB
Go

package logging
import (
"errors"
"net/http"
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
)
func TestGinLogrusRecoveryRepanicsErrAbortHandler(t *testing.T) {
gin.SetMode(gin.TestMode)
engine := gin.New()
engine.Use(GinLogrusRecovery())
engine.GET("/abort", func(c *gin.Context) {
panic(http.ErrAbortHandler)
})
req := httptest.NewRequest(http.MethodGet, "/abort", nil)
recorder := httptest.NewRecorder()
defer func() {
recovered := recover()
if recovered == nil {
t.Fatalf("expected panic, got nil")
}
err, ok := recovered.(error)
if !ok {
t.Fatalf("expected error panic, got %T", recovered)
}
if !errors.Is(err, http.ErrAbortHandler) {
t.Fatalf("expected ErrAbortHandler, got %v", err)
}
if err != http.ErrAbortHandler {
t.Fatalf("expected exact ErrAbortHandler sentinel, got %v", err)
}
}()
engine.ServeHTTP(recorder, req)
}
func TestGinLogrusRecoveryHandlesRegularPanic(t *testing.T) {
gin.SetMode(gin.TestMode)
engine := gin.New()
engine.Use(GinLogrusRecovery())
engine.GET("/panic", func(c *gin.Context) {
panic("boom")
})
req := httptest.NewRequest(http.MethodGet, "/panic", nil)
recorder := httptest.NewRecorder()
engine.ServeHTTP(recorder, req)
if recorder.Code != http.StatusInternalServerError {
t.Fatalf("expected 500, got %d", recorder.Code)
}
}
func TestIsAIAPIPathIncludesImages(t *testing.T) {
if !isAIAPIPath("/v1/images/generations") {
t.Fatalf("expected /v1/images/generations to be treated as AI API path")
}
if !isAIAPIPath("/v1/images/edits") {
t.Fatalf("expected /v1/images/edits to be treated as AI API path")
}
if !isAIAPIPath("/v1/videos") {
t.Fatalf("expected /v1/videos to be treated as AI API path")
}
if !isAIAPIPath("/v1/videos/video_123") {
t.Fatalf("expected /v1/videos/video_123 to be treated as AI API path")
}
if !isAIAPIPath("/openai/v1/videos") {
t.Fatalf("expected /openai/v1/videos to be treated as AI API path")
}
if !isAIAPIPath("/openai/v1/videos/video_123/content") {
t.Fatalf("expected /openai/v1/videos/video_123/content to be treated as AI API path")
}
}
func TestIsAIAPIPathIncludesCodexBackend(t *testing.T) {
paths := []string{
"/backend-api/codex/responses",
"/backend-api/codex/responses/compact",
}
for _, path := range paths {
if !isAIAPIPath(path) {
t.Fatalf("expected %s to be treated as AI API path", path)
}
}
if isAIAPIPath("/backend-api/codex-status") {
t.Fatalf("expected /backend-api/codex-status not to be treated as AI API path")
}
}
func TestGinLogrusLoggerAddsRequestIDForCodexBackend(t *testing.T) {
gin.SetMode(gin.TestMode)
engine := gin.New()
engine.Use(GinLogrusLogger())
var requestIDFromContext string
var requestIDFromGin string
engine.POST("/backend-api/codex/responses", func(c *gin.Context) {
requestIDFromContext = GetRequestID(c.Request.Context())
requestIDFromGin = GetGinRequestID(c)
c.Status(http.StatusOK)
})
req := httptest.NewRequest(http.MethodPost, "/backend-api/codex/responses", nil)
recorder := httptest.NewRecorder()
engine.ServeHTTP(recorder, req)
if recorder.Code != http.StatusOK {
t.Fatalf("expected 200, got %d", recorder.Code)
}
if requestIDFromContext == "" {
t.Fatalf("expected request ID in request context")
}
if requestIDFromGin != requestIDFromContext {
t.Fatalf("expected Gin request ID %q to match context request ID %q", requestIDFromGin, requestIDFromContext)
}
}