feat: 统一顺运宝日期同步并记录历史 (#59)
This commit is contained in:
@@ -9,6 +9,8 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"cmautobuy/admin/model"
|
||||
)
|
||||
|
||||
// 本文件是工单 #20 的核心交付物:证明不管从哪种库起步,迁到最新版本后
|
||||
@@ -623,11 +625,10 @@ func TestMigrate_v6用户表与v7客户端归属表均存在(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// #52/#54:显式覆盖每一个已发布版本起点,证明 Client 现实库
|
||||
// 不会因为 v6/v7 的新增表而卡在中间版本。v2 的两种历史结构另由上面的收敛
|
||||
// 测试持续覆盖;这里验证顺序发布的 v1-v5 路径。
|
||||
func TestMigrate_v1到v5均可升级到最新版本(t *testing.T) {
|
||||
for version := 1; version <= 5; version++ {
|
||||
// 显式覆盖每一个已发布版本起点,证明现实库不会因为后续新增表而卡住。
|
||||
// v2 的两种历史结构另由上面的收敛测试持续覆盖。
|
||||
func TestMigrate_v1到v7均可升级到最新版本(t *testing.T) {
|
||||
for version := 1; version <= 7; version++ {
|
||||
t.Run(fmt.Sprintf("v%d", version), func(t *testing.T) {
|
||||
db := newPublishedVersionDB(t, version)
|
||||
if err := Migrate(db); err != nil {
|
||||
@@ -647,6 +648,41 @@ func TestMigrate_v1到v5均可升级到最新版本(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMigrate_v8新增顺运宝同步记录表(t *testing.T) {
|
||||
db := newPublishedVersionDB(t, 7)
|
||||
if err := Migrate(db); err != nil {
|
||||
t.Fatalf("v7 升级到 v8 失败: %v", err)
|
||||
}
|
||||
if !existingTableSet(t, db)["syb_sync_runs"] {
|
||||
t.Fatal("v8 应该新增 syb_sync_runs 表")
|
||||
}
|
||||
var version int
|
||||
if err := db.QueryRow(`PRAGMA user_version`).Scan(&version); err != nil || version != 8 {
|
||||
t.Fatalf("迁移版本错误: version=%d err=%v", version, err)
|
||||
}
|
||||
user := model.User{
|
||||
UserID: "USR-MIGRATE", Username: "buyer", PasswordHash: "test-hash",
|
||||
Role: model.RolePurchaser, Status: model.UserActive,
|
||||
PasswordChangedAt: model.NowISO(), CreatedAt: model.NowISO(), UpdatedAt: model.NowISO(),
|
||||
}
|
||||
if err := CreateInitialAdmin(db, user); err != nil {
|
||||
t.Fatalf("准备同步记录外键用户失败: %v", err)
|
||||
}
|
||||
// 状态和 running/finished_at 对应关系必须由数据库兜底,不能只靠 Go 校验。
|
||||
if _, err := db.Exec(`INSERT INTO syb_sync_runs
|
||||
(run_id, user_id, date_from, date_to, status, started_at, finished_at)
|
||||
VALUES ('bad', ?, '2026-08-09', '2026-08-09', 'unknown', ?, ?)`,
|
||||
user.UserID, model.NowISO(), model.NowISO()); err == nil {
|
||||
t.Fatal("非法同步状态应该被数据库约束拒绝")
|
||||
}
|
||||
if _, err := db.Exec(`INSERT INTO syb_sync_runs
|
||||
(run_id, user_id, date_from, date_to, status, started_at, finished_at)
|
||||
VALUES ('bad-running', ?, '2026-08-09', '2026-08-09', 'running', ?, ?)`,
|
||||
user.UserID, model.NowISO(), model.NowISO()); err == nil {
|
||||
t.Fatal("running 状态不应允许填写完成时间")
|
||||
}
|
||||
}
|
||||
|
||||
func newPublishedVersionDB(t *testing.T, version int) *sql.DB {
|
||||
t.Helper()
|
||||
db, err := Open(t.TempDir())
|
||||
@@ -683,6 +719,16 @@ func newPublishedVersionDB(t *testing.T, version int) *sql.DB {
|
||||
t.Fatalf("构造 v%d 时执行 v5 失败: %v", version, err)
|
||||
}
|
||||
}
|
||||
if version >= 6 {
|
||||
if err := runSQLMigration(db, 6, migrationV6); err != nil {
|
||||
t.Fatalf("构造 v%d 时执行 v6 失败: %v", version, err)
|
||||
}
|
||||
}
|
||||
if version >= 7 {
|
||||
if err := runSQLMigration(db, 7, migrationV7); err != nil {
|
||||
t.Fatalf("构造 v%d 时执行 v7 失败: %v", version, err)
|
||||
}
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
||||
@@ -1120,7 +1166,7 @@ func TestCheckSchema_缺少v4关键列时拒绝(t *testing.T) {
|
||||
if err := migrateV3(db); err != nil {
|
||||
t.Fatalf("准备 v3 数据库失败: %v", err)
|
||||
}
|
||||
// 故意跳过 v4(不加 shop_name),但把 v5-v7 补上——否则 CheckSchema 会先
|
||||
// 故意跳过 v4(不加 shop_name),但把 v5-v8 补上——否则 CheckSchema 会先
|
||||
// 因为缺后续表报错,测不到本测试真正要覆盖的"缺 shop_name"这条路径。
|
||||
if err := runSQLMigration(db, 5, migrationV5); err != nil {
|
||||
t.Fatalf("准备 v5 数据库失败: %v", err)
|
||||
@@ -1131,6 +1177,9 @@ func TestCheckSchema_缺少v4关键列时拒绝(t *testing.T) {
|
||||
if err := runSQLMigration(db, 7, migrationV7); err != nil {
|
||||
t.Fatalf("准备 v7 数据库失败: %v", err)
|
||||
}
|
||||
if err := runSQLMigration(db, 8, migrationV8); err != nil {
|
||||
t.Fatalf("准备 v8 数据库失败: %v", err)
|
||||
}
|
||||
|
||||
err := CheckSchema(db)
|
||||
if err == nil || !strings.Contains(err.Error(), "shop_name") {
|
||||
@@ -1152,3 +1201,14 @@ func TestCheckSchema_缺表时拒绝(t *testing.T) {
|
||||
t.Errorf("错误信息应该指出缺的是哪张表,实际: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckSchema_缺少同步记录表时拒绝(t *testing.T) {
|
||||
db := newFreshDB(t)
|
||||
if _, err := db.Exec(`DROP TABLE syb_sync_runs`); err != nil {
|
||||
t.Fatalf("删表失败: %v", err)
|
||||
}
|
||||
err := CheckSchema(db)
|
||||
if err == nil || !strings.Contains(err.Error(), "syb_sync_runs") {
|
||||
t.Fatalf("缺少同步记录表时应拒绝启动并指出表名,实际 %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user