107 lines
3.3 KiB
Go
107 lines
3.3 KiB
Go
package database
|
|
|
|
import (
|
|
"fmt"
|
|
"net/url"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"infinite-canvas/backend/internal/model"
|
|
)
|
|
|
|
func TestPostgresAssetIDMigration(t *testing.T) {
|
|
dsn := strings.TrimSpace(os.Getenv("CANVAS_TEST_POSTGRES_DSN"))
|
|
if dsn == "" {
|
|
t.Skip("CANVAS_TEST_POSTGRES_DSN is not configured")
|
|
}
|
|
|
|
base, err := Open(Config{Driver: "postgres", DSN: dsn})
|
|
if err != nil {
|
|
t.Fatalf("open postgres: %v", err)
|
|
}
|
|
baseSQL, err := base.DB()
|
|
if err != nil {
|
|
t.Fatalf("postgres sql db: %v", err)
|
|
}
|
|
defer baseSQL.Close()
|
|
|
|
schemaName := fmt.Sprintf("asset_id_migration_%d", time.Now().UnixNano())
|
|
if err := base.Exec(`CREATE SCHEMA "` + schemaName + `"`).Error; err != nil {
|
|
t.Fatalf("create test schema: %v", err)
|
|
}
|
|
defer func() {
|
|
if err := base.Exec(`DROP SCHEMA IF EXISTS "` + schemaName + `" CASCADE`).Error; err != nil {
|
|
t.Errorf("drop test schema: %v", err)
|
|
}
|
|
}()
|
|
|
|
testDSN, err := postgresDSNWithSearchPath(dsn, schemaName)
|
|
if err != nil {
|
|
t.Fatalf("test postgres dsn: %v", err)
|
|
}
|
|
db, err := Open(Config{Driver: "postgres", DSN: testDSN})
|
|
if err != nil {
|
|
t.Fatalf("open test schema: %v", err)
|
|
}
|
|
dbSQL, err := db.DB()
|
|
if err != nil {
|
|
t.Fatalf("test schema sql db: %v", err)
|
|
}
|
|
defer dbSQL.Close()
|
|
|
|
for _, statement := range []string{
|
|
`CREATE TABLE assets (id varchar(36) PRIMARY KEY)`,
|
|
`CREATE TABLE project_asset_links (id varchar(36) PRIMARY KEY, asset_id varchar(36))`,
|
|
`CREATE TABLE project_asset_candidates (id varchar(36) PRIMARY KEY, resolved_asset_id varchar(36))`,
|
|
`CREATE TABLE asset_versions (id varchar(36) PRIMARY KEY, asset_id varchar(36))`,
|
|
} {
|
|
if err := db.Exec(statement).Error; err != nil {
|
|
t.Fatalf("create legacy table: %v", err)
|
|
}
|
|
}
|
|
if err := MigrateSchema(db); err != nil {
|
|
t.Fatalf("migrate schema: %v", err)
|
|
}
|
|
|
|
for _, migration := range assetIDColumnMigrations {
|
|
var length int64
|
|
if err := db.Raw(
|
|
"SELECT character_maximum_length FROM information_schema.columns WHERE table_schema = current_schema() AND table_name = ? AND column_name = ?",
|
|
migration.table,
|
|
migration.column,
|
|
).Scan(&length).Error; err != nil {
|
|
t.Fatalf("read migrated column %s.%s: %v", migration.table, migration.column, err)
|
|
}
|
|
if length != model.AssetIDMaxLength {
|
|
t.Fatalf("%s.%s length = %d, want %d", migration.table, migration.column, length, model.AssetIDMaxLength)
|
|
}
|
|
}
|
|
|
|
assetID := "generation_" + strings.Repeat("a", 64)
|
|
if err := db.Create(&model.Asset{ID: assetID, UserID: "user-1", Kind: "image"}).Error; err != nil {
|
|
t.Fatalf("insert deterministic generation asset: %v", err)
|
|
}
|
|
if err := db.Create(&model.ProjectAssetLink{ID: "link-1", ProjectID: "project-1", AssetID: assetID}).Error; err != nil {
|
|
t.Fatalf("insert project asset link: %v", err)
|
|
}
|
|
if err := db.Create(&model.ProjectAssetCandidate{ID: "candidate-1", ProjectID: "project-1", ResolvedAssetID: assetID}).Error; err != nil {
|
|
t.Fatalf("insert project asset candidate: %v", err)
|
|
}
|
|
if err := db.Create(&model.AssetVersion{ID: "version-1", AssetID: assetID, Version: 1}).Error; err != nil {
|
|
t.Fatalf("insert asset version: %v", err)
|
|
}
|
|
}
|
|
|
|
func postgresDSNWithSearchPath(dsn string, schemaName string) (string, error) {
|
|
parsed, err := url.Parse(dsn)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
query := parsed.Query()
|
|
query.Set("search_path", schemaName)
|
|
parsed.RawQuery = query.Encode()
|
|
return parsed.String(), nil
|
|
}
|