Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/lib/gitlab/background_migration')
-rw-r--r--spec/lib/gitlab/background_migration/batching_strategies/primary_key_batching_strategy_spec.rb45
-rw-r--r--spec/lib/gitlab/background_migration/copy_column_using_background_migration_job_spec.rb29
-rw-r--r--spec/lib/gitlab/background_migration/merge_request_assignees_migration_progress_check_spec.rb99
-rw-r--r--spec/lib/gitlab/background_migration/migrate_legacy_artifacts_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/move_container_registry_enabled_to_project_feature_spec.rb86
-rw-r--r--spec/lib/gitlab/background_migration/populate_finding_uuid_for_vulnerability_feedback_spec.rb33
-rw-r--r--spec/lib/gitlab/background_migration/recalculate_vulnerabilities_occurrences_uuid_spec.rb149
-rw-r--r--spec/lib/gitlab/background_migration/set_default_iteration_cadences_spec.rb80
8 files changed, 391 insertions, 132 deletions
diff --git a/spec/lib/gitlab/background_migration/batching_strategies/primary_key_batching_strategy_spec.rb b/spec/lib/gitlab/background_migration/batching_strategies/primary_key_batching_strategy_spec.rb
new file mode 100644
index 00000000000..8febe850e04
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/batching_strategies/primary_key_batching_strategy_spec.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::BatchingStrategies::PrimaryKeyBatchingStrategy, '#next_batch' do
+ let(:batching_strategy) { described_class.new }
+ let(:namespaces) { table(:namespaces) }
+
+ let!(:namespace1) { namespaces.create!(name: 'batchtest1', path: 'batch-test1') }
+ let!(:namespace2) { namespaces.create!(name: 'batchtest2', path: 'batch-test2') }
+ let!(:namespace3) { namespaces.create!(name: 'batchtest3', path: 'batch-test3') }
+ let!(:namespace4) { namespaces.create!(name: 'batchtest4', path: 'batch-test4') }
+
+ context 'when starting on the first batch' do
+ it 'returns the bounds of the next batch' do
+ batch_bounds = batching_strategy.next_batch(:namespaces, :id, batch_min_value: namespace1.id, batch_size: 3)
+
+ expect(batch_bounds).to eq([namespace1.id, namespace3.id])
+ end
+ end
+
+ context 'when additional batches remain' do
+ it 'returns the bounds of the next batch' do
+ batch_bounds = batching_strategy.next_batch(:namespaces, :id, batch_min_value: namespace2.id, batch_size: 3)
+
+ expect(batch_bounds).to eq([namespace2.id, namespace4.id])
+ end
+ end
+
+ context 'when on the final batch' do
+ it 'returns the bounds of the next batch' do
+ batch_bounds = batching_strategy.next_batch(:namespaces, :id, batch_min_value: namespace4.id, batch_size: 3)
+
+ expect(batch_bounds).to eq([namespace4.id, namespace4.id])
+ end
+ end
+
+ context 'when no additional batches remain' do
+ it 'returns nil' do
+ batch_bounds = batching_strategy.next_batch(:namespaces, :id, batch_min_value: namespace4.id + 1, batch_size: 1)
+
+ expect(batch_bounds).to be_nil
+ end
+ 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 110a1ff8a08..7ad93c3124a 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
@@ -38,22 +38,9 @@ RSpec.describe Gitlab::BackgroundMigration::CopyColumnUsingBackgroundMigrationJo
describe '#perform' do
let(:migration_class) { described_class.name }
- let!(:job1) do
- table(:background_migration_jobs).create!(
- class_name: migration_class,
- arguments: [1, 10, table_name, 'id', 'id', 'id_convert_to_bigint', sub_batch_size]
- )
- end
-
- let!(:job2) do
- table(:background_migration_jobs).create!(
- class_name: migration_class,
- arguments: [11, 20, table_name, 'id', 'id', 'id_convert_to_bigint', sub_batch_size]
- )
- end
it 'copies all primary keys in range' do
- subject.perform(12, 15, table_name, 'id', 'id', 'id_convert_to_bigint', sub_batch_size)
+ subject.perform(12, 15, table_name, 'id', sub_batch_size, 'id', 'id_convert_to_bigint')
expect(test_table.where('id = id_convert_to_bigint').pluck(:id)).to contain_exactly(12, 15)
expect(test_table.where(id_convert_to_bigint: 0).pluck(:id)).to contain_exactly(11, 19)
@@ -61,7 +48,7 @@ RSpec.describe Gitlab::BackgroundMigration::CopyColumnUsingBackgroundMigrationJo
end
it 'copies all foreign keys in range' do
- subject.perform(10, 14, table_name, 'id', 'fk', 'fk_convert_to_bigint', sub_batch_size)
+ subject.perform(10, 14, table_name, 'id', sub_batch_size, 'fk', 'fk_convert_to_bigint')
expect(test_table.where('fk = fk_convert_to_bigint').pluck(:id)).to contain_exactly(11, 12)
expect(test_table.where(fk_convert_to_bigint: 0).pluck(:id)).to contain_exactly(15, 19)
@@ -71,21 +58,11 @@ RSpec.describe Gitlab::BackgroundMigration::CopyColumnUsingBackgroundMigrationJo
it 'copies columns with NULLs' do
expect(test_table.where("name_convert_to_text = 'no name'").count).to eq(4)
- subject.perform(10, 20, table_name, 'id', 'name', 'name_convert_to_text', sub_batch_size)
+ subject.perform(10, 20, table_name, 'id', sub_batch_size, 'name', 'name_convert_to_text')
expect(test_table.where('name = name_convert_to_text').pluck(:id)).to contain_exactly(11, 12, 19)
expect(test_table.where('name is NULL and name_convert_to_text is NULL').pluck(:id)).to contain_exactly(15)
expect(test_table.where("name_convert_to_text = 'no name'").count).to eq(0)
end
-
- it 'tracks completion with BackgroundMigrationJob' do
- expect do
- subject.perform(11, 20, table_name, 'id', 'id', 'id_convert_to_bigint', sub_batch_size)
- end.to change { Gitlab::Database::BackgroundMigrationJob.succeeded.count }.from(0).to(1)
-
- expect(job1.reload.status).to eq(0)
- expect(job2.reload.status).to eq(1)
- expect(test_table.where('id = id_convert_to_bigint').count).to eq(4)
- end
end
end
diff --git a/spec/lib/gitlab/background_migration/merge_request_assignees_migration_progress_check_spec.rb b/spec/lib/gitlab/background_migration/merge_request_assignees_migration_progress_check_spec.rb
deleted file mode 100644
index 85a9c88ebff..00000000000
--- a/spec/lib/gitlab/background_migration/merge_request_assignees_migration_progress_check_spec.rb
+++ /dev/null
@@ -1,99 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::MergeRequestAssigneesMigrationProgressCheck do
- context 'rescheduling' do
- context 'when there are ongoing and no dead jobs' do
- it 'reschedules check' do
- allow(Gitlab::BackgroundMigration).to receive(:exists?)
- .with('PopulateMergeRequestAssigneesTable')
- .and_return(true)
-
- allow(Gitlab::BackgroundMigration).to receive(:dead_jobs?)
- .with('PopulateMergeRequestAssigneesTable')
- .and_return(false)
-
- expect(BackgroundMigrationWorker).to receive(:perform_in).with(described_class::RESCHEDULE_DELAY, described_class.name)
-
- described_class.new.perform
- end
- end
-
- context 'when there are ongoing and dead jobs' do
- it 'reschedules check' do
- allow(Gitlab::BackgroundMigration).to receive(:exists?)
- .with('PopulateMergeRequestAssigneesTable')
- .and_return(true)
-
- allow(Gitlab::BackgroundMigration).to receive(:dead_jobs?)
- .with('PopulateMergeRequestAssigneesTable')
- .and_return(true)
-
- expect(BackgroundMigrationWorker).to receive(:perform_in).with(described_class::RESCHEDULE_DELAY, described_class.name)
-
- described_class.new.perform
- end
- end
-
- context 'when there retrying jobs and no scheduled' do
- it 'reschedules check' do
- allow(Gitlab::BackgroundMigration).to receive(:exists?)
- .with('PopulateMergeRequestAssigneesTable')
- .and_return(false)
-
- allow(Gitlab::BackgroundMigration).to receive(:retrying_jobs?)
- .with('PopulateMergeRequestAssigneesTable')
- .and_return(true)
-
- expect(BackgroundMigrationWorker).to receive(:perform_in).with(described_class::RESCHEDULE_DELAY, described_class.name)
-
- described_class.new.perform
- end
- end
- end
-
- context 'when there are no scheduled, or retrying or dead' do
- before do
- stub_feature_flags(multiple_merge_request_assignees: false)
- end
-
- it 'enables feature' do
- allow(Gitlab::BackgroundMigration).to receive(:exists?)
- .with('PopulateMergeRequestAssigneesTable')
- .and_return(false)
-
- allow(Gitlab::BackgroundMigration).to receive(:retrying_jobs?)
- .with('PopulateMergeRequestAssigneesTable')
- .and_return(false)
-
- allow(Gitlab::BackgroundMigration).to receive(:dead_jobs?)
- .with('PopulateMergeRequestAssigneesTable')
- .and_return(false)
-
- described_class.new.perform
-
- expect(Feature.enabled?(:multiple_merge_request_assignees, type: :licensed)).to eq(true)
- end
- end
-
- context 'when there are only dead jobs' do
- it 'raises DeadJobsError error' do
- allow(Gitlab::BackgroundMigration).to receive(:exists?)
- .with('PopulateMergeRequestAssigneesTable')
- .and_return(false)
-
- allow(Gitlab::BackgroundMigration).to receive(:retrying_jobs?)
- .with('PopulateMergeRequestAssigneesTable')
- .and_return(false)
-
- allow(Gitlab::BackgroundMigration).to receive(:dead_jobs?)
- .with('PopulateMergeRequestAssigneesTable')
- .and_return(true)
-
- expect { described_class.new.perform }
- .to raise_error(described_class::DeadJobsError,
- "Only dead background jobs in the queue for #{described_class::WORKER}")
- end
- end
-end
diff --git a/spec/lib/gitlab/background_migration/migrate_legacy_artifacts_spec.rb b/spec/lib/gitlab/background_migration/migrate_legacy_artifacts_spec.rb
index 08f2b2a043e..5c93e69b5e5 100644
--- a/spec/lib/gitlab/background_migration/migrate_legacy_artifacts_spec.rb
+++ b/spec/lib/gitlab/background_migration/migrate_legacy_artifacts_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::BackgroundMigration::MigrateLegacyArtifacts do
+RSpec.describe Gitlab::BackgroundMigration::MigrateLegacyArtifacts, schema: 20210210093901 do
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:pipelines) { table(:ci_pipelines) }
diff --git a/spec/lib/gitlab/background_migration/move_container_registry_enabled_to_project_feature_spec.rb b/spec/lib/gitlab/background_migration/move_container_registry_enabled_to_project_feature_spec.rb
new file mode 100644
index 00000000000..1c62d703a34
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/move_container_registry_enabled_to_project_feature_spec.rb
@@ -0,0 +1,86 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::MoveContainerRegistryEnabledToProjectFeature, :migration, schema: 2021_02_26_120851 do
+ let(:enabled) { 20 }
+ let(:disabled) { 0 }
+
+ let(:namespaces) { table(:namespaces) }
+ let(:project_features) { table(:project_features) }
+ let(:projects) { table(:projects) }
+
+ let(:namespace) { namespaces.create!(name: 'user', path: 'user') }
+ let!(:project1) { projects.create!(namespace_id: namespace.id) }
+ let!(:project2) { projects.create!(namespace_id: namespace.id) }
+ let!(:project3) { projects.create!(namespace_id: namespace.id) }
+ let!(:project4) { projects.create!(namespace_id: namespace.id) }
+
+ # pages_access_level cannot be null.
+ let(:non_null_project_features) { { pages_access_level: enabled } }
+ let!(:project_feature1) { project_features.create!(project_id: project1.id, **non_null_project_features) }
+ let!(:project_feature2) { project_features.create!(project_id: project2.id, **non_null_project_features) }
+ let!(:project_feature3) { project_features.create!(project_id: project3.id, **non_null_project_features) }
+
+ describe '#perform' do
+ before do
+ project1.update!(container_registry_enabled: true)
+ project2.update!(container_registry_enabled: false)
+ project3.update!(container_registry_enabled: nil)
+ project4.update!(container_registry_enabled: true)
+ end
+
+ it 'copies values to project_features' do
+ expect(project1.container_registry_enabled).to eq(true)
+ expect(project2.container_registry_enabled).to eq(false)
+ expect(project3.container_registry_enabled).to eq(nil)
+ expect(project4.container_registry_enabled).to eq(true)
+
+ expect(project_feature1.container_registry_access_level).to eq(disabled)
+ expect(project_feature2.container_registry_access_level).to eq(disabled)
+ expect(project_feature3.container_registry_access_level).to eq(disabled)
+
+ expect_next_instance_of(Gitlab::BackgroundMigration::Logger) do |logger|
+ expect(logger).to receive(:info)
+ .with(message: "#{described_class}: Copied container_registry_enabled values for projects with IDs between #{project1.id}..#{project4.id}")
+
+ expect(logger).not_to receive(:info)
+ end
+
+ subject.perform(project1.id, project4.id)
+
+ expect(project1.reload.container_registry_enabled).to eq(true)
+ expect(project2.reload.container_registry_enabled).to eq(false)
+ expect(project3.reload.container_registry_enabled).to eq(nil)
+ expect(project4.container_registry_enabled).to eq(true)
+
+ expect(project_feature1.reload.container_registry_access_level).to eq(enabled)
+ expect(project_feature2.reload.container_registry_access_level).to eq(disabled)
+ expect(project_feature3.reload.container_registry_access_level).to eq(disabled)
+ end
+
+ context 'when no projects exist in range' do
+ it 'does not fail' do
+ expect(project1.container_registry_enabled).to eq(true)
+ expect(project_feature1.container_registry_access_level).to eq(disabled)
+
+ expect { subject.perform(-1, -2) }.not_to raise_error
+
+ expect(project1.container_registry_enabled).to eq(true)
+ expect(project_feature1.container_registry_access_level).to eq(disabled)
+ end
+ end
+
+ context 'when projects in range all have nil container_registry_enabled' do
+ it 'does not fail' do
+ expect(project3.container_registry_enabled).to eq(nil)
+ expect(project_feature3.container_registry_access_level).to eq(disabled)
+
+ expect { subject.perform(project3.id, project3.id) }.not_to raise_error
+
+ expect(project3.container_registry_enabled).to eq(nil)
+ expect(project_feature3.container_registry_access_level).to eq(disabled)
+ end
+ end
+ end
+end
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 8e74935e127..07b1d99d333 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
@@ -27,12 +27,33 @@ RSpec.describe Gitlab::BackgroundMigration::PopulateFindingUuidForVulnerabilityF
let(:finding_1) { finding_creator.call(sast_report, location_fingerprint_1) }
let(:finding_2) { finding_creator.call(dast_report, location_fingerprint_2) }
let(:finding_3) { finding_creator.call(secret_detection_report, location_fingerprint_3) }
- let(:uuid_1_components) { ['sast', identifier.fingerprint, location_fingerprint_1, project.id].join('-') }
- let(:uuid_2_components) { ['dast', identifier.fingerprint, location_fingerprint_2, project.id].join('-') }
- let(:uuid_3_components) { ['secret_detection', identifier.fingerprint, location_fingerprint_3, project.id].join('-') }
- let(:expected_uuid_1) { Gitlab::UUID.v5(uuid_1_components) }
- let(:expected_uuid_2) { Gitlab::UUID.v5(uuid_2_components) }
- let(:expected_uuid_3) { Gitlab::UUID.v5(uuid_3_components) }
+ let(:expected_uuid_1) do
+ Security::VulnerabilityUUID.generate(
+ report_type: 'sast',
+ primary_identifier_fingerprint: identifier.fingerprint,
+ location_fingerprint: location_fingerprint_1,
+ project_id: project.id
+ )
+ end
+
+ let(:expected_uuid_2) do
+ Security::VulnerabilityUUID.generate(
+ report_type: 'dast',
+ primary_identifier_fingerprint: identifier.fingerprint,
+ location_fingerprint: location_fingerprint_2,
+ project_id: project.id
+ )
+ end
+
+ let(:expected_uuid_3) do
+ Security::VulnerabilityUUID.generate(
+ report_type: 'secret_detection',
+ primary_identifier_fingerprint: identifier.fingerprint,
+ location_fingerprint: location_fingerprint_3,
+ project_id: project.id
+ )
+ end
+
let(:finding_creator) do
-> (report_type, location_fingerprint) do
findings.create!(
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
new file mode 100644
index 00000000000..990ef4fbe6a
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/recalculate_vulnerabilities_occurrences_uuid_spec.rb
@@ -0,0 +1,149 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::RecalculateVulnerabilitiesOccurrencesUuid, schema: 20201110110454 do
+ 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(:scanners) { table(:vulnerability_scanners) }
+ let(:scanner) { scanners.create!(project_id: project.id, external_id: 'test 1', name: 'test scanner 1') }
+ let(:different_scanner) { scanners.create!(project_id: project.id, external_id: 'test 2', name: 'test scanner 2') }
+ let(:vulnerabilities) { table(:vulnerabilities) }
+ let(:vulnerabilities_findings) { table(:vulnerability_occurrences) }
+ let(:vulnerability_identifiers) { table(:vulnerability_identifiers) }
+ let(:vulnerability_identifier) do
+ vulnerability_identifiers.create!(
+ project_id: project.id,
+ external_type: 'uuid-v5',
+ external_id: 'uuid-v5',
+ fingerprint: '7e394d1b1eb461a7406d7b1e08f057a1cf11287a',
+ name: 'Identifier for UUIDv5')
+ end
+
+ let(:different_vulnerability_identifier) do
+ vulnerability_identifiers.create!(
+ project_id: project.id,
+ external_type: 'uuid-v4',
+ external_id: 'uuid-v4',
+ fingerprint: '772da93d34a1ba010bcb5efa9fb6f8e01bafcc89',
+ name: 'Identifier for UUIDv4')
+ end
+
+ let!(:vulnerability_for_uuidv4) do
+ create_vulnerability!(
+ project_id: project.id,
+ author_id: user.id
+ )
+ end
+
+ let!(:vulnerability_for_uuidv5) do
+ create_vulnerability!(
+ project_id: project.id,
+ author_id: user.id
+ )
+ end
+
+ let(:known_uuid_v5) { "77211ed6-7dff-5f6b-8c9a-da89ad0a9b60" }
+ let(:known_uuid_v4) { "b3cc2518-5446-4dea-871c-89d5e999c1ac" }
+ let(:desired_uuid_v5) { "3ca8ad45-6344-508b-b5e3-306a3bd6c6ba" }
+
+ subject { described_class.new.perform(finding.id, finding.id) }
+
+ context "when finding has a UUIDv4" do
+ before do
+ @uuid_v4 = create_finding!(
+ vulnerability_id: vulnerability_for_uuidv4.id,
+ project_id: project.id,
+ scanner_id: different_scanner.id,
+ primary_identifier_id: different_vulnerability_identifier.id,
+ report_type: 0, # "sast"
+ location_fingerprint: "fa18f432f1d56675f4098d318739c3cd5b14eb3e",
+ uuid: known_uuid_v4
+ )
+ end
+
+ let(:finding) { @uuid_v4 }
+
+ it "replaces it with UUIDv5" do
+ expect(vulnerabilities_findings.pluck(:uuid)).to eq([known_uuid_v4])
+
+ subject
+
+ expect(vulnerabilities_findings.pluck(:uuid)).to eq([desired_uuid_v5])
+ end
+ end
+
+ context "when finding has a UUIDv5" do
+ before do
+ @uuid_v5 = create_finding!(
+ vulnerability_id: vulnerability_for_uuidv5.id,
+ project_id: project.id,
+ scanner_id: scanner.id,
+ primary_identifier_id: vulnerability_identifier.id,
+ report_type: 0, # "sast"
+ location_fingerprint: "838574be0210968bf6b9f569df9c2576242cbf0a",
+ uuid: known_uuid_v5
+ )
+ end
+
+ let(:finding) { @uuid_v5 }
+
+ it "stays the same" do
+ expect(vulnerabilities_findings.pluck(:uuid)).to eq([known_uuid_v5])
+
+ subject
+
+ expect(vulnerabilities_findings.pluck(:uuid)).to eq([known_uuid_v5])
+ end
+ end
+
+ private
+
+ def create_vulnerability!(project_id:, author_id:, title: 'test', severity: 7, confidence: 7, report_type: 0)
+ vulnerabilities.create!(
+ project_id: project_id,
+ author_id: author_id,
+ title: title,
+ severity: severity,
+ confidence: confidence,
+ report_type: report_type
+ )
+ end
+
+ # rubocop:disable Metrics/ParameterLists
+ def create_finding!(
+ 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')
+ vulnerabilities_findings.create!(
+ vulnerability_id: vulnerability_id,
+ project_id: project_id,
+ name: name,
+ severity: severity,
+ confidence: confidence,
+ report_type: report_type,
+ project_fingerprint: project_fingerprint,
+ scanner_id: scanner.id,
+ primary_identifier_id: vulnerability_identifier.id,
+ location_fingerprint: location_fingerprint,
+ metadata_version: metadata_version,
+ raw_metadata: raw_metadata,
+ uuid: uuid
+ )
+ end
+ # rubocop:enable Metrics/ParameterLists
+
+ def create_user!(name: "Example User", email: "user@example.com", user_type: nil, created_at: Time.zone.now, confirmed_at: Time.zone.now)
+ users.create!(
+ name: name,
+ email: email,
+ username: name,
+ projects_limit: 0,
+ user_type: user_type,
+ confirmed_at: confirmed_at
+ )
+ end
+end
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
new file mode 100644
index 00000000000..46c919f0854
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/set_default_iteration_cadences_spec.rb
@@ -0,0 +1,80 @@
+# 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