73 lines
2.9 KiB
Go
73 lines
2.9 KiB
Go
package database
|
||
|
||
import (
|
||
"strings"
|
||
"testing"
|
||
)
|
||
|
||
func TestMySQLRealProjectMigrationRetry(t *testing.T) {
|
||
fixture := startRealMySQL(t)
|
||
db := fixture.database(t)
|
||
ctx := t.Context()
|
||
if _, err := db.DB.ExecContext(ctx, migrationTableSQL("mysql")); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
for version := 1; version <= 9; version++ {
|
||
if err := applyMigration(ctx, db.DB, "mysql", version); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
}
|
||
if _, err := db.DB.ExecContext(ctx, `INSERT INTO tasks (id, domain_id, task_type, status, message)
|
||
VALUES ('historical-task', 'historical-domain', 'deploy', 'success', '保留历史任务')`); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
// MySQL 的 DDL 不会随事务回滚,必须验证建表后版本登记失败可安全重试。
|
||
var schema string
|
||
if err := db.DB.QueryRowContext(ctx, "SELECT DATABASE()").Scan(&schema); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
schema = "`" + strings.ReplaceAll(schema, "`", "``") + "`"
|
||
// 故障注入仅使用隔离实例管理连接,不给产品连接增加全局权限。
|
||
if _, err := fixture.admin.ExecContext(ctx, `CREATE TRIGGER `+schema+`.fail_project_version BEFORE INSERT ON `+schema+`.schema_migrations
|
||
FOR EACH ROW SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'test-only'`); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if err := Migrate(ctx, db.DB, "mysql"); err == nil {
|
||
t.Fatal("版本登记故障未阻断 MySQL 迁移")
|
||
}
|
||
version, err := currentMigrationVersion(ctx, db.DB)
|
||
if err != nil || version != 9 {
|
||
t.Fatalf("失败迁移错误登记版本:%d,%v", version, err)
|
||
}
|
||
var name string
|
||
if err := db.DB.QueryRowContext(ctx, "SELECT name FROM projects WHERE id = 'default'").Scan(&name); err != nil || name != "默认项目" {
|
||
t.Fatalf("MySQL 部分迁移的默认项目缺失:%q,%v", name, err)
|
||
}
|
||
if _, err := db.DB.ExecContext(ctx, "UPDATE projects SET name = '保留用户调整' WHERE id = 'default'"); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if _, err := fixture.admin.ExecContext(ctx, "DROP TRIGGER "+schema+".fail_project_version"); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
for repeat := 0; repeat < 2; repeat++ {
|
||
if err := Migrate(ctx, db.DB, "mysql"); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
}
|
||
var count int
|
||
if err := db.DB.QueryRowContext(ctx, "SELECT COUNT(*) FROM projects").Scan(&count); err != nil || count != 1 {
|
||
t.Fatalf("重试后项目数量错误:%d,%v", count, err)
|
||
}
|
||
if err := db.DB.QueryRowContext(ctx, "SELECT name FROM projects WHERE id = 'default'").Scan(&name); err != nil || name != "保留用户调整" {
|
||
t.Fatalf("重试覆盖已有默认项目:%q,%v", name, err)
|
||
}
|
||
var message string
|
||
if err := db.DB.QueryRowContext(ctx, "SELECT message FROM tasks WHERE id = 'historical-task'").Scan(&message); err != nil || message != "保留历史任务" {
|
||
t.Fatalf("迁移影响历史任务:%q,%v", message, err)
|
||
}
|
||
version, err = currentMigrationVersion(ctx, db.DB)
|
||
if err != nil || version != latestMigrationVersion {
|
||
t.Fatalf("重试后迁移版本不完整:%d,%v", version, err)
|
||
}
|
||
}
|