Commit 28abc4fc authored by Luke Duncalfe's avatar Luke Duncalfe Committed by Mayra Cabrera

Adding reversible_migration migration helper

Can be used to test the reversibility of migrations.
parent 46db8bf1
......@@ -44,6 +44,10 @@ autoloaded with Rails. Example:
require Rails.root.join('db', 'post_migrate', '20170526185842_migrate_pipeline_stages.rb')
```
### Test helpers
#### `table`
Use the `table` helper to create a temporary `ActiveRecord::Base`-derived model
for a table. [FactoryBot](https://docs.gitlab.com/ee/development/testing_guide/best_practices.html#factories)
**should not** be used to create data for migration specs. For example, to
......@@ -53,6 +57,8 @@ create a record in the `projects` table:
project = table(:projects).create!(id: 1, name: 'gitlab1', path: 'gitlab1')
```
#### `migrate!`
Use the `migrate!` helper to run the migration that is under test. It will not only
run the migration, but will also bump the schema version in the `schema_migrations`
table. It is necessary because in the `after` hook we trigger the rest of
......@@ -68,6 +74,33 @@ it 'migrates successfully' do
end
```
#### `reversible_migration`
Use the `reversible_migration` helper to test migrations with either a
`change` or both `up` and `down` hooks. This will test that the state of
the application and its data after the migration becomes reversed is the
same as it was before the migration ran in the first place. The helper:
1. Runs the `before` expectations before the **up** migration.
1. Migrates **up**.
1. Runs the `after` expectations.
1. Migrates **down**.
1. Runs the `before` expectations a second time.
Example:
```ruby
reversible_migration do |migration|
migration.before -> {
# ... pre-migration expectations
}
migration.after -> {
# ... post-migration expectations
}
end
```
### Example database migration test
This spec tests the
......@@ -93,7 +126,7 @@ describe MigratePipelineStages, :migration do
jobs.create!(id: 2, commit_id: 1, project_id: 123, stage_idx: 1, stage: 'test')
end
# Test the up migration.
# Test just the up migration.
it 'correctly migrates pipeline stages' do
expect(stages.count).to be_zero
......@@ -102,6 +135,22 @@ describe MigratePipelineStages, :migration do
expect(stages.count).to eq 2
expect(stages.all.pluck(:name)).to match_array %w[test build]
end
# Test a reversible migration.
it 'correctly migrates up and down pipeline stages' do
reversible_migration do |migration|
# Expectations will run before the up migration,
# and then again after the down migration
migration.before -> {
expect(stages.count).to be_zero
}
# Expectations will run after the up migration.
migration.after -> {
expect(stages.count).to eq 2
expect(stages.all.pluck(:name)).to match_array %w[test build]
}
end
end
```
......
......@@ -132,6 +132,41 @@ module MigrationsHelpers
migration.name == described_class.name
end
end
class ReversibleMigrationTest
attr_reader :before_up, :after_up
def initialize
@before_up = -> {}
@after_up = -> {}
end
def before(expectations)
@before_up = expectations
self
end
def after(expectations)
@after_up = expectations
self
end
end
def reversible_migration(&block)
tests = yield(ReversibleMigrationTest.new)
tests.before_up.call
migrate!
tests.after_up.call
schema_migrate_down!
tests.before_up.call
end
end
MigrationsHelpers.prepend_if_ee('EE::MigrationsHelpers')
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment