Files
sub2api/backend/internal/service/gateway_dateline_normalization_test.go
T
李建琦 6d655c9903
Release / update-version (push) Has been cancelled
Release / build-frontend (push) Has been cancelled
Release / release (push) Has been cancelled
Release / sync-version-file (push) Has been cancelled
CI / shell (push) Canceled after 0s
CI / test (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
Security Scan / backend-security (push) Canceled after 0s
Security Scan / frontend-security (push) Canceled after 0s
Sub2API v1.0 - AI API 网关(二开初始版本,基于上游 Wei-Shaw/sub2api)
2026-08-21 18:30:13 +08:00

124 lines
5.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package service
import (
"context"
"testing"
"github.com/Wei-Shaw/sub2api/internal/config"
"github.com/Wei-Shaw/sub2api/internal/pkg/anthropicfp"
"github.com/stretchr/testify/require"
)
// TestGatewayClientDatelineNormalization_Scope covers the account/switch matrix
// for the shouldNormalizeClientDateline gate: Anthropic OAuth/SetupToken pass
// only when the switch is on; API-Key and non-Anthropic platforms are excluded
// unconditionally.
func TestGatewayClientDatelineNormalization_Scope(t *testing.T) {
repo := &gatewayTTLSettingRepo{data: map[string]string{}}
gatewayForwardingCache.Store(&cachedGatewayForwardingSettings{})
svc := &GatewayService{
settingService: NewSettingService(repo, &config.Config{}),
}
ctx := context.Background()
// Default (missing key): fallback in parseSettings/cache loader is true.
require.True(t, svc.shouldNormalizeClientDateline(ctx, &Account{Platform: PlatformAnthropic, Type: AccountTypeOAuth}))
require.True(t, svc.shouldNormalizeClientDateline(ctx, &Account{Platform: PlatformAnthropic, Type: AccountTypeSetupToken}))
require.False(t, svc.shouldNormalizeClientDateline(ctx, &Account{Platform: PlatformAnthropic, Type: AccountTypeAPIKey}))
require.False(t, svc.shouldNormalizeClientDateline(ctx, &Account{Platform: PlatformOpenAI, Type: AccountTypeOAuth}))
// Switch off: no account qualifies.
repo.data[SettingKeyEnableClientDatelineNormalization] = "false"
gatewayForwardingCache.Store(&cachedGatewayForwardingSettings{})
require.False(t, svc.shouldNormalizeClientDateline(ctx, &Account{Platform: PlatformAnthropic, Type: AccountTypeOAuth}))
require.False(t, svc.shouldNormalizeClientDateline(ctx, &Account{Platform: PlatformAnthropic, Type: AccountTypeSetupToken}))
// Switch back on: OAuth qualifies again.
repo.data[SettingKeyEnableClientDatelineNormalization] = "true"
gatewayForwardingCache.Store(&cachedGatewayForwardingSettings{})
require.True(t, svc.shouldNormalizeClientDateline(ctx, &Account{Platform: PlatformAnthropic, Type: AccountTypeOAuth}))
}
// TestGatewayClientDatelineNormalization_HelperNoRewrite exercises the code
// path used by Forward: the helper must return ok=false when the switch is
// off, when the account is API-Key, when the account is nil, and when the
// body carries no fingerprinted dateline. It must return ok=true and a
// rewritten body when both the switch is on and the account is Anthropic
// OAuth/SetupToken and a rewrite actually happened.
func TestGatewayClientDatelineNormalization_HelperNoRewrite(t *testing.T) {
repo := &gatewayTTLSettingRepo{data: map[string]string{
SettingKeyEnableClientDatelineNormalization: "true",
}}
gatewayForwardingCache.Store(&cachedGatewayForwardingSettings{})
svc := &GatewayService{
settingService: NewSettingService(repo, &config.Config{}),
}
ctx := context.Background()
dirty := []byte(`{"messages":[{"role":"user","content":"<system-reminder>\nTodays date is 2026/07/01.\n</system-reminder>"}]}`)
clean := []byte(`{"messages":[{"role":"user","content":"just hello"}]}`)
// API-Key account: never rewrites, even with dirty payload.
next, ok := svc.normalizeClientDatelineIfEnabled(ctx, &Account{Platform: PlatformAnthropic, Type: AccountTypeAPIKey}, dirty)
require.False(t, ok)
require.Nil(t, next)
// Nil account: safe no-op.
next, ok = svc.normalizeClientDatelineIfEnabled(ctx, nil, dirty)
require.False(t, ok)
require.Nil(t, next)
// OAuth account + clean body: no changes, ok=false.
next, ok = svc.normalizeClientDatelineIfEnabled(ctx, &Account{Platform: PlatformAnthropic, Type: AccountTypeOAuth}, clean)
require.False(t, ok)
require.Nil(t, next)
// OAuth account + dirty body: rewritten, ok=true.
next, ok = svc.normalizeClientDatelineIfEnabled(ctx, &Account{Platform: PlatformAnthropic, Type: AccountTypeOAuth}, dirty)
require.True(t, ok)
require.NotNil(t, next)
require.Contains(t, string(next), "Today's date is 2026-07-01.")
require.NotContains(t, string(next), "2026/07/01")
require.NotContains(t, string(next), "Todays date is")
// SetupToken account + dirty body: rewritten, ok=true.
next, ok = svc.normalizeClientDatelineIfEnabled(ctx, &Account{Platform: PlatformAnthropic, Type: AccountTypeSetupToken}, dirty)
require.True(t, ok)
require.Contains(t, string(next), "Today's date is 2026-07-01.")
// Switch off: even OAuth account is not rewritten.
repo.data[SettingKeyEnableClientDatelineNormalization] = "false"
gatewayForwardingCache.Store(&cachedGatewayForwardingSettings{})
next, ok = svc.normalizeClientDatelineIfEnabled(ctx, &Account{Platform: PlatformAnthropic, Type: AccountTypeOAuth}, dirty)
require.False(t, ok)
require.Nil(t, next)
}
// TestGatewayClientDatelineNormalization_LeavesUserProseUntouched double-checks
// that the pure normalizer never touches content outside <system-reminder>
// blocks. This is an integration guard between the switch-gated helper and
// the pkg/anthropicfp scope contract, tripped by anyone who broadens scope.
func TestGatewayClientDatelineNormalization_LeavesUserProseUntouched(t *testing.T) {
repo := &gatewayTTLSettingRepo{data: map[string]string{
SettingKeyEnableClientDatelineNormalization: "true",
}}
gatewayForwardingCache.Store(&cachedGatewayForwardingSettings{})
svc := &GatewayService{
settingService: NewSettingService(repo, &config.Config{}),
}
ctx := context.Background()
// User prose that happens to include a fingerprint-looking sentence
// (outside <system-reminder>) must be preserved byte-for-byte.
body := []byte(`{"messages":[{"role":"user","content":"I wrote: Todays date is 2026/07/01. What do you think?"}]}`)
next, ok := svc.normalizeClientDatelineIfEnabled(ctx, &Account{Platform: PlatformAnthropic, Type: AccountTypeOAuth}, body)
require.False(t, ok, "must not rewrite user prose outside <system-reminder>")
require.Nil(t, next)
// Direct pure-fn check for redundancy.
out, hits, changed := anthropicfp.NormalizeDateline(body)
require.False(t, changed)
require.Empty(t, hits)
require.Equal(t, body, out)
}