diff options
Diffstat (limited to 'doc/development/testing_guide/testing_migrations_guide.md')
-rw-r--r-- | doc/development/testing_guide/testing_migrations_guide.md | 173 |
1 files changed, 113 insertions, 60 deletions
diff --git a/doc/development/testing_guide/testing_migrations_guide.md b/doc/development/testing_guide/testing_migrations_guide.md index 757a70fb4e0..4092c1a2f6d 100644 --- a/doc/development/testing_guide/testing_migrations_guide.md +++ b/doc/development/testing_guide/testing_migrations_guide.md @@ -38,7 +38,7 @@ ensures proper isolation. ## Testing an `ActiveRecord::Migration` class -To test an `ActiveRecord::Migration` class (i.e., a +To test an `ActiveRecord::Migration` class (for example, a regular migration `db/migrate` or a post-migration `db/post_migrate`), you must load the migration file by using the `require_migration!` helper method because it is not autoloaded by Rails. @@ -61,14 +61,35 @@ Since the migration files are not autoloaded by Rails, you must manually load the migration file. To do so, you can use the `require_migration!` helper method which can automatically load the correct migration file based on the spec filename. -For example, if your spec file is named as `populate_foo_column_spec.rb` then the -helper method tries to load `${schema_version}_populate_foo_column.rb` migration file. +In GitLab 14.4 and later, you can use `require_migration!` to load migration files from spec files +that contain the schema version in the filename (for example, +`2021101412150000_populate_foo_column_spec.rb`). -In case there is no pattern between your spec file and the actual migration file, -you can provide the migration filename without the schema version, like so: +```ruby +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe PopulateFooColumn do + ... +end +``` + +In some cases, you must require multiple migration files to use them in your specs. Here, there's no +pattern between your spec file and the other migration file. You can provide the migration filename +like so: ```ruby -require_migration!('populate_foo_column') +# frozen_string_literal: true + +require 'spec_helper' +require_migration! +require_migration!('populate_bar_column') + +RSpec.describe PopulateFooColumn do + ... +end ``` #### `table` @@ -213,54 +234,65 @@ Migration tests depend on what the migration does exactly, the most common types #### Example of a data migration test This spec tests the -[`db/post_migrate/20170526185842_migrate_pipeline_stages.rb`](https://gitlab.com/gitlab-org/gitlab-foss/blob/v11.6.5/db/post_migrate/20170526185842_migrate_pipeline_stages.rb) +[`db/post_migrate/20200723040950_migrate_incident_issues_to_incident_type.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/db/post_migrate/20200723040950_migrate_incident_issues_to_incident_type.rb) migration. You can find the complete spec in -[`spec/migrations/migrate_pipeline_stages_spec.rb`](https://gitlab.com/gitlab-org/gitlab-foss/blob/v11.6.5/spec/migrations/migrate_pipeline_stages_spec.rb). +[`spec/migrations/migrate_incident_issues_to_incident_type_spec.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/spec/migrations/migrate_incident_issues_to_incident_type_spec.rb). ```ruby -require 'spec_helper' +# frozen_string_literal: true +require 'spec_helper' require_migration! -RSpec.describe MigratePipelineStages do - # Create test data - pipeline and CI/CD jobs. - let(:jobs) { table(:ci_builds) } - let(:stages) { table(:ci_stages) } - let(:pipelines) { table(:ci_pipelines) } +RSpec.describe MigrateIncidentIssuesToIncidentType do + let(:migration) { described_class.new } + let(:projects) { table(:projects) } + let(:namespaces) { table(:namespaces) } + let(:labels) { table(:labels) } + let(:issues) { table(:issues) } + let(:label_links) { table(:label_links) } + let(:label_props) { IncidentManagement::CreateIncidentLabelService::LABEL_PROPERTIES } + + let(:namespace) { namespaces.create!(name: 'foo', path: 'foo') } + let!(:project) { projects.create!(namespace_id: namespace.id) } + let(:label) { labels.create!(project_id: project.id, **label_props) } + let!(:incident_issue) { issues.create!(project_id: project.id) } + let!(:other_issue) { issues.create!(project_id: project.id) } + + # Issue issue_type enum + let(:issue_type) { 0 } + let(:incident_type) { 1 } before do - projects.create!(id: 123, name: 'gitlab1', path: 'gitlab1') - pipelines.create!(id: 1, project_id: 123, ref: 'master', sha: 'adf43c3a') - jobs.create!(id: 1, commit_id: 1, project_id: 123, stage_idx: 2, stage: 'build') - jobs.create!(id: 2, commit_id: 1, project_id: 123, stage_idx: 1, stage: 'test') + label_links.create!(target_id: incident_issue.id, label_id: label.id, target_type: 'Issue') end - # Test just the up migration. - it 'correctly migrates pipeline stages' do - expect(stages.count).to be_zero - - migrate! + describe '#up' do + it 'updates the incident issue type' do + expect { migrate! } + .to change { incident_issue.reload.issue_type } + .from(issue_type) + .to(incident_type) - expect(stages.count).to eq 2 - expect(stages.all.pluck(:name)).to match_array %w[test build] + expect(other_issue.reload.issue_type).to eql(issue_type) + end 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] - } + describe '#down' do + let!(:incident_issue) { issues.create!(project_id: project.id, issue_type: issue_type) } + + it 'updates the incident issue type' do + migration.up + + expect { migration.down } + .to change { incident_issue.reload.issue_type } + .from(incident_type) + .to(issue_type) + + expect(other_issue.reload.issue_type).to eql(issue_type) end + end end ``` @@ -336,41 +368,62 @@ end ### Example background migration test This spec tests the -[`lib/gitlab/background_migration/archive_legacy_traces.rb`](https://gitlab.com/gitlab-org/gitlab-foss/blob/v11.6.5/lib/gitlab/background_migration/archive_legacy_traces.rb) +[`lib/gitlab/background_migration/backfill_draft_status_on_merge_requests.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/background_migration/backfill_draft_status_on_merge_requests.rb) background migration. You can find the complete spec on -[`spec/lib/gitlab/background_migration/archive_legacy_traces_spec.rb`](https://gitlab.com/gitlab-org/gitlab-foss/blob/v11.6.5/spec/lib/gitlab/background_migration/archive_legacy_traces_spec.rb) +[`spec/lib/gitlab/background_migration/backfill_draft_status_on_merge_requests_spec.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/spec/lib/gitlab/background_migration/backfill_draft_status_on_merge_requests_spec.rb) ```ruby +# frozen_string_literal: true + require 'spec_helper' -describe Gitlab::BackgroundMigration::ArchiveLegacyTraces, schema: 20180529152628 do - include TraceHelpers +RSpec.describe Gitlab::BackgroundMigration::BackfillDraftStatusOnMergeRequests do + let(:namespaces) { table(:namespaces) } + let(:projects) { table(:projects) } + let(:merge_requests) { table(:merge_requests) } - let(:namespaces) { table(:namespaces) } - let(:projects) { table(:projects) } - let(:builds) { table(:ci_builds) } - let(:job_artifacts) { table(:ci_job_artifacts) } + let(:group) { namespaces.create!(name: 'gitlab', path: 'gitlab') } + let(:project) { projects.create!(namespace_id: group.id) } - before do - namespaces.create!(id: 123, name: 'gitlab1', path: 'gitlab1') - projects.create!(id: 123, name: 'gitlab1', path: 'gitlab1', namespace_id: 123) - @build = builds.create!(id: 1, project_id: 123, status: 'success', type: 'Ci::Build') + let(:draft_prefixes) { ["[Draft]", "(Draft)", "Draft:", "Draft", "[WIP]", "WIP:", "WIP"] } + + def create_merge_request(params) + common_params = { + target_project_id: project.id, + target_branch: 'feature1', + source_branch: 'master' + } + + merge_requests.create!(common_params.merge(params)) end - context 'when trace file exists at the right place' do + context "for MRs with #draft? == true titles but draft attribute false" do + let(:mr_ids) { merge_requests.all.collect(&:id) } + before do - create_legacy_trace(@build, 'trace in file') + draft_prefixes.each do |prefix| + (1..4).each do |n| + create_merge_request( + title: "#{prefix} This is a title", + draft: false, + state_id: n + ) + end + end end - it 'correctly archive legacy traces' do - expect(job_artifacts.count).to eq(0) - expect(File.exist?(legacy_trace_path(@build))).to be_truthy + it "updates all open draft merge request's draft field to true" do + mr_count = merge_requests.all.count + + expect { subject.perform(mr_ids.first, mr_ids.last) } + .to change { MergeRequest.where(draft: false).count } + .from(mr_count).to(mr_count - draft_prefixes.length) + end - described_class.new.perform(1, 1) + it "marks successful slices as completed" do + expect(subject).to receive(:mark_job_as_succeeded).with(mr_ids.first, mr_ids.last) - expect(job_artifacts.count).to eq(1) - expect(File.exist?(legacy_trace_path(@build))).to be_falsy - expect(File.read(archived_trace_path(job_artifacts.first))).to eq('trace in file') + subject.perform(mr_ids.first, mr_ids.last) end end end |