sub2api/backend/internal/repository/scheduler_cache_unit_test.go
win 158785bfc9 chore: merge upstream v0.1.127 — keep omniroute customizations
Upstream highlights:
- v0.1.127 release (150 commits): channel-monitor 协议管理、OpenAI
  Responses 路由配置、模型定价 LiteLLM 默认、payment 强制扫码、
  钉钉 OAuth、用户用量按平台拆分、Ops 错误分类 SLA 调整、
  Anthropic passthrough keepalive、Gemini chat completions 路由 ...
- 91da8159 feat(risk-control): 内容审计新增关键词拦截
- 3d22dd34 feat: gemini-3.5-flash 模型支持

Conflicts resolved:
- Dockerfile: keep pnpm pin to 9.15.9 (upstream pinned generic v9 floating).
- wire_gen.go: combine upstream NewSettingHandler(+userAttributeService)
  with local NewOpsHandler(opsService, requestEventBus, opsLogBroadcaster).
  Verified by re-running wire generate.
- scheduler_cache.go: keep both upstream openai_responses_{mode,supported}
  keys and local model_rate_limits key in filterSchedulerExtra().
- gateway_service.go: keep local context-compression block; drop now-dead
  setOpsUpstreamRequestBody call (upstream removed ops retry replay).
- docker-compose.yml: keep local windsurf-ls service profile and named
  volumes; keep local healthcheck start_period values.

Test mock signatures bumped to match current constructors:
- gateway_models_test.go: add nil for RPMTokenBucketService.
- account_handler_available_models_test.go: add nil for windsurfChatService.
2026-05-20 12:39:40 +08:00

103 lines
3.4 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.

//go:build unit
package repository
import (
"testing"
"github.com/Wei-Shaw/sub2api/internal/service"
"github.com/stretchr/testify/require"
)
func TestBuildSchedulerMetadataAccount_KeepsOpenAIWSFlags(t *testing.T) {
account := service.Account{
ID: 42,
Platform: service.PlatformOpenAI,
Type: service.AccountTypeOAuth,
Extra: map[string]any{
"openai_oauth_responses_websockets_v2_enabled": true,
"openai_oauth_responses_websockets_v2_mode": service.OpenAIWSIngressModePassthrough,
"openai_ws_force_http": true,
"openai_responses_mode": "force_chat_completions",
"openai_responses_supported": false,
"mixed_scheduling": true,
"unused_large_field": "drop-me",
},
}
got := buildSchedulerMetadataAccount(account)
require.Equal(t, true, got.Extra["openai_oauth_responses_websockets_v2_enabled"])
require.Equal(t, service.OpenAIWSIngressModePassthrough, got.Extra["openai_oauth_responses_websockets_v2_mode"])
require.Equal(t, true, got.Extra["openai_ws_force_http"])
require.Equal(t, "force_chat_completions", got.Extra["openai_responses_mode"])
require.Equal(t, false, got.Extra["openai_responses_supported"])
require.Equal(t, true, got.Extra["mixed_scheduling"])
require.Nil(t, got.Extra["unused_large_field"])
}
// 回归测试model_rate_limits 必须透传到调度快照,否则选号阶段无法感知模型级限流,
// 会出现"限流账号被反复选中 → failover 切号 → 重复切号"的死循环(对应 windsurf 日志里的现象)。
func TestBuildSchedulerMetadataAccount_KeepsModelRateLimits(t *testing.T) {
modelLimits := map[string]any{
"claude-opus-4-7-medium": map[string]any{
"rate_limited_at": "2026-04-24T02:28:51Z",
"rate_limit_reset_at": "2026-04-24T02:58:51Z",
},
}
account := service.Account{
ID: 7,
Platform: service.PlatformWindsurf,
Type: service.AccountTypeSetupToken,
Extra: map[string]any{
"model_rate_limits": modelLimits,
"unused_large_field": "drop-me",
},
}
got := buildSchedulerMetadataAccount(account)
require.Equal(t, modelLimits, got.Extra["model_rate_limits"], "model_rate_limits must be carried into scheduler snapshot for rate-limit-aware selection")
require.Nil(t, got.Extra["unused_large_field"])
}
func TestBuildSchedulerMetadataAccount_KeepsSlimGroupMembership(t *testing.T) {
account := service.Account{
ID: 42,
Platform: service.PlatformAnthropic,
GroupIDs: []int64{7, 9, 7, 0},
AccountGroups: []service.AccountGroup{
{
AccountID: 42,
GroupID: 7,
Priority: 2,
Account: &service.Account{ID: 42, Name: "drop-from-metadata"},
Group: &service.Group{ID: 7, Name: "drop-from-metadata"},
},
{
AccountID: 42,
GroupID: 11,
Priority: 3,
Group: &service.Group{ID: 11, Name: "drop-from-metadata"},
},
{
AccountID: 42,
GroupID: 0,
Priority: 4,
},
},
}
got := buildSchedulerMetadataAccount(account)
require.Equal(t, []int64{7, 9, 11}, got.GroupIDs)
require.Len(t, got.AccountGroups, 2)
require.Equal(t, int64(42), got.AccountGroups[0].AccountID)
require.Equal(t, int64(7), got.AccountGroups[0].GroupID)
require.Equal(t, 2, got.AccountGroups[0].Priority)
require.Nil(t, got.AccountGroups[0].Account)
require.Nil(t, got.AccountGroups[0].Group)
require.Equal(t, int64(11), got.AccountGroups[1].GroupID)
require.Nil(t, got.Groups)
}