topfans/backend/services/galleryService/repository/gallery_repository_test.go
2026-04-07 22:29:48 +08:00

510 lines
16 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 repository
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/topfans/backend/pkg/database"
"github.com/topfans/backend/pkg/models"
"github.com/topfans/backend/services/galleryService/config"
"gorm.io/gorm"
)
// setupTestDB 设置测试数据库
func setupTestDB(t *testing.T) *gorm.DB {
dbConfig := database.Config{
Host: "localhost",
Port: 5432,
User: "haihuizhu",
Password: "admin",
DBName: "top-fans",
SSLMode: "disable",
TimeZone: "Asia/Shanghai",
}
if err := database.Init(dbConfig); err != nil {
t.Skipf("Skipping test: failed to connect to test database: %v", err)
}
db := database.GetDB()
// 迁移展馆相关表
if err := db.AutoMigrate(&models.BoothSlot{}, &models.Exhibition{}); err != nil {
t.Logf("Warning: Failed to migrate gallery tables (may already exist): %v", err)
}
// 测试开始前先清理一次,确保测试环境干净
cleanupTestDB(t, db)
return db
}
// cleanupTestDB 清理测试数据
func cleanupTestDB(t *testing.T, db *gorm.DB) {
// 清理测试数据(注意外键约束顺序)
// 先清理展品展示记录,再清理展位
db.Exec("DELETE FROM exhibitions WHERE occupier_uid IN (SELECT id FROM users WHERE mobile LIKE '199%')")
db.Exec("DELETE FROM booth_slots WHERE user_id IN (SELECT id FROM users WHERE mobile LIKE '199%')")
}
// createTestStar 创建测试用明星
func createTestStar(t *testing.T, db *gorm.DB, identityID string) *models.Star {
// 先检查是否已存在
var existingStar models.Star
if err := db.Where("identity_id = ?", identityID).First(&existingStar).Error; err == nil {
// 已存在,返回现有的
return &existingStar
}
// 不存在,创建新的
star := &models.Star{
Name: "测试明星-" + identityID,
IdentityID: identityID,
IsActive: true,
}
if err := db.Create(star).Error; err != nil {
t.Fatalf("Failed to create test star: %v", err)
}
return star
}
// createTestUser 创建测试用户
func createTestUser(t *testing.T, db *gorm.DB, mobile string) *models.User {
user := &models.User{
Mobile: mobile,
PasswordHash: "test_hash",
IsActive: true,
}
if err := db.Create(user).Error; err != nil {
t.Fatalf("Failed to create test user: %v", err)
}
return user
}
// createTestFanProfile 创建测试粉丝档案
func createTestFanProfile(t *testing.T, db *gorm.DB, userID, starID int64, nickname string) *models.FanProfile {
profile := &models.FanProfile{
UserID: userID,
StarID: starID,
Nickname: nickname,
Level: 1,
}
if err := db.Create(profile).Error; err != nil {
t.Fatalf("Failed to create test fan profile: %v", err)
}
return profile
}
// TestCreateInitialSlots 测试创建初始展位
func TestCreateInitialSlots(t *testing.T) {
db := setupTestDB(t)
defer cleanupTestDB(t, db)
repo := NewGalleryRepository(db)
// 创建测试用户和明星
star := createTestStar(t, db, "test_gallery_001")
user := createTestUser(t, db, "19900000001")
createTestFanProfile(t, db, user.ID, star.StarID, "测试用户001")
// 测试创建初始展位
err := repo.CreateInitialSlots(user.ID, star.StarID, user.ID*1000000+star.StarID)
assert.NoError(t, err, "创建初始展位应该成功")
// 验证展位数量
count, err := repo.GetSlotCount(user.ID, star.StarID)
assert.NoError(t, err)
assert.Equal(t, int64(config.GalleryRules.InitialSlotCount), count, "初始展位数量应该为3")
// 验证展位信息
slots, err := repo.GetSlotsByUser(user.ID, star.StarID)
assert.NoError(t, err)
assert.Len(t, slots, config.GalleryRules.InitialSlotCount, "展位列表长度应该为3")
// 验证展位属性
for i, slot := range slots {
assert.Equal(t, i+1, slot.SlotIndex, "展位序号应该从1开始")
assert.True(t, slot.IsEnabled, "初始展位应该已解锁")
assert.Equal(t, "public", slot.Visibility, "初始展位应该是公有的")
assert.Equal(t, "free", slot.UnlockType, "初始展位应该是免费的")
assert.Equal(t, 0, slot.UnlockValue, "初始展位解锁值应该为0")
}
}
// TestCreateInitialSlots_Idempotent 测试懒加载的幂等性(避免重复创建)
func TestCreateInitialSlots_Idempotent(t *testing.T) {
db := setupTestDB(t)
defer cleanupTestDB(t, db)
repo := NewGalleryRepository(db)
// 创建测试用户和明星
star := createTestStar(t, db, "test_gallery_002")
user := createTestUser(t, db, "19900000002")
createTestFanProfile(t, db, user.ID, star.StarID, "测试用户002")
// 第一次创建
err := repo.CreateInitialSlots(user.ID, star.StarID, user.ID*1000000+star.StarID)
assert.NoError(t, err, "第一次创建应该成功")
// 第二次创建(应该不会报错,也不会重复创建)
err = repo.CreateInitialSlots(user.ID, star.StarID, user.ID*1000000+star.StarID)
assert.NoError(t, err, "第二次创建应该不报错(幂等性)")
// 验证展位数量仍然是3
count, err := repo.GetSlotCount(user.ID, star.StarID)
assert.NoError(t, err)
assert.Equal(t, int64(config.GalleryRules.InitialSlotCount), count, "展位数量应该仍然为3不会重复创建")
}
// TestGetSlotsByUser 测试查询展位列表
func TestGetSlotsByUser(t *testing.T) {
db := setupTestDB(t)
defer cleanupTestDB(t, db)
repo := NewGalleryRepository(db)
// 创建测试用户和明星
star := createTestStar(t, db, "test_gallery_003")
user := createTestUser(t, db, "19900000003")
createTestFanProfile(t, db, user.ID, star.StarID, "测试用户003")
// 创建初始展位
err := repo.CreateInitialSlots(user.ID, star.StarID, user.ID*1000000+star.StarID)
assert.NoError(t, err)
// 查询展位列表
slots, err := repo.GetSlotsByUser(user.ID, star.StarID)
assert.NoError(t, err)
assert.Len(t, slots, config.GalleryRules.InitialSlotCount, "应该返回3个展位")
// 验证排序(按 slot_index 升序)
for i, slot := range slots {
assert.Equal(t, i+1, slot.SlotIndex, "展位应该按序号升序排列")
}
}
// TestGetSlotByID 测试根据ID获取展位
func TestGetSlotByID(t *testing.T) {
db := setupTestDB(t)
defer cleanupTestDB(t, db)
repo := NewGalleryRepository(db)
// 创建测试用户和明星
star := createTestStar(t, db, "test_gallery_004")
user := createTestUser(t, db, "19900000004")
createTestFanProfile(t, db, user.ID, star.StarID, "测试用户004")
// 创建初始展位
err := repo.CreateInitialSlots(user.ID, star.StarID, user.ID*1000000+star.StarID)
assert.NoError(t, err)
// 获取展位列表
slots, err := repo.GetSlotsByUser(user.ID, star.StarID)
assert.NoError(t, err)
assert.NotEmpty(t, slots)
// 根据ID获取第一个展位
firstSlot := slots[0]
slot, err := repo.GetSlotByID(firstSlot.SlotID)
assert.NoError(t, err)
assert.NotNil(t, slot)
assert.Equal(t, firstSlot.SlotID, slot.SlotID, "展位ID应该匹配")
assert.Equal(t, firstSlot.SlotIndex, slot.SlotIndex, "展位序号应该匹配")
// 测试获取不存在的展位
_, err = repo.GetSlotByID(999999)
assert.Error(t, err, "获取不存在的展位应该返回错误")
}
// TestCreateSlot 测试创建新展位(解锁)
func TestCreateSlot(t *testing.T) {
db := setupTestDB(t)
defer cleanupTestDB(t, db)
repo := NewGalleryRepository(db)
// 创建测试用户和明星
star := createTestStar(t, db, "test_gallery_005")
user := createTestUser(t, db, "19900000005")
createTestFanProfile(t, db, user.ID, star.StarID, "测试用户005")
// 创建初始展位
err := repo.CreateInitialSlots(user.ID, star.StarID, user.ID*1000000+star.StarID)
assert.NoError(t, err)
// 创建第4个展位需要解锁
hostProfileID := generateHostProfileID(user.ID, star.StarID)
newSlot := &models.BoothSlot{
HostProfileID: hostProfileID,
UserID: user.ID,
StarID: star.StarID,
SlotIndex: 4,
Visibility: "public",
IsEnabled: true,
UnlockType: "level",
UnlockValue: 5,
}
err = repo.CreateSlot(newSlot)
assert.NoError(t, err, "创建新展位应该成功")
// 验证展位数量
count, err := repo.GetSlotCount(user.ID, star.StarID)
assert.NoError(t, err)
assert.Equal(t, int64(4), count, "展位数量应该为4")
// 验证新展位信息
slots, err := repo.GetSlotsByUser(user.ID, star.StarID)
assert.NoError(t, err)
assert.Len(t, slots, 4, "展位列表长度应该为4")
lastSlot := slots[3]
assert.Equal(t, 4, lastSlot.SlotIndex, "新展位序号应该为4")
assert.True(t, lastSlot.IsEnabled, "新展位应该已解锁")
assert.Equal(t, "level", lastSlot.UnlockType, "解锁方式应该为等级")
assert.Equal(t, 5, lastSlot.UnlockValue, "解锁条件应该为等级5")
}
// TestCreateExhibition 测试创建展品展示记录
func TestCreateExhibition(t *testing.T) {
db := setupTestDB(t)
defer cleanupTestDB(t, db)
repo := NewGalleryRepository(db)
// 创建测试用户和明星
star := createTestStar(t, db, "test_gallery_006")
user := createTestUser(t, db, "19900000006")
createTestFanProfile(t, db, user.ID, star.StarID, "测试用户006")
// 创建初始展位
err := repo.CreateInitialSlots(user.ID, star.StarID, user.ID*1000000+star.StarID)
assert.NoError(t, err)
// 获取第一个展位
slots, err := repo.GetSlotsByUser(user.ID, star.StarID)
assert.NoError(t, err)
firstSlot := slots[0]
// 创建展品展示记录
now := time.Now().UnixMilli()
expireAt := now + config.GalleryRules.GrabSlotDuration*1000
exhibition := &models.Exhibition{
AssetID: 12345,
SlotID: firstSlot.SlotID,
HostProfileID: firstSlot.HostProfileID,
OccupierUID: user.ID,
OccupierStarID: star.StarID,
StartTime: now,
ExpireAt: expireAt,
}
err = repo.CreateExhibition(exhibition)
assert.NoError(t, err, "创建展品展示记录应该成功")
// 验证展品展示记录
fetchedExhibition, err := repo.GetExhibitionByAsset(12345)
assert.NoError(t, err)
assert.NotNil(t, fetchedExhibition)
assert.Equal(t, int64(12345), fetchedExhibition.AssetID, "资产ID应该匹配")
assert.Equal(t, firstSlot.SlotID, fetchedExhibition.SlotID, "展位ID应该匹配")
}
// TestGetExhibitionBySlot 测试根据展位ID获取展品展示记录
func TestGetExhibitionBySlot(t *testing.T) {
db := setupTestDB(t)
defer cleanupTestDB(t, db)
repo := NewGalleryRepository(db)
// 创建测试用户和明星
star := createTestStar(t, db, "test_gallery_007")
user := createTestUser(t, db, "19900000007")
createTestFanProfile(t, db, user.ID, star.StarID, "测试用户007")
// 创建初始展位
err := repo.CreateInitialSlots(user.ID, star.StarID, user.ID*1000000+star.StarID)
assert.NoError(t, err)
// 获取第一个展位
slots, err := repo.GetSlotsByUser(user.ID, star.StarID)
assert.NoError(t, err)
firstSlot := slots[0]
// 创建展品展示记录
now := time.Now().UnixMilli()
expireAt := now + config.GalleryRules.GrabSlotDuration*1000
exhibition := &models.Exhibition{
AssetID: 23456,
SlotID: firstSlot.SlotID,
HostProfileID: firstSlot.HostProfileID,
OccupierUID: user.ID,
OccupierStarID: star.StarID,
StartTime: now,
ExpireAt: expireAt,
}
err = repo.CreateExhibition(exhibition)
assert.NoError(t, err)
// 根据展位ID获取展品展示记录
fetchedExhibition, err := repo.GetExhibitionBySlot(firstSlot.SlotID)
assert.NoError(t, err)
assert.NotNil(t, fetchedExhibition)
assert.Equal(t, int64(23456), fetchedExhibition.AssetID, "资产ID应该匹配")
assert.Equal(t, firstSlot.SlotID, fetchedExhibition.SlotID, "展位ID应该匹配")
}
// TestDeleteExhibition 测试删除展品展示记录
func TestDeleteExhibition(t *testing.T) {
db := setupTestDB(t)
defer cleanupTestDB(t, db)
repo := NewGalleryRepository(db)
// 创建测试用户和明星
star := createTestStar(t, db, "test_gallery_008")
user := createTestUser(t, db, "19900000008")
createTestFanProfile(t, db, user.ID, star.StarID, "测试用户008")
// 创建初始展位
err := repo.CreateInitialSlots(user.ID, star.StarID, user.ID*1000000+star.StarID)
assert.NoError(t, err)
// 获取第一个展位
slots, err := repo.GetSlotsByUser(user.ID, star.StarID)
assert.NoError(t, err)
firstSlot := slots[0]
// 创建展品展示记录
now := time.Now().UnixMilli()
expireAt := now + config.GalleryRules.GrabSlotDuration*1000
exhibition := &models.Exhibition{
AssetID: 34567,
SlotID: firstSlot.SlotID,
HostProfileID: firstSlot.HostProfileID,
OccupierUID: user.ID,
OccupierStarID: star.StarID,
StartTime: now,
ExpireAt: expireAt,
}
err = repo.CreateExhibition(exhibition)
assert.NoError(t, err)
// 验证展品展示记录存在
fetchedExhibition, err := repo.GetExhibitionByAsset(34567)
assert.NoError(t, err)
assert.NotNil(t, fetchedExhibition)
// 删除展品展示记录
err = repo.DeleteExhibition(fetchedExhibition.ID)
assert.NoError(t, err, "删除展品展示记录应该成功")
// 验证展品展示记录已删除
fetchedExhibition, err = repo.GetExhibitionByAsset(34567)
assert.NoError(t, err)
assert.Nil(t, fetchedExhibition, "展品展示记录应该已被删除")
}
// TestDeleteExhibitionByAsset 测试根据资产ID删除展品展示记录
func TestDeleteExhibitionByAsset(t *testing.T) {
db := setupTestDB(t)
defer cleanupTestDB(t, db)
repo := NewGalleryRepository(db)
// 创建测试用户和明星
star := createTestStar(t, db, "test_gallery_009")
user := createTestUser(t, db, "19900000009")
createTestFanProfile(t, db, user.ID, star.StarID, "测试用户009")
// 创建初始展位
err := repo.CreateInitialSlots(user.ID, star.StarID, user.ID*1000000+star.StarID)
assert.NoError(t, err)
// 获取第一个展位
slots, err := repo.GetSlotsByUser(user.ID, star.StarID)
assert.NoError(t, err)
firstSlot := slots[0]
// 创建展品展示记录
now := time.Now().UnixMilli()
expireAt := now + config.GalleryRules.GrabSlotDuration*1000
exhibition := &models.Exhibition{
AssetID: 45678,
SlotID: firstSlot.SlotID,
HostProfileID: firstSlot.HostProfileID,
OccupierUID: user.ID,
OccupierStarID: star.StarID,
StartTime: now,
ExpireAt: expireAt,
}
err = repo.CreateExhibition(exhibition)
assert.NoError(t, err)
// 根据资产ID删除展品展示记录
err = repo.DeleteExhibitionByAsset(45678)
assert.NoError(t, err, "根据资产ID删除展品展示记录应该成功")
// 验证展品展示记录已删除
fetchedExhibition, err := repo.GetExhibitionByAsset(45678)
assert.NoError(t, err)
assert.Nil(t, fetchedExhibition, "展品展示记录应该已被删除")
}
// TestGetExpiredExhibitions 测试获取过期的展品展示记录
func TestGetExpiredExhibitions(t *testing.T) {
db := setupTestDB(t)
defer cleanupTestDB(t, db)
repo := NewGalleryRepository(db)
// 创建测试用户和明星
star := createTestStar(t, db, "test_gallery_010")
user := createTestUser(t, db, "19900000010")
createTestFanProfile(t, db, user.ID, star.StarID, "测试用户010")
// 创建初始展位
err := repo.CreateInitialSlots(user.ID, star.StarID, user.ID*1000000+star.StarID)
assert.NoError(t, err)
// 获取展位
slots, err := repo.GetSlotsByUser(user.ID, star.StarID)
assert.NoError(t, err)
// 创建已过期的展品展示记录
now := time.Now().UnixMilli()
pastExpireTime := now - 1000*60*60 // 1小时前过期
expiredExhibition := &models.Exhibition{
AssetID: 56789,
SlotID: slots[0].SlotID,
HostProfileID: slots[0].HostProfileID,
OccupierUID: user.ID,
OccupierStarID: star.StarID,
StartTime: now - 1000*60*60*5, // 5小时前开始
ExpireAt: pastExpireTime,
}
err = repo.CreateExhibition(expiredExhibition)
assert.NoError(t, err)
// 创建未过期的展品展示记录
futureExpireTime := now + 1000*60*60 // 1小时后过期
validExhibition := &models.Exhibition{
AssetID: 67890,
SlotID: slots[1].SlotID,
HostProfileID: slots[1].HostProfileID,
OccupierUID: user.ID,
OccupierStarID: star.StarID,
StartTime: now,
ExpireAt: futureExpireTime,
}
err = repo.CreateExhibition(validExhibition)
assert.NoError(t, err)
// 获取过期的展品展示记录
expiredExhibitions, err := repo.GetExpiredExhibitions(now)
assert.NoError(t, err)
assert.Len(t, expiredExhibitions, 1, "应该只有1个过期的展品展示记录")
assert.Equal(t, int64(56789), expiredExhibitions[0].AssetID, "过期的展品资产ID应该为56789")
}