diff --git a/sqldb/migrations_test.go b/sqldb/migrations_test.go index 385840364..264b4b5b9 100644 --- a/sqldb/migrations_test.go +++ b/sqldb/migrations_test.go @@ -452,3 +452,129 @@ func TestCustomMigration(t *testing.T) { }) } } + +// TestSchemaMigrationIdempotency tests that the our schema migrations are +// idempotent. This means that we can apply the migrations multiple times and +// the schema version will always be the same. +func TestSchemaMigrationIdempotency(t *testing.T) { + dropMigrationTrackerEntries := func(t *testing.T, db *BaseDB) { + _, err := db.Exec("DELETE FROM migration_tracker;") + require.NoError(t, err) + } + + lastMigration := migrationConfig[len(migrationConfig)-1] + + t.Run("SQLite", func(t *testing.T) { + // First instantiate the database and run the migrations + // including the custom migrations. + t.Logf("Creating new SQLite DB for testing migrations") + + dbFileName := filepath.Join(t.TempDir(), "tmp.db") + var ( + db *SqliteStore + err error + ) + + // Run the migration 3 times to test that the migrations + // are idempotent. + for i := 0; i < 3; i++ { + db, err = NewSqliteStore(&SqliteConfig{ + SkipMigrations: false, + }, dbFileName) + require.NoError(t, err) + + dbToCleanup := db.DB + t.Cleanup(func() { + require.NoError( + t, dbToCleanup.Close(), + ) + }) + + ctxb := context.Background() + require.NoError( + t, db.ApplyAllMigrations(ctxb, GetMigrations()), + ) + + version, dirty, err := db.GetSchemaVersion() + require.NoError(t, err) + + // Now reset the schema version to 0 and make sure that + // we can apply the migrations again. + require.Equal(t, lastMigration.SchemaVersion, version) + require.False(t, dirty) + + require.NoError( + t, db.SetSchemaVersion( + database.NilVersion, false, + ), + ) + dropMigrationTrackerEntries(t, db.BaseDB) + + // Make sure that we reset the schema version. + version, dirty, err = db.GetSchemaVersion() + require.NoError(t, err) + require.Equal(t, -1, version) + require.False(t, dirty) + } + }) + + t.Run("Postgres", func(t *testing.T) { + // First create a temporary Postgres database to run + // the migrations on. + fixture := NewTestPgFixture( + t, DefaultPostgresFixtureLifetime, + ) + t.Cleanup(func() { + fixture.TearDown(t) + }) + + dbName := randomDBName(t) + + // Next instantiate the database and run the migrations + // including the custom migrations. + t.Logf("Creating new Postgres DB '%s' for testing "+ + "migrations", dbName) + + _, err := fixture.db.ExecContext( + context.Background(), "CREATE DATABASE "+dbName, + ) + require.NoError(t, err) + + cfg := fixture.GetConfig(dbName) + var db *PostgresStore + + // Run the migration 3 times to test that the migrations + // are idempotent. + for i := 0; i < 3; i++ { + cfg.SkipMigrations = false + db, err = NewPostgresStore(cfg) + require.NoError(t, err) + + ctxb := context.Background() + require.NoError( + t, db.ApplyAllMigrations(ctxb, GetMigrations()), + ) + + version, dirty, err := db.GetSchemaVersion() + require.NoError(t, err) + + // Now reset the schema version to 0 and make sure that + // we can apply the migrations again. + require.Equal(t, lastMigration.SchemaVersion, version) + require.False(t, dirty) + + require.NoError( + t, db.SetSchemaVersion( + database.NilVersion, false, + ), + ) + dropMigrationTrackerEntries(t, db.BaseDB) + + // Make sure that we reset the schema version. + version, dirty, err = db.GetSchemaVersion() + require.NoError(t, err) + require.Equal(t, -1, version) + require.False(t, dirty) + } + }) +}