middleware/logger_test.go
Rama main · réplica de lectura del repositorio original.
package middleware
import (
"bytes"
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
"github.com/QuantumNous/new-api/common"
"github.com/QuantumNous/new-api/logger"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestSetUpLoggerMasksQueryCredentials(t *testing.T) {
previousMode, previousWriter := gin.Mode(), gin.DefaultWriter
gin.SetMode(gin.TestMode)
t.Cleanup(func() {
gin.SetMode(previousMode)
gin.DefaultWriter = previousWriter
})
for _, tc := range []struct{ target, loggedPath string }{
{"/v1/models?%6bey=first&key=second&API-Key=third&session_token=fourth&alt=sse",
"/v1/models?API-Key=%2A%2A%2Amasked%2A%2A%2A&alt=sse&key=%2A%2A%2Amasked%2A%2A%2A&session_token=%2A%2A%2Amasked%2A%2A%2A"},
{"/v1/models%23test%25?key=#secret&alt=#sse",
"/v1/models%23test%25?alt=%23sse&key=%2A%2A%2Amasked%2A%2A%2A"},
{"//v1%2Fmodels?key=secret", "//v1%2Fmodels?key=%2A%2A%2Amasked%2A%2A%2A"},
{"/v1/models?key=bad%ZZ&%ZZ=bad&token=bad;other=true&alt=sse", "/v1/models?alt=sse"},
{"/v1/models?key=bad%ZZ", "/v1/models?"},
{"/v1/models?alt=sse&api-version=2024-02-01", "/v1/models?alt=sse&api-version=2024-02-01"},
{"/v1/models", "/v1/models"},
{"/%61pi/oauth/test?code=secret&state=secret", "/api/oauth/test"},
} {
t.Run(tc.target, func(t *testing.T) {
var output bytes.Buffer
gin.DefaultWriter = &output
router := gin.New()
SetUpLogger(router)
request := httptest.NewRequest(http.MethodGet, tc.target, nil)
originalURL := *request.URL
router.NoRoute(func(c *gin.Context) {
assert.Equal(t, originalURL, *c.Request.URL)
assert.Equal(t, tc.target, c.Request.RequestURI)
c.Status(http.StatusUnauthorized)
})
response := httptest.NewRecorder()
router.ServeHTTP(response, request)
require.Equal(t, http.StatusUnauthorized, response.Code)
_, loggedPath, found := strings.Cut(strings.TrimSuffix(output.String(), "\n"), "GET ")
require.True(t, found)
assert.Equal(t, tc.loggedPath, loggedPath)
assert.Equal(t, originalURL, *request.URL)
assert.Equal(t, tc.target, request.RequestURI)
})
}
}
func TestAccessAndPanicLogsFollowLogRotation(t *testing.T) {
previousMode, previousWriter, previousErrorWriter := gin.Mode(), gin.DefaultWriter, gin.DefaultErrorWriter
previousLogDir := *common.LogDir
gin.SetMode(gin.TestMode)
*common.LogDir = t.TempDir()
t.Cleanup(func() {
gin.SetMode(previousMode)
gin.DefaultWriter, gin.DefaultErrorWriter = previousWriter, previousErrorWriter
*common.LogDir = previousLogDir
})
logger.SetupLogger()
router := gin.New()
router.Use(PanicRecover())
SetUpLogger(router)
router.GET("/ok/:step", func(c *gin.Context) { c.Status(http.StatusNoContent) })
router.GET("/panic", func(c *gin.Context) { panic("rotation-panic-marker") })
router.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest(http.MethodGet, "/ok/before-rotation", nil))
content, err := os.ReadFile(logger.GetCurrentLogPath())
require.NoError(t, err)
assert.Contains(t, string(content), "/ok/before-rotation")
// Rotation closes the file the middleware saw at startup. The new file may
// reuse the old name when both calls land in the same second; the checks
// below hold either way because only the new descriptor stays open.
logger.SetupLogger()
router.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest(http.MethodGet, "/ok/after-rotation", nil))
panicResponse := httptest.NewRecorder()
router.ServeHTTP(panicResponse, httptest.NewRequest(http.MethodGet, "/panic", nil))
require.Equal(t, http.StatusInternalServerError, panicResponse.Code)
content, err = os.ReadFile(logger.GetCurrentLogPath())
require.NoError(t, err)
assert.Contains(t, string(content), "/ok/after-rotation")
assert.Contains(t, string(content), "[Recovery]")
assert.Contains(t, string(content), "rotation-panic-marker\n")
assert.Contains(t, string(content), "middleware/logger_test.go")
}
func TestSetUpLoggerOmitsQueryCredentialsTakenOutByHandlers(t *testing.T) {
previousMode, previousWriter := gin.Mode(), gin.DefaultWriter
gin.SetMode(gin.TestMode)
t.Cleanup(func() {
gin.SetMode(previousMode)
gin.DefaultWriter = previousWriter
})
for _, tc := range []struct{ target, loggedPath string }{
{"/v1beta/models/veo:predictLongRunning?key=sk-secret", "/v1beta/models/veo:predictLongRunning"},
{"/v1beta/models/veo:predictLongRunning?key=sk-secret&alt=sse", "/v1beta/models/veo:predictLongRunning?alt=sse"},
} {
t.Run(tc.target, func(t *testing.T) {
var output bytes.Buffer
gin.DefaultWriter = &output
router := gin.New()
SetUpLogger(router)
router.POST("/v1beta/models/:action", NativeRouteCredential("google"), func(c *gin.Context) {
c.Status(http.StatusNoContent)
})
response := httptest.NewRecorder()
router.ServeHTTP(response, httptest.NewRequest(http.MethodPost, tc.target, nil))
require.Equal(t, http.StatusNoContent, response.Code)
assert.NotContains(t, output.String(), "sk-secret")
_, loggedPath, found := strings.Cut(strings.TrimSuffix(output.String(), "\n"), "POST ")
require.True(t, found)
assert.Equal(t, tc.loggedPath, loggedPath)
})
}
}