grok_media_eligibility_handler_test.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. package admin
  2. import (
  3. "bytes"
  4. "context"
  5. "encoding/json"
  6. "net/http"
  7. "net/http/httptest"
  8. "testing"
  9. "github.com/Wei-Shaw/sub2api/internal/service"
  10. "github.com/gin-gonic/gin"
  11. "github.com/stretchr/testify/require"
  12. )
  13. type grokMediaEligibilityAdminServiceStub struct {
  14. *stubAdminService
  15. account *service.Account
  16. }
  17. func (s *grokMediaEligibilityAdminServiceStub) GetAccount(_ context.Context, _ int64) (*service.Account, error) {
  18. return s.account, nil
  19. }
  20. func (s *grokMediaEligibilityAdminServiceStub) UpdateAccountExtra(_ context.Context, _ int64, updates map[string]any) error {
  21. if s.account.Extra == nil {
  22. s.account.Extra = map[string]any{}
  23. }
  24. for key, value := range updates {
  25. if value == nil {
  26. delete(s.account.Extra, key)
  27. } else {
  28. s.account.Extra[key] = value
  29. }
  30. }
  31. return nil
  32. }
  33. func newGrokMediaEligibilityRouter(account *service.Account) *gin.Engine {
  34. stub := &grokMediaEligibilityAdminServiceStub{
  35. stubAdminService: newStubAdminService(),
  36. account: account,
  37. }
  38. h := NewAccountHandler(stub, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil)
  39. router := gin.New()
  40. router.GET("/accounts/:id/grok-media-eligibility", h.GetGrokMediaEligibility)
  41. router.PUT("/accounts/:id/grok-media-eligibility", h.UpdateGrokMediaEligibility)
  42. return router
  43. }
  44. func TestGrokMediaEligibilityHandlerGetReturnsModeAndReason(t *testing.T) {
  45. gin.SetMode(gin.TestMode)
  46. router := newGrokMediaEligibilityRouter(&service.Account{
  47. ID: 12,
  48. Platform: service.PlatformGrok,
  49. Type: service.AccountTypeOAuth,
  50. Extra: map[string]any{
  51. "grok_billing_snapshot": map[string]any{"status_code": 200, "partial": true},
  52. "unrelated_setting": "preserve",
  53. },
  54. })
  55. req := httptest.NewRequest(http.MethodGet, "/accounts/12/grok-media-eligibility", nil)
  56. rec := httptest.NewRecorder()
  57. router.ServeHTTP(rec, req)
  58. require.Equal(t, http.StatusOK, rec.Code)
  59. var envelope struct {
  60. Data grokMediaEligibilityResponse `json:"data"`
  61. }
  62. require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &envelope))
  63. require.Equal(t, int64(12), envelope.Data.AccountID)
  64. require.Equal(t, grokMediaEligibilityModeAuto, envelope.Data.Mode)
  65. require.Equal(t, "billing_inconclusive", envelope.Data.Reason)
  66. }
  67. func TestGrokMediaEligibilityHandlerUpdateModesPreservesExtra(t *testing.T) {
  68. gin.SetMode(gin.TestMode)
  69. account := &service.Account{
  70. ID: 12,
  71. Platform: service.PlatformGrok,
  72. Type: service.AccountTypeOAuth,
  73. Extra: map[string]any{"unrelated_setting": "preserve"},
  74. }
  75. router := newGrokMediaEligibilityRouter(account)
  76. tests := []struct {
  77. mode string
  78. wantMode string
  79. wantExtra any
  80. wantEligible bool
  81. wantReason string
  82. }{
  83. {mode: "enabled", wantMode: grokMediaEligibilityModeEnabled, wantExtra: true, wantEligible: true, wantReason: "override_enabled"},
  84. {mode: "disabled", wantMode: grokMediaEligibilityModeDisabled, wantExtra: false, wantEligible: false, wantReason: "override_disabled"},
  85. {mode: "auto", wantMode: grokMediaEligibilityModeAuto, wantExtra: nil, wantEligible: false, wantReason: "billing_unobserved"},
  86. }
  87. for _, tt := range tests {
  88. t.Run(tt.mode, func(t *testing.T) {
  89. body, err := json.Marshal(map[string]string{"mode": tt.mode})
  90. require.NoError(t, err)
  91. req := httptest.NewRequest(http.MethodPut, "/accounts/12/grok-media-eligibility", bytes.NewReader(body))
  92. req.Header.Set("Content-Type", "application/json")
  93. rec := httptest.NewRecorder()
  94. router.ServeHTTP(rec, req)
  95. require.Equal(t, http.StatusOK, rec.Code)
  96. var envelope struct {
  97. Data grokMediaEligibilityResponse `json:"data"`
  98. }
  99. require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &envelope))
  100. require.Equal(t, tt.wantMode, envelope.Data.Mode)
  101. require.Equal(t, tt.wantEligible, envelope.Data.Eligible)
  102. require.Equal(t, tt.wantReason, envelope.Data.Reason)
  103. require.Equal(t, "preserve", account.Extra["unrelated_setting"])
  104. if tt.wantExtra == nil {
  105. _, exists := account.Extra[service.GrokMediaEligibleExtraKey]
  106. require.False(t, exists)
  107. } else {
  108. require.Equal(t, tt.wantExtra, account.Extra[service.GrokMediaEligibleExtraKey])
  109. }
  110. })
  111. }
  112. }
  113. func TestGrokMediaEligibilityHandlerRejectsUnsupportedAndInvalidModes(t *testing.T) {
  114. gin.SetMode(gin.TestMode)
  115. for _, tt := range []struct {
  116. name string
  117. account *service.Account
  118. body string
  119. }{
  120. {name: "unsupported account", account: &service.Account{ID: 1, Platform: service.PlatformOpenAI, Type: service.AccountTypeOAuth}, body: `{"mode":"enabled"}`},
  121. {name: "invalid mode", account: &service.Account{ID: 1, Platform: service.PlatformGrok, Type: service.AccountTypeOAuth}, body: `{"mode":"force"}`},
  122. } {
  123. t.Run(tt.name, func(t *testing.T) {
  124. router := newGrokMediaEligibilityRouter(tt.account)
  125. req := httptest.NewRequest(http.MethodPut, "/accounts/1/grok-media-eligibility", bytes.NewBufferString(tt.body))
  126. req.Header.Set("Content-Type", "application/json")
  127. rec := httptest.NewRecorder()
  128. router.ServeHTTP(rec, req)
  129. require.Equal(t, http.StatusBadRequest, rec.Code)
  130. })
  131. }
  132. }