package store_test import ( "context" "database/sql" "os" "testing" "github.com/golang-migrate/migrate/v4" migratepgx "github.com/golang-migrate/migrate/v4/database/pgx/v5" "github.com/golang-migrate/migrate/v4/source/iofs" "github.com/stretchr/testify/require" _ "github.com/jackc/pgx/v5/stdlib" // register the "pgx" database/sql driver ) // fileMigrator builds a golang-migrate instance from the on-disk migration files // (not the embedded FS the production Migrate uses), so a test can step the schema // up and down. os.DirFS(".") is rooted at the package dir; the SQL lives under // "migrations". Mirrors store.Migrate's construction otherwise. func fileMigrator(t *testing.T) *migrate.Migrate { t.Helper() db, err := sql.Open("pgx", dsn) require.NoError(t, err) t.Cleanup(func() { _ = db.Close() }) drv, err := migratepgx.WithInstance(db, &migratepgx.Config{}) require.NoError(t, err) src, err := iofs.New(os.DirFS("."), "migrations") require.NoError(t, err) m, err := migrate.NewWithInstance("iofs", src, "pgx", drv) require.NoError(t, err) t.Cleanup(func() { _, _ = m.Close() }) return m } // loginEventsExists reports whether the login_events relation is present. func loginEventsExists(t *testing.T) bool { t.Helper() var reg *string require.NoError(t, rawPool(t).QueryRow(context.Background(), `SELECT to_regclass('public.login_events')::text`).Scan(®)) return reg != nil } // TestMigration010LoginEventsUpDown proves migration 010 is reversible: the down // migration drops login_events cleanly and the up migration recreates it. A rotten // down migration (forgotten DROP, dangling policy) would fail here rather than in // production during a rollback. The test restores the schema to latest before // returning so the shared embedded-postgres stays at HEAD for sibling tests. func TestMigration010LoginEventsUpDown(t *testing.T) { newStore(t) // ensure the schema is migrated to latest (010 applied) require.True(t, loginEventsExists(t), "login_events must exist at latest migration") m := fileMigrator(t) require.NoError(t, m.Steps(-1), "down one migration must drop login_events") require.False(t, loginEventsExists(t), "login_events must be gone after the down migration") require.NoError(t, m.Steps(1), "up one migration must recreate login_events") require.True(t, loginEventsExists(t), "login_events must be restored after the up migration") }