diff options
Diffstat (limited to 'spec/lib/gitlab/background_migration')
50 files changed, 1095 insertions, 1214 deletions
diff --git a/spec/lib/gitlab/background_migration/add_modified_to_approval_merge_request_rule_spec.rb b/spec/lib/gitlab/background_migration/add_modified_to_approval_merge_request_rule_spec.rb index 81b8b5dde08..0b29163671c 100644 --- a/spec/lib/gitlab/background_migration/add_modified_to_approval_merge_request_rule_spec.rb +++ b/spec/lib/gitlab/background_migration/add_modified_to_approval_merge_request_rule_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::AddModifiedToApprovalMergeRequestRule, schema: 20200817195628 do +RSpec.describe Gitlab::BackgroundMigration::AddModifiedToApprovalMergeRequestRule, schema: 20181228175414 do let(:determine_if_rules_are_modified) { described_class.new } let(:namespace) { table(:namespaces).create!(name: 'gitlab', path: 'gitlab') } diff --git a/spec/lib/gitlab/background_migration/add_primary_email_to_emails_if_user_confirmed_spec.rb b/spec/lib/gitlab/background_migration/add_primary_email_to_emails_if_user_confirmed_spec.rb new file mode 100644 index 00000000000..b50a55a9e41 --- /dev/null +++ b/spec/lib/gitlab/background_migration/add_primary_email_to_emails_if_user_confirmed_spec.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::BackgroundMigration::AddPrimaryEmailToEmailsIfUserConfirmed do + let(:users) { table(:users) } + let(:emails) { table(:emails) } + + let!(:unconfirmed_user) { users.create!(name: 'unconfirmed', email: 'unconfirmed@example.com', confirmed_at: nil, projects_limit: 100) } + let!(:confirmed_user_1) { users.create!(name: 'confirmed-1', email: 'confirmed-1@example.com', confirmed_at: 1.day.ago, projects_limit: 100) } + let!(:confirmed_user_2) { users.create!(name: 'confirmed-2', email: 'confirmed-2@example.com', confirmed_at: 1.day.ago, projects_limit: 100) } + let!(:email) { emails.create!(user_id: confirmed_user_1.id, email: 'confirmed-1@example.com', confirmed_at: 1.day.ago) } + + let(:perform) { described_class.new.perform(users.first.id, users.last.id) } + + it 'adds the primary email of confirmed users to Emails, unless already added', :aggregate_failures do + expect(emails.where(email: [unconfirmed_user.email, confirmed_user_2.email])).to be_empty + + expect { perform }.not_to raise_error + + expect(emails.where(email: unconfirmed_user.email).count).to eq(0) + expect(emails.where(email: confirmed_user_1.email, user_id: confirmed_user_1.id).count).to eq(1) + expect(emails.where(email: confirmed_user_2.email, user_id: confirmed_user_2.id).count).to eq(1) + + email_2 = emails.find_by(email: confirmed_user_2.email, user_id: confirmed_user_2.id) + expect(email_2.confirmed_at).to eq(confirmed_user_2.reload.confirmed_at) + end + + it 'sets timestamps on the created Emails' do + perform + + email_2 = emails.find_by(email: confirmed_user_2.email, user_id: confirmed_user_2.id) + + expect(email_2.created_at).not_to be_nil + expect(email_2.updated_at).not_to be_nil + end + + context 'when a range of IDs is specified' do + let!(:confirmed_user_3) { users.create!(name: 'confirmed-3', email: 'confirmed-3@example.com', confirmed_at: 1.hour.ago, projects_limit: 100) } + let!(:confirmed_user_4) { users.create!(name: 'confirmed-4', email: 'confirmed-4@example.com', confirmed_at: 1.hour.ago, projects_limit: 100) } + + it 'only acts on the specified range of IDs', :aggregate_failures do + expect do + described_class.new.perform(confirmed_user_2.id, confirmed_user_3.id) + end.to change { Email.count }.by(2) + expect(emails.where(email: confirmed_user_4.email).count).to eq(0) + end + end +end diff --git a/spec/lib/gitlab/background_migration/backfill_artifact_expiry_date_spec.rb b/spec/lib/gitlab/background_migration/backfill_artifact_expiry_date_spec.rb index 49fa7b41916..6ab1e3ecd70 100644 --- a/spec/lib/gitlab/background_migration/backfill_artifact_expiry_date_spec.rb +++ b/spec/lib/gitlab/background_migration/backfill_artifact_expiry_date_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::BackfillArtifactExpiryDate, :migration, schema: 20201111152859 do +RSpec.describe Gitlab::BackgroundMigration::BackfillArtifactExpiryDate, :migration, schema: 20181228175414 do subject(:perform) { migration.perform(1, 99) } let(:migration) { described_class.new } diff --git a/spec/lib/gitlab/background_migration/backfill_deployment_clusters_from_deployments_spec.rb b/spec/lib/gitlab/background_migration/backfill_deployment_clusters_from_deployments_spec.rb index 54c14e7a4b8..1404ada3647 100644 --- a/spec/lib/gitlab/background_migration/backfill_deployment_clusters_from_deployments_spec.rb +++ b/spec/lib/gitlab/background_migration/backfill_deployment_clusters_from_deployments_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::BackfillDeploymentClustersFromDeployments, :migration, schema: 20200227140242 do +RSpec.describe Gitlab::BackgroundMigration::BackfillDeploymentClustersFromDeployments, :migration, schema: 20181228175414 do subject { described_class.new } describe '#perform' do diff --git a/spec/lib/gitlab/background_migration/backfill_design_internal_ids_spec.rb b/spec/lib/gitlab/background_migration/backfill_design_internal_ids_spec.rb deleted file mode 100644 index 4bf59a02a31..00000000000 --- a/spec/lib/gitlab/background_migration/backfill_design_internal_ids_spec.rb +++ /dev/null @@ -1,69 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Gitlab::BackgroundMigration::BackfillDesignInternalIds, :migration, schema: 20201030203854 do - subject { described_class.new(designs) } - - let_it_be(:namespaces) { table(:namespaces) } - let_it_be(:projects) { table(:projects) } - let_it_be(:designs) { table(:design_management_designs) } - - let(:namespace) { namespaces.create!(name: 'foo', path: 'foo') } - let(:project) { projects.create!(namespace_id: namespace.id) } - let(:project_2) { projects.create!(namespace_id: namespace.id) } - - def create_design!(proj = project) - designs.create!(project_id: proj.id, filename: generate(:filename)) - end - - def migrate! - relation = designs.where(project_id: [project.id, project_2.id]).select(:project_id).distinct - - subject.perform(relation) - end - - it 'backfills the iid for designs' do - 3.times { create_design! } - - expect do - migrate! - end.to change { designs.pluck(:iid) }.from(contain_exactly(nil, nil, nil)).to(contain_exactly(1, 2, 3)) - end - - it 'scopes IIDs and handles range and starting-point correctly' do - create_design!.update!(iid: 10) - create_design!.update!(iid: 12) - create_design!(project_2).update!(iid: 7) - project_3 = projects.create!(namespace_id: namespace.id) - - 2.times { create_design! } - 2.times { create_design!(project_2) } - 2.times { create_design!(project_3) } - - migrate! - - expect(designs.where(project_id: project.id).pluck(:iid)).to contain_exactly(10, 12, 13, 14) - expect(designs.where(project_id: project_2.id).pluck(:iid)).to contain_exactly(7, 8, 9) - expect(designs.where(project_id: project_3.id).pluck(:iid)).to contain_exactly(nil, nil) - end - - it 'updates the internal ID records' do - design = create_design! - 2.times { create_design! } - design.update!(iid: 10) - scope = { project_id: project.id } - usage = :design_management_designs - init = ->(_d, _s) { 0 } - - ::InternalId.track_greatest(design, scope, usage, 10, init) - - migrate! - - next_iid = ::InternalId.generate_next(design, scope, usage, init) - - expect(designs.pluck(:iid)).to contain_exactly(10, 11, 12) - expect(design.reload.iid).to eq(10) - expect(next_iid).to eq(13) - end -end diff --git a/spec/lib/gitlab/background_migration/backfill_environment_id_deployment_merge_requests_spec.rb b/spec/lib/gitlab/background_migration/backfill_environment_id_deployment_merge_requests_spec.rb index 550bdc484c9..9194525e713 100644 --- a/spec/lib/gitlab/background_migration/backfill_environment_id_deployment_merge_requests_spec.rb +++ b/spec/lib/gitlab/background_migration/backfill_environment_id_deployment_merge_requests_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::BackfillEnvironmentIdDeploymentMergeRequests, schema: 20200312134637 do +RSpec.describe Gitlab::BackgroundMigration::BackfillEnvironmentIdDeploymentMergeRequests, schema: 20181228175414 do let(:environments) { table(:environments) } let(:merge_requests) { table(:merge_requests) } let(:deployments) { table(:deployments) } diff --git a/spec/lib/gitlab/background_migration/backfill_jira_tracker_deployment_type2_spec.rb b/spec/lib/gitlab/background_migration/backfill_jira_tracker_deployment_type2_spec.rb index 58864aac084..446d62bbd2a 100644 --- a/spec/lib/gitlab/background_migration/backfill_jira_tracker_deployment_type2_spec.rb +++ b/spec/lib/gitlab/background_migration/backfill_jira_tracker_deployment_type2_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::BackfillJiraTrackerDeploymentType2, :migration, schema: 20201028182809 do +RSpec.describe Gitlab::BackgroundMigration::BackfillJiraTrackerDeploymentType2, :migration, schema: 20181228175414 do let_it_be(:jira_integration_temp) { described_class::JiraServiceTemp } let_it_be(:jira_tracker_data_temp) { described_class::JiraTrackerDataTemp } let_it_be(:atlassian_host) { 'https://api.atlassian.net' } diff --git a/spec/lib/gitlab/background_migration/backfill_merge_request_cleanup_schedules_spec.rb b/spec/lib/gitlab/background_migration/backfill_merge_request_cleanup_schedules_spec.rb index c2daa35703d..d33f52514da 100644 --- a/spec/lib/gitlab/background_migration/backfill_merge_request_cleanup_schedules_spec.rb +++ b/spec/lib/gitlab/background_migration/backfill_merge_request_cleanup_schedules_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::BackfillMergeRequestCleanupSchedules, schema: 20201103110018 do +RSpec.describe Gitlab::BackgroundMigration::BackfillMergeRequestCleanupSchedules, schema: 20181228175414 do let(:merge_requests) { table(:merge_requests) } let(:cleanup_schedules) { table(:merge_request_cleanup_schedules) } let(:metrics) { table(:merge_request_metrics) } diff --git a/spec/lib/gitlab/background_migration/backfill_namespace_settings_spec.rb b/spec/lib/gitlab/background_migration/backfill_namespace_settings_spec.rb index 43e76a2952e..0f8adca2ca4 100644 --- a/spec/lib/gitlab/background_migration/backfill_namespace_settings_spec.rb +++ b/spec/lib/gitlab/background_migration/backfill_namespace_settings_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::BackfillNamespaceSettings, schema: 20200703125016 do +RSpec.describe Gitlab::BackgroundMigration::BackfillNamespaceSettings, schema: 20181228175414 do let(:namespaces) { table(:namespaces) } let(:namespace_settings) { table(:namespace_settings) } let(:namespace) { table(:namespaces).create!(name: 'user', path: 'user') } diff --git a/spec/lib/gitlab/background_migration/backfill_project_settings_spec.rb b/spec/lib/gitlab/background_migration/backfill_project_settings_spec.rb index 48c5674822a..e6b0db2ab73 100644 --- a/spec/lib/gitlab/background_migration/backfill_project_settings_spec.rb +++ b/spec/lib/gitlab/background_migration/backfill_project_settings_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::BackfillProjectSettings, schema: 20200114113341 do +RSpec.describe Gitlab::BackgroundMigration::BackfillProjectSettings, schema: 20181228175414 do let(:projects) { table(:projects) } let(:project_settings) { table(:project_settings) } let(:namespace) { table(:namespaces).create!(name: 'user', path: 'user') } diff --git a/spec/lib/gitlab/background_migration/backfill_push_rules_id_in_projects_spec.rb b/spec/lib/gitlab/background_migration/backfill_push_rules_id_in_projects_spec.rb index 9ce6a3227b5..3468df3dccd 100644 --- a/spec/lib/gitlab/background_migration/backfill_push_rules_id_in_projects_spec.rb +++ b/spec/lib/gitlab/background_migration/backfill_push_rules_id_in_projects_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::BackfillPushRulesIdInProjects, :migration, schema: 2020_03_25_162730 do +RSpec.describe Gitlab::BackgroundMigration::BackfillPushRulesIdInProjects, :migration, schema: 20181228175414 do let(:push_rules) { table(:push_rules) } let(:projects) { table(:projects) } let(:project_settings) { table(:project_settings) } diff --git a/spec/lib/gitlab/background_migration/backfill_user_namespace_spec.rb b/spec/lib/gitlab/background_migration/backfill_user_namespace_spec.rb new file mode 100644 index 00000000000..395248b786d --- /dev/null +++ b/spec/lib/gitlab/background_migration/backfill_user_namespace_spec.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::BackgroundMigration::BackfillUserNamespace, :migration, schema: 20210930211936 do + let(:migration) { described_class.new } + let(:namespaces_table) { table(:namespaces) } + + let(:table_name) { 'namespaces' } + let(:batch_column) { :id } + let(:sub_batch_size) { 100 } + let(:pause_ms) { 0 } + + subject(:perform_migration) { migration.perform(1, 10, table_name, batch_column, sub_batch_size, pause_ms) } + + before do + namespaces_table.create!(id: 1, name: 'test1', path: 'test1', type: nil) + namespaces_table.create!(id: 2, name: 'test2', path: 'test2', type: 'User') + namespaces_table.create!(id: 3, name: 'test3', path: 'test3', type: 'Group') + namespaces_table.create!(id: 4, name: 'test4', path: 'test4', type: nil) + namespaces_table.create!(id: 11, name: 'test11', path: 'test11', type: nil) + end + + it 'backfills `type` for the selected records', :aggregate_failures do + queries = ActiveRecord::QueryRecorder.new do + perform_migration + end + + expect(queries.count).to eq(3) + expect(namespaces_table.where(type: 'User').count).to eq 3 + expect(namespaces_table.where(type: 'User').pluck(:id)).to match_array([1, 2, 4]) + end + + it 'tracks timings of queries' do + expect(migration.batch_metrics.timings).to be_empty + + expect { perform_migration }.to change { migration.batch_metrics.timings } + end +end diff --git a/spec/lib/gitlab/background_migration/copy_column_using_background_migration_job_spec.rb b/spec/lib/gitlab/background_migration/copy_column_using_background_migration_job_spec.rb index 3e378db04d4..d4fc24d0559 100644 --- a/spec/lib/gitlab/background_migration/copy_column_using_background_migration_job_spec.rb +++ b/spec/lib/gitlab/background_migration/copy_column_using_background_migration_job_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe Gitlab::BackgroundMigration::CopyColumnUsingBackgroundMigrationJob do - let(:table_name) { :copy_primary_key_test } + let(:table_name) { :_test_copy_primary_key_test } let(:test_table) { table(table_name) } let(:sub_batch_size) { 1000 } let(:pause_ms) { 0 } diff --git a/spec/lib/gitlab/background_migration/copy_merge_request_target_project_to_merge_request_metrics_spec.rb b/spec/lib/gitlab/background_migration/copy_merge_request_target_project_to_merge_request_metrics_spec.rb deleted file mode 100644 index 71bb794d539..00000000000 --- a/spec/lib/gitlab/background_migration/copy_merge_request_target_project_to_merge_request_metrics_spec.rb +++ /dev/null @@ -1,39 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Gitlab::BackgroundMigration::CopyMergeRequestTargetProjectToMergeRequestMetrics, :migration, schema: 20200723125205 do - let(:migration) { described_class.new } - - let_it_be(:namespaces) { table(:namespaces) } - let_it_be(:projects) { table(:projects) } - let_it_be(:merge_requests) { table(:merge_requests) } - let_it_be(:metrics) { table(:merge_request_metrics) } - - let!(:namespace) { namespaces.create!(name: 'namespace', path: 'namespace') } - let!(:project_1) { projects.create!(namespace_id: namespace.id) } - let!(:project_2) { projects.create!(namespace_id: namespace.id) } - let!(:merge_request_to_migrate_1) { merge_requests.create!(source_branch: 'a', target_branch: 'b', target_project_id: project_1.id) } - let!(:merge_request_to_migrate_2) { merge_requests.create!(source_branch: 'c', target_branch: 'd', target_project_id: project_2.id) } - let!(:merge_request_without_metrics) { merge_requests.create!(source_branch: 'e', target_branch: 'f', target_project_id: project_2.id) } - - let!(:metrics_1) { metrics.create!(merge_request_id: merge_request_to_migrate_1.id) } - let!(:metrics_2) { metrics.create!(merge_request_id: merge_request_to_migrate_2.id) } - - let(:merge_request_ids) { [merge_request_to_migrate_1.id, merge_request_to_migrate_2.id, merge_request_without_metrics.id] } - - subject { migration.perform(merge_request_ids.min, merge_request_ids.max) } - - it 'copies `target_project_id` to the associated `merge_request_metrics` record' do - subject - - expect(metrics_1.reload.target_project_id).to eq(project_1.id) - expect(metrics_2.reload.target_project_id).to eq(project_2.id) - end - - it 'does not create metrics record when it is missing' do - subject - - expect(metrics.find_by_merge_request_id(merge_request_without_metrics.id)).to be_nil - end -end diff --git a/spec/lib/gitlab/background_migration/drop_invalid_vulnerabilities_spec.rb b/spec/lib/gitlab/background_migration/drop_invalid_vulnerabilities_spec.rb index c4beb719e1e..b83dc6fff7a 100644 --- a/spec/lib/gitlab/background_migration/drop_invalid_vulnerabilities_spec.rb +++ b/spec/lib/gitlab/background_migration/drop_invalid_vulnerabilities_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::DropInvalidVulnerabilities, schema: 20201110110454 do +RSpec.describe Gitlab::BackgroundMigration::DropInvalidVulnerabilities, schema: 20181228175414 do let_it_be(:background_migration_jobs) { table(:background_migration_jobs) } let_it_be(:namespace) { table(:namespaces).create!(name: 'user', path: 'user') } let_it_be(:users) { table(:users) } diff --git a/spec/lib/gitlab/background_migration/fix_merge_request_diff_commit_users_spec.rb b/spec/lib/gitlab/background_migration/fix_merge_request_diff_commit_users_spec.rb new file mode 100644 index 00000000000..c343ee438b8 --- /dev/null +++ b/spec/lib/gitlab/background_migration/fix_merge_request_diff_commit_users_spec.rb @@ -0,0 +1,316 @@ +# frozen_string_literal: true + +require 'spec_helper' + +# The underlying migration relies on the global models (e.g. Project). This +# means we also need to use FactoryBot factories to ensure everything is +# operating using the same types. If we use `table()` and similar methods we +# would have to duplicate a lot of logic just for these tests. +# +# rubocop: disable RSpec/FactoriesInMigrationSpecs +RSpec.describe Gitlab::BackgroundMigration::FixMergeRequestDiffCommitUsers do + let(:migration) { described_class.new } + + describe '#perform' do + context 'when the project exists' do + it 'processes the project' do + project = create(:project) + + expect(migration).to receive(:process).with(project) + expect(migration).to receive(:schedule_next_job) + + migration.perform(project.id) + end + + it 'marks the background job as finished' do + project = create(:project) + + Gitlab::Database::BackgroundMigrationJob.create!( + class_name: 'FixMergeRequestDiffCommitUsers', + arguments: [project.id] + ) + + migration.perform(project.id) + + job = Gitlab::Database::BackgroundMigrationJob + .find_by(class_name: 'FixMergeRequestDiffCommitUsers') + + expect(job.status).to eq('succeeded') + end + end + + context 'when the project does not exist' do + it 'does nothing' do + expect(migration).not_to receive(:process) + expect(migration).to receive(:schedule_next_job) + + migration.perform(-1) + end + end + end + + describe '#process' do + it 'processes the merge requests of the project' do + project = create(:project, :repository) + commit = project.commit + mr = create( + :merge_request_with_diffs, + source_project: project, + target_project: project + ) + + diff = mr.merge_request_diffs.first + + create( + :merge_request_diff_commit, + merge_request_diff: diff, + sha: commit.sha, + relative_order: 9000 + ) + + migration.process(project) + + updated = diff + .merge_request_diff_commits + .find_by(sha: commit.sha, relative_order: 9000) + + expect(updated.commit_author_id).not_to be_nil + expect(updated.committer_id).not_to be_nil + end + end + + describe '#update_commit' do + let(:project) { create(:project, :repository) } + let(:mr) do + create( + :merge_request_with_diffs, + source_project: project, + target_project: project + ) + end + + let(:diff) { mr.merge_request_diffs.first } + let(:commit) { project.commit } + + def update_row(migration, project, diff, row) + migration.update_commit(project, row) + + diff + .merge_request_diff_commits + .find_by(sha: row.sha, relative_order: row.relative_order) + end + + it 'populates missing commit authors' do + commit_row = create( + :merge_request_diff_commit, + merge_request_diff: diff, + sha: commit.sha, + relative_order: 9000 + ) + + updated = update_row(migration, project, diff, commit_row) + + expect(updated.commit_author.name).to eq(commit.to_hash[:author_name]) + expect(updated.commit_author.email).to eq(commit.to_hash[:author_email]) + end + + it 'populates missing committers' do + commit_row = create( + :merge_request_diff_commit, + merge_request_diff: diff, + sha: commit.sha, + relative_order: 9000 + ) + + updated = update_row(migration, project, diff, commit_row) + + expect(updated.committer.name).to eq(commit.to_hash[:committer_name]) + expect(updated.committer.email).to eq(commit.to_hash[:committer_email]) + end + + it 'leaves existing commit authors as-is' do + user = create(:merge_request_diff_commit_user) + commit_row = create( + :merge_request_diff_commit, + merge_request_diff: diff, + sha: commit.sha, + relative_order: 9000, + commit_author: user + ) + + updated = update_row(migration, project, diff, commit_row) + + expect(updated.commit_author).to eq(user) + end + + it 'leaves existing committers as-is' do + user = create(:merge_request_diff_commit_user) + commit_row = create( + :merge_request_diff_commit, + merge_request_diff: diff, + sha: commit.sha, + relative_order: 9000, + committer: user + ) + + updated = update_row(migration, project, diff, commit_row) + + expect(updated.committer).to eq(user) + end + + it 'does nothing when both the author and committer are present' do + user = create(:merge_request_diff_commit_user) + commit_row = create( + :merge_request_diff_commit, + merge_request_diff: diff, + sha: commit.sha, + relative_order: 9000, + committer: user, + commit_author: user + ) + + recorder = ActiveRecord::QueryRecorder.new do + migration.update_commit(project, commit_row) + end + + expect(recorder.count).to be_zero + end + + it 'does nothing if the commit does not exist in Git' do + user = create(:merge_request_diff_commit_user) + commit_row = create( + :merge_request_diff_commit, + merge_request_diff: diff, + sha: 'kittens', + relative_order: 9000, + committer: user, + commit_author: user + ) + + recorder = ActiveRecord::QueryRecorder.new do + migration.update_commit(project, commit_row) + end + + expect(recorder.count).to be_zero + end + + it 'does nothing when the committer/author are missing in the Git commit' do + user = create(:merge_request_diff_commit_user) + commit_row = create( + :merge_request_diff_commit, + merge_request_diff: diff, + sha: commit.sha, + relative_order: 9000, + committer: user, + commit_author: user + ) + + allow(migration).to receive(:find_or_create_user).and_return(nil) + + recorder = ActiveRecord::QueryRecorder.new do + migration.update_commit(project, commit_row) + end + + expect(recorder.count).to be_zero + end + end + + describe '#schedule_next_job' do + it 'schedules the next background migration' do + Gitlab::Database::BackgroundMigrationJob + .create!(class_name: 'FixMergeRequestDiffCommitUsers', arguments: [42]) + + expect(BackgroundMigrationWorker) + .to receive(:perform_in) + .with(2.minutes, 'FixMergeRequestDiffCommitUsers', [42]) + + migration.schedule_next_job + end + + it 'does nothing when there are no jobs' do + expect(BackgroundMigrationWorker) + .not_to receive(:perform_in) + + migration.schedule_next_job + end + end + + describe '#find_commit' do + let(:project) { create(:project, :repository) } + + it 'finds a commit using Git' do + commit = project.commit + found = migration.find_commit(project, commit.sha) + + expect(found).to eq(commit.to_hash) + end + + it 'caches the results' do + commit = project.commit + + migration.find_commit(project, commit.sha) + + expect { migration.find_commit(project, commit.sha) } + .not_to change { Gitlab::GitalyClient.get_request_count } + end + + it 'returns an empty hash if the commit does not exist' do + expect(migration.find_commit(project, 'kittens')).to eq({}) + end + end + + describe '#find_or_create_user' do + let(:project) { create(:project, :repository) } + + it 'creates missing users' do + commit = project.commit.to_hash + id = migration.find_or_create_user(commit, :author_name, :author_email) + + expect(MergeRequest::DiffCommitUser.count).to eq(1) + + created = MergeRequest::DiffCommitUser.first + + expect(created.name).to eq(commit[:author_name]) + expect(created.email).to eq(commit[:author_email]) + expect(created.id).to eq(id) + end + + it 'returns users that already exist' do + commit = project.commit.to_hash + user1 = migration.find_or_create_user(commit, :author_name, :author_email) + user2 = migration.find_or_create_user(commit, :author_name, :author_email) + + expect(user1).to eq(user2) + end + + it 'caches the results' do + commit = project.commit.to_hash + + migration.find_or_create_user(commit, :author_name, :author_email) + + recorder = ActiveRecord::QueryRecorder.new do + migration.find_or_create_user(commit, :author_name, :author_email) + end + + expect(recorder.count).to be_zero + end + + it 'returns nil if the commit details are missing' do + id = migration.find_or_create_user({}, :author_name, :author_email) + + expect(id).to be_nil + end + end + + describe '#matches_row' do + it 'returns the query matches for the composite primary key' do + row = double(:commit, merge_request_diff_id: 4, relative_order: 5) + arel = migration.matches_row(row) + + expect(arel.to_sql).to eq( + '("merge_request_diff_commits"."merge_request_diff_id", "merge_request_diff_commits"."relative_order") = (4, 5)' + ) + end + end +end +# rubocop: enable RSpec/FactoriesInMigrationSpecs diff --git a/spec/lib/gitlab/background_migration/fix_projects_without_project_feature_spec.rb b/spec/lib/gitlab/background_migration/fix_projects_without_project_feature_spec.rb deleted file mode 100644 index d503824041b..00000000000 --- a/spec/lib/gitlab/background_migration/fix_projects_without_project_feature_spec.rb +++ /dev/null @@ -1,75 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Gitlab::BackgroundMigration::FixProjectsWithoutProjectFeature, schema: 2020_01_27_111840 do - let(:namespaces) { table(:namespaces) } - let(:projects) { table(:projects) } - let(:project_features) { table(:project_features) } - - let(:namespace) { namespaces.create!(name: 'foo', path: 'foo') } - - let!(:project) { projects.create!(namespace_id: namespace.id) } - let(:private_project_without_feature) { projects.create!(namespace_id: namespace.id, visibility_level: 0) } - let(:public_project_without_feature) { projects.create!(namespace_id: namespace.id, visibility_level: 20) } - let!(:projects_without_feature) { [private_project_without_feature, public_project_without_feature] } - - before do - project_features.create!({ project_id: project.id, pages_access_level: 20 }) - end - - subject { described_class.new.perform(Project.minimum(:id), Project.maximum(:id)) } - - def project_feature_records - project_features.order(:project_id).pluck(:project_id) - end - - def features(project) - project_features.find_by(project_id: project.id)&.attributes - end - - it 'creates a ProjectFeature for projects without it' do - expect { subject }.to change { project_feature_records }.from([project.id]).to([project.id, *projects_without_feature.map(&:id)]) - end - - it 'creates ProjectFeature records with default values for a public project' do - subject - - expect(features(public_project_without_feature)).to include( - { - "merge_requests_access_level" => 20, - "issues_access_level" => 20, - "wiki_access_level" => 20, - "snippets_access_level" => 20, - "builds_access_level" => 20, - "repository_access_level" => 20, - "pages_access_level" => 20, - "forking_access_level" => 20 - } - ) - end - - it 'creates ProjectFeature records with default values for a private project' do - subject - - expect(features(private_project_without_feature)).to include("pages_access_level" => 10) - end - - context 'when access control to pages is forced' do - before do - allow(::Gitlab::Pages).to receive(:access_control_is_forced?).and_return(true) - end - - it 'creates ProjectFeature records with default values for a public project' do - subject - - expect(features(public_project_without_feature)).to include("pages_access_level" => 10) - end - end - - it 'sets created_at/updated_at timestamps' do - subject - - expect(project_features.where('created_at IS NULL OR updated_at IS NULL')).to be_empty - end -end diff --git a/spec/lib/gitlab/background_migration/fix_projects_without_prometheus_service_spec.rb b/spec/lib/gitlab/background_migration/fix_projects_without_prometheus_service_spec.rb deleted file mode 100644 index 9a497a9e01a..00000000000 --- a/spec/lib/gitlab/background_migration/fix_projects_without_prometheus_service_spec.rb +++ /dev/null @@ -1,234 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Gitlab::BackgroundMigration::FixProjectsWithoutPrometheusService, :migration, schema: 2020_02_20_115023 do - def service_params_for(project_id, params = {}) - { - project_id: project_id, - active: false, - properties: '{}', - type: 'PrometheusService', - template: false, - push_events: true, - issues_events: true, - merge_requests_events: true, - tag_push_events: true, - note_events: true, - category: 'monitoring', - default: false, - wiki_page_events: true, - pipeline_events: true, - confidential_issues_events: true, - commit_events: true, - job_events: true, - confidential_note_events: true, - deployment_events: false - }.merge(params) - end - - let(:namespaces) { table(:namespaces) } - let(:projects) { table(:projects) } - let(:services) { table(:services) } - let(:clusters) { table(:clusters) } - let(:cluster_groups) { table(:cluster_groups) } - let(:clusters_applications_prometheus) { table(:clusters_applications_prometheus) } - let(:namespace) { namespaces.create!(name: 'user', path: 'user') } - let(:project) { projects.create!(namespace_id: namespace.id) } - - let(:application_statuses) do - { - errored: -1, - installed: 3, - updated: 5 - } - end - - let(:cluster_types) do - { - instance_type: 1, - group_type: 2, - project_type: 3 - } - end - - let(:columns) do - %w(project_id active properties type template push_events - issues_events merge_requests_events tag_push_events - note_events category default wiki_page_events pipeline_events - confidential_issues_events commit_events job_events - confidential_note_events deployment_events) - end - - describe '#perform' do - shared_examples 'fix services entries state' do - it 'is idempotent' do - expect { subject.perform(project.id, project.id + 1) }.to change { services.order(:id).map { |row| row.attributes } } - - expect { subject.perform(project.id, project.id + 1) }.not_to change { services.order(:id).map { |row| row.attributes } } - end - - context 'non prometheus services' do - it 'does not change them' do - other_type = 'SomeOtherService' - services.create!(service_params_for(project.id, active: true, type: other_type)) - - expect { subject.perform(project.id, project.id + 1) }.not_to change { services.where(type: other_type).order(:id).map { |row| row.attributes } } - end - end - - context 'prometheus integration services do not exist' do - it 'creates missing services entries', :aggregate_failures do - expect { subject.perform(project.id, project.id + 1) }.to change { services.count }.by(1) - expect([service_params_for(project.id, active: true)]).to eq services.order(:id).map { |row| row.attributes.slice(*columns).symbolize_keys } - end - - context 'template is present for prometheus services' do - it 'creates missing services entries', :aggregate_failures do - services.create!(service_params_for(nil, template: true, properties: { 'from_template' => true }.to_json)) - - expect { subject.perform(project.id, project.id + 1) }.to change { services.count }.by(1) - updated_rows = services.where(template: false).order(:id).map { |row| row.attributes.slice(*columns).symbolize_keys } - expect([service_params_for(project.id, active: true, properties: { 'from_template' => true }.to_json)]).to eq updated_rows - end - end - end - - context 'prometheus integration services exist' do - context 'in active state' do - it 'does not change them' do - services.create!(service_params_for(project.id, active: true)) - - expect { subject.perform(project.id, project.id + 1) }.not_to change { services.order(:id).map { |row| row.attributes } } - end - end - - context 'not in active state' do - it 'sets active attribute to true' do - service = services.create!(service_params_for(project.id, active: false)) - - expect { subject.perform(project.id, project.id + 1) }.to change { service.reload.active? }.from(false).to(true) - end - - context 'prometheus services are configured manually ' do - it 'does not change them' do - properties = '{"api_url":"http://test.dev","manual_configuration":"1"}' - services.create!(service_params_for(project.id, properties: properties, active: false)) - - expect { subject.perform(project.id, project.id + 1) }.not_to change { services.order(:id).map { |row| row.attributes } } - end - end - end - end - end - - context 'k8s cluster shared on instance level' do - let(:cluster) { clusters.create!(name: 'cluster', cluster_type: cluster_types[:instance_type]) } - - context 'with installed prometheus application' do - before do - clusters_applications_prometheus.create!(cluster_id: cluster.id, status: application_statuses[:installed], version: '123') - end - - it_behaves_like 'fix services entries state' - end - - context 'with updated prometheus application' do - before do - clusters_applications_prometheus.create!(cluster_id: cluster.id, status: application_statuses[:updated], version: '123') - end - - it_behaves_like 'fix services entries state' - end - - context 'with errored prometheus application' do - before do - clusters_applications_prometheus.create!(cluster_id: cluster.id, status: application_statuses[:errored], version: '123') - end - - it 'does not change services entries' do - expect { subject.perform(project.id, project.id + 1) }.not_to change { services.order(:id).map { |row| row.attributes } } - end - end - end - - context 'k8s cluster shared on group level' do - let(:cluster) { clusters.create!(name: 'cluster', cluster_type: cluster_types[:group_type]) } - - before do - cluster_groups.create!(cluster_id: cluster.id, group_id: project.namespace_id) - end - - context 'with installed prometheus application' do - before do - clusters_applications_prometheus.create!(cluster_id: cluster.id, status: application_statuses[:installed], version: '123') - end - - it_behaves_like 'fix services entries state' - - context 'second k8s cluster without application available' do - let(:namespace_2) { namespaces.create!(name: 'namespace2', path: 'namespace2') } - let(:project_2) { projects.create!(namespace_id: namespace_2.id) } - - before do - cluster_2 = clusters.create!(name: 'cluster2', cluster_type: cluster_types[:group_type]) - cluster_groups.create!(cluster_id: cluster_2.id, group_id: project_2.namespace_id) - end - - it 'changed only affected services entries' do - expect { subject.perform(project.id, project_2.id + 1) }.to change { services.count }.by(1) - expect([service_params_for(project.id, active: true)]).to eq services.order(:id).map { |row| row.attributes.slice(*columns).symbolize_keys } - end - end - end - - context 'with updated prometheus application' do - before do - clusters_applications_prometheus.create!(cluster_id: cluster.id, status: application_statuses[:updated], version: '123') - end - - it_behaves_like 'fix services entries state' - end - - context 'with errored prometheus application' do - before do - clusters_applications_prometheus.create!(cluster_id: cluster.id, status: application_statuses[:errored], version: '123') - end - - it 'does not change services entries' do - expect { subject.perform(project.id, project.id + 1) }.not_to change { services.order(:id).map { |row| row.attributes } } - end - end - - context 'with missing prometheus application' do - it 'does not change services entries' do - expect { subject.perform(project.id, project.id + 1) }.not_to change { services.order(:id).map { |row| row.attributes } } - end - - context 'with inactive service' do - it 'does not change services entries' do - services.create!(service_params_for(project.id)) - - expect { subject.perform(project.id, project.id + 1) }.not_to change { services.order(:id).map { |row| row.attributes } } - end - end - end - end - - context 'k8s cluster for single project' do - let(:cluster) { clusters.create!(name: 'cluster', cluster_type: cluster_types[:project_type]) } - let(:cluster_projects) { table(:cluster_projects) } - - context 'with installed prometheus application' do - before do - cluster_projects.create!(cluster_id: cluster.id, project_id: project.id) - clusters_applications_prometheus.create!(cluster_id: cluster.id, status: application_statuses[:installed], version: '123') - end - - it 'does not change services entries' do - expect { subject.perform(project.id, project.id + 1) }.not_to change { services.order(:id).map { |row| row.attributes } } - end - end - end - end -end diff --git a/spec/lib/gitlab/background_migration/job_coordinator_spec.rb b/spec/lib/gitlab/background_migration/job_coordinator_spec.rb new file mode 100644 index 00000000000..a0543ca9958 --- /dev/null +++ b/spec/lib/gitlab/background_migration/job_coordinator_spec.rb @@ -0,0 +1,344 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::BackgroundMigration::JobCoordinator do + let(:database) { :main } + let(:worker_class) { BackgroundMigrationWorker } + let(:coordinator) { described_class.new(database, worker_class) } + + describe '.for_database' do + it 'returns an executor with the correct worker class and database' do + coordinator = described_class.for_database(database) + + expect(coordinator.database).to eq(database) + expect(coordinator.worker_class).to eq(worker_class) + end + + context 'when passed in as a string' do + it 'retruns an executor with the correct worker class and database' do + coordinator = described_class.for_database(database.to_s) + + expect(coordinator.database).to eq(database) + expect(coordinator.worker_class).to eq(worker_class) + end + end + + context 'when an invalid value is given' do + it 'raises an error' do + expect do + described_class.for_database('notvalid') + end.to raise_error(ArgumentError, "database must be one of [main], got 'notvalid'") + end + end + end + + describe '#queue' do + it 'returns background migration worker queue' do + expect(coordinator.queue).to eq(worker_class.sidekiq_options['queue']) + end + end + + describe '#with_shared_connection' do + it 'yields to the block after properly configuring SharedModel' do + expect(Gitlab::Database::SharedModel).to receive(:using_connection) + .with(ActiveRecord::Base.connection).and_yield + + expect { |b| coordinator.with_shared_connection(&b) }.to yield_with_no_args + end + end + + describe '#steal' do + context 'when there are enqueued jobs present' do + let(:queue) do + [ + double(args: ['Foo', [10, 20]], klass: worker_class.name), + double(args: ['Bar', [20, 30]], klass: worker_class.name), + double(args: ['Foo', [20, 30]], klass: 'MergeWorker') + ] + end + + before do + allow(Sidekiq::Queue).to receive(:new) + .with(coordinator.queue) + .and_return(queue) + end + + context 'when queue contains unprocessed jobs' do + it 'steals jobs from a queue' do + expect(queue[0]).to receive(:delete).and_return(true) + + expect(coordinator).to receive(:perform).with('Foo', [10, 20]) + + coordinator.steal('Foo') + end + + it 'sets up the shared connection while stealing jobs' do + connection = double('connection') + allow(coordinator).to receive(:connection).and_return(connection) + + expect(coordinator).to receive(:with_shared_connection).and_call_original + + expect(queue[0]).to receive(:delete).and_return(true) + + expect(coordinator).to receive(:perform).with('Foo', [10, 20]) do + expect(Gitlab::Database::SharedModel.connection).to be(connection) + end + + coordinator.steal('Foo') do + expect(Gitlab::Database::SharedModel.connection).to be(connection) + + true # the job is only performed if the block returns true + end + end + + it 'does not steal job that has already been taken' do + expect(queue[0]).to receive(:delete).and_return(false) + + expect(coordinator).not_to receive(:perform) + + coordinator.steal('Foo') + end + + it 'does not steal jobs for a different migration' do + expect(coordinator).not_to receive(:perform) + + expect(queue[0]).not_to receive(:delete) + + coordinator.steal('Baz') + end + + context 'when a custom predicate is given' do + it 'steals jobs that match the predicate' do + expect(queue[0]).to receive(:delete).and_return(true) + + expect(coordinator).to receive(:perform).with('Foo', [10, 20]) + + coordinator.steal('Foo') { |job| job.args.second.first == 10 && job.args.second.second == 20 } + end + + it 'does not steal jobs that do not match the predicate' do + expect(described_class).not_to receive(:perform) + + expect(queue[0]).not_to receive(:delete) + + coordinator.steal('Foo') { |(arg1, _)| arg1 == 5 } + end + end + end + + context 'when one of the jobs raises an error' do + let(:migration) { spy(:migration) } + + let(:queue) do + [double(args: ['Foo', [10, 20]], klass: worker_class.name), + double(args: ['Foo', [20, 30]], klass: worker_class.name)] + end + + before do + stub_const('Gitlab::BackgroundMigration::Foo', migration) + + allow(queue[0]).to receive(:delete).and_return(true) + allow(queue[1]).to receive(:delete).and_return(true) + end + + it 'enqueues the migration again and re-raises the error' do + allow(migration).to receive(:perform).with(10, 20).and_raise(Exception, 'Migration error').once + + expect(worker_class).to receive(:perform_async).with('Foo', [10, 20]).once + + expect { coordinator.steal('Foo') }.to raise_error(Exception) + end + end + end + + context 'when there are scheduled jobs present', :redis do + it 'steals all jobs from the scheduled sets' do + Sidekiq::Testing.disable! do + worker_class.perform_in(10.minutes, 'Object') + + expect(Sidekiq::ScheduledSet.new).to be_one + expect(coordinator).to receive(:perform).with('Object', any_args) + + coordinator.steal('Object') + + expect(Sidekiq::ScheduledSet.new).to be_none + end + end + end + + context 'when there are enqueued and scheduled jobs present', :redis do + it 'steals from the scheduled sets queue first' do + Sidekiq::Testing.disable! do + expect(coordinator).to receive(:perform).with('Object', [1]).ordered + expect(coordinator).to receive(:perform).with('Object', [2]).ordered + + worker_class.perform_async('Object', [2]) + worker_class.perform_in(10.minutes, 'Object', [1]) + + coordinator.steal('Object') + end + end + end + + context 'when retry_dead_jobs is true', :redis do + let(:retry_queue) do + [double(args: ['Object', [3]], klass: worker_class.name, delete: true)] + end + + let(:dead_queue) do + [double(args: ['Object', [4]], klass: worker_class.name, delete: true)] + end + + before do + allow(Sidekiq::RetrySet).to receive(:new).and_return(retry_queue) + allow(Sidekiq::DeadSet).to receive(:new).and_return(dead_queue) + end + + it 'steals from the dead and retry queue' do + Sidekiq::Testing.disable! do + expect(coordinator).to receive(:perform).with('Object', [1]).ordered + expect(coordinator).to receive(:perform).with('Object', [2]).ordered + expect(coordinator).to receive(:perform).with('Object', [3]).ordered + expect(coordinator).to receive(:perform).with('Object', [4]).ordered + + worker_class.perform_async('Object', [2]) + worker_class.perform_in(10.minutes, 'Object', [1]) + + coordinator.steal('Object', retry_dead_jobs: true) + end + end + end + end + + describe '#perform' do + let(:migration) { spy(:migration) } + let(:connection) { double('connection') } + + before do + stub_const('Gitlab::BackgroundMigration::Foo', migration) + + allow(coordinator).to receive(:connection).and_return(connection) + end + + it 'performs a background migration with the configured shared connection' do + expect(coordinator).to receive(:with_shared_connection).and_call_original + + expect(migration).to receive(:perform).with(10, 20).once do + expect(Gitlab::Database::SharedModel.connection).to be(connection) + end + + coordinator.perform('Foo', [10, 20]) + end + end + + describe '.remaining', :redis do + context 'when there are jobs remaining' do + before do + Sidekiq::Testing.disable! do + MergeWorker.perform_async('Foo') + MergeWorker.perform_in(10.minutes, 'Foo') + + 5.times do + worker_class.perform_async('Foo') + end + 3.times do + worker_class.perform_in(10.minutes, 'Foo') + end + end + end + + it 'returns the enqueued jobs plus the scheduled jobs' do + expect(coordinator.remaining).to eq(8) + end + end + + context 'when there are no jobs remaining' do + it 'returns zero' do + expect(coordinator.remaining).to be_zero + end + end + end + + describe '.exists?', :redis do + context 'when there are enqueued jobs present' do + before do + Sidekiq::Testing.disable! do + MergeWorker.perform_async('Bar') + worker_class.perform_async('Foo') + end + end + + it 'returns true if specific job exists' do + expect(coordinator.exists?('Foo')).to eq(true) + end + + it 'returns false if specific job does not exist' do + expect(coordinator.exists?('Bar')).to eq(false) + end + end + + context 'when there are scheduled jobs present' do + before do + Sidekiq::Testing.disable! do + MergeWorker.perform_in(10.minutes, 'Bar') + worker_class.perform_in(10.minutes, 'Foo') + end + end + + it 'returns true if specific job exists' do + expect(coordinator.exists?('Foo')).to eq(true) + end + + it 'returns false if specific job does not exist' do + expect(coordinator.exists?('Bar')).to eq(false) + end + end + end + + describe '.dead_jobs?' do + let(:queue) do + [ + double(args: ['Foo', [10, 20]], klass: worker_class.name), + double(args: ['Bar'], klass: 'MergeWorker') + ] + end + + context 'when there are dead jobs present' do + before do + allow(Sidekiq::DeadSet).to receive(:new).and_return(queue) + end + + it 'returns true if specific job exists' do + expect(coordinator.dead_jobs?('Foo')).to eq(true) + end + + it 'returns false if specific job does not exist' do + expect(coordinator.dead_jobs?('Bar')).to eq(false) + end + end + end + + describe '.retrying_jobs?' do + let(:queue) do + [ + double(args: ['Foo', [10, 20]], klass: worker_class.name), + double(args: ['Bar'], klass: 'MergeWorker') + ] + end + + context 'when there are dead jobs present' do + before do + allow(Sidekiq::RetrySet).to receive(:new).and_return(queue) + end + + it 'returns true if specific job exists' do + expect(coordinator.retrying_jobs?('Foo')).to eq(true) + end + + it 'returns false if specific job does not exist' do + expect(coordinator.retrying_jobs?('Bar')).to eq(false) + end + end + end +end diff --git a/spec/lib/gitlab/background_migration/link_lfs_objects_projects_spec.rb b/spec/lib/gitlab/background_migration/link_lfs_objects_projects_spec.rb index b7cf101dd8a..64e8afedf52 100644 --- a/spec/lib/gitlab/background_migration/link_lfs_objects_projects_spec.rb +++ b/spec/lib/gitlab/background_migration/link_lfs_objects_projects_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::LinkLfsObjectsProjects, :migration, schema: 2020_03_10_075115 do +RSpec.describe Gitlab::BackgroundMigration::LinkLfsObjectsProjects, :migration, schema: 20181228175414 do let(:namespaces) { table(:namespaces) } let(:projects) { table(:projects) } let(:fork_networks) { table(:fork_networks) } diff --git a/spec/lib/gitlab/background_migration/migrate_fingerprint_sha256_within_keys_spec.rb b/spec/lib/gitlab/background_migration/migrate_fingerprint_sha256_within_keys_spec.rb index c58b2d609e9..4287d6723cf 100644 --- a/spec/lib/gitlab/background_migration/migrate_fingerprint_sha256_within_keys_spec.rb +++ b/spec/lib/gitlab/background_migration/migrate_fingerprint_sha256_within_keys_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::MigrateFingerprintSha256WithinKeys, schema: 20200106071113 do +RSpec.describe Gitlab::BackgroundMigration::MigrateFingerprintSha256WithinKeys, schema: 20181228175414 do subject(:fingerprint_migrator) { described_class.new } let(:key_table) { table(:keys) } diff --git a/spec/lib/gitlab/background_migration/migrate_issue_trackers_sensitive_data_spec.rb b/spec/lib/gitlab/background_migration/migrate_issue_trackers_sensitive_data_spec.rb deleted file mode 100644 index f2cd2acd4f3..00000000000 --- a/spec/lib/gitlab/background_migration/migrate_issue_trackers_sensitive_data_spec.rb +++ /dev/null @@ -1,327 +0,0 @@ -# frozen_string_literal: true -require 'spec_helper' - -RSpec.describe Gitlab::BackgroundMigration::MigrateIssueTrackersSensitiveData, schema: 20200130145430 do - let(:services) { table(:services) } - - before do - # we need to define the classes due to encryption - issue_tracker_data = Class.new(ApplicationRecord) do - self.table_name = 'issue_tracker_data' - - def self.encryption_options - { - key: Settings.attr_encrypted_db_key_base_32, - encode: true, - mode: :per_attribute_iv, - algorithm: 'aes-256-gcm' - } - end - - attr_encrypted :project_url, encryption_options - attr_encrypted :issues_url, encryption_options - attr_encrypted :new_issue_url, encryption_options - end - - jira_tracker_data = Class.new(ApplicationRecord) do - self.table_name = 'jira_tracker_data' - - def self.encryption_options - { - key: Settings.attr_encrypted_db_key_base_32, - encode: true, - mode: :per_attribute_iv, - algorithm: 'aes-256-gcm' - } - end - - attr_encrypted :url, encryption_options - attr_encrypted :api_url, encryption_options - attr_encrypted :username, encryption_options - attr_encrypted :password, encryption_options - end - - stub_const('IssueTrackerData', issue_tracker_data) - stub_const('JiraTrackerData', jira_tracker_data) - end - - let(:url) { 'http://base-url.tracker.com' } - let(:new_issue_url) { 'http://base-url.tracker.com/new_issue' } - let(:issues_url) { 'http://base-url.tracker.com/issues' } - let(:api_url) { 'http://api.tracker.com' } - let(:password) { 'passw1234' } - let(:username) { 'user9' } - let(:title) { 'Issue tracker' } - let(:description) { 'Issue tracker description' } - - let(:jira_properties) do - { - 'api_url' => api_url, - 'jira_issue_transition_id' => '5', - 'password' => password, - 'url' => url, - 'username' => username, - 'title' => title, - 'description' => description, - 'other_field' => 'something' - } - end - - let(:tracker_properties) do - { - 'project_url' => url, - 'new_issue_url' => new_issue_url, - 'issues_url' => issues_url, - 'title' => title, - 'description' => description, - 'other_field' => 'something' - } - end - - let(:tracker_properties_no_url) do - { - 'new_issue_url' => new_issue_url, - 'issues_url' => issues_url, - 'title' => title, - 'description' => description - } - end - - subject { described_class.new.perform(1, 100) } - - shared_examples 'handle properties' do - it 'does not clear the properties' do - expect { subject }.not_to change { service.reload.properties} - end - end - - context 'with Jira service' do - let!(:service) do - services.create!(id: 10, type: 'JiraService', title: nil, properties: jira_properties.to_json, category: 'issue_tracker') - end - - it_behaves_like 'handle properties' - - it 'migrates data' do - expect { subject }.to change { JiraTrackerData.count }.by(1) - - service.reload - data = JiraTrackerData.find_by(service_id: service.id) - - expect(data.url).to eq(url) - expect(data.api_url).to eq(api_url) - expect(data.username).to eq(username) - expect(data.password).to eq(password) - expect(service.title).to eq(title) - expect(service.description).to eq(description) - end - end - - context 'with bugzilla service' do - let!(:service) do - services.create!(id: 11, type: 'BugzillaService', title: nil, properties: tracker_properties.to_json, category: 'issue_tracker') - end - - it_behaves_like 'handle properties' - - it 'migrates data' do - expect { subject }.to change { IssueTrackerData.count }.by(1) - - service.reload - data = IssueTrackerData.find_by(service_id: service.id) - - expect(data.project_url).to eq(url) - expect(data.issues_url).to eq(issues_url) - expect(data.new_issue_url).to eq(new_issue_url) - expect(service.title).to eq(title) - expect(service.description).to eq(description) - end - end - - context 'with youtrack service' do - let!(:service) do - services.create!(id: 12, type: 'YoutrackService', title: nil, properties: tracker_properties_no_url.to_json, category: 'issue_tracker') - end - - it_behaves_like 'handle properties' - - it 'migrates data' do - expect { subject }.to change { IssueTrackerData.count }.by(1) - - service.reload - data = IssueTrackerData.find_by(service_id: service.id) - - expect(data.project_url).to be_nil - expect(data.issues_url).to eq(issues_url) - expect(data.new_issue_url).to eq(new_issue_url) - expect(service.title).to eq(title) - expect(service.description).to eq(description) - end - end - - context 'with gitlab service with no properties' do - let!(:service) do - services.create!(id: 13, type: 'GitlabIssueTrackerService', title: nil, properties: {}, category: 'issue_tracker') - end - - it_behaves_like 'handle properties' - - it 'does not migrate data' do - expect { subject }.not_to change { IssueTrackerData.count } - end - end - - context 'with redmine service already with data fields' do - let!(:service) do - services.create!(id: 14, type: 'RedmineService', title: nil, properties: tracker_properties_no_url.to_json, category: 'issue_tracker').tap do |service| - IssueTrackerData.create!(service_id: service.id, project_url: url, new_issue_url: new_issue_url, issues_url: issues_url) - end - end - - it_behaves_like 'handle properties' - - it 'does not create new data fields record' do - expect { subject }.not_to change { IssueTrackerData.count } - end - end - - context 'with custom issue tracker which has data fields record inconsistent with properties field' do - let!(:service) do - services.create!(id: 15, type: 'CustomIssueTrackerService', title: 'Existing title', properties: jira_properties.to_json, category: 'issue_tracker').tap do |service| - IssueTrackerData.create!(service_id: service.id, project_url: 'http://other_url', new_issue_url: 'http://other_url/new_issue', issues_url: 'http://other_url/issues') - end - end - - it_behaves_like 'handle properties' - - it 'does not update the data fields record' do - expect { subject }.not_to change { IssueTrackerData.count } - - service.reload - data = IssueTrackerData.find_by(service_id: service.id) - - expect(data.project_url).to eq('http://other_url') - expect(data.issues_url).to eq('http://other_url/issues') - expect(data.new_issue_url).to eq('http://other_url/new_issue') - expect(service.title).to eq('Existing title') - end - end - - context 'with Jira service which has data fields record inconsistent with properties field' do - let!(:service) do - services.create!(id: 16, type: 'CustomIssueTrackerService', description: 'Existing description', properties: jira_properties.to_json, category: 'issue_tracker').tap do |service| - JiraTrackerData.create!(service_id: service.id, url: 'http://other_jira_url') - end - end - - it_behaves_like 'handle properties' - - it 'does not update the data fields record' do - expect { subject }.not_to change { JiraTrackerData.count } - - service.reload - data = JiraTrackerData.find_by(service_id: service.id) - - expect(data.url).to eq('http://other_jira_url') - expect(data.password).to be_nil - expect(data.username).to be_nil - expect(data.api_url).to be_nil - expect(service.description).to eq('Existing description') - end - end - - context 'non issue tracker service' do - let!(:service) do - services.create!(id: 17, title: nil, description: nil, type: 'OtherService', properties: tracker_properties.to_json) - end - - it_behaves_like 'handle properties' - - it 'does not migrate any data' do - expect { subject }.not_to change { IssueTrackerData.count } - - service.reload - expect(service.title).to be_nil - expect(service.description).to be_nil - end - end - - context 'Jira service with empty properties' do - let!(:service) do - services.create!(id: 18, type: 'JiraService', properties: '', category: 'issue_tracker') - end - - it_behaves_like 'handle properties' - - it 'does not migrate any data' do - expect { subject }.not_to change { JiraTrackerData.count } - end - end - - context 'Jira service with nil properties' do - let!(:service) do - services.create!(id: 18, type: 'JiraService', properties: nil, category: 'issue_tracker') - end - - it_behaves_like 'handle properties' - - it 'does not migrate any data' do - expect { subject }.not_to change { JiraTrackerData.count } - end - end - - context 'Jira service with invalid properties' do - let!(:service) do - services.create!(id: 18, type: 'JiraService', properties: 'invalid data', category: 'issue_tracker') - end - - it_behaves_like 'handle properties' - - it 'does not migrate any data' do - expect { subject }.not_to change { JiraTrackerData.count } - end - end - - context 'with Jira service with invalid properties, valid Jira service and valid bugzilla service' do - let!(:jira_integration_invalid) do - services.create!(id: 19, title: 'invalid - title', description: 'invalid - description', type: 'JiraService', properties: 'invalid data', category: 'issue_tracker') - end - - let!(:jira_integration_valid) do - services.create!(id: 20, type: 'JiraService', properties: jira_properties.to_json, category: 'issue_tracker') - end - - let!(:bugzilla_integration_valid) do - services.create!(id: 11, type: 'BugzillaService', title: nil, properties: tracker_properties.to_json, category: 'issue_tracker') - end - - it 'migrates data for the valid service' do - subject - - jira_integration_invalid.reload - expect(JiraTrackerData.find_by(service_id: jira_integration_invalid.id)).to be_nil - expect(jira_integration_invalid.title).to eq('invalid - title') - expect(jira_integration_invalid.description).to eq('invalid - description') - expect(jira_integration_invalid.properties).to eq('invalid data') - - jira_integration_valid.reload - data = JiraTrackerData.find_by(service_id: jira_integration_valid.id) - - expect(data.url).to eq(url) - expect(data.api_url).to eq(api_url) - expect(data.username).to eq(username) - expect(data.password).to eq(password) - expect(jira_integration_valid.title).to eq(title) - expect(jira_integration_valid.description).to eq(description) - - bugzilla_integration_valid.reload - data = IssueTrackerData.find_by(service_id: bugzilla_integration_valid.id) - - expect(data.project_url).to eq(url) - expect(data.issues_url).to eq(issues_url) - expect(data.new_issue_url).to eq(new_issue_url) - expect(bugzilla_integration_valid.title).to eq(title) - expect(bugzilla_integration_valid.description).to eq(description) - end - end -end diff --git a/spec/lib/gitlab/background_migration/migrate_merge_request_diff_commit_users_spec.rb b/spec/lib/gitlab/background_migration/migrate_merge_request_diff_commit_users_spec.rb index 91e8dcdf880..31b6ee0c7cd 100644 --- a/spec/lib/gitlab/background_migration/migrate_merge_request_diff_commit_users_spec.rb +++ b/spec/lib/gitlab/background_migration/migrate_merge_request_diff_commit_users_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::MigrateMergeRequestDiffCommitUsers do +RSpec.describe Gitlab::BackgroundMigration::MigrateMergeRequestDiffCommitUsers, schema: 20211012134316 do let(:namespaces) { table(:namespaces) } let(:projects) { table(:projects) } let(:users) { table(:users) } diff --git a/spec/lib/gitlab/background_migration/migrate_u2f_webauthn_spec.rb b/spec/lib/gitlab/background_migration/migrate_u2f_webauthn_spec.rb index 9eda51f6ec4..ab183d01357 100644 --- a/spec/lib/gitlab/background_migration/migrate_u2f_webauthn_spec.rb +++ b/spec/lib/gitlab/background_migration/migrate_u2f_webauthn_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' require 'webauthn/u2f_migrator' -RSpec.describe Gitlab::BackgroundMigration::MigrateU2fWebauthn, :migration, schema: 20200925125321 do +RSpec.describe Gitlab::BackgroundMigration::MigrateU2fWebauthn, :migration, schema: 20181228175414 do let(:users) { table(:users) } let(:user) { users.create!(email: 'email@email.com', name: 'foo', username: 'foo', projects_limit: 0) } diff --git a/spec/lib/gitlab/background_migration/migrate_users_bio_to_user_details_spec.rb b/spec/lib/gitlab/background_migration/migrate_users_bio_to_user_details_spec.rb deleted file mode 100644 index d90a5d30954..00000000000 --- a/spec/lib/gitlab/background_migration/migrate_users_bio_to_user_details_spec.rb +++ /dev/null @@ -1,85 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Gitlab::BackgroundMigration::MigrateUsersBioToUserDetails, :migration, schema: 20200323074147 do - let(:users) { table(:users) } - - let(:user_details) do - klass = table(:user_details) - klass.primary_key = :user_id - klass - end - - let!(:user_needs_migration) { users.create!(name: 'user1', email: 'test1@test.com', projects_limit: 1, bio: 'bio') } - let!(:user_needs_no_migration) { users.create!(name: 'user2', email: 'test2@test.com', projects_limit: 1) } - let!(:user_also_needs_no_migration) { users.create!(name: 'user3', email: 'test3@test.com', projects_limit: 1, bio: '') } - let!(:user_with_long_bio) { users.create!(name: 'user4', email: 'test4@test.com', projects_limit: 1, bio: 'a' * 256) } # 255 is the max - - let!(:user_already_has_details) { users.create!(name: 'user5', email: 'test5@test.com', projects_limit: 1, bio: 'my bio') } - let!(:existing_user_details) { user_details.find_or_create_by!(user_id: user_already_has_details.id).update!(bio: 'my bio') } - - # unlikely scenario since we have triggers - let!(:user_has_different_details) { users.create!(name: 'user6', email: 'test6@test.com', projects_limit: 1, bio: 'different') } - let!(:different_existing_user_details) { user_details.find_or_create_by!(user_id: user_has_different_details.id).update!(bio: 'bio') } - - let(:user_ids) do - [ - user_needs_migration, - user_needs_no_migration, - user_also_needs_no_migration, - user_with_long_bio, - user_already_has_details, - user_has_different_details - ].map(&:id) - end - - subject { described_class.new.perform(user_ids.min, user_ids.max) } - - it 'migrates all relevant records' do - subject - - all_user_details = user_details.all - expect(all_user_details.size).to eq(4) - end - - it 'migrates `bio`' do - subject - - user_detail = user_details.find_by!(user_id: user_needs_migration.id) - - expect(user_detail.bio).to eq('bio') - end - - it 'migrates long `bio`' do - subject - - user_detail = user_details.find_by!(user_id: user_with_long_bio.id) - - expect(user_detail.bio).to eq('a' * 255) - end - - it 'does not change existing user detail' do - expect { subject }.not_to change { user_details.find_by!(user_id: user_already_has_details.id).attributes } - end - - it 'changes existing user detail when the columns are different' do - expect { subject }.to change { user_details.find_by!(user_id: user_has_different_details.id).bio }.from('bio').to('different') - end - - it 'does not migrate record' do - subject - - user_detail = user_details.find_by(user_id: user_needs_no_migration.id) - - expect(user_detail).to be_nil - end - - it 'does not migrate empty bio' do - subject - - user_detail = user_details.find_by(user_id: user_also_needs_no_migration.id) - - expect(user_detail).to be_nil - end -end diff --git a/spec/lib/gitlab/background_migration/populate_canonical_emails_spec.rb b/spec/lib/gitlab/background_migration/populate_canonical_emails_spec.rb index 36000dc3ffd..944ee98ed4a 100644 --- a/spec/lib/gitlab/background_migration/populate_canonical_emails_spec.rb +++ b/spec/lib/gitlab/background_migration/populate_canonical_emails_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::PopulateCanonicalEmails, :migration, schema: 20200312053852 do +RSpec.describe Gitlab::BackgroundMigration::PopulateCanonicalEmails, :migration, schema: 20181228175414 do let(:migration) { described_class.new } let_it_be(:users_table) { table(:users) } diff --git a/spec/lib/gitlab/background_migration/populate_dismissed_state_for_vulnerabilities_spec.rb b/spec/lib/gitlab/background_migration/populate_dismissed_state_for_vulnerabilities_spec.rb index bc55f240a58..dc8c8c75b83 100644 --- a/spec/lib/gitlab/background_migration/populate_dismissed_state_for_vulnerabilities_spec.rb +++ b/spec/lib/gitlab/background_migration/populate_dismissed_state_for_vulnerabilities_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe ::Gitlab::BackgroundMigration::PopulateDismissedStateForVulnerabilities, schema: 2020_11_30_103926 do +RSpec.describe ::Gitlab::BackgroundMigration::PopulateDismissedStateForVulnerabilities, schema: 20181228175414 do let(:users) { table(:users) } let(:namespaces) { table(:namespaces) } let(:projects) { table(:projects) } diff --git a/spec/lib/gitlab/background_migration/populate_finding_uuid_for_vulnerability_feedback_spec.rb b/spec/lib/gitlab/background_migration/populate_finding_uuid_for_vulnerability_feedback_spec.rb index 07b1d99d333..25006e663ab 100644 --- a/spec/lib/gitlab/background_migration/populate_finding_uuid_for_vulnerability_feedback_spec.rb +++ b/spec/lib/gitlab/background_migration/populate_finding_uuid_for_vulnerability_feedback_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::PopulateFindingUuidForVulnerabilityFeedback, schema: 20201211090634 do +RSpec.describe Gitlab::BackgroundMigration::PopulateFindingUuidForVulnerabilityFeedback, schema: 20181228175414 do let(:namespaces) { table(:namespaces) } let(:projects) { table(:projects) } let(:users) { table(:users) } diff --git a/spec/lib/gitlab/background_migration/populate_has_vulnerabilities_spec.rb b/spec/lib/gitlab/background_migration/populate_has_vulnerabilities_spec.rb index c6385340ca3..6722321d5f7 100644 --- a/spec/lib/gitlab/background_migration/populate_has_vulnerabilities_spec.rb +++ b/spec/lib/gitlab/background_migration/populate_has_vulnerabilities_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::PopulateHasVulnerabilities, schema: 20201103192526 do +RSpec.describe Gitlab::BackgroundMigration::PopulateHasVulnerabilities, schema: 20181228175414 do let(:users) { table(:users) } let(:namespaces) { table(:namespaces) } let(:projects) { table(:projects) } diff --git a/spec/lib/gitlab/background_migration/populate_issue_email_participants_spec.rb b/spec/lib/gitlab/background_migration/populate_issue_email_participants_spec.rb index f724b007e01..a03a11489b5 100644 --- a/spec/lib/gitlab/background_migration/populate_issue_email_participants_spec.rb +++ b/spec/lib/gitlab/background_migration/populate_issue_email_participants_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::PopulateIssueEmailParticipants, schema: 20201128210234 do +RSpec.describe Gitlab::BackgroundMigration::PopulateIssueEmailParticipants, schema: 20181228175414 do let!(:namespace) { table(:namespaces).create!(name: 'namespace', path: 'namespace') } let!(:project) { table(:projects).create!(id: 1, namespace_id: namespace.id) } let!(:issue1) { table(:issues).create!(id: 1, project_id: project.id, service_desk_reply_to: "a@gitlab.com") } diff --git a/spec/lib/gitlab/background_migration/populate_missing_vulnerability_dismissal_information_spec.rb b/spec/lib/gitlab/background_migration/populate_missing_vulnerability_dismissal_information_spec.rb index 44c5f3d1381..1c987d3876f 100644 --- a/spec/lib/gitlab/background_migration/populate_missing_vulnerability_dismissal_information_spec.rb +++ b/spec/lib/gitlab/background_migration/populate_missing_vulnerability_dismissal_information_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::PopulateMissingVulnerabilityDismissalInformation, schema: 20201028160832 do +RSpec.describe Gitlab::BackgroundMigration::PopulateMissingVulnerabilityDismissalInformation, schema: 20181228175414 do let(:users) { table(:users) } let(:namespaces) { table(:namespaces) } let(:projects) { table(:projects) } diff --git a/spec/lib/gitlab/background_migration/populate_personal_snippet_statistics_spec.rb b/spec/lib/gitlab/background_migration/populate_personal_snippet_statistics_spec.rb index e746451b1b9..f9628849dbf 100644 --- a/spec/lib/gitlab/background_migration/populate_personal_snippet_statistics_spec.rb +++ b/spec/lib/gitlab/background_migration/populate_personal_snippet_statistics_spec.rb @@ -111,11 +111,11 @@ RSpec.describe Gitlab::BackgroundMigration::PopulatePersonalSnippetStatistics do if with_repo allow(snippet).to receive(:disk_path).and_return(disk_path(snippet)) + raw_repository(snippet).create_repository + TestEnv.copy_repo(snippet, bare_repo: TestEnv.factory_repo_path_bare, refs: TestEnv::BRANCH_SHA) - - raw_repository(snippet).create_repository end end end diff --git a/spec/lib/gitlab/background_migration/populate_project_snippet_statistics_spec.rb b/spec/lib/gitlab/background_migration/populate_project_snippet_statistics_spec.rb index 897f5e81372..7884e0d97c0 100644 --- a/spec/lib/gitlab/background_migration/populate_project_snippet_statistics_spec.rb +++ b/spec/lib/gitlab/background_migration/populate_project_snippet_statistics_spec.rb @@ -183,11 +183,11 @@ RSpec.describe Gitlab::BackgroundMigration::PopulateProjectSnippetStatistics do if with_repo allow(snippet).to receive(:disk_path).and_return(disk_path(snippet)) + raw_repository(snippet).create_repository + TestEnv.copy_repo(snippet, bare_repo: TestEnv.factory_repo_path_bare, refs: TestEnv::BRANCH_SHA) - - raw_repository(snippet).create_repository end end end diff --git a/spec/lib/gitlab/background_migration/populate_user_highest_roles_table_spec.rb b/spec/lib/gitlab/background_migration/populate_user_highest_roles_table_spec.rb deleted file mode 100644 index b3cacc60cdc..00000000000 --- a/spec/lib/gitlab/background_migration/populate_user_highest_roles_table_spec.rb +++ /dev/null @@ -1,71 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Gitlab::BackgroundMigration::PopulateUserHighestRolesTable, schema: 20200311130802 do - let(:members) { table(:members) } - let(:users) { table(:users) } - let(:user_highest_roles) { table(:user_highest_roles) } - - def create_user(id, params = {}) - user_params = { - id: id, - state: 'active', - user_type: nil, - bot_type: nil, - ghost: nil, - email: "user#{id}@example.com", - projects_limit: 0 - }.merge(params) - - users.create!(user_params) - end - - def create_member(id, access_level, params = {}) - params = { - user_id: id, - access_level: access_level, - source_id: 1, - source_type: 'Group', - notification_level: 0 - }.merge(params) - - members.create!(params) - end - - before do - create_user(1) - create_user(2, state: 'blocked') - create_user(3, user_type: 2) - create_user(4) - create_user(5, bot_type: 1) - create_user(6, ghost: true) - create_user(7, ghost: false) - create_user(8) - - create_member(1, 40) - create_member(7, 30) - create_member(8, 20, requested_at: Time.current) - - user_highest_roles.create!(user_id: 1, highest_access_level: 50) - end - - describe '#perform' do - it 'creates user_highest_roles rows according to users', :aggregate_failures do - expect { subject.perform(1, 8) }.to change(UserHighestRole, :count).from(1).to(4) - - created_or_updated_rows = [ - { 'user_id' => 1, 'highest_access_level' => 40 }, - { 'user_id' => 4, 'highest_access_level' => nil }, - { 'user_id' => 7, 'highest_access_level' => 30 }, - { 'user_id' => 8, 'highest_access_level' => nil } - ] - - rows = user_highest_roles.order(:user_id).map do |row| - row.attributes.slice('user_id', 'highest_access_level') - end - - expect(rows).to match_array(created_or_updated_rows) - end - end -end diff --git a/spec/lib/gitlab/background_migration/project_namespaces/backfill_project_namespaces_spec.rb b/spec/lib/gitlab/background_migration/project_namespaces/backfill_project_namespaces_spec.rb new file mode 100644 index 00000000000..24259b06469 --- /dev/null +++ b/spec/lib/gitlab/background_migration/project_namespaces/backfill_project_namespaces_spec.rb @@ -0,0 +1,254 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::BackgroundMigration::ProjectNamespaces::BackfillProjectNamespaces, :migration do + include MigrationsHelpers + + context 'when migrating data', :aggregate_failures do + let(:projects) { table(:projects) } + let(:namespaces) { table(:namespaces) } + + let(:parent_group1) { namespaces.create!(name: 'parent_group1', path: 'parent_group1', visibility_level: 20, type: 'Group') } + let(:parent_group2) { namespaces.create!(name: 'test1', path: 'test1', runners_token: 'my-token1', project_creation_level: 1, visibility_level: 20, type: 'Group') } + + let(:parent_group1_project) { projects.create!(name: 'parent_group1_project', path: 'parent_group1_project', namespace_id: parent_group1.id, visibility_level: 20) } + let(:parent_group2_project) { projects.create!(name: 'parent_group2_project', path: 'parent_group2_project', namespace_id: parent_group2.id, visibility_level: 20) } + + let(:child_nodes_count) { 2 } + let(:tree_depth) { 3 } + + let(:backfilled_namespace) { nil } + + before do + BackfillProjectNamespaces::TreeGenerator.new(namespaces, projects, [parent_group1, parent_group2], child_nodes_count, tree_depth).build_tree + end + + describe '#up' do + shared_examples 'back-fill project namespaces' do + it 'back-fills all project namespaces' do + start_id = ::Project.minimum(:id) + end_id = ::Project.maximum(:id) + projects_count = ::Project.count + batches_count = (projects_count / described_class::BATCH_SIZE.to_f).ceil + project_namespaces_count = ::Namespace.where(type: 'Project').count + migration = described_class.new + + expect(projects_count).not_to eq(project_namespaces_count) + expect(migration).to receive(:batch_insert_namespaces).exactly(batches_count).and_call_original + expect(migration).to receive(:batch_update_projects).exactly(batches_count).and_call_original + expect(migration).to receive(:batch_update_project_namespaces_traversal_ids).exactly(batches_count).and_call_original + + expect { migration.perform(start_id, end_id, nil, 'up') }.to change(Namespace.where(type: 'Project'), :count) + + expect(projects_count).to eq(::Namespace.where(type: 'Project').count) + check_projects_in_sync_with(Namespace.where(type: 'Project')) + end + + context 'when passing specific group as parameter' do + let(:backfilled_namespace) { parent_group1 } + + it 'back-fills project namespaces for the specified group hierarchy' do + backfilled_namespace_projects = base_ancestor(backfilled_namespace).first.all_projects + start_id = backfilled_namespace_projects.minimum(:id) + end_id = backfilled_namespace_projects.maximum(:id) + group_projects_count = backfilled_namespace_projects.count + batches_count = (group_projects_count / described_class::BATCH_SIZE.to_f).ceil + project_namespaces_in_hierarchy = project_namespaces_in_hierarchy(base_ancestor(backfilled_namespace)) + + migration = described_class.new + + expect(project_namespaces_in_hierarchy.count).to eq(0) + expect(migration).to receive(:batch_insert_namespaces).exactly(batches_count).and_call_original + expect(migration).to receive(:batch_update_projects).exactly(batches_count).and_call_original + expect(migration).to receive(:batch_update_project_namespaces_traversal_ids).exactly(batches_count).and_call_original + + expect(group_projects_count).to eq(14) + expect(project_namespaces_in_hierarchy.count).to eq(0) + + migration.perform(start_id, end_id, backfilled_namespace.id, 'up') + + expect(project_namespaces_in_hierarchy.count).to eq(14) + check_projects_in_sync_with(project_namespaces_in_hierarchy) + end + end + + context 'when projects already have project namespaces' do + before do + hierarchy1_projects = base_ancestor(parent_group1).first.all_projects + start_id = hierarchy1_projects.minimum(:id) + end_id = hierarchy1_projects.maximum(:id) + + described_class.new.perform(start_id, end_id, parent_group1.id, 'up') + end + + it 'does not duplicate project namespaces' do + # check there are already some project namespaces but not for all + projects_count = ::Project.count + start_id = ::Project.minimum(:id) + end_id = ::Project.maximum(:id) + batches_count = (projects_count / described_class::BATCH_SIZE.to_f).ceil + project_namespaces = ::Namespace.where(type: 'Project') + migration = described_class.new + + expect(project_namespaces_in_hierarchy(base_ancestor(parent_group1)).count).to be >= 14 + expect(project_namespaces_in_hierarchy(base_ancestor(parent_group2)).count).to eq(0) + expect(projects_count).not_to eq(project_namespaces.count) + + # run migration again to test we do not generate extra project namespaces + expect(migration).to receive(:batch_insert_namespaces).exactly(batches_count).and_call_original + expect(migration).to receive(:batch_update_projects).exactly(batches_count).and_call_original + expect(migration).to receive(:batch_update_project_namespaces_traversal_ids).exactly(batches_count).and_call_original + + expect { migration.perform(start_id, end_id, nil, 'up') }.to change(project_namespaces, :count).by(14) + + expect(projects_count).to eq(project_namespaces.count) + end + end + end + + it 'checks no project namespaces exist in the defined hierarchies' do + hierarchy1_project_namespaces = project_namespaces_in_hierarchy(base_ancestor(parent_group1)) + hierarchy2_project_namespaces = project_namespaces_in_hierarchy(base_ancestor(parent_group2)) + hierarchy1_projects_count = base_ancestor(parent_group1).first.all_projects.count + hierarchy2_projects_count = base_ancestor(parent_group2).first.all_projects.count + + expect(hierarchy1_project_namespaces).to be_empty + expect(hierarchy2_project_namespaces).to be_empty + expect(hierarchy1_projects_count).to eq(14) + expect(hierarchy2_projects_count).to eq(14) + end + + context 'back-fill project namespaces in a single batch' do + it_behaves_like 'back-fill project namespaces' + end + + context 'back-fill project namespaces in batches' do + before do + stub_const("#{described_class.name}::BATCH_SIZE", 2) + end + + it_behaves_like 'back-fill project namespaces' + end + end + + describe '#down' do + before do + start_id = ::Project.minimum(:id) + end_id = ::Project.maximum(:id) + # back-fill first + described_class.new.perform(start_id, end_id, nil, 'up') + end + + shared_examples 'cleanup project namespaces' do + it 'removes project namespaces' do + projects_count = ::Project.count + start_id = ::Project.minimum(:id) + end_id = ::Project.maximum(:id) + migration = described_class.new + batches_count = (projects_count / described_class::BATCH_SIZE.to_f).ceil + + expect(projects_count).to be > 0 + expect(projects_count).to eq(::Namespace.where(type: 'Project').count) + + expect(migration).to receive(:nullify_project_namespaces_in_projects).exactly(batches_count).and_call_original + expect(migration).to receive(:delete_project_namespace_records).exactly(batches_count).and_call_original + + migration.perform(start_id, end_id, nil, 'down') + + expect(::Project.count).to be > 0 + expect(::Namespace.where(type: 'Project').count).to eq(0) + end + + context 'when passing specific group as parameter' do + let(:backfilled_namespace) { parent_group1 } + + it 'removes project namespaces only for the specific group hierarchy' do + backfilled_namespace_projects = base_ancestor(backfilled_namespace).first.all_projects + start_id = backfilled_namespace_projects.minimum(:id) + end_id = backfilled_namespace_projects.maximum(:id) + group_projects_count = backfilled_namespace_projects.count + batches_count = (group_projects_count / described_class::BATCH_SIZE.to_f).ceil + project_namespaces_in_hierarchy = project_namespaces_in_hierarchy(base_ancestor(backfilled_namespace)) + migration = described_class.new + + expect(project_namespaces_in_hierarchy.count).to eq(14) + expect(migration).to receive(:nullify_project_namespaces_in_projects).exactly(batches_count).and_call_original + expect(migration).to receive(:delete_project_namespace_records).exactly(batches_count).and_call_original + + migration.perform(start_id, end_id, backfilled_namespace.id, 'down') + + expect(::Namespace.where(type: 'Project').count).to be > 0 + expect(project_namespaces_in_hierarchy.count).to eq(0) + end + end + end + + context 'cleanup project namespaces in a single batch' do + it_behaves_like 'cleanup project namespaces' + end + + context 'cleanup project namespaces in batches' do + before do + stub_const("#{described_class.name}::BATCH_SIZE", 2) + end + + it_behaves_like 'cleanup project namespaces' + end + end + end + + def base_ancestor(ancestor) + ::Namespace.where(id: ancestor.id) + end + + def project_namespaces_in_hierarchy(base_node) + Gitlab::ObjectHierarchy.new(base_node).base_and_descendants.where(type: 'Project') + end + + def check_projects_in_sync_with(namespaces) + project_namespaces_attrs = namespaces.order(:id).pluck(:id, :name, :path, :parent_id, :visibility_level, :shared_runners_enabled) + corresponding_projects_attrs = Project.where(project_namespace_id: project_namespaces_attrs.map(&:first)) + .order(:project_namespace_id).pluck(:project_namespace_id, :name, :path, :namespace_id, :visibility_level, :shared_runners_enabled) + + expect(project_namespaces_attrs).to eq(corresponding_projects_attrs) + end +end + +module BackfillProjectNamespaces + class TreeGenerator + def initialize(namespaces, projects, parent_nodes, child_nodes_count, tree_depth) + parent_nodes_ids = parent_nodes.map(&:id) + + @namespaces = namespaces + @projects = projects + @subgroups_depth = tree_depth + @resource_count = child_nodes_count + @all_groups = [parent_nodes_ids] + end + + def build_tree + (1..@subgroups_depth).each do |level| + parent_level = level - 1 + current_level = level + parent_groups = @all_groups[parent_level] + + parent_groups.each do |parent_id| + @resource_count.times do |i| + group_path = "child#{i}_level#{level}" + project_path = "project#{i}_level#{level}" + sub_group = @namespaces.create!(name: group_path, path: group_path, parent_id: parent_id, visibility_level: 20, type: 'Group') + @projects.create!(name: project_path, path: project_path, namespace_id: sub_group.id, visibility_level: 20) + + track_group_id(current_level, sub_group.id) + end + end + end + end + + def track_group_id(depth_level, group_id) + @all_groups[depth_level] ||= [] + @all_groups[depth_level] << group_id + end + end +end diff --git a/spec/lib/gitlab/background_migration/recalculate_project_authorizations_with_min_max_user_id_spec.rb b/spec/lib/gitlab/background_migration/recalculate_project_authorizations_with_min_max_user_id_spec.rb index c1ba1607b89..1830a7fc099 100644 --- a/spec/lib/gitlab/background_migration/recalculate_project_authorizations_with_min_max_user_id_spec.rb +++ b/spec/lib/gitlab/background_migration/recalculate_project_authorizations_with_min_max_user_id_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::RecalculateProjectAuthorizationsWithMinMaxUserId, schema: 20200204113224 do +RSpec.describe Gitlab::BackgroundMigration::RecalculateProjectAuthorizationsWithMinMaxUserId, schema: 20181228175414 do let(:users_table) { table(:users) } let(:min) { 1 } let(:max) { 5 } diff --git a/spec/lib/gitlab/background_migration/recalculate_vulnerabilities_occurrences_uuid_spec.rb b/spec/lib/gitlab/background_migration/recalculate_vulnerabilities_occurrences_uuid_spec.rb index 30908145782..4cdb56d3d3b 100644 --- a/spec/lib/gitlab/background_migration/recalculate_vulnerabilities_occurrences_uuid_spec.rb +++ b/spec/lib/gitlab/background_migration/recalculate_vulnerabilities_occurrences_uuid_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::RecalculateVulnerabilitiesOccurrencesUuid, schema: 20201110110454 do +RSpec.describe Gitlab::BackgroundMigration::RecalculateVulnerabilitiesOccurrencesUuid, schema: 20181228175414 do let(:namespace) { table(:namespaces).create!(name: 'user', path: 'user') } let(:users) { table(:users) } let(:user) { create_user! } diff --git a/spec/lib/gitlab/background_migration/remove_duplicate_services_spec.rb b/spec/lib/gitlab/background_migration/remove_duplicate_services_spec.rb index 391b27b28e6..afcdaaf1cb8 100644 --- a/spec/lib/gitlab/background_migration/remove_duplicate_services_spec.rb +++ b/spec/lib/gitlab/background_migration/remove_duplicate_services_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::RemoveDuplicateServices, :migration, schema: 20201207165956 do +RSpec.describe Gitlab::BackgroundMigration::RemoveDuplicateServices, :migration, schema: 20181228175414 do let_it_be(:users) { table(:users) } let_it_be(:namespaces) { table(:namespaces) } let_it_be(:projects) { table(:projects) } diff --git a/spec/lib/gitlab/background_migration/remove_duplicate_vulnerabilities_findings_spec.rb b/spec/lib/gitlab/background_migration/remove_duplicate_vulnerabilities_findings_spec.rb index 47e1d4620cd..7214225c32c 100644 --- a/spec/lib/gitlab/background_migration/remove_duplicate_vulnerabilities_findings_spec.rb +++ b/spec/lib/gitlab/background_migration/remove_duplicate_vulnerabilities_findings_spec.rb @@ -5,9 +5,9 @@ RSpec.describe Gitlab::BackgroundMigration::RemoveDuplicateVulnerabilitiesFindin let(:namespace) { table(:namespaces).create!(name: 'user', path: 'user') } let(:users) { table(:users) } let(:user) { create_user! } - let(:project) { table(:projects).create!(id: 123, namespace_id: namespace.id) } + let(:project) { table(:projects).create!(id: 14219619, namespace_id: namespace.id) } let(:scanners) { table(:vulnerability_scanners) } - let!(:scanner) { scanners.create!(project_id: project.id, external_id: 'test 1', name: 'test scanner 1') } + let!(:scanner1) { scanners.create!(project_id: project.id, external_id: 'test 1', name: 'test scanner 1') } let!(:scanner2) { scanners.create!(project_id: project.id, external_id: 'test 2', name: 'test scanner 2') } let!(:scanner3) { scanners.create!(project_id: project.id, external_id: 'test 3', name: 'test scanner 3') } let!(:unrelated_scanner) { scanners.create!(project_id: project.id, external_id: 'unreleated_scanner', name: 'unrelated scanner') } @@ -16,43 +16,68 @@ RSpec.describe Gitlab::BackgroundMigration::RemoveDuplicateVulnerabilitiesFindin let(:vulnerability_identifiers) { table(:vulnerability_identifiers) } let(:vulnerability_identifier) do vulnerability_identifiers.create!( + id: 1244459, project_id: project.id, external_type: 'vulnerability-identifier', external_id: 'vulnerability-identifier', - fingerprint: '7e394d1b1eb461a7406d7b1e08f057a1cf11287a', + fingerprint: '0a203e8cd5260a1948edbedc76c7cb91ad6a2e45', name: 'vulnerability identifier') end - let!(:first_finding) do + let!(:vulnerability_for_first_duplicate) do + create_vulnerability!( + project_id: project.id, + author_id: user.id + ) + end + + let!(:first_finding_duplicate) do create_finding!( - uuid: "test1", - vulnerability_id: nil, + id: 5606961, + uuid: "bd95c085-71aa-51d7-9bb6-08ae669c262e", + vulnerability_id: vulnerability_for_first_duplicate.id, report_type: 0, - location_fingerprint: '2bda3014914481791847d8eca38d1a8d13b6ad76', + location_fingerprint: '00049d5119c2cb3bfb3d1ee1f6e031fe925aed75', primary_identifier_id: vulnerability_identifier.id, - scanner_id: scanner.id, + scanner_id: scanner1.id, project_id: project.id ) end - let!(:first_duplicate) do + let!(:vulnerability_for_second_duplicate) do + create_vulnerability!( + project_id: project.id, + author_id: user.id + ) + end + + let!(:second_finding_duplicate) do create_finding!( - uuid: "test2", - vulnerability_id: nil, + id: 8765432, + uuid: "5b714f58-1176-5b26-8fd5-e11dfcb031b5", + vulnerability_id: vulnerability_for_second_duplicate.id, report_type: 0, - location_fingerprint: '2bda3014914481791847d8eca38d1a8d13b6ad76', + location_fingerprint: '00049d5119c2cb3bfb3d1ee1f6e031fe925aed75', primary_identifier_id: vulnerability_identifier.id, scanner_id: scanner2.id, project_id: project.id ) end - let!(:second_duplicate) do + let!(:vulnerability_for_third_duplicate) do + create_vulnerability!( + project_id: project.id, + author_id: user.id + ) + end + + let!(:third_finding_duplicate) do create_finding!( - uuid: "test3", - vulnerability_id: nil, + id: 8832995, + uuid: "cfe435fa-b25b-5199-a56d-7b007cc9e2d4", + vulnerability_id: vulnerability_for_third_duplicate.id, report_type: 0, - location_fingerprint: '2bda3014914481791847d8eca38d1a8d13b6ad76', + location_fingerprint: '00049d5119c2cb3bfb3d1ee1f6e031fe925aed75', primary_identifier_id: vulnerability_identifier.id, scanner_id: scanner3.id, project_id: project.id @@ -61,6 +86,7 @@ RSpec.describe Gitlab::BackgroundMigration::RemoveDuplicateVulnerabilitiesFindin let!(:unrelated_finding) do create_finding!( + id: 9999999, uuid: "unreleated_finding", vulnerability_id: nil, report_type: 1, @@ -71,7 +97,7 @@ RSpec.describe Gitlab::BackgroundMigration::RemoveDuplicateVulnerabilitiesFindin ) end - subject { described_class.new.perform(first_finding.id, unrelated_finding.id) } + subject { described_class.new.perform(first_finding_duplicate.id, unrelated_finding.id) } before do stub_const("#{described_class}::DELETE_BATCH_SIZE", 1) @@ -82,7 +108,15 @@ RSpec.describe Gitlab::BackgroundMigration::RemoveDuplicateVulnerabilitiesFindin expect { subject }.to change { vulnerability_findings.count }.from(4).to(2) - expect(vulnerability_findings.pluck(:id)).to eq([second_duplicate.id, unrelated_finding.id]) + expect(vulnerability_findings.pluck(:id)).to match_array([third_finding_duplicate.id, unrelated_finding.id]) + end + + it "removes vulnerabilites without findings" do + expect(vulnerabilities.count).to eq(3) + + expect { subject }.to change { vulnerabilities.count }.from(3).to(1) + + expect(vulnerabilities.pluck(:id)).to match_array([vulnerability_for_third_duplicate.id]) end private @@ -100,11 +134,12 @@ RSpec.describe Gitlab::BackgroundMigration::RemoveDuplicateVulnerabilitiesFindin # rubocop:disable Metrics/ParameterLists def create_finding!( + id: nil, vulnerability_id:, project_id:, scanner_id:, primary_identifier_id:, name: "test", severity: 7, confidence: 7, report_type: 0, project_fingerprint: '123qweasdzxc', location_fingerprint: 'test', metadata_version: 'test', raw_metadata: 'test', uuid: 'test') - vulnerability_findings.create!( + params = { vulnerability_id: vulnerability_id, project_id: project_id, name: name, @@ -118,7 +153,9 @@ RSpec.describe Gitlab::BackgroundMigration::RemoveDuplicateVulnerabilitiesFindin metadata_version: metadata_version, raw_metadata: raw_metadata, uuid: uuid - ) + } + params[:id] = id unless id.nil? + vulnerability_findings.create!(params) end # rubocop:enable Metrics/ParameterLists diff --git a/spec/lib/gitlab/background_migration/replace_blocked_by_links_spec.rb b/spec/lib/gitlab/background_migration/replace_blocked_by_links_spec.rb index 561a602fab9..6cfdbb5a14e 100644 --- a/spec/lib/gitlab/background_migration/replace_blocked_by_links_spec.rb +++ b/spec/lib/gitlab/background_migration/replace_blocked_by_links_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::ReplaceBlockedByLinks, schema: 20201015073808 do +RSpec.describe Gitlab::BackgroundMigration::ReplaceBlockedByLinks, schema: 20181228175414 do let(:namespace) { table(:namespaces).create!(name: 'gitlab', path: 'gitlab-org') } let(:project) { table(:projects).create!(namespace_id: namespace.id, name: 'gitlab') } let(:issue1) { table(:issues).create!(project_id: project.id, title: 'a') } diff --git a/spec/lib/gitlab/background_migration/reset_shared_runners_for_transferred_projects_spec.rb b/spec/lib/gitlab/background_migration/reset_shared_runners_for_transferred_projects_spec.rb index 68aa64a1c7d..ef90b5674f0 100644 --- a/spec/lib/gitlab/background_migration/reset_shared_runners_for_transferred_projects_spec.rb +++ b/spec/lib/gitlab/background_migration/reset_shared_runners_for_transferred_projects_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::ResetSharedRunnersForTransferredProjects, schema: 20201110161542 do +RSpec.describe Gitlab::BackgroundMigration::ResetSharedRunnersForTransferredProjects, schema: 20181228175414 do let(:namespaces) { table(:namespaces) } let(:projects) { table(:projects) } diff --git a/spec/lib/gitlab/background_migration/set_default_iteration_cadences_spec.rb b/spec/lib/gitlab/background_migration/set_default_iteration_cadences_spec.rb deleted file mode 100644 index 46c919f0854..00000000000 --- a/spec/lib/gitlab/background_migration/set_default_iteration_cadences_spec.rb +++ /dev/null @@ -1,80 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Gitlab::BackgroundMigration::SetDefaultIterationCadences, schema: 20201231133921 do - let(:namespaces) { table(:namespaces) } - let(:iterations) { table(:sprints) } - let(:iterations_cadences) { table(:iterations_cadences) } - - describe '#perform' do - context 'when no iteration cadences exists' do - let!(:group_1) { namespaces.create!(name: 'group 1', path: 'group-1') } - let!(:group_2) { namespaces.create!(name: 'group 2', path: 'group-2') } - let!(:group_3) { namespaces.create!(name: 'group 3', path: 'group-3') } - - let!(:iteration_1) { iterations.create!(group_id: group_1.id, iid: 1, title: 'Iteration 1', start_date: 10.days.ago, due_date: 8.days.ago) } - let!(:iteration_2) { iterations.create!(group_id: group_3.id, iid: 1, title: 'Iteration 2', start_date: 10.days.ago, due_date: 8.days.ago) } - let!(:iteration_3) { iterations.create!(group_id: group_3.id, iid: 1, title: 'Iteration 3', start_date: 5.days.ago, due_date: 2.days.ago) } - - subject { described_class.new.perform(group_1.id, group_2.id, group_3.id, namespaces.last.id + 1) } - - before do - subject - end - - it 'creates iterations_cadence records for the requested groups' do - expect(iterations_cadences.count).to eq(2) - end - - it 'assigns the iteration cadences to the iterations correctly' do - iterations_cadence = iterations_cadences.find_by(group_id: group_1.id) - iteration_records = iterations.where(iterations_cadence_id: iterations_cadence.id) - - expect(iterations_cadence.start_date).to eq(iteration_1.start_date) - expect(iterations_cadence.last_run_date).to eq(iteration_1.start_date) - expect(iterations_cadence.title).to eq('group 1 Iterations') - expect(iteration_records.size).to eq(1) - expect(iteration_records.first.id).to eq(iteration_1.id) - - iterations_cadence = iterations_cadences.find_by(group_id: group_3.id) - iteration_records = iterations.where(iterations_cadence_id: iterations_cadence.id) - - expect(iterations_cadence.start_date).to eq(iteration_3.start_date) - expect(iterations_cadence.last_run_date).to eq(iteration_3.start_date) - expect(iterations_cadence.title).to eq('group 3 Iterations') - expect(iteration_records.size).to eq(2) - expect(iteration_records.first.id).to eq(iteration_2.id) - expect(iteration_records.second.id).to eq(iteration_3.id) - end - - it 'does not call Group class' do - expect(::Group).not_to receive(:where) - - subject - end - end - - context 'when an iteration cadence exists for a group' do - let!(:group) { namespaces.create!(name: 'group', path: 'group') } - - let!(:iterations_cadence_1) { iterations_cadences.create!(group_id: group.id, start_date: 2.days.ago, title: 'Cadence 1') } - - let!(:iteration_1) { iterations.create!(group_id: group.id, iid: 1, title: 'Iteration 1', start_date: 10.days.ago, due_date: 8.days.ago) } - let!(:iteration_2) { iterations.create!(group_id: group.id, iterations_cadence_id: iterations_cadence_1.id, iid: 2, title: 'Iteration 2', start_date: 5.days.ago, due_date: 3.days.ago) } - - subject { described_class.new.perform(group.id) } - - it 'does not create a new iterations_cadence' do - expect { subject }.not_to change { iterations_cadences.count } - end - - it 'assigns iteration cadences to iterations if needed' do - subject - - expect(iteration_1.reload.iterations_cadence_id).to eq(iterations_cadence_1.id) - expect(iteration_2.reload.iterations_cadence_id).to eq(iterations_cadence_1.id) - end - end - end -end diff --git a/spec/lib/gitlab/background_migration/set_merge_request_diff_files_count_spec.rb b/spec/lib/gitlab/background_migration/set_merge_request_diff_files_count_spec.rb index f23518625e4..1fdbdf25706 100644 --- a/spec/lib/gitlab/background_migration/set_merge_request_diff_files_count_spec.rb +++ b/spec/lib/gitlab/background_migration/set_merge_request_diff_files_count_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::SetMergeRequestDiffFilesCount, schema: 20200807152315 do +RSpec.describe Gitlab::BackgroundMigration::SetMergeRequestDiffFilesCount, schema: 20181228175414 do let(:merge_request_diff_files) { table(:merge_request_diff_files) } let(:merge_request_diffs) { table(:merge_request_diffs) } let(:merge_requests) { table(:merge_requests) } diff --git a/spec/lib/gitlab/background_migration/set_null_external_diff_store_to_local_value_spec.rb b/spec/lib/gitlab/background_migration/set_null_external_diff_store_to_local_value_spec.rb deleted file mode 100644 index 6079ad2dd2a..00000000000 --- a/spec/lib/gitlab/background_migration/set_null_external_diff_store_to_local_value_spec.rb +++ /dev/null @@ -1,33 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -# The test setup must begin before -# 20200804041930_add_not_null_constraint_on_external_diff_store_to_merge_request_diffs.rb -# has run, or else we cannot insert a row with `NULL` `external_diff_store` to -# test against. -RSpec.describe Gitlab::BackgroundMigration::SetNullExternalDiffStoreToLocalValue, schema: 20200804035230 do - let!(:merge_request_diffs) { table(:merge_request_diffs) } - let!(:merge_requests) { table(:merge_requests) } - let!(:namespaces) { table(:namespaces) } - let!(:projects) { table(:projects) } - let!(:namespace) { namespaces.create!(name: 'foo', path: 'foo') } - let!(:project) { projects.create!(namespace_id: namespace.id) } - let!(:merge_request) { merge_requests.create!(source_branch: 'x', target_branch: 'master', target_project_id: project.id) } - - it 'correctly migrates nil external_diff_store to 1' do - external_diff_store_1 = merge_request_diffs.create!(external_diff_store: 1, merge_request_id: merge_request.id) - external_diff_store_2 = merge_request_diffs.create!(external_diff_store: 2, merge_request_id: merge_request.id) - external_diff_store_nil = merge_request_diffs.create!(external_diff_store: nil, merge_request_id: merge_request.id) - - described_class.new.perform(external_diff_store_1.id, external_diff_store_nil.id) - - external_diff_store_1.reload - external_diff_store_2.reload - external_diff_store_nil.reload - - expect(external_diff_store_1.external_diff_store).to eq(1) # unchanged - expect(external_diff_store_2.external_diff_store).to eq(2) # unchanged - expect(external_diff_store_nil.external_diff_store).to eq(1) # nil => 1 - end -end diff --git a/spec/lib/gitlab/background_migration/set_null_package_files_file_store_to_local_value_spec.rb b/spec/lib/gitlab/background_migration/set_null_package_files_file_store_to_local_value_spec.rb deleted file mode 100644 index 40d41262fc7..00000000000 --- a/spec/lib/gitlab/background_migration/set_null_package_files_file_store_to_local_value_spec.rb +++ /dev/null @@ -1,33 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -# The test setup must begin before -# 20200806004742_add_not_null_constraint_on_file_store_to_package_files.rb -# has run, or else we cannot insert a row with `NULL` `file_store` to -# test against. -RSpec.describe Gitlab::BackgroundMigration::SetNullPackageFilesFileStoreToLocalValue, schema: 20200806004232 do - let!(:packages_package_files) { table(:packages_package_files) } - let!(:packages_packages) { table(:packages_packages) } - let!(:projects) { table(:projects) } - let!(:namespaces) { table(:namespaces) } - let!(:namespace) { namespaces.create!(name: 'foo', path: 'foo') } - let!(:project) { projects.create!(namespace_id: namespace.id) } - let!(:package) { packages_packages.create!(project_id: project.id, name: 'bar', package_type: 1) } - - it 'correctly migrates nil file_store to 1' do - file_store_1 = packages_package_files.create!(file_store: 1, file_name: 'foo_1', file: 'foo_1', package_id: package.id) - file_store_2 = packages_package_files.create!(file_store: 2, file_name: 'foo_2', file: 'foo_2', package_id: package.id) - file_store_nil = packages_package_files.create!(file_store: nil, file_name: 'foo_nil', file: 'foo_nil', package_id: package.id) - - described_class.new.perform(file_store_1.id, file_store_nil.id) - - file_store_1.reload - file_store_2.reload - file_store_nil.reload - - expect(file_store_1.file_store).to eq(1) # unchanged - expect(file_store_2.file_store).to eq(2) # unchanged - expect(file_store_nil.file_store).to eq(1) # nil => 1 - end -end diff --git a/spec/lib/gitlab/background_migration/steal_migrate_merge_request_diff_commit_users_spec.rb b/spec/lib/gitlab/background_migration/steal_migrate_merge_request_diff_commit_users_spec.rb index f2fb2ab6b6e..841a7f306d7 100644 --- a/spec/lib/gitlab/background_migration/steal_migrate_merge_request_diff_commit_users_spec.rb +++ b/spec/lib/gitlab/background_migration/steal_migrate_merge_request_diff_commit_users_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::StealMigrateMergeRequestDiffCommitUsers do +RSpec.describe Gitlab::BackgroundMigration::StealMigrateMergeRequestDiffCommitUsers, schema: 20211012134316 do let(:migration) { described_class.new } describe '#perform' do diff --git a/spec/lib/gitlab/background_migration/update_existing_subgroup_to_match_visibility_level_of_parent_spec.rb b/spec/lib/gitlab/background_migration/update_existing_subgroup_to_match_visibility_level_of_parent_spec.rb index 6c0a1d3a5b0..de9799c3642 100644 --- a/spec/lib/gitlab/background_migration/update_existing_subgroup_to_match_visibility_level_of_parent_spec.rb +++ b/spec/lib/gitlab/background_migration/update_existing_subgroup_to_match_visibility_level_of_parent_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::UpdateExistingSubgroupToMatchVisibilityLevelOfParent, schema: 2020_01_10_121314 do +RSpec.describe Gitlab::BackgroundMigration::UpdateExistingSubgroupToMatchVisibilityLevelOfParent, schema: 20181228175414 do include MigrationHelpers::NamespacesHelpers context 'private visibility level' do diff --git a/spec/lib/gitlab/background_migration/update_existing_users_that_require_two_factor_auth_spec.rb b/spec/lib/gitlab/background_migration/update_existing_users_that_require_two_factor_auth_spec.rb index bebb398413b..33f5e38100e 100644 --- a/spec/lib/gitlab/background_migration/update_existing_users_that_require_two_factor_auth_spec.rb +++ b/spec/lib/gitlab/background_migration/update_existing_users_that_require_two_factor_auth_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::UpdateExistingUsersThatRequireTwoFactorAuth, schema: 20201030121314 do +RSpec.describe Gitlab::BackgroundMigration::UpdateExistingUsersThatRequireTwoFactorAuth, schema: 20181228175414 do include MigrationHelpers::NamespacesHelpers let(:group_with_2fa_parent) { create_namespace('parent', Gitlab::VisibilityLevel::PRIVATE) } diff --git a/spec/lib/gitlab/background_migration/user_mentions/create_resource_user_mention_spec.rb b/spec/lib/gitlab/background_migration/user_mentions/create_resource_user_mention_spec.rb index 2dae4a65eeb..7af11ffa1e0 100644 --- a/spec/lib/gitlab/background_migration/user_mentions/create_resource_user_mention_spec.rb +++ b/spec/lib/gitlab/background_migration/user_mentions/create_resource_user_mention_spec.rb @@ -1,120 +1,8 @@ # frozen_string_literal: true require 'spec_helper' -require './db/post_migrate/20200128134110_migrate_commit_notes_mentions_to_db' -require './db/post_migrate/20200211155539_migrate_merge_request_mentions_to_db' - -RSpec.describe Gitlab::BackgroundMigration::UserMentions::CreateResourceUserMention, schema: 20200211155539 do - include MigrationsHelpers - - context 'when migrating data' do - let(:users) { table(:users) } - let(:namespaces) { table(:namespaces) } - let(:projects) { table(:projects) } - let(:notes) { table(:notes) } - let(:routes) { table(:routes) } - - let(:author) { users.create!(email: 'author@example.com', notification_email: 'author@example.com', name: 'author', username: 'author', projects_limit: 10, state: 'active') } - let(:member) { users.create!(email: 'member@example.com', notification_email: 'member@example.com', name: 'member', username: 'member', projects_limit: 10, state: 'active') } - let(:admin) { users.create!(email: 'administrator@example.com', notification_email: 'administrator@example.com', name: 'administrator', username: 'administrator', admin: 1, projects_limit: 10, state: 'active') } - let(:john_doe) { users.create!(email: 'john_doe@example.com', notification_email: 'john_doe@example.com', name: 'john_doe', username: 'john_doe', projects_limit: 10, state: 'active') } - let(:skipped) { users.create!(email: 'skipped@example.com', notification_email: 'skipped@example.com', name: 'skipped', username: 'skipped', projects_limit: 10, state: 'active') } - - let(:mentioned_users) { [author, member, admin, john_doe, skipped] } - let(:mentioned_users_refs) { mentioned_users.map { |u| "@#{u.username}" }.join(' ') } - - let(:group) { namespaces.create!(name: 'test1', path: 'test1', runners_token: 'my-token1', project_creation_level: 1, visibility_level: 20, type: 'Group') } - let(:inaccessible_group) { namespaces.create!(name: 'test2', path: 'test2', runners_token: 'my-token2', project_creation_level: 1, visibility_level: 0, type: 'Group') } - let(:project) { projects.create!(name: 'gitlab1', path: 'gitlab1', namespace_id: group.id, visibility_level: 0) } - - let(:mentioned_groups) { [group, inaccessible_group] } - let(:group_mentions) { [group, inaccessible_group].map { |gr| "@#{gr.path}" }.join(' ') } - let(:description_mentions) { "description with mentions #{mentioned_users_refs} and #{group_mentions}" } - - before do - # build personal namespaces and routes for users - mentioned_users.each do |u| - namespace = namespaces.create!(path: u.username, name: u.name, runners_token: "my-token-u#{u.id}", owner_id: u.id, type: nil) - routes.create!(path: namespace.path, source_type: 'Namespace', source_id: namespace.id) - end - - # build namespaces and routes for groups - mentioned_groups.each do |gr| - routes.create!(path: gr.path, source_type: 'Namespace', source_id: gr.id) - end - end - - context 'migrate merge request mentions' do - let(:merge_requests) { table(:merge_requests) } - let(:merge_request_user_mentions) { table(:merge_request_user_mentions) } - - let!(:mr1) do - merge_requests.create!( - title: "title 1", state_id: 1, target_branch: 'feature1', source_branch: 'master', - source_project_id: project.id, target_project_id: project.id, author_id: author.id, - description: description_mentions - ) - end - - let!(:mr2) do - merge_requests.create!( - title: "title 2", state_id: 1, target_branch: 'feature2', source_branch: 'master', - source_project_id: project.id, target_project_id: project.id, author_id: author.id, - description: 'some description' - ) - end - - let!(:mr3) do - merge_requests.create!( - title: "title 3", state_id: 1, target_branch: 'feature3', source_branch: 'master', - source_project_id: project.id, target_project_id: project.id, author_id: author.id, - description: 'description with an email@example.com and some other @ char here.') - end - - let(:user_mentions) { merge_request_user_mentions } - let(:resource) { merge_request } - - it_behaves_like 'resource mentions migration', MigrateMergeRequestMentionsToDb, 'MergeRequest' - - context 'when FF disabled' do - before do - stub_feature_flags(migrate_user_mentions: false) - end - - it_behaves_like 'resource migration not run', MigrateMergeRequestMentionsToDb, 'MergeRequest' - end - end - - context 'migrate commit mentions' do - let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '', 'group/project') } - let(:commit) { Commit.new(RepoHelpers.sample_commit, project) } - let(:commit_user_mentions) { table(:commit_user_mentions) } - - let!(:note1) { notes.create!(commit_id: commit.id, noteable_type: 'Commit', project_id: project.id, author_id: author.id, note: description_mentions) } - let!(:note2) { notes.create!(commit_id: commit.id, noteable_type: 'Commit', project_id: project.id, author_id: author.id, note: 'sample note') } - let!(:note3) { notes.create!(commit_id: commit.id, noteable_type: 'Commit', project_id: project.id, author_id: author.id, note: description_mentions, system: true) } - - # this not does not have actual mentions - let!(:note4) { notes.create!(commit_id: commit.id, noteable_type: 'Commit', project_id: project.id, author_id: author.id, note: 'note for an email@somesite.com and some other random @ ref' ) } - # this should have pointed to an innexisted commit record in a commits table - # but because commit is not an AR we'll just make it so that it does not have mentions - let!(:note5) { notes.create!(commit_id: 'abc', noteable_type: 'Commit', project_id: project.id, author_id: author.id, note: 'note for an email@somesite.com and some other random @ ref') } - - let(:user_mentions) { commit_user_mentions } - let(:resource) { commit } - - it_behaves_like 'resource notes mentions migration', MigrateCommitNotesMentionsToDb, 'Commit' - - context 'when FF disabled' do - before do - stub_feature_flags(migrate_user_mentions: false) - end - - it_behaves_like 'resource notes migration not run', MigrateCommitNotesMentionsToDb, 'Commit' - end - end - end +RSpec.describe Gitlab::BackgroundMigration::UserMentions::CreateResourceUserMention, schema: 20181228175414 do context 'checks no_quote_columns' do it 'has correct no_quote_columns' do expect(Gitlab::BackgroundMigration::UserMentions::Models::MergeRequest.no_quote_columns).to match([:note_id, :merge_request_id]) diff --git a/spec/lib/gitlab/background_migration/wrongfully_confirmed_email_unconfirmer_spec.rb b/spec/lib/gitlab/background_migration/wrongfully_confirmed_email_unconfirmer_spec.rb index 07f4429f7d9..5c197526a55 100644 --- a/spec/lib/gitlab/background_migration/wrongfully_confirmed_email_unconfirmer_spec.rb +++ b/spec/lib/gitlab/background_migration/wrongfully_confirmed_email_unconfirmer_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::WrongfullyConfirmedEmailUnconfirmer, schema: 20200615111857 do +RSpec.describe Gitlab::BackgroundMigration::WrongfullyConfirmedEmailUnconfirmer, schema: 20181228175414 do let(:users) { table(:users) } let(:emails) { table(:emails) } let(:user_synced_attributes_metadata) { table(:user_synced_attributes_metadata) } |