package main import ( "os" "path/filepath" "testing" "github.com/glebarez/sqlite" "gorm.io/gorm" ) func openMigrationTestDB(t *testing.T) *gorm.DB { t.Helper() db, err := gorm.Open(sqlite.Open(filepath.Join(t.TempDir(), "migration.db")), &gorm.Config{}) if err != nil { t.Fatal(err) } return db } func TestMigrateDatabaseLegacySchema(t *testing.T) { db := openMigrationTestDB(t) if err := db.Exec(`CREATE TABLE tasks ( id integer PRIMARY KEY AUTOINCREMENT, source text, r_id text, title text, artist text, album text, pic text, quality text, format text, status text, error text, local_path text, remote_path text, created_at datetime, updated_at datetime, total_bytes integer, downloaded_bytes integer, progress real, resolved_quality text, actual_quality text )`).Error; err != nil { t.Fatal(err) } if err := db.Exec("CREATE UNIQUE INDEX idx_tasks_source_rid_quality ON tasks(source, r_id, quality)").Error; err != nil { t.Fatal(err) } if err := db.Exec("INSERT INTO tasks(source,r_id,quality,status) VALUES('kw','legacy-1','standard','done')").Error; err != nil { t.Fatal(err) } if err := migrateDatabase(db); err != nil { t.Fatal(err) } var task Task if err := db.First(&task).Error; err != nil { t.Fatal(err) } if task.UserID != 0 { t.Fatalf("legacy task user id = %d, want 0 before bootstrap", task.UserID) } var indexes []struct{ Name string } if err := db.Raw("SELECT name FROM sqlite_master WHERE type='index' AND tbl_name='tasks'").Scan(&indexes).Error; err != nil { t.Fatal(err) } found := false for _, idx := range indexes { if idx.Name == "idx_tasks_user_source_rid_quality" { found = true } if idx.Name == "idx_tasks_source_rid_quality" { t.Fatalf("legacy global task index still exists") } } if !found { t.Fatalf("scoped task index not created") } } func TestBackfillMediaAssetsLinksExistingFiles(t *testing.T) { db := openMigrationTestDB(t) if err := migrateDatabase(db); err != nil { t.Fatal(err) } dir := t.TempDir() path := filepath.Join(dir, "Artist - Title.mp3") if err := os.WriteFile(path, []byte("audio"), 0644); err != nil { t.Fatal(err) } task := Task{UserID: 1, Source: "kw", RID: "rid-1", Title: "Title", Artist: "Artist", Quality: "standard", Format: "mp3", Status: "done", LocalPath: path} if err := db.Create(&task).Error; err != nil { t.Fatal(err) } if err := backfillMediaAssets(db, dir); err != nil { t.Fatal(err) } var asset MediaAsset if err := db.Where("asset_key = ?", assetKey(task.Source, task.RID, task.Quality)).First(&asset).Error; err != nil { t.Fatal(err) } if asset.Status != "done" || asset.LocalPath != path || asset.Size != int64(len("audio")) { t.Fatalf("unexpected asset: %+v", asset) } var got Task if err := db.First(&got, task.ID).Error; err != nil { t.Fatal(err) } if got.AssetID != asset.ID { t.Fatalf("task asset id = %d, want %d", got.AssetID, asset.ID) } }