| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- package service
- import (
- "fmt"
- "net/http"
- "net/http/httptest"
- "strings"
- "testing"
- "time"
- relaycommon "github.com/QuantumNous/new-api/relay/common"
- "github.com/QuantumNous/new-api/setting/operation_setting"
- "github.com/gin-gonic/gin"
- "github.com/stretchr/testify/require"
- )
- func buildChannelAffinityTemplateContextForTest(meta channelAffinityMeta) *gin.Context {
- rec := httptest.NewRecorder()
- ctx, _ := gin.CreateTestContext(rec)
- setChannelAffinityContext(ctx, meta)
- return ctx
- }
- func TestApplyChannelAffinityOverrideTemplate_NoTemplate(t *testing.T) {
- ctx := buildChannelAffinityTemplateContextForTest(channelAffinityMeta{
- RuleName: "rule-no-template",
- })
- base := map[string]interface{}{
- "temperature": 0.7,
- }
- merged, applied := ApplyChannelAffinityOverrideTemplate(ctx, base)
- require.False(t, applied)
- require.Equal(t, base, merged)
- }
- func TestApplyChannelAffinityOverrideTemplate_MergeTemplate(t *testing.T) {
- ctx := buildChannelAffinityTemplateContextForTest(channelAffinityMeta{
- RuleName: "rule-with-template",
- ParamTemplate: map[string]interface{}{
- "temperature": 0.2,
- "top_p": 0.95,
- },
- UsingGroup: "default",
- ModelName: "gpt-4.1",
- RequestPath: "/v1/responses",
- KeySourceType: "gjson",
- KeySourcePath: "prompt_cache_key",
- KeyHint: "abcd...wxyz",
- KeyFingerprint: "abcd1234",
- })
- base := map[string]interface{}{
- "temperature": 0.7,
- "max_tokens": 2000,
- }
- merged, applied := ApplyChannelAffinityOverrideTemplate(ctx, base)
- require.True(t, applied)
- require.Equal(t, 0.7, merged["temperature"])
- require.Equal(t, 0.95, merged["top_p"])
- require.Equal(t, 2000, merged["max_tokens"])
- require.Equal(t, 0.7, base["temperature"])
- anyInfo, ok := ctx.Get(ginKeyChannelAffinityLogInfo)
- require.True(t, ok)
- info, ok := anyInfo.(map[string]interface{})
- require.True(t, ok)
- overrideInfoAny, ok := info["override_template"]
- require.True(t, ok)
- overrideInfo, ok := overrideInfoAny.(map[string]interface{})
- require.True(t, ok)
- require.Equal(t, true, overrideInfo["applied"])
- require.Equal(t, "rule-with-template", overrideInfo["rule_name"])
- require.EqualValues(t, 2, overrideInfo["param_override_keys"])
- }
- func TestApplyChannelAffinityOverrideTemplate_MergeOperations(t *testing.T) {
- ctx := buildChannelAffinityTemplateContextForTest(channelAffinityMeta{
- RuleName: "rule-with-ops-template",
- ParamTemplate: map[string]interface{}{
- "operations": []map[string]interface{}{
- {
- "mode": "pass_headers",
- "value": []string{"Originator"},
- },
- },
- },
- })
- base := map[string]interface{}{
- "temperature": 0.7,
- "operations": []map[string]interface{}{
- {
- "path": "model",
- "mode": "trim_prefix",
- "value": "openai/",
- },
- },
- }
- merged, applied := ApplyChannelAffinityOverrideTemplate(ctx, base)
- require.True(t, applied)
- require.Equal(t, 0.7, merged["temperature"])
- opsAny, ok := merged["operations"]
- require.True(t, ok)
- ops, ok := opsAny.([]interface{})
- require.True(t, ok)
- require.Len(t, ops, 2)
- firstOp, ok := ops[0].(map[string]interface{})
- require.True(t, ok)
- require.Equal(t, "pass_headers", firstOp["mode"])
- secondOp, ok := ops[1].(map[string]interface{})
- require.True(t, ok)
- require.Equal(t, "trim_prefix", secondOp["mode"])
- }
- func TestChannelAffinityHitCodexTemplatePassHeadersEffective(t *testing.T) {
- gin.SetMode(gin.TestMode)
- setting := operation_setting.GetChannelAffinitySetting()
- require.NotNil(t, setting)
- var codexRule *operation_setting.ChannelAffinityRule
- for i := range setting.Rules {
- rule := &setting.Rules[i]
- if strings.EqualFold(strings.TrimSpace(rule.Name), "codex cli trace") {
- codexRule = rule
- break
- }
- }
- require.NotNil(t, codexRule)
- affinityValue := fmt.Sprintf("pc-hit-%d", time.Now().UnixNano())
- cacheKeySuffix := buildChannelAffinityCacheKeySuffix(*codexRule, "default", affinityValue)
- cache := getChannelAffinityCache()
- require.NoError(t, cache.SetWithTTL(cacheKeySuffix, 9527, time.Minute))
- t.Cleanup(func() {
- _, _ = cache.DeleteMany([]string{cacheKeySuffix})
- })
- rec := httptest.NewRecorder()
- ctx, _ := gin.CreateTestContext(rec)
- ctx.Request = httptest.NewRequest(http.MethodPost, "/v1/responses", strings.NewReader(fmt.Sprintf(`{"prompt_cache_key":"%s"}`, affinityValue)))
- ctx.Request.Header.Set("Content-Type", "application/json")
- channelID, found := GetPreferredChannelByAffinity(ctx, "gpt-5", "default")
- require.True(t, found)
- require.Equal(t, 9527, channelID)
- baseOverride := map[string]interface{}{
- "temperature": 0.2,
- }
- mergedOverride, applied := ApplyChannelAffinityOverrideTemplate(ctx, baseOverride)
- require.True(t, applied)
- require.Equal(t, 0.2, mergedOverride["temperature"])
- info := &relaycommon.RelayInfo{
- RequestHeaders: map[string]string{
- "Originator": "Codex CLI",
- "Session_id": "sess-123",
- "User-Agent": "codex-cli-test",
- },
- ChannelMeta: &relaycommon.ChannelMeta{
- ParamOverride: mergedOverride,
- HeadersOverride: map[string]interface{}{
- "X-Static": "legacy-static",
- },
- },
- }
- _, err := relaycommon.ApplyParamOverrideWithRelayInfo([]byte(`{"model":"gpt-5"}`), info)
- require.NoError(t, err)
- require.True(t, info.UseRuntimeHeadersOverride)
- require.Equal(t, "legacy-static", info.RuntimeHeadersOverride["x-static"])
- require.Equal(t, "Codex CLI", info.RuntimeHeadersOverride["originator"])
- require.Equal(t, "sess-123", info.RuntimeHeadersOverride["session_id"])
- require.Equal(t, "codex-cli-test", info.RuntimeHeadersOverride["user-agent"])
- _, exists := info.RuntimeHeadersOverride["x-codex-beta-features"]
- require.False(t, exists)
- _, exists = info.RuntimeHeadersOverride["x-codex-turn-metadata"]
- require.False(t, exists)
- }
|