account_anti_degrade_test.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. package service
  2. import (
  3. "context"
  4. "testing"
  5. "github.com/stretchr/testify/require"
  6. )
  7. type stubAntiDegradeStore struct {
  8. account *Account
  9. updated *UpdateAccountInput
  10. }
  11. func (s *stubAntiDegradeStore) GetAccount(context.Context, int64) (*Account, error) {
  12. cp := *s.account
  13. return &cp, nil
  14. }
  15. func (s *stubAntiDegradeStore) UpdateAccount(_ context.Context, _ int64, input *UpdateAccountInput) (*Account, error) {
  16. s.updated = input
  17. return s.account, nil
  18. }
  19. func TestPreviewAntiDegradeOpenAI(t *testing.T) {
  20. p := PreviewAntiDegrade(&Account{ID: 1, Platform: PlatformOpenAI, Type: AccountTypeOAuth})
  21. require.True(t, p.Eligible)
  22. require.Len(t, p.Changes, 3) // session + Node.js 24 TLS + concurrency
  23. require.Equal(t, "extra.codex_fingerprint_mode", p.Changes[0].Key)
  24. require.Equal(t, "session", p.Changes[0].To)
  25. }
  26. func TestPreviewMode1Anthropic(t *testing.T) {
  27. p := PreviewAntiDegradeMode(&Account{ID: 2, Platform: PlatformAnthropic, Type: AccountTypeOAuth, Concurrency: 8}, AntiDegradeMode1)
  28. require.False(t, p.Eligible)
  29. require.Contains(t, p.Reason, "OpenAI")
  30. }
  31. func TestPreviewAntiDegradeNothingToDo(t *testing.T) {
  32. p := PreviewAntiDegrade(&Account{
  33. ID: 3, Platform: PlatformOpenAI, Type: AccountTypeOAuth, Concurrency: 8,
  34. Extra: map[string]any{"codex_fingerprint_mode": "session"},
  35. })
  36. require.True(t, p.Eligible, "session-only configuration still needs the legacy TLS template")
  37. }
  38. func TestPreviewAntiDegradeAlreadyEnabled(t *testing.T) {
  39. p := PreviewAntiDegradeMode(&Account{
  40. ID: 4, Platform: PlatformOpenAI, Type: AccountTypeOAuth,
  41. Extra: map[string]any{AntiDegradeMarkerExtraKey: map[string]any{"enabled": true}},
  42. }, AntiDegradeMode1)
  43. require.True(t, p.Enabled)
  44. require.False(t, p.Eligible)
  45. }
  46. func TestApplyRevertAntiDegrade(t *testing.T) {
  47. store := &stubAntiDegradeStore{account: &Account{ID: 5, Platform: PlatformOpenAI, Type: AccountTypeOAuth}}
  48. svc := NewAntiDegradeService(store)
  49. _, err := svc.ApplyAntiDegrade(context.Background(), 5)
  50. require.NoError(t, err)
  51. require.NotNil(t, store.updated)
  52. require.Equal(t, "session", store.updated.Extra["codex_fingerprint_mode"])
  53. require.NotNil(t, store.updated.Concurrency)
  54. require.Equal(t, AntiDegradeConcurrencyCap, *store.updated.Concurrency)
  55. marker, ok := store.updated.Extra[AntiDegradeMarkerExtraKey].(map[string]any)
  56. require.True(t, ok)
  57. require.Equal(t, true, marker["enabled"])
  58. require.Equal(t, "legacy", marker["mode"])
  59. // 还原:marker 存在则恢复旧值
  60. store.account.Extra = store.updated.Extra
  61. _, err = svc.RevertAntiDegrade(context.Background(), 5)
  62. require.NoError(t, err)
  63. require.NotContains(t, store.updated.Extra, AntiDegradeMarkerExtraKey)
  64. require.NotContains(t, store.updated.Extra, "codex_fingerprint_mode")
  65. require.NotNil(t, store.updated.Concurrency)
  66. require.Equal(t, 0, *store.updated.Concurrency)
  67. }
  68. func TestApplyLegacyUsesInitialStrategy(t *testing.T) {
  69. store := &stubAntiDegradeStore{account: &Account{ID: 7, Platform: PlatformOpenAI, Type: AccountTypeOAuth}}
  70. svc := NewAntiDegradeService(store)
  71. _, err := svc.ApplyAntiDegradeMode(context.Background(), 7, AntiDegradeModeLegacy)
  72. require.NoError(t, err)
  73. require.Equal(t, "session", store.updated.Extra["codex_fingerprint_mode"])
  74. require.Equal(t, true, store.updated.Extra["enable_tls_fingerprint"])
  75. require.Equal(t, "nodejs24", store.updated.Extra["tls_fingerprint_builtin"])
  76. marker, ok := store.updated.Extra[AntiDegradeMarkerExtraKey].(map[string]any)
  77. require.True(t, ok)
  78. require.Equal(t, "legacy", marker["mode"])
  79. require.NotContains(t, marker, "policy_version", "legacy must not be interpreted as mode1-v3")
  80. }
  81. func TestRevertAntiDegradeRejectsBadSnapshot(t *testing.T) {
  82. store := &stubAntiDegradeStore{account: &Account{
  83. ID: 6, Platform: PlatformOpenAI, Type: AccountTypeOAuth,
  84. Extra: map[string]any{
  85. AntiDegradeMarkerExtraKey: map[string]any{
  86. "enabled": true,
  87. "prev": map[string]any{"concurrency": "unlimited"},
  88. },
  89. },
  90. }}
  91. svc := NewAntiDegradeService(store)
  92. _, err := svc.RevertAntiDegrade(context.Background(), 6)
  93. require.Error(t, err)
  94. require.Nil(t, store.updated, "类型非法时不得写库")
  95. }
  96. func TestAntiDegradeDefaultDoesNotReinterpretStoredModes(t *testing.T) {
  97. require.Equal(t, AntiDegradeModeLegacy, normalizeAntiDegradeMode(""))
  98. for _, tt := range []struct {
  99. marker map[string]any
  100. want AntiDegradeMode
  101. }{
  102. {map[string]any{"enabled": true}, AntiDegradeMode1},
  103. {map[string]any{"enabled": true, "mode": "mode1", "policy_version": 2}, AntiDegradeMode1},
  104. {map[string]any{"enabled": true, "mode": "generic"}, "generic"},
  105. } {
  106. require.Equal(t, tt.want, antiDegradeMode(&Account{Extra: map[string]any{AntiDegradeMarkerExtraKey: tt.marker}}))
  107. }
  108. }
  109. func TestAntiDegradeUnknownModeDoesNotApplyDefault(t *testing.T) {
  110. store := &stubAntiDegradeStore{account: &Account{ID: 1, Platform: PlatformOpenAI, Type: AccountTypeOAuth}}
  111. svc := NewAntiDegradeService(store)
  112. _, err := svc.ApplyAntiDegradeMode(context.Background(), 1, "mode_typo")
  113. require.ErrorIs(t, err, ErrUnknownAntiDegradeMode)
  114. _, err = svc.PreviewMode(context.Background(), 1, "mode_typo")
  115. require.ErrorIs(t, err, ErrUnknownAntiDegradeMode)
  116. require.Nil(t, store.updated)
  117. }