Files
backend_v2/internal/repository/admin_mixed_integration_test.go
toom1996 42f6316125 update
2026-09-25 11:31:52 +08:00

175 lines
5.8 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.

//go:build integration
// 集成测试:文章管理混合列表必须跨 brand_runways / street_snaps 统一排序与过滤。
//
// 运行(库需先就绪,见 dedup_integration_test.go 顶部说明):
//
// go test -tags integration ./internal/repository/ -run TestAdminMixed -v
package repository
import (
"testing"
"gorm.io/gorm"
)
// seedMixedRecords 各插一条走秀(已发布)与街拍(待审),返回它们的内部 id。
// 用测试专用 city / season_code 隔离,避免与库里既有行撞唯一实体键。
func seedMixedRecords(t *testing.T, db *gorm.DB) (runwayID, streetID uint32) {
t.Helper()
if err := db.Raw(`
INSERT INTO brand_runways (brand_id, title_en, image_count, status, is_deleted, year, season_code, collection_type, created_at)
VALUES (999999, 'AdminRepoTestRunway', 3, ?, 0, 2099, 'ZZZ', 'test', 1800000000)
RETURNING id`, "published").Scan(&runwayID).Error; err != nil {
t.Fatalf("插入走秀种子失败: %v", err)
}
if err := db.Raw(`
INSERT INTO street_snaps (city, title, image_count, status, is_deleted, year, created_at)
VALUES ('TestCityZZZ', 'AdminRepoTestStreet', 2, ?, 0, 2099, 1800000000)
RETURNING id`, "pending").Scan(&streetID).Error; err != nil {
t.Fatalf("插入街拍种子失败: %v", err)
}
t.Cleanup(func() {
_ = db.Exec("DELETE FROM brand_runways WHERE id = ?", runwayID).Error
_ = db.Exec("DELETE FROM street_snaps WHERE id = ?", streetID).Error
})
return runwayID, streetID
}
// TestAdminMixedListFilterAndOrder 验证:
// 1. 全部视图同时返回走秀与街拍;
// 2. 待审核视图只返回 pending 的街拍,不含已发布的走秀;
// 3. 排序为「pending 优先、其次 id 倒序」—— 任一 pending 都排在所有 published 之前。
func TestAdminMixedListFilterAndOrder(t *testing.T) {
db := testDB(t)
runwayID, streetID := seedMixedRecords(t, db)
repo := NewAdminRepository(db)
all, total, err := repo.ListMixed(t.Context(), "", "", 1, 100)
if err != nil {
t.Fatalf("ListMixed 全部失败: %v", err)
}
if total < 2 {
t.Fatalf("全部视图至少应含 2 条种子,实际 total=%d", total)
}
var sawRunway, sawStreet bool
for _, c := range all {
if c.Kind == "runway" && c.ID == runwayID {
sawRunway = true
}
if c.Kind == "street" && c.ID == streetID {
sawStreet = true
}
}
if !sawRunway || !sawStreet {
t.Fatalf("全部视图应同时含走秀与街拍: runway=%v street=%v", sawRunway, sawStreet)
}
// 待审核过滤:街拍(pending) 出现,走秀(published) 不出现。
pending, _, err := repo.ListMixed(t.Context(), "pending", "", 1, 100)
if err != nil {
t.Fatalf("ListMixed pending 失败: %v", err)
}
var pendingHasStreet, pendingHasRunway bool
for _, c := range pending {
if c.Kind == "street" && c.ID == streetID {
pendingHasStreet = true
}
if c.Kind == "runway" && c.ID == runwayID {
pendingHasRunway = true
}
}
if !pendingHasStreet {
t.Fatalf("待审核视图应含待审街拍")
}
if pendingHasRunway {
t.Fatalf("待审核视图不应含已发布走秀")
}
// 排序:任一 pending 必须排在所有 published 之前。
var maxPendingIdx, minPublishedIdx = -1, 1 << 30
for i, c := range all {
if c.Status == "pending" {
if i > maxPendingIdx {
maxPendingIdx = i
}
} else if c.Status == "published" {
if i < minPublishedIdx {
minPublishedIdx = i
}
}
}
if maxPendingIdx >= 0 && minPublishedIdx < 1<<30 && maxPendingIdx > minPublishedIdx {
t.Fatalf("排序错误:存在 published 排在 pending 之前 (pending@%d, published@%d)", maxPendingIdx, minPublishedIdx)
}
// CountMixed 与列表口径一致。
if n, err := repo.CountMixed(t.Context(), "pending", ""); err != nil || n < 1 {
t.Fatalf("CountMixed(pending) 应 >=1,实际 n=%d err=%v", n, err)
}
}
// TestAdminMixedKindFilter 验证 kind 筛选:只取走秀 / 只取街拍 / 全部。
func TestAdminMixedKindFilter(t *testing.T) {
db := testDB(t)
applyMigration(t, db, "2026-09-22-01-single-table-publish.sql")
repo := NewAdminRepository(db)
ctx := t.Context()
// 直接插入各一条,用独特 city / title 隔离唯一实体键。
var runwayID, streetID uint32
if err := db.Raw(`
INSERT INTO brand_runways (brand_id, title_en, image_count, status, is_deleted, year, season_code, collection_type, created_at)
VALUES (999999, 'KindFilterRunway', 1, 'published', 0, 2097, 'KFZ', 'test', 1800000000)
RETURNING id`,
).Scan(&runwayID).Error; err != nil {
t.Fatalf("插入走秀种子失败: %v", err)
}
if err := db.Raw(`
INSERT INTO street_snaps (city, title, image_count, status, is_deleted, year, created_at)
VALUES ('KindFilterCity', 'KindFilterStreet', 1, 'published', 0, 2097, 1800000000)
RETURNING id`,
).Scan(&streetID).Error; err != nil {
t.Fatalf("插入街拍种子失败: %v", err)
}
t.Cleanup(func() {
_ = db.Exec("DELETE FROM brand_runways WHERE id = ?", runwayID).Error
_ = db.Exec("DELETE FROM street_snaps WHERE id = ?", streetID).Error
})
runwayOnly, _, err := repo.ListMixed(ctx, "", "runway", 1, 50)
if err != nil {
t.Fatalf("kind=runway 失败: %v", err)
}
for _, c := range runwayOnly {
if c.Kind != "runway" {
t.Fatalf("kind=runway 不应含 %s", c.Kind)
}
}
if len(runwayOnly) == 0 {
t.Fatalf("kind=runway 至少应含 1 条")
}
streetOnly, _, err := repo.ListMixed(ctx, "", "street", 1, 50)
if err != nil {
t.Fatalf("kind=street 失败: %v", err)
}
for _, c := range streetOnly {
if c.Kind != "street" {
t.Fatalf("kind=street 不应含 %s", c.Kind)
}
}
if len(streetOnly) == 0 {
t.Fatalf("kind=street 至少应含 1 条")
}
all, _, err := repo.ListMixed(ctx, "", "", 1, 50)
if err != nil {
t.Fatalf("kind='' 失败: %v", err)
}
if len(all) != len(runwayOnly)+len(streetOnly) {
t.Fatalf("全部应等于两类型之和:all=%d runway=%d street=%d", len(all), len(runwayOnly), len(streetOnly))
}
}