package service import ( "testing" "github.com/stretchr/testify/assert" "github.com/topfans/backend/pkg/database" "github.com/topfans/backend/pkg/models" "github.com/topfans/backend/services/galleryService/client" "github.com/topfans/backend/services/galleryService/repository" "gorm.io/gorm" ) // mockAssetRPCClient Mock Asset RPC客户端 type mockAssetRPCClient struct{} func (m *mockAssetRPCClient) GetAssetForRPC(assetID, userID, starID int64) (*client.AssetInfo, error) { return &client.AssetInfo{ AssetId: assetID, OwnerUid: userID, StarId: starID, Name: "测试资产", CoverUrl: "https://example.com/cover.jpg", LikeCount: 10, }, nil } func (m *mockAssetRPCClient) GetAssetInfo(assetID, userID, starID int64) (*client.AssetInfo, error) { return &client.AssetInfo{ AssetId: assetID, Name: "测试资产", CoverUrl: "https://example.com/cover.jpg", LikeCount: 10, }, nil } func (m *mockAssetRPCClient) ClearAssetLikeRecords(assetID int64) error { return nil } func (m *mockAssetRPCClient) GetAssetLikeCount(assetID int64) int { return 10 } // mockUserRPCClient Mock User RPC客户端 type mockUserRPCClient struct{} func (m *mockUserRPCClient) GetFanProfile(userID, starID int64) (*client.FanProfile, error) { return &client.FanProfile{ ID: userID*1000000 + starID, // 模拟真实的 fan_profile ID UserID: userID, StarID: starID, Nickname: "测试用户", Level: 5, CrystalBalance: 1000, }, nil } func (m *mockUserRPCClient) UpdateCrystalBalance(userID, starID int64, delta int64, changeType string, sourceID string, description string) (int64, error) { // 简单返回更新后的余额(1000 + delta) return 1000 + delta, nil } func (m *mockUserRPCClient) AddExhibitionHours(userID, starID int64, hours int64, sourceID string) (int32, int32, int64, error) { // 简单返回模拟的升级结果 return 5, 0, 0, nil } // 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 tables: %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 } // TestGetMyGallery_LazyLoading 测试获取我的展馆(懒加载逻辑) func TestGetMyGallery_LazyLoading(t *testing.T) { db := setupTestDB(t) defer cleanupTestDB(t, db) repo := repository.NewGalleryRepository(db) assetClient := &mockAssetRPCClient{} userClient := &mockUserRPCClient{} service := NewGalleryService(repo, assetClient, userClient) // 创建测试用户和明星 star := createTestStar(t, db, "test_service_001") user := createTestUser(t, db, "19900000011") createTestFanProfile(t, db, user.ID, star.StarID, "测试用户011") // 首次查询,应该触发懒加载 gallery, err := service.GetMyGallery(user.ID, star.StarID) assert.NoError(t, err, "获取展馆应该成功") assert.NotNil(t, gallery, "展馆数据不应该为空") assert.Equal(t, int32(3), gallery.SlotTotal, "初始展位数应该为3") assert.Len(t, gallery.Slots, 3, "展位列表长度应该为3") // 验证展位状态 for _, slot := range gallery.Slots { assert.True(t, slot.IsEnabled, "初始展位应该已解锁") assert.Equal(t, "EMPTY", slot.Status, "初始展位应该为空") } } // TestGetMyGallery_ExistingSlots 测试获取我的展馆(已有展位) func TestGetMyGallery_ExistingSlots(t *testing.T) { db := setupTestDB(t) defer cleanupTestDB(t, db) repo := repository.NewGalleryRepository(db) assetClient := &mockAssetRPCClient{} userClient := &mockUserRPCClient{} service := NewGalleryService(repo, assetClient, userClient) // 创建测试用户和明星 star := createTestStar(t, db, "test_service_002") user := createTestUser(t, db, "19900000012") createTestFanProfile(t, db, user.ID, star.StarID, "测试用户012") // 预先创建展位(使用模拟的 hostProfileID) err := repo.CreateInitialSlots(user.ID, star.StarID, user.ID*1000000+star.StarID) assert.NoError(t, err) // 查询展馆 gallery, err := service.GetMyGallery(user.ID, star.StarID) assert.NoError(t, err) assert.NotNil(t, gallery) assert.Equal(t, int32(3), gallery.SlotTotal) } // TestGetUserGallery 测试获取他人展馆 func TestGetUserGallery(t *testing.T) { db := setupTestDB(t) defer cleanupTestDB(t, db) repo := repository.NewGalleryRepository(db) assetClient := &mockAssetRPCClient{} userClient := &mockUserRPCClient{} service := NewGalleryService(repo, assetClient, userClient) // 创建测试用户和明星 star := createTestStar(t, db, "test_service_003") user := createTestUser(t, db, "19900000013") createTestFanProfile(t, db, user.ID, star.StarID, "测试用户013") // 预先创建展位(使用模拟的 hostProfileID) err := repo.CreateInitialSlots(user.ID, star.StarID, user.ID*1000000+star.StarID) assert.NoError(t, err) // 另一个用户查询该用户的展馆 otherUser := createTestUser(t, db, "19900000014") gallery, err := service.GetUserGallery(otherUser.ID, star.StarID, user.ID) assert.NoError(t, err) assert.NotNil(t, gallery) assert.Equal(t, int32(3), gallery.SlotTotal) } // TestGetUserGallery_EmptyGallery 测试获取他人展馆(空展馆) func TestGetUserGallery_EmptyGallery(t *testing.T) { db := setupTestDB(t) defer cleanupTestDB(t, db) repo := repository.NewGalleryRepository(db) assetClient := &mockAssetRPCClient{} userClient := &mockUserRPCClient{} service := NewGalleryService(repo, assetClient, userClient) // 创建测试用户和明星 star := createTestStar(t, db, "test_service_004") user := createTestUser(t, db, "19900000015") createTestFanProfile(t, db, user.ID, star.StarID, "测试用户015") // 不创建展位,直接查询 otherUser := createTestUser(t, db, "19900000016") gallery, err := service.GetUserGallery(otherUser.ID, star.StarID, user.ID) assert.NoError(t, err) assert.NotNil(t, gallery) assert.Equal(t, int32(0), gallery.SlotTotal, "应该返回空展馆") assert.Empty(t, gallery.Slots, "展位列表应该为空") }