Files
hi-server/internal/logic/common/promoEligibility_test.go
T
2026-05-26 22:05:23 -07:00

151 lines
4.8 KiB
Go

package common
import (
"context"
"testing"
"time"
)
type fakePromoEligibilitySource struct {
userCreatedAt time.Time
lastExpireAt time.Time
}
func (s fakePromoEligibilitySource) UserCreatedAt(context.Context, int64) (time.Time, error) {
return s.userCreatedAt, nil
}
func (s fakePromoEligibilitySource) LastSubscribeExpireAt(context.Context, int64) (time.Time, error) {
return s.lastExpireAt, nil
}
func TestEvaluatePromoRulesAtPriorityFirstMatch(t *testing.T) {
now := time.Date(2026, 5, 27, 12, 0, 0, 0, time.UTC)
campaignEnd := now.Add(24 * time.Hour)
rules := []promoRule{
{
Id: 2,
Name: "campaign",
Type: PromoRuleTypeCampaign,
Priority: 20,
Enabled: true,
EndTime: &campaignEnd,
},
{
Id: 1,
Name: "new user",
Type: PromoRuleTypeNewUser,
Params: `{"window_hours":168}`,
Priority: 10,
Enabled: true,
},
}
prices := []subscribePromo{
{SubscribeId: 100, PromoRuleId: 1, PromoPrice: 599},
{SubscribeId: 100, PromoRuleId: 2, PromoPrice: 499},
}
got, err := evaluatePromoRulesAt(context.Background(), rules, prices, fakePromoEligibilitySource{
userCreatedAt: now.Add(-time.Hour),
}, 10, now)
if err != nil {
t.Fatalf("evaluatePromoRulesAt error: %v", err)
}
if !got.Eligible || got.RuleID != 2 || got.PromoPrice != 499 || got.RuleType != PromoRuleTypeCampaign {
t.Fatalf("unexpected promo result: %+v", got)
}
if !got.ExpiresAt.Equal(campaignEnd) {
t.Fatalf("expires_at = %v, want %v", got.ExpiresAt, campaignEnd)
}
}
func TestEvaluatePromoRulesAtSkipsUnavailableRules(t *testing.T) {
now := time.Date(2026, 5, 27, 12, 0, 0, 0, time.UTC)
futureStart := now.Add(time.Hour)
expiredEnd := now.Add(-time.Hour)
rules := []promoRule{
{Id: 1, Type: PromoRuleTypeCampaign, Enabled: true, StartTime: &futureStart},
{Id: 2, Type: PromoRuleTypeCampaign, Enabled: true, EndTime: &expiredEnd},
{Id: 3, Type: PromoRuleTypeCampaign, Enabled: false},
{Id: 4, Type: "unknown", Enabled: true},
{Id: 5, Type: PromoRuleTypeCampaign, Enabled: true},
}
prices := []subscribePromo{
{SubscribeId: 100, PromoRuleId: 1, PromoPrice: 100},
{SubscribeId: 100, PromoRuleId: 2, PromoPrice: 100},
{SubscribeId: 100, PromoRuleId: 3, PromoPrice: 100},
{SubscribeId: 100, PromoRuleId: 4, PromoPrice: 100},
{SubscribeId: 100, PromoRuleId: 5, PromoPrice: 88},
}
got, err := evaluatePromoRulesAt(context.Background(), rules, prices, fakePromoEligibilitySource{}, 10, now)
if err != nil {
t.Fatalf("evaluatePromoRulesAt error: %v", err)
}
if !got.Eligible || got.RuleID != 5 || got.PromoPrice != 88 {
t.Fatalf("unexpected promo result: %+v", got)
}
}
func TestEvaluatePromoNewUser(t *testing.T) {
now := time.Date(2026, 5, 27, 12, 0, 0, 0, time.UTC)
createdAt := now.Add(-23 * time.Hour)
eligible, expiresAt := evaluatePromoNewUser(createdAt, promoRuleParams{WindowHours: 24}, now)
if !eligible {
t.Fatal("new user should be eligible inside configured window")
}
if !expiresAt.Equal(createdAt.Add(24 * time.Hour)) {
t.Fatalf("expires_at = %v, want %v", expiresAt, createdAt.Add(24*time.Hour))
}
eligible, _ = evaluatePromoNewUser(createdAt, promoRuleParams{WindowHours: 12}, now)
if eligible {
t.Fatal("new user should not be eligible after configured window")
}
eligible, _ = evaluatePromoNewUser(createdAt, promoRuleParams{}, now)
if eligible {
t.Fatal("new user should not be eligible without positive window_hours")
}
}
func TestEvaluatePromoInactiveUser(t *testing.T) {
now := time.Date(2026, 5, 27, 12, 0, 0, 0, time.UTC)
endTime := now.Add(48 * time.Hour)
rule := promoRule{EndTime: &endTime}
eligible, expiresAt := evaluatePromoInactiveUser(time.Time{}, promoRuleParams{InactiveMonths: 3}, rule, now)
if !eligible {
t.Fatal("never purchased user should be eligible for inactive promo")
}
if !expiresAt.Equal(endTime) {
t.Fatalf("expires_at = %v, want %v", expiresAt, endTime)
}
eligible, _ = evaluatePromoInactiveUser(now.AddDate(0, -4, 0), promoRuleParams{InactiveMonths: 3}, rule, now)
if !eligible {
t.Fatal("expired before inactive threshold should be eligible")
}
eligible, _ = evaluatePromoInactiveUser(now.AddDate(0, -1, 0), promoRuleParams{InactiveMonths: 3}, rule, now)
if eligible {
t.Fatal("recently expired subscription should not be eligible")
}
eligible, _ = evaluatePromoInactiveUser(time.UnixMilli(0), promoRuleParams{InactiveMonths: 3}, rule, now)
if eligible {
t.Fatal("unlimited active subscription should not be eligible")
}
eligible, _ = evaluatePromoInactiveUser(now.Add(time.Hour), promoRuleParams{InactiveMonths: 3}, rule, now)
if eligible {
t.Fatal("currently active subscription should not be eligible")
}
eligible, _ = evaluatePromoInactiveUser(now.AddDate(0, -4, 0), promoRuleParams{}, rule, now)
if eligible {
t.Fatal("inactive promo should require positive inactive_months")
}
}