hi-server/queue/logic/order/activateOrderLogic_newUserEligibility_test.go
shanshanzhong 9db4762904
All checks were successful
Build docker and publish / build (20.15.1) (push) Successful in 5m6s
fix(order): prevent duplicate subscriptions and repair invite gifts
2026-04-24 21:16:21 -07:00

200 lines
6.2 KiB
Go

package orderLogic
import (
"context"
"testing"
"time"
modelOrder "github.com/perfect-panel/server/internal/model/order"
"github.com/perfect-panel/server/internal/model/subscribe"
"github.com/perfect-panel/server/internal/model/user"
"github.com/stretchr/testify/require"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
func setupActivationEligibilityDB(t *testing.T) *gorm.DB {
t.Helper()
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{
Logger: logger.Default.LogMode(logger.Silent),
})
require.NoError(t, err)
sqls := []string{
`CREATE TABLE IF NOT EXISTS "user" (
id INTEGER PRIMARY KEY AUTOINCREMENT,
password VARCHAR(100) NOT NULL DEFAULT '',
created_at DATETIME,
updated_at DATETIME,
deleted_at DATETIME DEFAULT NULL
)`,
`CREATE TABLE IF NOT EXISTS "user_device" (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL DEFAULT 0,
identifier VARCHAR(255) NOT NULL DEFAULT '' UNIQUE,
created_at DATETIME,
updated_at DATETIME
)`,
`CREATE TABLE IF NOT EXISTS "user_family" (
id INTEGER PRIMARY KEY AUTOINCREMENT,
owner_user_id INTEGER NOT NULL DEFAULT 0,
status TINYINT NOT NULL DEFAULT 1,
deleted_at DATETIME DEFAULT NULL
)`,
`CREATE TABLE IF NOT EXISTS "user_family_member" (
id INTEGER PRIMARY KEY AUTOINCREMENT,
family_id INTEGER NOT NULL DEFAULT 0,
user_id INTEGER NOT NULL DEFAULT 0,
role TINYINT NOT NULL DEFAULT 0,
status TINYINT NOT NULL DEFAULT 0,
join_source VARCHAR(32) NOT NULL DEFAULT '',
deleted_at DATETIME DEFAULT NULL
)`,
`CREATE TABLE IF NOT EXISTS "order" (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL DEFAULT 0,
order_no VARCHAR(255) NOT NULL DEFAULT '' UNIQUE,
type TINYINT NOT NULL DEFAULT 1,
status TINYINT NOT NULL DEFAULT 1,
subscribe_id INTEGER NOT NULL DEFAULT 0,
quantity INTEGER NOT NULL DEFAULT 1,
created_at DATETIME,
updated_at DATETIME
)`,
}
for _, sql := range sqls {
require.NoError(t, db.Exec(sql).Error)
}
return db
}
func insertActivationUser(t *testing.T, db *gorm.DB, userID int64, createdAt time.Time) {
t.Helper()
require.NoError(t, db.Exec(
`INSERT INTO "user" (id, created_at, updated_at) VALUES (?, ?, datetime('now'))`,
userID,
createdAt.UTC().Format("2006-01-02 15:04:05"),
).Error)
}
func insertActivationDevice(t *testing.T, db *gorm.DB, userID int64, identifier string, createdAt time.Time) {
t.Helper()
require.NoError(t, db.Exec(
`INSERT INTO "user_device" (user_id, identifier, created_at, updated_at) VALUES (?, ?, ?, datetime('now'))`,
userID,
identifier,
createdAt.UTC().Format("2006-01-02 15:04:05"),
).Error)
}
func insertActivationFamily(t *testing.T, db *gorm.DB, familyID, ownerUserID int64) {
t.Helper()
require.NoError(t, db.Exec(
`INSERT INTO "user_family" (id, owner_user_id, status) VALUES (?, ?, 1)`,
familyID,
ownerUserID,
).Error)
}
func insertActivationFamilyMember(t *testing.T, db *gorm.DB, familyID, userID int64, role, status uint8, joinSource string) {
t.Helper()
require.NoError(t, db.Exec(
`INSERT INTO "user_family_member" (family_id, user_id, role, status, join_source) VALUES (?, ?, ?, ?, ?)`,
familyID,
userID,
role,
status,
joinSource,
).Error)
}
func insertActivationOrder(t *testing.T, db *gorm.DB, orderNo string, userID, subscribeID int64, status uint8) {
t.Helper()
require.NoError(t, db.Exec(
`INSERT INTO "order" (user_id, order_no, type, status, subscribe_id, quantity, created_at, updated_at)
VALUES (?, ?, 1, ?, ?, 1, datetime('now'), datetime('now'))`,
userID,
orderNo,
status,
subscribeID,
).Error)
}
func TestValidateNewUserOnlyEligibilityAtActivation_UsesEarliestBoundDeviceTime(t *testing.T) {
db := setupActivationEligibilityDB(t)
const (
ownerUserID = int64(1)
memberUserID = int64(2)
familyID = int64(10)
subscribeID = int64(100)
)
insertActivationUser(t, db, ownerUserID, time.Now().Add(-1*time.Hour))
insertActivationUser(t, db, memberUserID, time.Now().Add(-72*time.Hour))
insertActivationDevice(t, db, memberUserID, "activation-old-device", time.Now().Add(-72*time.Hour))
insertActivationFamily(t, db, familyID, ownerUserID)
insertActivationFamilyMember(t, db, familyID, ownerUserID, user.FamilyRoleOwner, user.FamilyMemberActive, "owner_init")
insertActivationFamilyMember(t, db, familyID, memberUserID, user.FamilyRoleMember, user.FamilyMemberActive, "bind_email_with_verification")
err := validateNewUserOnlyEligibilityAtActivation(
context.Background(),
db,
&modelOrder.Order{
UserId: ownerUserID,
OrderNo: "activation-check-old-device",
Type: OrderTypeSubscribe,
Quantity: 1,
SubscribeId: subscribeID,
},
&subscribe.Subscribe{
Id: subscribeID,
Discount: `[{"quantity":1,"discount":90,"new_user_only":true}]`,
},
)
require.Error(t, err)
require.Contains(t, err.Error(), "is not a new user")
}
func TestValidateNewUserOnlyEligibilityAtActivation_SharesHistoryAcrossBoundScope(t *testing.T) {
db := setupActivationEligibilityDB(t)
const (
ownerUserID = int64(11)
memberUserID = int64(12)
familyID = int64(20)
subscribeID = int64(200)
)
insertActivationUser(t, db, ownerUserID, time.Now().Add(-1*time.Hour))
insertActivationUser(t, db, memberUserID, time.Now().Add(-2*time.Hour))
insertActivationDevice(t, db, memberUserID, "activation-shared-device", time.Now().Add(-2*time.Hour))
insertActivationFamily(t, db, familyID, ownerUserID)
insertActivationFamilyMember(t, db, familyID, ownerUserID, user.FamilyRoleOwner, user.FamilyMemberActive, "owner_init")
insertActivationFamilyMember(t, db, familyID, memberUserID, user.FamilyRoleMember, user.FamilyMemberActive, "bind_email_with_verification")
insertActivationOrder(t, db, "previous-finished-order", memberUserID, subscribeID, OrderStatusFinished)
err := validateNewUserOnlyEligibilityAtActivation(
context.Background(),
db,
&modelOrder.Order{
UserId: ownerUserID,
OrderNo: "current-paid-order",
Type: OrderTypeSubscribe,
Quantity: 1,
SubscribeId: subscribeID,
},
&subscribe.Subscribe{
Id: subscribeID,
Discount: `[{"quantity":1,"discount":90,"new_user_only":true}]`,
},
)
require.Error(t, err)
require.Contains(t, err.Error(), "already activated")
}