owpengram-server/internal/app/users/premium_test.go

145 lines
4.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package users
import (
"context"
"errors"
"testing"
"time"
"telesrv/internal/domain"
"telesrv/internal/store/memory"
)
func TestGrantPremiumSemantics(t *testing.T) {
ctx := context.Background()
store := memory.NewUserStore()
u, err := store.Create(ctx, domain.User{AccessHash: 1, Phone: "15550000101", FirstName: "P"})
if err != nil {
t.Fatalf("create: %v", err)
}
svc := NewService(store)
// 首次授予:从 now 起算 3 个月。
granted, err := svc.GrantPremium(ctx, u.ID, 3)
if err != nil {
t.Fatalf("GrantPremium: %v", err)
}
wantMin := time.Now().AddDate(0, 3, 0).Add(-time.Minute).Unix()
wantMax := time.Now().AddDate(0, 3, 0).Add(time.Minute).Unix()
if int64(granted.PremiumUntil) < wantMin || int64(granted.PremiumUntil) > wantMax {
t.Fatalf("first grant until = %d, want ~now+3mo [%d,%d]", granted.PremiumUntil, wantMin, wantMax)
}
// 未过期续期:在现有到期时间上累加。
renewed, err := svc.GrantPremium(ctx, u.ID, 1)
if err != nil {
t.Fatalf("renew: %v", err)
}
base := time.Unix(int64(granted.PremiumUntil), 0)
if got, want := int64(renewed.PremiumUntil), base.AddDate(0, 1, 0).Unix(); got != want {
t.Fatalf("renew until = %d, want %d (accumulated)", got, want)
}
// 清除。
cleared, err := svc.GrantPremium(ctx, u.ID, 0)
if err != nil {
t.Fatalf("clear: %v", err)
}
if cleared.PremiumUntil != 0 {
t.Fatalf("cleared until = %d, want 0", cleared.PremiumUntil)
}
// 已过期重授:从 now 起算而非累加。
if _, err := store.SetPremiumUntil(ctx, u.ID, int(time.Now().Add(-time.Hour).Unix())); err != nil {
t.Fatalf("seed expired: %v", err)
}
regranted, err := svc.GrantPremium(ctx, u.ID, 3)
if err != nil {
t.Fatalf("regrant: %v", err)
}
if int64(regranted.PremiumUntil) < wantMin {
t.Fatalf("regrant until = %d, want from now (≥%d)", regranted.PremiumUntil, wantMin)
}
// bot 拒绝授予。
if _, err := svc.GrantPremium(ctx, domain.BotFatherUserID, 3); !errors.Is(err, domain.ErrPremiumBotUnsupported) {
t.Fatalf("grant bot err = %v, want ErrPremiumBotUnsupported", err)
}
}
func TestSweepExpiredPremium(t *testing.T) {
ctx := context.Background()
store := memory.NewUserStore()
expired, _ := store.Create(ctx, domain.User{AccessHash: 1, Phone: "15550000102", FirstName: "E"})
active, _ := store.Create(ctx, domain.User{AccessHash: 2, Phone: "15550000103", FirstName: "A"})
now := time.Now().Unix()
if _, err := store.SetPremiumUntil(ctx, expired.ID, int(now-10)); err != nil {
t.Fatalf("seed expired: %v", err)
}
if _, err := store.SetPremiumUntil(ctx, active.ID, int(now+3600)); err != nil {
t.Fatalf("seed active: %v", err)
}
svc := NewService(store)
swept, err := svc.SweepExpiredPremium(ctx, now, 100)
if err != nil {
t.Fatalf("sweep: %v", err)
}
if len(swept) != 1 || swept[0].ID != expired.ID || swept[0].PremiumUntil != 0 {
t.Fatalf("swept = %+v, want 仅过期用户且 until 清零", swept)
}
// 幂等:第二轮无事可做。
again, err := svc.SweepExpiredPremium(ctx, now, 100)
if err != nil || len(again) != 0 {
t.Fatalf("second sweep = %+v err %v, want empty", again, err)
}
// 活跃用户不受影响。
got, _, _ := store.ByID(ctx, active.ID)
if got.PremiumUntil != int(now+3600) {
t.Fatalf("active until = %d, want untouched", got.PremiumUntil)
}
}
func TestUpdateEmojiStatusPremiumGate(t *testing.T) {
ctx := context.Background()
store := memory.NewUserStore()
u, _ := store.Create(ctx, domain.User{AccessHash: 1, Phone: "15550000104", FirstName: "S"})
svc := NewService(store)
// 非会员设置被拒PREMIUM_ACCOUNT_REQUIRED
if _, err := svc.UpdateEmojiStatus(ctx, u.ID, 42, 0); !errors.Is(err, domain.ErrPremiumRequired) {
t.Fatalf("non-premium set err = %v, want ErrPremiumRequired", err)
}
// 会员可设置;到期清理后残值不再下发,但显式清除仍允许。
if _, err := store.SetPremiumUntil(ctx, u.ID, int(time.Now().Add(time.Hour).Unix())); err != nil {
t.Fatalf("grant: %v", err)
}
set, err := svc.UpdateEmojiStatus(ctx, u.ID, 42, 0)
if err != nil || set.EmojiStatusDocumentID != 42 {
t.Fatalf("premium set = %+v err %v, want document 42", set, err)
}
if _, err := store.SetPremiumUntil(ctx, u.ID, 0); err != nil {
t.Fatalf("downgrade: %v", err)
}
cleared, err := svc.UpdateEmojiStatus(ctx, u.ID, 0, 0)
if err != nil || cleared.EmojiStatusDocumentID != 0 {
t.Fatalf("clear after downgrade = %+v err %v, want cleared", cleared, err)
}
}
func TestPremiumActiveUsesBaseUser(t *testing.T) {
ctx := context.Background()
store := memory.NewUserStore()
u, _ := store.Create(ctx, domain.User{AccessHash: 1, Phone: "15550000105", FirstName: "B"})
svc := NewService(store)
if svc.PremiumActive(ctx, u.ID) {
t.Fatal("non-premium user reported active")
}
if _, err := store.SetPremiumUntil(ctx, u.ID, int(time.Now().Add(time.Hour).Unix())); err != nil {
t.Fatalf("grant: %v", err)
}
if !svc.PremiumActive(ctx, u.ID) {
t.Fatal("premium user reported inactive")
}
}