setting_service_platform_threshold_test.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. //go:build unit
  2. package service
  3. import (
  4. "context"
  5. "testing"
  6. "time"
  7. "github.com/Wei-Shaw/sub2api/internal/config"
  8. "github.com/stretchr/testify/require"
  9. )
  10. func newSettingServiceForPlatformThresholdTest(seed map[string]string) *SettingService {
  11. accountSchedulingThresholdsSF.Forget(SettingKeyAccountSchedulingThresholds)
  12. accountSchedulingThresholdsCache.Store(&cachedAccountSchedulingThresholds{})
  13. repo := newMockSettingRepo()
  14. for k, v := range seed {
  15. repo.data[k] = v
  16. }
  17. return NewSettingService(repo, &config.Config{})
  18. }
  19. func TestPlatformSchedulingThresholds_RoundTrip_DefaultsAndStoredValues(t *testing.T) {
  20. svc := newSettingServiceForPlatformThresholdTest(nil)
  21. got := svc.parseSettings(map[string]string{})
  22. require.Equal(t, map[string]int{
  23. PlatformOpenAI: 100,
  24. PlatformAnthropic: 100,
  25. PlatformGrok: 100,
  26. }, got.AccountSchedulingThresholds)
  27. got = svc.parseSettings(map[string]string{
  28. SettingKeyAccountSchedulingThresholds: `{"openai":91,"grok":77,"gemini":85,"kiro":99}`,
  29. })
  30. require.Equal(t, 91, got.AccountSchedulingThresholds[PlatformOpenAI])
  31. require.Equal(t, 100, got.AccountSchedulingThresholds[PlatformAnthropic])
  32. require.Equal(t, 77, got.AccountSchedulingThresholds[PlatformGrok])
  33. require.NotContains(t, got.AccountSchedulingThresholds, PlatformGemini)
  34. require.NotContains(t, got.AccountSchedulingThresholds, "kiro")
  35. }
  36. func TestBuildSystemSettingsUpdates_PersistsAccountSchedulingThresholds(t *testing.T) {
  37. svc := newSettingServiceForPlatformThresholdTest(nil)
  38. updates, err := svc.buildSystemSettingsUpdates(context.Background(), &SystemSettings{
  39. AccountSchedulingThresholds: map[string]int{
  40. PlatformOpenAI: 91,
  41. PlatformAnthropic: 88,
  42. PlatformGrok: 77,
  43. },
  44. })
  45. require.NoError(t, err)
  46. require.JSONEq(t, `{"openai":91,"anthropic":88,"grok":77}`, updates[SettingKeyAccountSchedulingThresholds])
  47. }
  48. func TestValidateAndNormalizeAccountSchedulingThresholds_FillsMissingPlatforms(t *testing.T) {
  49. normalized, err := validateAndNormalizeAccountSchedulingThresholds(map[string]int{
  50. PlatformOpenAI: 91,
  51. })
  52. require.NoError(t, err)
  53. require.Equal(t, 91, normalized[PlatformOpenAI])
  54. require.Equal(t, 100, normalized[PlatformAnthropic])
  55. require.Equal(t, 100, normalized[PlatformGrok])
  56. require.NotContains(t, normalized, PlatformGemini)
  57. require.NotContains(t, normalized, "kiro")
  58. require.NotContains(t, normalized, PlatformAntigravity)
  59. }
  60. func TestValidateAndNormalizeAccountSchedulingThresholds_RejectsUnsupportedPlatforms(t *testing.T) {
  61. _, err := validateAndNormalizeAccountSchedulingThresholds(map[string]int{
  62. PlatformGemini: 85,
  63. })
  64. require.Error(t, err)
  65. }
  66. func TestUpdateSettings_StoresAccountSchedulingThresholds(t *testing.T) {
  67. svc := newSettingServiceForPlatformThresholdTest(nil)
  68. err := svc.UpdateSettings(context.Background(), &SystemSettings{
  69. AccountSchedulingThresholds: map[string]int{
  70. PlatformOpenAI: 92,
  71. PlatformAnthropic: 89,
  72. PlatformGrok: 76,
  73. },
  74. })
  75. require.NoError(t, err)
  76. got := svc.parseSettings(map[string]string{
  77. SettingKeyAccountSchedulingThresholds: svc.settingRepo.(*mockSettingRepo).data[SettingKeyAccountSchedulingThresholds],
  78. })
  79. require.Equal(t, 92, got.AccountSchedulingThresholds[PlatformOpenAI])
  80. require.Equal(t, 89, got.AccountSchedulingThresholds[PlatformAnthropic])
  81. require.Equal(t, 76, got.AccountSchedulingThresholds[PlatformGrok])
  82. require.NotContains(t, got.AccountSchedulingThresholds, "kiro")
  83. }
  84. func TestGetAccountSchedulingThresholds_ReadsStoredValue(t *testing.T) {
  85. svc := newSettingServiceForPlatformThresholdTest(map[string]string{
  86. SettingKeyAccountSchedulingThresholds: `{"openai":93,"grok":88,"kiro":87}`,
  87. })
  88. got := svc.GetAccountSchedulingThresholds(context.Background())
  89. require.Equal(t, 93, got[PlatformOpenAI])
  90. require.Equal(t, 100, got[PlatformAnthropic])
  91. require.Equal(t, 88, got[PlatformGrok])
  92. require.NotContains(t, got, "kiro")
  93. }
  94. func TestGetAccountSchedulingThresholds_MissingSettingUsesDefaultsAndNormalCacheTTL(t *testing.T) {
  95. svc := newSettingServiceForPlatformThresholdTest(nil)
  96. repo := svc.settingRepo.(*mockSettingRepo)
  97. repo.getValueErr = ErrSettingNotFound
  98. got := svc.GetAccountSchedulingThresholds(context.Background())
  99. require.Equal(t, defaultAccountSchedulingThresholds(), got)
  100. require.Equal(t, 1, repo.getValueCalls)
  101. repo.data[SettingKeyAccountSchedulingThresholds] = `{"openai":91}`
  102. got = svc.GetAccountSchedulingThresholds(context.Background())
  103. require.Equal(t, 100, got[PlatformOpenAI], "missing-setting defaults should remain cached for the normal TTL")
  104. require.Equal(t, 1, repo.getValueCalls)
  105. cached, ok := accountSchedulingThresholdsCache.Load().(*cachedAccountSchedulingThresholds)
  106. require.True(t, ok)
  107. require.Greater(t, cached.expiresAt, time.Now().Add(accountSchedulingThresholdsCacheTTL-time.Second).UnixNano())
  108. }
  109. func TestUpdateSettings_OmittedAccountSchedulingThresholdsDoesNotCacheDefaults(t *testing.T) {
  110. svc := newSettingServiceForPlatformThresholdTest(map[string]string{
  111. SettingKeyAccountSchedulingThresholds: `{"openai":85,"grok":88,"kiro":87}`,
  112. })
  113. err := svc.UpdateSettings(context.Background(), &SystemSettings{
  114. FrontendURL: "https://example.test",
  115. })
  116. require.NoError(t, err)
  117. got := svc.GetAccountSchedulingThresholds(context.Background())
  118. require.Equal(t, 85, got[PlatformOpenAI])
  119. require.Equal(t, 88, got[PlatformGrok])
  120. require.NotContains(t, got, "kiro")
  121. }
  122. func TestAccountSchedulingThresholds_InvalidStoredValueUsesSameDefaultsInSettingsAndCache(t *testing.T) {
  123. svc := newSettingServiceForPlatformThresholdTest(map[string]string{
  124. SettingKeyAccountSchedulingThresholds: `{"openai":0,"grok":88,"kiro":87}`,
  125. })
  126. settings := svc.parseSettings(map[string]string{
  127. SettingKeyAccountSchedulingThresholds: `{"openai":0,"grok":88,"kiro":87}`,
  128. })
  129. cached := svc.GetAccountSchedulingThresholds(context.Background())
  130. require.Equal(t, settings.AccountSchedulingThresholds, cached)
  131. require.Equal(t, 100, cached[PlatformOpenAI])
  132. require.Equal(t, 88, cached[PlatformGrok])
  133. require.NotContains(t, cached, "kiro")
  134. }
  135. func TestGetAccountSchedulingThresholds_NilRepoReturnsDefaults(t *testing.T) {
  136. svc := &SettingService{}
  137. got := svc.GetAccountSchedulingThresholds(context.Background())
  138. require.Equal(t, map[string]int{
  139. PlatformOpenAI: 100,
  140. PlatformAnthropic: 100,
  141. PlatformGrok: 100,
  142. }, got)
  143. }