88 lines
3.9 KiB
Go
88 lines
3.9 KiB
Go
package models
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/glebarez/sqlite"
|
|
"github.com/stretchr/testify/require"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
func TestAutoMigrateUpgradesLegacyProjectsAndTagsWithoutLosingAssociations(t *testing.T) {
|
|
database, err := gorm.Open(sqlite.Open(fmt.Sprintf("file:%s?mode=memory&cache=shared", t.Name())), &gorm.Config{TranslateError: true})
|
|
require.NoError(t, err)
|
|
|
|
legacySchema := []string{
|
|
`CREATE TABLE senlin_agent_projects (id integer primary key, owner_id integer not null, name text not null, identifier text)`,
|
|
`CREATE TABLE senlin_agent_tags (id integer primary key, identity text, project_id integer not null, name text not null)`,
|
|
`CREATE TABLE senlin_agent_tasks (id integer primary key, project_id integer not null, created_by integer not null, tag_id integer, tag_identity text, title text not null, status text not null)`,
|
|
`INSERT INTO senlin_agent_projects (id, owner_id, name, identifier) VALUES
|
|
(1, 7, 'Blank one', ''),
|
|
(2, 7, 'Blank two', NULL),
|
|
(3, 7, 'Keeper', 'DUP'),
|
|
(4, 7, 'Duplicate', 'DUP'),
|
|
(5, 7, 'Reserved suffix', 'DUP-4'),
|
|
(6, 8, 'Other owner', 'DUP')`,
|
|
`INSERT INTO senlin_agent_tags (id, identity, project_id, name) VALUES
|
|
(10, 'tag-keeper', 1, 'UI'),
|
|
(11, 'tag-duplicate', 1, 'UI'),
|
|
(12, 'tag-other-project', 2, 'UI')`,
|
|
`INSERT INTO senlin_agent_tasks (id, project_id, created_by, tag_id, tag_identity, title, status)
|
|
VALUES (20, 1, 7, 11, 'tag-duplicate', 'Keep association', 'open')`,
|
|
}
|
|
for _, statement := range legacySchema {
|
|
require.NoError(t, database.Exec(statement).Error)
|
|
}
|
|
|
|
// PostgreSQL migrations run through database.Connection, whose callback DB can
|
|
// carry an initialized Gorm statement. Exercise that mode so model state from
|
|
// the migration-version lookup cannot leak into the data-repair transaction.
|
|
require.NoError(t, AutoMigrate(database.Session(&gorm.Session{Initialized: true})))
|
|
|
|
var projects []SenlinAgentProject
|
|
require.NoError(t, database.Order("id asc").Find(&projects).Error)
|
|
require.Len(t, projects, 6, "项目迁移不得删除 legacy 行")
|
|
require.Equal(t, []string{"project-1", "project-2", "DUP", "DUP-4-2", "DUP-4", "DUP"}, projectIdentifiers(projects))
|
|
|
|
var tags []SenlinAgentTag
|
|
require.NoError(t, database.Order("id asc").Find(&tags).Error)
|
|
require.Equal(t, []uint{10, 12}, tagIDs(tags), "同项目同名标签应保留最早记录,不影响其他项目")
|
|
var task SenlinAgentTask
|
|
require.NoError(t, database.First(&task, 20).Error)
|
|
require.NotNil(t, task.TagID)
|
|
require.Equal(t, uint(10), *task.TagID)
|
|
require.NotNil(t, task.TagIdentity)
|
|
require.Equal(t, "tag-keeper", *task.TagIdentity)
|
|
|
|
var migrationCount int64
|
|
require.NoError(t, database.Table("senlin_agent_schema_migrations").Count(&migrationCount).Error)
|
|
require.Equal(t, int64(2), migrationCount)
|
|
var auditDetails []string
|
|
require.NoError(t, database.Table("senlin_agent_schema_migrations").Order("version asc").Pluck("details", &auditDetails).Error)
|
|
require.Contains(t, auditDetails[0], `"updated":3`)
|
|
require.Contains(t, auditDetails[1], `"deduplicated":1`)
|
|
require.NoError(t, AutoMigrate(database), "versioned migrations must be safe to run again")
|
|
require.NoError(t, database.Table("senlin_agent_schema_migrations").Count(&migrationCount).Error)
|
|
require.Equal(t, int64(2), migrationCount)
|
|
|
|
require.Error(t, database.Exec(`INSERT INTO senlin_agent_projects (owner_id, name, identifier) VALUES (7, 'still duplicate', 'DUP')`).Error)
|
|
require.Error(t, database.Exec(`INSERT INTO senlin_agent_tags (project_id, name) VALUES (1, 'UI')`).Error)
|
|
}
|
|
|
|
func projectIdentifiers(projects []SenlinAgentProject) []string {
|
|
result := make([]string, 0, len(projects))
|
|
for _, project := range projects {
|
|
result = append(result, project.Identifier)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func tagIDs(tags []SenlinAgentTag) []uint {
|
|
result := make([]uint, 0, len(tags))
|
|
for _, tag := range tags {
|
|
result = append(result, tag.ID)
|
|
}
|
|
return result
|
|
}
|