//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, "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, 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) }