Scert/backend/internal/database/project_migration_test.go
xuans 7284958819 完善域名服务器项目归属与数据库关联约束
保存资源项目、所有者和操作人,接口从会话记录归属,普通更新保留创建信息。
新增三库第十一版迁移、同项目绑定约束和 SQLite 触发器保护,补充迁移回滚重试、仓储、接口及备份恢复测试。
本次整理验证:后端构建、静态检查、关联改造针对性测试和 CLI 包测试通过。
范围说明:项目成员权限及其他资源归属尚未完成;本次未重新执行外部数据库实库、独立程序及生产部署验收。
2026-09-28 10:45:00 +08:00

79 lines
3.0 KiB
Go
Raw Permalink 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 database
import (
"testing"
)
func TestSQLiteProjectMigrationPreservesBusiness(t *testing.T) {
db, err := Open(t.Context(), sqliteBusinessUpgradeConfig(t))
if err != nil {
t.Fatal(err)
}
defer db.Close()
createSQLiteHistoricalBusiness(t, db.DB, 9)
before := snapshotSQLiteHistoricalBusiness(t, db.DB)
if err := applyMigration(t.Context(), db.DB, "sqlite", 10); err != nil {
t.Fatal(err)
}
assertSQLiteHistoricalBusiness(t, db.DB, before)
var name string
if err := db.DB.QueryRowContext(t.Context(), "SELECT name FROM projects WHERE id = 'default'").Scan(&name); err != nil || name != "默认项目" {
t.Fatalf("默认项目未创建:%q,%v", name, err)
}
if _, err := db.DB.ExecContext(t.Context(), "UPDATE projects SET name = '调整后的默认项目' WHERE id = 'default'"); err != nil {
t.Fatal(err)
}
// 模拟建表、种子写入已成功,但版本记录尚未落盘的可重试情况。
if _, err := db.DB.ExecContext(t.Context(), "DELETE FROM schema_migrations WHERE version = 10"); err != nil {
t.Fatal(err)
}
for round := 0; round < 2; round++ {
if err := Migrate(t.Context(), db.DB, "sqlite"); err != nil {
t.Fatal(err)
}
}
var count int
if err := db.DB.QueryRowContext(t.Context(), "SELECT COUNT(*) FROM projects").Scan(&count); err != nil || count != 1 {
t.Fatalf("重复迁移改变项目数量:%d,%v", count, err)
}
if err := db.DB.QueryRowContext(t.Context(), "SELECT name FROM projects WHERE id = 'default'").Scan(&name); err != nil || name != "调整后的默认项目" {
t.Fatalf("重复迁移覆盖用户修改:%q,%v", name, err)
}
assertSQLiteHistoricalBusiness(t, db.DB, before)
}
func TestSQLiteProjectMigrationRollsBackAndRetries(t *testing.T) {
db, err := Open(t.Context(), sqliteBusinessUpgradeConfig(t))
if err != nil {
t.Fatal(err)
}
defer db.Close()
createSQLiteHistoricalBusiness(t, db.DB, 9)
before := snapshotSQLiteHistoricalBusiness(t, db.DB)
// 在登记版本时制造失败,验证同一事务中的新表及默认项目也会回滚。
_, err = db.DB.ExecContext(t.Context(), `CREATE TRIGGER fail_project_version BEFORE INSERT ON schema_migrations
WHEN NEW.version = 10 BEGIN SELECT RAISE(ABORT, 'test-only'); END`)
if err != nil {
t.Fatal(err)
}
if err := Migrate(t.Context(), db.DB, "sqlite"); err == nil {
t.Fatal("版本登记故障未阻断迁移")
}
version, err := currentMigrationVersion(t.Context(), db.DB)
if err != nil || version != 9 {
t.Fatalf("失败迁移错误登记版本:%d,%v", version, err)
}
var count int
if err := db.DB.QueryRowContext(t.Context(), "SELECT COUNT(*) FROM sqlite_master WHERE name = 'projects'").Scan(&count); err != nil || count != 0 {
t.Fatalf("失败迁移未回滚项目表:%d,%v", count, err)
}
assertSQLiteHistoricalBusiness(t, db.DB, before)
if _, err := db.DB.ExecContext(t.Context(), "DROP TRIGGER fail_project_version"); err != nil {
t.Fatal(err)
}
if err := Migrate(t.Context(), db.DB, "sqlite"); err != nil {
t.Fatal(err)
}
assertSQLiteHistoricalBusiness(t, db.DB, before)
}