134 lines
5.1 KiB
Go
134 lines
5.1 KiB
Go
//go:build integration
|
||
|
||
// 集成测试:公开视图必须屏蔽未发布内容 —— 这是「单表发布模型」的核心保证。
|
||
//
|
||
// 运行(库需先就绪,见 internal/repository/dedup_integration_test.go 顶部说明):
|
||
//
|
||
// go test -tags integration ./internal/repository/ -run TestPublicViews -v
|
||
package repository
|
||
|
||
import (
|
||
"context"
|
||
"os"
|
||
"path/filepath"
|
||
"testing"
|
||
|
||
"fashionapi/internal/model"
|
||
|
||
"gorm.io/gorm"
|
||
)
|
||
|
||
// applyMigration 读取并执行 db/migrations 下的迁移文件。
|
||
// 迁移 SQL 因此每次测试都被真实跑一遍:语法错、视图列集漂移会立刻暴露。
|
||
// 迁移文件必须幂等,重复调用安全。
|
||
func applyMigration(t *testing.T, db *gorm.DB, name string) {
|
||
t.Helper()
|
||
path := filepath.Join("..", "..", "db", "migrations", name)
|
||
sqlBytes, err := os.ReadFile(path)
|
||
if err != nil {
|
||
t.Fatalf("读取迁移失败 %s: %v", path, err)
|
||
}
|
||
if err := db.Exec(string(sqlBytes)).Error; err != nil {
|
||
t.Fatalf("执行迁移失败 %s: %v", name, err)
|
||
}
|
||
}
|
||
|
||
// seedRunway 插入一条指定状态的走秀记录 + 一张主图,返回记录 id。
|
||
// year 用测试专用值(入参),便于列表按年份隔离断言;created_at 取未来时间戳,
|
||
// 保证不会被迁移里「存量行置已发布」的时间戳护栏误刷。
|
||
func seedRunway(t *testing.T, db *gorm.DB, status string, year uint16) uint32 {
|
||
t.Helper()
|
||
now := uint32(1_800_000_000)
|
||
rw := model.BrandRunway{TitleEn: "view-test", Year: year, Status: status, CreatedAt: now, UpdatedAt: now}
|
||
if err := db.Create(&rw).Error; err != nil {
|
||
t.Fatalf("插入走秀失败: %v", err)
|
||
}
|
||
img := model.BrandRunwayImage{
|
||
RunwayID: rw.ID, BrandID: 1, Image: "view-test.jpg", Name: "look",
|
||
SortOrder: 1, CreatedAt: now, UpdatedAt: now,
|
||
}
|
||
if err := db.Create(&img).Error; err != nil {
|
||
t.Fatalf("插入走秀图片失败: %v", err)
|
||
}
|
||
t.Cleanup(func() {
|
||
db.Exec("DELETE FROM brand_runway_images WHERE runway_id = ?", rw.ID)
|
||
db.Exec("DELETE FROM brand_runways WHERE id = ?", rw.ID)
|
||
})
|
||
return rw.ID
|
||
}
|
||
|
||
// seedStreetSnap 插入一条指定状态的街拍记录 + 一张图,返回记录 id。
|
||
func seedStreetSnap(t *testing.T, db *gorm.DB, status string, year uint16) uint32 {
|
||
t.Helper()
|
||
now := uint32(1_800_000_000)
|
||
snap := model.StreetSnap{Title: "view-test", City: "ViewTestCity", Year: year, Status: status, CreatedAt: now, UpdatedAt: now}
|
||
if err := db.Create(&snap).Error; err != nil {
|
||
t.Fatalf("插入街拍失败: %v", err)
|
||
}
|
||
img := model.StreetSnapImage{SnapID: snap.ID, Image: "view-test.jpg", Name: "look", SortOrder: 1, CreatedAt: now, UpdatedAt: now}
|
||
if err := db.Create(&img).Error; err != nil {
|
||
t.Fatalf("插入街拍图片失败: %v", err)
|
||
}
|
||
t.Cleanup(func() {
|
||
db.Exec("DELETE FROM street_snap_images WHERE snap_id = ?", snap.ID)
|
||
db.Exec("DELETE FROM street_snaps WHERE id = ?", snap.ID)
|
||
})
|
||
return snap.ID
|
||
}
|
||
|
||
// TestPublicViewsHideUnpublished 走秀:pending / rejected 的记录与图片都不得出现在公开视图,published 才可见。
|
||
func TestPublicViewsHideUnpublished(t *testing.T) {
|
||
db := testDB(t)
|
||
applyMigration(t, db, "2026-09-22-01-single-table-publish.sql")
|
||
ctx := context.Background()
|
||
|
||
id := seedRunway(t, db, model.StatusPending, 1999)
|
||
|
||
count := func() (records, images int64) {
|
||
db.WithContext(ctx).Table("public_brand_runways").Where("id = ?", id).Count(&records)
|
||
db.WithContext(ctx).Table("public_brand_runway_images").Where("runway_id = ?", id).Count(&images)
|
||
return
|
||
}
|
||
|
||
if r, i := count(); r != 0 || i != 0 {
|
||
t.Fatalf("pending 不应出现在公开视图,实际 records=%d images=%d", r, i)
|
||
}
|
||
if err := db.Model(&model.BrandRunway{}).Where("id = ?", id).Update("status", model.StatusPublished).Error; err != nil {
|
||
t.Fatalf("置为已发布失败: %v", err)
|
||
}
|
||
if r, i := count(); r != 1 || i != 1 {
|
||
t.Fatalf("published 应出现在公开视图,实际 records=%d images=%d", r, i)
|
||
}
|
||
if err := db.Model(&model.BrandRunway{}).Where("id = ?", id).Update("status", model.StatusRejected).Error; err != nil {
|
||
t.Fatalf("置为已驳回失败: %v", err)
|
||
}
|
||
if r, i := count(); r != 0 || i != 0 {
|
||
t.Fatalf("rejected 不应出现在公开视图,实际 records=%d images=%d", r, i)
|
||
}
|
||
}
|
||
|
||
// TestPublicViewsHideUnpublishedStreet 街拍:同上,覆盖另外两个视图。
|
||
func TestPublicViewsHideUnpublishedStreet(t *testing.T) {
|
||
db := testDB(t)
|
||
applyMigration(t, db, "2026-09-22-01-single-table-publish.sql")
|
||
ctx := context.Background()
|
||
|
||
id := seedStreetSnap(t, db, model.StatusPending, 1998)
|
||
|
||
count := func() (records, images int64) {
|
||
db.WithContext(ctx).Table("public_street_snaps").Where("id = ?", id).Count(&records)
|
||
db.WithContext(ctx).Table("public_street_snap_images").Where("snap_id = ?", id).Count(&images)
|
||
return
|
||
}
|
||
|
||
if r, i := count(); r != 0 || i != 0 {
|
||
t.Fatalf("pending 不应出现在公开视图,实际 records=%d images=%d", r, i)
|
||
}
|
||
if err := db.Model(&model.StreetSnap{}).Where("id = ?", id).Update("status", model.StatusPublished).Error; err != nil {
|
||
t.Fatalf("置为已发布失败: %v", err)
|
||
}
|
||
if r, i := count(); r != 1 || i != 1 {
|
||
t.Fatalf("published 应出现在公开视图,实际 records=%d images=%d", r, i)
|
||
}
|
||
}
|