subscription_expiry_service_test.go 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. package service
  2. import (
  3. "bytes"
  4. "context"
  5. "errors"
  6. "log"
  7. "testing"
  8. "time"
  9. "github.com/Wei-Shaw/sub2api/internal/pkg/pagination"
  10. "github.com/stretchr/testify/require"
  11. )
  12. type subscriptionExpiryRepoStub struct {
  13. listCalls int
  14. }
  15. func (r *subscriptionExpiryRepoStub) Create(context.Context, *UserSubscription) error {
  16. return nil
  17. }
  18. func (r *subscriptionExpiryRepoStub) GetByID(context.Context, int64) (*UserSubscription, error) {
  19. return nil, ErrSubscriptionNotFound
  20. }
  21. func (r *subscriptionExpiryRepoStub) GetByIDForUpdate(context.Context, int64) (*UserSubscription, error) {
  22. return nil, ErrSubscriptionNotFound
  23. }
  24. func (r *subscriptionExpiryRepoStub) GetByIDIncludeDeleted(context.Context, int64) (*UserSubscription, error) {
  25. return nil, ErrSubscriptionNotFound
  26. }
  27. func (r *subscriptionExpiryRepoStub) GetByUserIDAndGroupID(context.Context, int64, int64) (*UserSubscription, error) {
  28. return nil, ErrSubscriptionNotFound
  29. }
  30. func (r *subscriptionExpiryRepoStub) GetActiveByUserIDAndGroupID(context.Context, int64, int64) (*UserSubscription, error) {
  31. return nil, ErrSubscriptionNotFound
  32. }
  33. func (r *subscriptionExpiryRepoStub) Update(context.Context, *UserSubscription) error {
  34. return nil
  35. }
  36. func (r *subscriptionExpiryRepoStub) Delete(context.Context, int64) error {
  37. return nil
  38. }
  39. func (r *subscriptionExpiryRepoStub) Restore(context.Context, int64, string) (*UserSubscription, error) {
  40. return nil, ErrSubscriptionNotFound
  41. }
  42. func (r *subscriptionExpiryRepoStub) ListByUserID(context.Context, int64) ([]UserSubscription, error) {
  43. return nil, nil
  44. }
  45. func (r *subscriptionExpiryRepoStub) ListActiveByUserID(context.Context, int64) ([]UserSubscription, error) {
  46. return nil, nil
  47. }
  48. func (r *subscriptionExpiryRepoStub) ListByGroupID(context.Context, int64, pagination.PaginationParams) ([]UserSubscription, *pagination.PaginationResult, error) {
  49. return nil, nil, nil
  50. }
  51. func (r *subscriptionExpiryRepoStub) List(context.Context, pagination.PaginationParams, *int64, *int64, string, string, string, string) ([]UserSubscription, *pagination.PaginationResult, error) {
  52. r.listCalls++
  53. return nil, &pagination.PaginationResult{Page: 1, Pages: 1}, nil
  54. }
  55. func (r *subscriptionExpiryRepoStub) ExistsByUserIDAndGroupID(context.Context, int64, int64) (bool, error) {
  56. return false, nil
  57. }
  58. func (r *subscriptionExpiryRepoStub) ExistsActiveByUserIDAndGroupID(context.Context, int64, int64) (bool, error) {
  59. return false, nil
  60. }
  61. func (r *subscriptionExpiryRepoStub) ExtendExpiry(context.Context, int64, time.Time) error {
  62. return nil
  63. }
  64. func (r *subscriptionExpiryRepoStub) UpdateStatus(context.Context, int64, string) error {
  65. return nil
  66. }
  67. func (r *subscriptionExpiryRepoStub) UpdateNotes(context.Context, int64, string) error {
  68. return nil
  69. }
  70. func (r *subscriptionExpiryRepoStub) ActivateWindows(context.Context, int64, time.Time, time.Time) error {
  71. return nil
  72. }
  73. func (r *subscriptionExpiryRepoStub) ResetUsageWindows(context.Context, int64, bool, bool, bool, time.Time, time.Time) error {
  74. return nil
  75. }
  76. func (r *subscriptionExpiryRepoStub) ResetDailyUsage(context.Context, int64, *time.Time, time.Time) error {
  77. return nil
  78. }
  79. func (r *subscriptionExpiryRepoStub) ResetWeeklyUsage(context.Context, int64, *time.Time, time.Time) error {
  80. return nil
  81. }
  82. func (r *subscriptionExpiryRepoStub) ResetMonthlyUsage(context.Context, int64, *time.Time, time.Time) error {
  83. return nil
  84. }
  85. func (r *subscriptionExpiryRepoStub) IncrementUsage(context.Context, int64, float64) error {
  86. return nil
  87. }
  88. func (r *subscriptionExpiryRepoStub) BatchUpdateExpiredStatus(context.Context) (int64, error) {
  89. return 0, nil
  90. }
  91. type subscriptionExpirySettingRepoStub struct {
  92. values map[string]string
  93. err error
  94. multiErr error
  95. }
  96. func (r *subscriptionExpirySettingRepoStub) Get(context.Context, string) (*Setting, error) {
  97. return nil, ErrSettingNotFound
  98. }
  99. func (r *subscriptionExpirySettingRepoStub) GetValue(_ context.Context, key string) (string, error) {
  100. if r.err != nil {
  101. return "", r.err
  102. }
  103. value, ok := r.values[key]
  104. if !ok {
  105. return "", ErrSettingNotFound
  106. }
  107. return value, nil
  108. }
  109. func (r *subscriptionExpirySettingRepoStub) Set(context.Context, string, string) error {
  110. return nil
  111. }
  112. func (r *subscriptionExpirySettingRepoStub) GetMultiple(_ context.Context, keys []string) (map[string]string, error) {
  113. if r.multiErr != nil {
  114. return nil, r.multiErr
  115. }
  116. values := make(map[string]string, len(keys))
  117. for _, key := range keys {
  118. if value, ok := r.values[key]; ok {
  119. values[key] = value
  120. }
  121. }
  122. return values, nil
  123. }
  124. func (r *subscriptionExpirySettingRepoStub) SetMultiple(context.Context, map[string]string) error {
  125. return nil
  126. }
  127. func (r *subscriptionExpirySettingRepoStub) GetAll(context.Context) (map[string]string, error) {
  128. return nil, nil
  129. }
  130. func (r *subscriptionExpirySettingRepoStub) Delete(context.Context, string) error {
  131. return nil
  132. }
  133. func TestSubscriptionExpiryService_ExpiryReminderEnabledDefaultsToTrue(t *testing.T) {
  134. svc := NewSubscriptionExpiryService(nil, time.Minute)
  135. svc.SetSettingRepository(&subscriptionExpirySettingRepoStub{values: map[string]string{}})
  136. require.True(t, svc.expiryReminderEnabled(context.Background()))
  137. }
  138. func TestSubscriptionExpiryService_ExpiryReminderDisabledSkipsSubscriptionScan(t *testing.T) {
  139. repo := &subscriptionExpiryRepoStub{}
  140. settingRepo := &subscriptionExpirySettingRepoStub{
  141. values: map[string]string{SettingKeySubscriptionExpiryNotifyEnabled: "false"},
  142. }
  143. svc := NewSubscriptionExpiryService(repo, time.Minute)
  144. svc.SetSettingRepository(settingRepo)
  145. svc.SetNotificationEmailService(NewNotificationEmailService(settingRepo, nil))
  146. svc.sendExpiryReminders(context.Background())
  147. require.Zero(t, repo.listCalls)
  148. }
  149. func TestSubscriptionExpiryService_ExpiryReminderSettingReadErrorFailsClosed(t *testing.T) {
  150. svc := NewSubscriptionExpiryService(nil, time.Minute)
  151. svc.SetSettingRepository(&subscriptionExpirySettingRepoStub{err: errors.New("db down")})
  152. require.False(t, svc.expiryReminderEnabled(context.Background()))
  153. }
  154. func TestSubscriptionExpiryService_MissingSMTPSkipsReminderScanAndLogsOncePerInterval(t *testing.T) {
  155. repo := &subscriptionExpiryRepoStub{}
  156. settingRepo := &subscriptionExpirySettingRepoStub{values: map[string]string{}}
  157. emailService := NewEmailService(settingRepo, nil)
  158. svc := NewSubscriptionExpiryService(repo, time.Minute)
  159. svc.SetSettingRepository(settingRepo)
  160. svc.SetNotificationEmailService(NewNotificationEmailService(settingRepo, emailService))
  161. var logs bytes.Buffer
  162. previousWriter := log.Writer()
  163. previousFlags := log.Flags()
  164. log.SetOutput(&logs)
  165. log.SetFlags(0)
  166. t.Cleanup(func() {
  167. log.SetOutput(previousWriter)
  168. log.SetFlags(previousFlags)
  169. })
  170. svc.sendExpiryReminders(context.Background())
  171. svc.sendExpiryReminders(context.Background())
  172. require.Zero(t, repo.listCalls)
  173. require.Equal(t, 1, bytes.Count(logs.Bytes(), []byte("SMTP is not configured")))
  174. }
  175. func TestSubscriptionExpiryService_SMTPConfigReadErrorSkipsReminderScan(t *testing.T) {
  176. repo := &subscriptionExpiryRepoStub{}
  177. settingRepo := &subscriptionExpirySettingRepoStub{
  178. values: map[string]string{},
  179. multiErr: errors.New("db down"),
  180. }
  181. emailService := NewEmailService(settingRepo, nil)
  182. svc := NewSubscriptionExpiryService(repo, time.Minute)
  183. svc.SetSettingRepository(settingRepo)
  184. svc.SetNotificationEmailService(NewNotificationEmailService(settingRepo, emailService))
  185. svc.sendExpiryReminders(context.Background())
  186. require.Zero(t, repo.listCalls)
  187. }