feat: publish sanitized custom.97 source
This commit is contained in:
1022 files changed
+69903
-19207
No files matched your search
@@ -4,13 +4,16 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/QuantumNous/new-api/common"
|
||||
"github.com/QuantumNous/new-api/constant"
|
||||
"github.com/QuantumNous/new-api/i18n"
|
||||
relaycommon "github.com/QuantumNous/new-api/relay/common"
|
||||
"github.com/QuantumNous/new-api/setting"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -43,17 +46,18 @@ func TestModelRedisRateLimitUsesUTCRegardlessOfLocalTimezone(t *testing.T) {
|
||||
var modelRateLimitTestUsers atomic.Int64
|
||||
|
||||
func TestModelRateLimitStreamFailuresDoNotConsumeSuccessLimit(t *testing.T) {
|
||||
require.NoError(t, i18n.Init())
|
||||
for _, backend := range []string{"memory", "redis"} {
|
||||
for _, totalLimit := range []int{0, 2} {
|
||||
t.Run(fmt.Sprintf("%s/total=%d", backend, totalLimit), func(t *testing.T) {
|
||||
userID := 7200000 + int(modelRateLimitTestUsers.Add(1))
|
||||
handler := memoryRateLimitHandler(60, totalLimit, 1)
|
||||
subject := strconv.Itoa(7200000 + int(modelRateLimitTestUsers.Add(1)))
|
||||
handler := memoryRateLimitHandler(subject, 60, totalLimit, 1)
|
||||
if backend == "redis" {
|
||||
useRateLimitMiniRedis(t)
|
||||
handler = redisRateLimitHandler(60, totalLimit, 1)
|
||||
handler = redisRateLimitHandler(subject, 60, totalLimit, 1)
|
||||
}
|
||||
router := gin.New()
|
||||
router.GET("/:outcome", func(c *gin.Context) { c.Set("id", userID) }, handler, func(c *gin.Context) {
|
||||
router.GET("/:outcome", handler, func(c *gin.Context) {
|
||||
status := relaycommon.NewStreamStatus()
|
||||
if c.Param("outcome") == "failed" {
|
||||
status.MarkFailed("server_error", "", 0)
|
||||
@@ -76,10 +80,11 @@ func TestModelRateLimitStreamFailuresDoNotConsumeSuccessLimit(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestModelMemoryRateLimitReservesConcurrentSuccessAdmission(t *testing.T) {
|
||||
userID := 7200000 + int(modelRateLimitTestUsers.Add(1))
|
||||
require.NoError(t, i18n.Init())
|
||||
subject := strconv.Itoa(7200000 + int(modelRateLimitTestUsers.Add(1)))
|
||||
entered, release, finished := make(chan struct{}), make(chan struct{}), make(chan struct{})
|
||||
router := gin.New()
|
||||
router.GET("/:outcome", func(c *gin.Context) { c.Set("id", userID) }, memoryRateLimitHandler(60, 0, 1), func(c *gin.Context) {
|
||||
router.GET("/:outcome", memoryRateLimitHandler(subject, 60, 0, 1), func(c *gin.Context) {
|
||||
if c.Param("outcome") == "failed" {
|
||||
close(entered)
|
||||
<-release
|
||||
@@ -100,3 +105,95 @@ func TestModelMemoryRateLimitReservesConcurrentSuccessAdmission(t *testing.T) {
|
||||
assert.Equal(t, http.StatusOK, performRateLimitRequest(router, "/completed", "127.0.0.1:1000").Code)
|
||||
assert.Equal(t, http.StatusTooManyRequests, performRateLimitRequest(router, "/completed", "127.0.0.1:1000").Code)
|
||||
}
|
||||
|
||||
// The memory limiter answers like the Redis limiter: an OpenAI error body
|
||||
// naming the limit that was reached, not an empty 429.
|
||||
func TestModelMemoryRateLimitRejectionsReturnOpenAIError(t *testing.T) {
|
||||
require.NoError(t, i18n.Init())
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
totalLimit, successLimit int
|
||||
messageKey string
|
||||
}{
|
||||
{name: "total", totalLimit: 1, messageKey: i18n.MsgRateLimitTotalReached},
|
||||
{name: "success", successLimit: 1, messageKey: i18n.MsgRateLimitReached},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
subject := strconv.Itoa(7200000 + int(modelRateLimitTestUsers.Add(1)))
|
||||
router := gin.New()
|
||||
router.GET("/", func(c *gin.Context) {
|
||||
c.Set(common.RequestIdKey, "req-limited")
|
||||
}, memoryRateLimitHandler(subject, 60, tc.totalLimit, tc.successLimit), func(c *gin.Context) {
|
||||
c.Status(http.StatusOK)
|
||||
})
|
||||
require.Equal(t, http.StatusOK, performRateLimitRequest(router, "/", "127.0.0.1:1000").Code)
|
||||
|
||||
resp := performRateLimitRequest(router, "/", "127.0.0.1:1000")
|
||||
assert.Equal(t, http.StatusTooManyRequests, resp.Code)
|
||||
message := i18n.Translate("", tc.messageKey, map[string]any{"Minutes": setting.ModelRequestRateLimitDurationMinutes, "Max": 1})
|
||||
want, err := common.Marshal(gin.H{"error": gin.H{
|
||||
"message": common.MessageWithRequestId(message, "req-limited"),
|
||||
"type": "new_api_error",
|
||||
"code": "",
|
||||
}})
|
||||
require.NoError(t, err)
|
||||
assert.JSONEq(t, string(want), resp.Body.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// A group with its own limit counts each user's requests on its own; groups
|
||||
// without one keep sharing the user's global limit.
|
||||
func TestModelRateLimitCountsConfiguredGroupsSeparately(t *testing.T) {
|
||||
require.NoError(t, i18n.Init())
|
||||
previousEnabled, previousMinutes := setting.ModelRequestRateLimitEnabled, setting.ModelRequestRateLimitDurationMinutes
|
||||
previousTotal, previousSuccess := setting.ModelRequestRateLimitCount, setting.ModelRequestRateLimitSuccessCount
|
||||
previousGroups, previousRedisEnabled := setting.ModelRequestRateLimitGroup, common.RedisEnabled
|
||||
t.Cleanup(func() {
|
||||
setting.ModelRequestRateLimitEnabled, setting.ModelRequestRateLimitDurationMinutes = previousEnabled, previousMinutes
|
||||
setting.ModelRequestRateLimitCount, setting.ModelRequestRateLimitSuccessCount = previousTotal, previousSuccess
|
||||
setting.ModelRequestRateLimitGroup, common.RedisEnabled = previousGroups, previousRedisEnabled
|
||||
})
|
||||
setting.ModelRequestRateLimitEnabled, setting.ModelRequestRateLimitDurationMinutes = true, 1
|
||||
common.RedisEnabled = false
|
||||
|
||||
// Groups a and b have their own limits; c and d have none and share the global one.
|
||||
steps := []struct {
|
||||
group string
|
||||
want int
|
||||
}{
|
||||
{"a", http.StatusOK}, {"a", http.StatusTooManyRequests},
|
||||
{"b", http.StatusOK}, {"b", http.StatusTooManyRequests},
|
||||
{"c", http.StatusOK}, {"d", http.StatusTooManyRequests},
|
||||
}
|
||||
// The Redis token bucket binds to the first Redis client it sees and another
|
||||
// test already drives it, so the total limit runs on the memory backend only.
|
||||
for _, tc := range []struct {
|
||||
backend, limit string
|
||||
counts [2]int // [total, success] for groups a and b and for the global limit
|
||||
}{
|
||||
{"memory", "success", [2]int{0, 1}},
|
||||
{"redis", "success", [2]int{0, 1}},
|
||||
{"memory", "total", [2]int{1, 1000}},
|
||||
} {
|
||||
t.Run(tc.backend+"/"+tc.limit, func(t *testing.T) {
|
||||
if tc.backend == "redis" {
|
||||
useRateLimitMiniRedis(t)
|
||||
}
|
||||
setting.ModelRequestRateLimitCount, setting.ModelRequestRateLimitSuccessCount = tc.counts[0], tc.counts[1]
|
||||
setting.ModelRequestRateLimitGroup = map[string][2]int{"a": tc.counts, "b": tc.counts}
|
||||
userID := 7200000 + int(modelRateLimitTestUsers.Add(1))
|
||||
router := gin.New()
|
||||
router.GET("/:group", func(c *gin.Context) {
|
||||
c.Set("id", userID)
|
||||
common.SetContextKey(c, constant.ContextKeyTokenGroup, c.Param("group"))
|
||||
}, ModelRequestRateLimit(), func(c *gin.Context) {
|
||||
c.Status(http.StatusOK)
|
||||
})
|
||||
|
||||
for _, step := range steps {
|
||||
assert.Equal(t, step.want, performRateLimitRequest(router, "/"+step.group, "127.0.0.1:1000").Code, "group %s", step.group)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user