package db import ( "errors" "io/fs" "kooltap-updateserver/internal/models" "os" "path/filepath" "testing" "github.com/glebarez/sqlite" "gorm.io/gorm" "gorm.io/gorm/logger" ) func openSQLite(t *testing.T, dsn string) *gorm.DB { t.Helper() d, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{Logger: logger.Discard}) if err != nil { t.Fatal(err) } if err := Migrate(d); err != nil { t.Fatal(err) } return d } // target returns the database to import into: Postgres when TEST_DATABASE_URL // is set, otherwise an in-memory SQLite database. func target(t *testing.T) *gorm.DB { t.Helper() if dsn := os.Getenv("TEST_DATABASE_URL"); dsn != "" { d, err := Connect(dsn) if err != nil { t.Fatal(err) } if err := d.Exec("TRUNCATE releases RESTART IDENTITY").Error; err != nil { t.Fatal(err) } return d } return openSQLite(t, "file:"+t.Name()+"?mode=memory&cache=shared") } func TestImportSQLite(t *testing.T) { path := filepath.Join(t.TempDir(), "updater.db") old := openSQLite(t, path) old.Create(&models.Release{Version: "1.0.0", VersionCode: 1, APKFile: "app-1.0.0.apk"}) old.Create(&models.Release{Version: "1.1.0", VersionCode: 2, APKFile: "app-1.1.0.apk", Notes: "fixes"}) old.Delete(&models.Release{}, 1) // leave a gap so IDs must be preserved, not renumbered old.Create(&models.Release{Version: "1.2.0", VersionCode: 3, APKFile: "app-1.2.0.apk", Mandatory: true}) if sqlDB, err := old.DB(); err == nil { sqlDB.Close() } dst := target(t) if err := ImportSQLite(dst, path); err != nil { t.Fatal(err) } var got []models.Release dst.Order("id").Find(&got) if len(got) != 2 || got[0].ID != 2 || got[1].ID != 3 || got[0].Notes != "fixes" || !got[1].Mandatory { t.Fatalf("imported %+v", got) } if _, err := os.Stat(path); !errors.Is(err, fs.ErrNotExist) { t.Fatalf("sqlite file not renamed: %v", err) } if _, err := os.Stat(path + ".imported"); err != nil { t.Fatal(err) } // New rows must not collide with the imported IDs next := models.Release{Version: "1.3.0", VersionCode: 4, APKFile: "app-1.3.0.apk"} if err := dst.Create(&next).Error; err != nil { t.Fatal(err) } if next.ID <= 3 { t.Fatalf("new id %d collides with imported rows", next.ID) } // A missing file is not an error if err := ImportSQLite(dst, path); err != nil { t.Fatal(err) } }