diff options
Diffstat (limited to 'spec/lib/gitlab/background_migration')
26 files changed, 826 insertions, 423 deletions
diff --git a/spec/lib/gitlab/background_migration/backfill_ci_namespace_mirrors_spec.rb b/spec/lib/gitlab/background_migration/backfill_ci_namespace_mirrors_spec.rb deleted file mode 100644 index 8980a26932b..00000000000 --- a/spec/lib/gitlab/background_migration/backfill_ci_namespace_mirrors_spec.rb +++ /dev/null @@ -1,45 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Gitlab::BackgroundMigration::BackfillCiNamespaceMirrors, :migration, schema: 20211208122200 do - let(:namespaces) { table(:namespaces) } - let(:ci_namespace_mirrors) { table(:ci_namespace_mirrors) } - - subject { described_class.new } - - describe '#perform' do - it 'creates hierarchies for all namespaces in range' do - namespaces.create!(id: 5, name: 'test1', path: 'test1') - namespaces.create!(id: 7, name: 'test2', path: 'test2') - namespaces.create!(id: 8, name: 'test3', path: 'test3') - - subject.perform(5, 7) - - expect(ci_namespace_mirrors.all).to contain_exactly( - an_object_having_attributes(namespace_id: 5, traversal_ids: [5]), - an_object_having_attributes(namespace_id: 7, traversal_ids: [7]) - ) - end - - it 'handles existing hierarchies gracefully' do - namespaces.create!(id: 5, name: 'test1', path: 'test1') - test2 = namespaces.create!(id: 7, name: 'test2', path: 'test2') - namespaces.create!(id: 8, name: 'test3', path: 'test3', parent_id: 7) - namespaces.create!(id: 9, name: 'test4', path: 'test4') - - # Simulate a situation where a user has had a chance to move a group to another parent - # before the background migration has had a chance to run - test2.update!(parent_id: 5) - ci_namespace_mirrors.create!(namespace_id: test2.id, traversal_ids: [5, 7]) - - subject.perform(5, 8) - - expect(ci_namespace_mirrors.all).to contain_exactly( - an_object_having_attributes(namespace_id: 5, traversal_ids: [5]), - an_object_having_attributes(namespace_id: 7, traversal_ids: [5, 7]), - an_object_having_attributes(namespace_id: 8, traversal_ids: [5, 7, 8]) - ) - end - end -end diff --git a/spec/lib/gitlab/background_migration/backfill_ci_project_mirrors_spec.rb b/spec/lib/gitlab/background_migration/backfill_ci_project_mirrors_spec.rb deleted file mode 100644 index 4eec83879e3..00000000000 --- a/spec/lib/gitlab/background_migration/backfill_ci_project_mirrors_spec.rb +++ /dev/null @@ -1,46 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Gitlab::BackgroundMigration::BackfillCiProjectMirrors, :migration, schema: 20211208122201 do - let(:namespaces) { table(:namespaces) } - let(:projects) { table(:projects) } - let(:ci_project_mirrors) { table(:ci_project_mirrors) } - - subject { described_class.new } - - describe '#perform' do - it 'creates ci_project_mirrors for all projects in range' do - namespaces.create!(id: 10, name: 'namespace1', path: 'namespace1') - projects.create!(id: 5, namespace_id: 10, name: 'test1', path: 'test1') - projects.create!(id: 7, namespace_id: 10, name: 'test2', path: 'test2') - projects.create!(id: 8, namespace_id: 10, name: 'test3', path: 'test3') - - subject.perform(5, 7) - - expect(ci_project_mirrors.all).to contain_exactly( - an_object_having_attributes(project_id: 5, namespace_id: 10), - an_object_having_attributes(project_id: 7, namespace_id: 10) - ) - end - - it 'handles existing ci_project_mirrors gracefully' do - namespaces.create!(id: 10, name: 'namespace1', path: 'namespace1') - namespaces.create!(id: 11, name: 'namespace2', path: 'namespace2', parent_id: 10) - projects.create!(id: 5, namespace_id: 10, name: 'test1', path: 'test1') - projects.create!(id: 7, namespace_id: 11, name: 'test2', path: 'test2') - projects.create!(id: 8, namespace_id: 11, name: 'test3', path: 'test3') - - # Simulate a situation where a user has had a chance to move a project to another namespace - # before the background migration has had a chance to run - ci_project_mirrors.create!(project_id: 7, namespace_id: 10) - - subject.perform(5, 7) - - expect(ci_project_mirrors.all).to contain_exactly( - an_object_having_attributes(project_id: 5, namespace_id: 10), - an_object_having_attributes(project_id: 7, namespace_id: 10) - ) - end - end -end diff --git a/spec/lib/gitlab/background_migration/backfill_ci_queuing_tables_spec.rb b/spec/lib/gitlab/background_migration/backfill_ci_queuing_tables_spec.rb index 1aac5970a77..aaf8c124a83 100644 --- a/spec/lib/gitlab/background_migration/backfill_ci_queuing_tables_spec.rb +++ b/spec/lib/gitlab/background_migration/backfill_ci_queuing_tables_spec.rb @@ -2,7 +2,8 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::BackfillCiQueuingTables, :migration, schema: 20220208115439 do +RSpec.describe Gitlab::BackgroundMigration::BackfillCiQueuingTables, :migration, + :suppress_gitlab_schemas_validate_connection, schema: 20220208115439 do let(:namespaces) { table(:namespaces) } let(:projects) { table(:projects) } let(:ci_cd_settings) { table(:project_ci_cd_settings) } diff --git a/spec/lib/gitlab/background_migration/backfill_ci_runner_semver_spec.rb b/spec/lib/gitlab/background_migration/backfill_ci_runner_semver_spec.rb deleted file mode 100644 index 7c78d8b0305..00000000000 --- a/spec/lib/gitlab/background_migration/backfill_ci_runner_semver_spec.rb +++ /dev/null @@ -1,54 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Gitlab::BackgroundMigration::BackfillCiRunnerSemver, :migration, schema: 20220601151900 do - let(:ci_runners) { table(:ci_runners, database: :ci) } - - subject do - described_class.new( - start_id: 10, - end_id: 15, - batch_table: :ci_runners, - batch_column: :id, - sub_batch_size: 10, - pause_ms: 0, - connection: Ci::ApplicationRecord.connection) - end - - describe '#perform' do - it 'populates semver column on all runners in range' do - ci_runners.create!(id: 10, runner_type: 1, version: %q(HEAD-fd84d97)) - ci_runners.create!(id: 11, runner_type: 1, version: %q(v1.2.3)) - ci_runners.create!(id: 12, runner_type: 1, version: %q(2.1.0)) - ci_runners.create!(id: 13, runner_type: 1, version: %q(11.8.0~beta.935.g7f6d2abc)) - ci_runners.create!(id: 14, runner_type: 1, version: %q(13.2.2/1.1.0)) - ci_runners.create!(id: 15, runner_type: 1, version: %q('14.3.4')) - - subject.perform - - expect(ci_runners.all).to contain_exactly( - an_object_having_attributes(id: 10, semver: nil), - an_object_having_attributes(id: 11, semver: '1.2.3'), - an_object_having_attributes(id: 12, semver: '2.1.0'), - an_object_having_attributes(id: 13, semver: '11.8.0'), - an_object_having_attributes(id: 14, semver: '13.2.2'), - an_object_having_attributes(id: 15, semver: '14.3.4') - ) - end - - it 'skips runners that already have semver value' do - ci_runners.create!(id: 10, runner_type: 1, version: %q(1.2.4), semver: '1.2.3') - ci_runners.create!(id: 11, runner_type: 1, version: %q(1.2.5)) - ci_runners.create!(id: 12, runner_type: 1, version: %q(HEAD), semver: '1.2.4') - - subject.perform - - expect(ci_runners.all).to contain_exactly( - an_object_having_attributes(id: 10, semver: '1.2.3'), - an_object_having_attributes(id: 11, semver: '1.2.5'), - an_object_having_attributes(id: 12, semver: '1.2.4') - ) - end - end -end diff --git a/spec/lib/gitlab/background_migration/backfill_group_features_spec.rb b/spec/lib/gitlab/background_migration/backfill_group_features_spec.rb index d84bc479554..e0be5a785b8 100644 --- a/spec/lib/gitlab/background_migration/backfill_group_features_spec.rb +++ b/spec/lib/gitlab/background_migration/backfill_group_features_spec.rb @@ -13,6 +13,7 @@ RSpec.describe Gitlab::BackgroundMigration::BackfillGroupFeatures, :migration, s batch_column: :id, sub_batch_size: 10, pause_ms: 0, + job_arguments: [4], connection: ActiveRecord::Base.connection) end @@ -27,7 +28,7 @@ RSpec.describe Gitlab::BackgroundMigration::BackfillGroupFeatures, :migration, s group_features.create!(id: 1, group_id: 4) expect(group_features.count).to eq 1 - expect { subject.perform(4) }.to change { group_features.count }.by(2) + expect { subject.perform }.to change { group_features.count }.by(2) expect(group_features.count).to eq 3 expect(group_features.all.pluck(:group_id)).to contain_exactly(1, 3, 4) diff --git a/spec/lib/gitlab/background_migration/backfill_namespace_id_of_vulnerability_reads_spec.rb b/spec/lib/gitlab/background_migration/backfill_namespace_id_of_vulnerability_reads_spec.rb new file mode 100644 index 00000000000..564aa3b8c01 --- /dev/null +++ b/spec/lib/gitlab/background_migration/backfill_namespace_id_of_vulnerability_reads_spec.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::BackgroundMigration::BackfillNamespaceIdOfVulnerabilityReads, schema: 20220722145845 do + let(:namespaces) { table(:namespaces) } + let(:projects) { table(:projects) } + let(:users) { table(:users) } + let(:scanners) { table(:vulnerability_scanners) } + let(:vulnerabilities) { table(:vulnerabilities) } + let(:vulnerability_reads) { table(:vulnerability_reads) } + + let(:namespace) { namespaces.create!(name: 'user', path: 'user') } + let(:project) { projects.create!(namespace_id: namespace.id, project_namespace_id: namespace.id) } + let(:user) { users.create!(username: 'john_doe', email: 'johndoe@gitlab.com', projects_limit: 10) } + let(:scanner) { scanners.create!(project_id: project.id, external_id: 'external_id', name: 'Test Scanner') } + let(:vulnerability) do + vulnerabilities.create!( + project_id: project.id, + author_id: user.id, + title: 'test', + severity: 1, + confidence: 1, + report_type: 1 + ) + end + + let(:vulnerability_read) do + vulnerability_reads.create!( + project_id: project.id, + vulnerability_id: vulnerability.id, + scanner_id: scanner.id, + severity: 1, + report_type: 1, + state: 1, + uuid: SecureRandom.uuid + ) + end + + subject(:perform_migration) do + described_class.new(start_id: vulnerability_read.vulnerability_id, + end_id: vulnerability_read.vulnerability_id, + batch_table: :vulnerability_reads, + batch_column: :vulnerability_id, + sub_batch_size: 1, + pause_ms: 0, + connection: ActiveRecord::Base.connection) + .perform + end + + it 'sets the namespace_id of existing record' do + expect { perform_migration }.to change { vulnerability_read.reload.namespace_id }.from(nil).to(namespace.id) + end +end diff --git a/spec/lib/gitlab/background_migration/backfill_project_import_level_spec.rb b/spec/lib/gitlab/background_migration/backfill_project_import_level_spec.rb new file mode 100644 index 00000000000..ae296483166 --- /dev/null +++ b/spec/lib/gitlab/background_migration/backfill_project_import_level_spec.rb @@ -0,0 +1,123 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +# rubocop:disable Layout/HashAlignment +RSpec.describe Gitlab::BackgroundMigration::BackfillProjectImportLevel do + let(:migration) do + described_class.new( + start_id: table(:namespaces).minimum(:id), + end_id: table(:namespaces).maximum(:id), + batch_table: :namespaces, + batch_column: :id, + sub_batch_size: 2, + pause_ms: 0, + connection: ApplicationRecord.connection + ) + end + # rubocop:enable Layout/HashAlignment + + let(:namespaces_table) { table(:namespaces) } + let(:namespace_settings_table) { table(:namespace_settings) } + + let!(:user_namespace) do + namespaces_table.create!( + name: 'user_namespace', + path: 'user_namespace', + type: 'User', + project_creation_level: 100 + ) + end + + let!(:group_namespace_nil) do + namespaces_table.create!( + name: 'group_namespace_nil', + path: 'group_namespace_nil', + type: 'Group', + project_creation_level: nil + ) + end + + let!(:group_namespace_0) do + namespaces_table.create!( + name: 'group_namespace_0', + path: 'group_namespace_0', + type: 'Group', + project_creation_level: 0 + ) + end + + let!(:group_namespace_1) do + namespaces_table.create!( + name: 'group_namespace_1', + path: 'group_namespace_1', + type: 'Group', + project_creation_level: 1 + ) + end + + let!(:group_namespace_2) do + namespaces_table.create!( + name: 'group_namespace_2', + path: 'group_namespace_2', + type: 'Group', + project_creation_level: 2 + ) + end + + let!(:group_namespace_9999) do + namespaces_table.create!( + name: 'group_namespace_9999', + path: 'group_namespace_9999', + type: 'Group', + project_creation_level: 9999 + ) + end + + subject(:perform_migration) { migration.perform } + + before do + namespace_settings_table.create!(namespace_id: user_namespace.id) + namespace_settings_table.create!(namespace_id: group_namespace_nil.id) + namespace_settings_table.create!(namespace_id: group_namespace_0.id) + namespace_settings_table.create!(namespace_id: group_namespace_1.id) + namespace_settings_table.create!(namespace_id: group_namespace_2.id) + namespace_settings_table.create!(namespace_id: group_namespace_9999.id) + end + + describe 'Groups' do + using RSpec::Parameterized::TableSyntax + + where(:namespace_id, :prev_level, :new_level) do + lazy { group_namespace_0.id } | ::Gitlab::Access::OWNER | ::Gitlab::Access::NO_ACCESS + lazy { group_namespace_1.id } | ::Gitlab::Access::OWNER | ::Gitlab::Access::MAINTAINER + lazy { group_namespace_2.id } | ::Gitlab::Access::OWNER | ::Gitlab::Access::DEVELOPER + end + + with_them do + it 'backfills the correct project_import_level of Group namespaces' do + expect { perform_migration } + .to change { namespace_settings_table.find_by(namespace_id: namespace_id).project_import_level } + .from(prev_level).to(new_level) + end + end + + it 'does not update `User` namespaces or values outside range' do + expect { perform_migration } + .not_to change { namespace_settings_table.find_by(namespace_id: user_namespace.id).project_import_level } + + expect { perform_migration } + .not_to change { namespace_settings_table.find_by(namespace_id: group_namespace_9999.id).project_import_level } + end + + it 'maintains default import_level if creation_level is nil' do + project_import_level = namespace_settings_table.find_by(namespace_id: group_namespace_nil.id).project_import_level + + expect { perform_migration } + .not_to change { project_import_level } + + expect(project_import_level).to eq(::Gitlab::Access::OWNER) + end + end +end diff --git a/spec/lib/gitlab/background_migration/backfill_projects_with_coverage_spec.rb b/spec/lib/gitlab/background_migration/backfill_projects_with_coverage_spec.rb index 49056154744..4a65ecf8c75 100644 --- a/spec/lib/gitlab/background_migration/backfill_projects_with_coverage_spec.rb +++ b/spec/lib/gitlab/background_migration/backfill_projects_with_coverage_spec.rb @@ -2,7 +2,8 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::BackfillProjectsWithCoverage, schema: 20210818185845 do +RSpec.describe Gitlab::BackgroundMigration::BackfillProjectsWithCoverage, + :suppress_gitlab_schemas_validate_connection, schema: 20210818185845 do let(:projects) { table(:projects) } let(:project_ci_feature_usages) { table(:project_ci_feature_usages) } let(:ci_pipelines) { table(:ci_pipelines) } diff --git a/spec/lib/gitlab/background_migration/backfill_snippet_repositories_spec.rb b/spec/lib/gitlab/background_migration/backfill_snippet_repositories_spec.rb index b5122af5cd4..6f75d3faef3 100644 --- a/spec/lib/gitlab/background_migration/backfill_snippet_repositories_spec.rb +++ b/spec/lib/gitlab/background_migration/backfill_snippet_repositories_spec.rb @@ -39,7 +39,7 @@ RSpec.describe Gitlab::BackgroundMigration::BackfillSnippetRepositories, :migrat let(:file_name) { 'file_name.rb' } let(:content) { 'content' } - let(:ids) { snippets.pluck('MIN(id)', 'MAX(id)').first } + let(:ids) { snippets.pick('MIN(id)', 'MAX(id)') } let(:service) { described_class.new } subject { service.perform(*ids) } diff --git a/spec/lib/gitlab/background_migration/backfill_vulnerability_reads_cluster_agent_spec.rb b/spec/lib/gitlab/background_migration/backfill_vulnerability_reads_cluster_agent_spec.rb new file mode 100644 index 00000000000..79699375a8d --- /dev/null +++ b/spec/lib/gitlab/background_migration/backfill_vulnerability_reads_cluster_agent_spec.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::BackgroundMigration::BackfillVulnerabilityReadsClusterAgent, :migration, schema: 20220525221133 do # rubocop:disable Layout/LineLength + let(:migration) do + described_class.new(start_id: 1, end_id: 10, + batch_table: table_name, batch_column: batch_column, + sub_batch_size: sub_batch_size, pause_ms: pause_ms, + connection: ApplicationRecord.connection) + end + + let(:users_table) { table(:users) } + let(:vulnerability_reads_table) { table(:vulnerability_reads) } + let(:vulnerability_scanners_table) { table(:vulnerability_scanners) } + let(:vulnerabilities_table) { table(:vulnerabilities) } + let(:namespaces_table) { table(:namespaces) } + let(:projects_table) { table(:projects) } + let(:cluster_agents_table) { table(:cluster_agents) } + + let(:table_name) { 'vulnerability_reads' } + let(:batch_column) { :id } + let(:sub_batch_size) { 1_000 } + let(:pause_ms) { 0 } + + subject(:perform_migration) { migration.perform } + + before do + users_table.create!(id: 1, name: 'John Doe', email: 'test@example.com', projects_limit: 5) + + namespaces_table.create!(id: 1, name: 'Namespace 1', path: 'namespace-1') + namespaces_table.create!(id: 2, name: 'Namespace 2', path: 'namespace-2') + + projects_table.create!(id: 1, namespace_id: 1, name: 'Project 1', path: 'project-1', project_namespace_id: 1) + projects_table.create!(id: 2, namespace_id: 2, name: 'Project 2', path: 'project-2', project_namespace_id: 2) + + cluster_agents_table.create!(id: 1, name: 'Agent 1', project_id: 1) + cluster_agents_table.create!(id: 2, name: 'Agent 2', project_id: 2) + + vulnerability_scanners_table.create!(id: 1, project_id: 1, external_id: 'starboard', name: 'Starboard') + vulnerability_scanners_table.create!(id: 2, project_id: 2, external_id: 'starboard', name: 'Starboard') + + add_vulnerability_read!(1, project_id: 1, cluster_agent_id: 1, report_type: 7) + add_vulnerability_read!(3, project_id: 1, cluster_agent_id: 2, report_type: 7) + add_vulnerability_read!(5, project_id: 2, cluster_agent_id: 2, report_type: 5) + add_vulnerability_read!(7, project_id: 2, cluster_agent_id: 3, report_type: 7) + add_vulnerability_read!(9, project_id: 2, cluster_agent_id: 2, report_type: 7) + add_vulnerability_read!(10, project_id: 1, cluster_agent_id: 1, report_type: 7) + add_vulnerability_read!(11, project_id: 1, cluster_agent_id: 1, report_type: 7) + end + + it 'backfills `casted_cluster_agent_id` for the selected records', :aggregate_failures do + queries = ActiveRecord::QueryRecorder.new do + perform_migration + end + + expect(queries.count).to eq(3) + expect(vulnerability_reads_table.where.not(casted_cluster_agent_id: nil).count).to eq 3 + expect(vulnerability_reads_table.where.not(casted_cluster_agent_id: nil).pluck(:id)).to match_array([1, 9, 10]) + 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 + + private + + def add_vulnerability_read!(id, project_id:, cluster_agent_id:, report_type:) + vulnerabilities_table.create!( + id: id, + project_id: project_id, + author_id: 1, + title: "Vulnerability #{id}", + severity: 5, + confidence: 5, + report_type: report_type + ) + + vulnerability_reads_table.create!( + id: id, + uuid: SecureRandom.uuid, + severity: 5, + state: 1, + vulnerability_id: id, + scanner_id: project_id, + cluster_agent_id: cluster_agent_id.to_s, + project_id: project_id, + report_type: report_type + ) + end +end diff --git a/spec/lib/gitlab/background_migration/batched_migration_job_spec.rb b/spec/lib/gitlab/background_migration/batched_migration_job_spec.rb index 98866bb765f..f03f90ddbbb 100644 --- a/spec/lib/gitlab/background_migration/batched_migration_job_spec.rb +++ b/spec/lib/gitlab/background_migration/batched_migration_job_spec.rb @@ -3,6 +3,113 @@ require 'spec_helper' RSpec.describe Gitlab::BackgroundMigration::BatchedMigrationJob do + let(:connection) { Gitlab::Database.database_base_models[:main].connection } + + describe '.generic_instance' do + it 'defines generic instance with only some of the attributes set' do + generic_instance = described_class.generic_instance( + batch_table: 'projects', batch_column: 'id', + job_arguments: %w(x y), connection: connection + ) + + expect(generic_instance.send(:batch_table)).to eq('projects') + expect(generic_instance.send(:batch_column)).to eq('id') + expect(generic_instance.instance_variable_get('@job_arguments')).to eq(%w(x y)) + expect(generic_instance.send(:connection)).to eq(connection) + + %i(start_id end_id sub_batch_size pause_ms).each do |attr| + expect(generic_instance.send(attr)).to eq(0) + end + end + end + + describe '.job_arguments' do + let(:job_class) do + Class.new(described_class) do + job_arguments :value_a, :value_b + end + end + + subject(:job_instance) do + job_class.new(start_id: 1, end_id: 10, + batch_table: '_test_table', + batch_column: 'id', + sub_batch_size: 2, + pause_ms: 1000, + job_arguments: %w(a b), + connection: connection) + end + + it 'defines methods' do + expect(job_instance.value_a).to eq('a') + expect(job_instance.value_b).to eq('b') + expect(job_class.job_arguments_count).to eq(2) + end + + context 'when no job arguments are defined' do + let(:job_class) do + Class.new(described_class) + end + + it 'job_arguments_count is 0' do + expect(job_class.job_arguments_count).to eq(0) + end + end + end + + describe '.scope_to' do + subject(:job_instance) do + job_class.new(start_id: 1, end_id: 10, + batch_table: '_test_table', + batch_column: 'id', + sub_batch_size: 2, + pause_ms: 1000, + job_arguments: %w(a b), + connection: connection) + end + + context 'when additional scoping is defined' do + let(:job_class) do + Class.new(described_class) do + job_arguments :value_a, :value_b + scope_to ->(r) { "#{r}-#{value_a}-#{value_b}".upcase } + end + end + + it 'applies additional scope to the provided relation' do + expect(job_instance.filter_batch('relation')).to eq('RELATION-A-B') + end + end + + context 'when there is no additional scoping defined' do + let(:job_class) do + Class.new(described_class) do + end + end + + it 'returns provided relation as is' do + expect(job_instance.filter_batch('relation')).to eq('relation') + end + end + end + + describe 'descendants', :eager_load do + it 'have the same method signature for #perform' do + expected_arity = described_class.instance_method(:perform).arity + offences = described_class.descendants.select { |klass| klass.instance_method(:perform).arity != expected_arity } + + expect(offences).to be_empty, "expected no descendants of #{described_class} to accept arguments for " \ + "'#perform', but some do: #{offences.join(", ")}" + end + + it 'do not use .batching_scope' do + offences = described_class.descendants.select { |klass| klass.respond_to?(:batching_scope) } + + expect(offences).to be_empty, "expected no descendants of #{described_class} to define '.batching_scope', " \ + "but some do: #{offences.join(", ")}" + end + end + describe '#perform' do let(:connection) { Gitlab::Database.database_base_models[:main].connection } @@ -66,6 +173,30 @@ RSpec.describe Gitlab::BackgroundMigration::BatchedMigrationJob do expect(test_table.order(:id).pluck(:to_column)).to contain_exactly(5, 10, nil, 20) end + context 'with additional scoping' do + let(:job_class) do + Class.new(described_class) do + scope_to ->(r) { r.where('mod(id, 2) = 0') } + + def perform(*job_arguments) + each_sub_batch( + operation_name: :update, + batching_arguments: { order_hint: :updated_at }, + batching_scope: -> (relation) { relation.where.not(bar: nil) } + ) do |sub_batch| + sub_batch.update_all('to_column = from_column') + end + end + end + end + + it 'respects #filter_batch' do + expect { perform_job }.to change { test_table.where(to_column: nil).count }.from(4).to(2) + + expect(test_table.order(:id).pluck(:to_column)).to contain_exactly(nil, 10, nil, 20) + end + end + it 'instruments the batch operation' do expect(job_instance.batch_metrics.affected_rows).to be_empty @@ -84,7 +215,7 @@ RSpec.describe Gitlab::BackgroundMigration::BatchedMigrationJob do context 'when batching_arguments are given' do it 'forwards them for batching' do - expect(job_instance).to receive(:parent_batch_relation).and_return(test_table) + expect(job_instance).to receive(:base_relation).and_return(test_table) expect(test_table).to receive(:each_batch).with(column: 'id', of: 2, order_hint: :updated_at) @@ -155,6 +286,24 @@ RSpec.describe Gitlab::BackgroundMigration::BatchedMigrationJob do expect(job_instance.batch_metrics.affected_rows[:insert]).to contain_exactly(2, 1) end + + context 'when used in combination with scope_to' do + let(:job_class) do + Class.new(described_class) do + scope_to ->(r) { r.where.not(from_column: 10) } + + def perform(*job_arguments) + distinct_each_batch(operation_name: :insert) do |sub_batch| + end + end + end + end + + it 'raises an error' do + expect { perform_job }.to raise_error RuntimeError, + /distinct_each_batch can not be used when additional filters are defined with scope_to/ + end + end end end end 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 index 943b5744b64..9fdd7bf8adc 100644 --- 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 @@ -45,19 +45,16 @@ RSpec.describe Gitlab::BackgroundMigration::BatchingStrategies::PrimaryKeyBatchi end end - context 'when job_class is provided with a batching_scope' do + context 'when job class supports batch scope DSL' do let(:job_class) do - Class.new(described_class) do - def self.batching_scope(relation, job_arguments:) - min_id = job_arguments.first - - relation.where.not(type: 'Project').where('id >= ?', min_id) - end + Class.new(Gitlab::BackgroundMigration::BatchedMigrationJob) do + job_arguments :min_id + scope_to ->(r) { r.where.not(type: 'Project').where('id >= ?', min_id) } end end - it 'applies the batching scope' do - expect(job_class).to receive(:batching_scope).and_call_original + it 'applies the additional scope' do + expect(job_class).to receive(:generic_instance).and_call_original batch_bounds = batching_strategy.next_batch(:namespaces, :id, batch_min_value: namespace4.id, batch_size: 3, job_arguments: [1], job_class: job_class) diff --git a/spec/lib/gitlab/background_migration/copy_ci_builds_columns_to_security_scans_spec.rb b/spec/lib/gitlab/background_migration/copy_ci_builds_columns_to_security_scans_spec.rb deleted file mode 100644 index db822f36c21..00000000000 --- a/spec/lib/gitlab/background_migration/copy_ci_builds_columns_to_security_scans_spec.rb +++ /dev/null @@ -1,51 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Gitlab::BackgroundMigration::CopyCiBuildsColumnsToSecurityScans, schema: 20210728174349 do - let(:migration) { described_class.new } - - let_it_be(:namespaces) { table(:namespaces) } - let_it_be(:projects) { table(:projects) } - let_it_be(:ci_pipelines) { table(:ci_pipelines) } - let_it_be(:ci_builds) { table(:ci_builds) } - let_it_be(:security_scans) { table(:security_scans) } - - let!(:namespace) { namespaces.create!(name: 'namespace', path: 'namespace') } - let!(:project1) { projects.create!(namespace_id: namespace.id) } - let!(:project2) { projects.create!(namespace_id: namespace.id) } - let!(:pipeline1) { ci_pipelines.create!(status: "success")} - let!(:pipeline2) { ci_pipelines.create!(status: "success")} - - let!(:build1) { ci_builds.create!(commit_id: pipeline1.id, type: 'Ci::Build', project_id: project1.id) } - let!(:build2) { ci_builds.create!(commit_id: pipeline2.id, type: 'Ci::Build', project_id: project2.id) } - let!(:build3) { ci_builds.create!(commit_id: pipeline1.id, type: 'Ci::Build', project_id: project1.id) } - - let!(:scan1) { security_scans.create!(build_id: build1.id, scan_type: 1) } - let!(:scan2) { security_scans.create!(build_id: build2.id, scan_type: 1) } - let!(:scan3) { security_scans.create!(build_id: build3.id, scan_type: 1) } - - subject { migration.perform(scan1.id, scan2.id) } - - before do - stub_const("#{described_class}::UPDATE_BATCH_SIZE", 2) - end - - it 'copies `project_id`, `commit_id` from `ci_builds` to `security_scans`', :aggregate_failures do - expect(migration).to receive(:mark_job_as_succeeded).with(scan1.id, scan2.id) - - subject - - scan1.reload - expect(scan1.project_id).to eq(project1.id) - expect(scan1.pipeline_id).to eq(pipeline1.id) - - scan2.reload - expect(scan2.project_id).to eq(project2.id) - expect(scan2.pipeline_id).to eq(pipeline2.id) - - scan3.reload - expect(scan3.project_id).to be_nil - expect(scan3.pipeline_id).to be_nil - 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 78bd1afd8d2..9c33100a0b3 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 @@ -16,6 +16,7 @@ RSpec.describe Gitlab::BackgroundMigration::CopyColumnUsingBackgroundMigrationJo ActiveRecord::Migration.new.extend(Gitlab::Database::MigrationHelpers) end + let(:job_arguments) { %w(name name_convert_to_text) } let(:copy_job) do described_class.new(start_id: 12, end_id: 20, @@ -23,6 +24,7 @@ RSpec.describe Gitlab::BackgroundMigration::CopyColumnUsingBackgroundMigrationJo batch_column: 'id', sub_batch_size: sub_batch_size, pause_ms: pause_ms, + job_arguments: job_arguments, connection: connection) end @@ -53,32 +55,42 @@ RSpec.describe Gitlab::BackgroundMigration::CopyColumnUsingBackgroundMigrationJo SQL end - it 'copies all primary keys in range' do - temporary_column = helpers.convert_to_bigint_column(:id) + context 'primary keys' do + let(:temporary_column) { helpers.convert_to_bigint_column(:id) } + let(:job_arguments) { ['id', temporary_column] } - copy_job.perform('id', temporary_column) + it 'copies all in range' do + copy_job.perform - expect(test_table.count).to eq(4) - expect(test_table.where("id = #{temporary_column}").pluck(:id)).to contain_exactly(12, 15, 19) - expect(test_table.where(temporary_column => 0).pluck(:id)).to contain_exactly(11) + expect(test_table.count).to eq(4) + expect(test_table.where("id = #{temporary_column}").pluck(:id)).to contain_exactly(12, 15, 19) + expect(test_table.where(temporary_column => 0).pluck(:id)).to contain_exactly(11) + end end - it 'copies all foreign keys in range' do - temporary_column = helpers.convert_to_bigint_column(:fk) + context 'foreign keys' do + let(:temporary_column) { helpers.convert_to_bigint_column(:fk) } + let(:job_arguments) { ['fk', temporary_column] } - copy_job.perform('fk', temporary_column) + it 'copies all in range' do + copy_job.perform - expect(test_table.count).to eq(4) - expect(test_table.where("fk = #{temporary_column}").pluck(:id)).to contain_exactly(12, 15, 19) - expect(test_table.where(temporary_column => 0).pluck(:id)).to contain_exactly(11) + expect(test_table.count).to eq(4) + expect(test_table.where("fk = #{temporary_column}").pluck(:id)).to contain_exactly(12, 15, 19) + expect(test_table.where(temporary_column => 0).pluck(:id)).to contain_exactly(11) + end end - it 'copies columns with NULLs' do - expect { copy_job.perform('name', 'name_convert_to_text') } - .to change { test_table.where("name_convert_to_text = 'no name'").count }.from(4).to(1) + context 'columns with NULLs' do + let(:job_arguments) { %w(name name_convert_to_text) } - expect(test_table.where('name = name_convert_to_text').pluck(:id)).to contain_exactly(12, 19) - expect(test_table.where('name is NULL and name_convert_to_text is NULL').pluck(:id)).to contain_exactly(15) + it 'copies all in range' do + expect { copy_job.perform } + .to change { test_table.where("name_convert_to_text = 'no name'").count }.from(4).to(1) + + expect(test_table.where('name = name_convert_to_text').pluck(:id)).to contain_exactly(12, 19) + expect(test_table.where('name is NULL and name_convert_to_text is NULL').pluck(:id)).to contain_exactly(15) + end end context 'when multiple columns are given' do @@ -87,8 +99,10 @@ RSpec.describe Gitlab::BackgroundMigration::CopyColumnUsingBackgroundMigrationJo let(:columns_to_copy_from) { %w[id fk] } let(:columns_to_copy_to) { [id_tmp_column, fk_tmp_column] } + let(:job_arguments) { [columns_to_copy_from, columns_to_copy_to] } + it 'copies all values in the range' do - copy_job.perform(columns_to_copy_from, columns_to_copy_to) + copy_job.perform expect(test_table.count).to eq(4) expect(test_table.where("id = #{id_tmp_column} AND fk = #{fk_tmp_column}").pluck(:id)).to contain_exactly(12, 15, 19) @@ -100,7 +114,7 @@ RSpec.describe Gitlab::BackgroundMigration::CopyColumnUsingBackgroundMigrationJo it 'raises an error' do expect do - copy_job.perform(columns_to_copy_from, columns_to_copy_to) + copy_job.perform end.to raise_error(ArgumentError, 'number of source and destination columns must match') end end @@ -109,7 +123,7 @@ RSpec.describe Gitlab::BackgroundMigration::CopyColumnUsingBackgroundMigrationJo it 'tracks timings of queries' do expect(copy_job.batch_metrics.timings).to be_empty - copy_job.perform('name', 'name_convert_to_text') + copy_job.perform expect(copy_job.batch_metrics.timings[:update_all]).not_to be_empty end @@ -120,7 +134,7 @@ RSpec.describe Gitlab::BackgroundMigration::CopyColumnUsingBackgroundMigrationJo it 'sleeps for the specified time between sub-batches' do expect(copy_job).to receive(:sleep).with(0.005) - copy_job.perform('name', 'name_convert_to_text') + copy_job.perform end context 'when pause_ms value is negative' do @@ -129,7 +143,7 @@ RSpec.describe Gitlab::BackgroundMigration::CopyColumnUsingBackgroundMigrationJo it 'treats it as a 0' do expect(copy_job).to receive(:sleep).with(0) - copy_job.perform('name', 'name_convert_to_text') + copy_job.perform end end end diff --git a/spec/lib/gitlab/background_migration/disable_legacy_open_source_license_for_no_issues_no_repo_projects_spec.rb b/spec/lib/gitlab/background_migration/disable_legacy_open_source_license_for_no_issues_no_repo_projects_spec.rb new file mode 100644 index 00000000000..d20eaef3650 --- /dev/null +++ b/spec/lib/gitlab/background_migration/disable_legacy_open_source_license_for_no_issues_no_repo_projects_spec.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::BackgroundMigration::DisableLegacyOpenSourceLicenseForNoIssuesNoRepoProjects, + :migration, + schema: 20220722084543 do + let(:namespaces_table) { table(:namespaces) } + let(:projects_table) { table(:projects) } + let(:project_settings_table) { table(:project_settings) } + let(:project_statistics_table) { table(:project_statistics) } + let(:issues_table) { table(:issues) } + + subject(:perform_migration) do + described_class.new(start_id: projects_table.minimum(:id), + end_id: projects_table.maximum(:id), + batch_table: :projects, + batch_column: :id, + sub_batch_size: 2, + pause_ms: 0, + connection: ActiveRecord::Base.connection) + .perform + end + + it 'sets `legacy_open_source_license_available` to false only for public projects with no issues and no repo', + :aggregate_failures do + project_with_no_issues_no_repo = create_legacy_license_public_project('project-with-no-issues-no-repo') + project_with_repo = create_legacy_license_public_project('project-with-repo', repo_size: 1) + project_with_issues = create_legacy_license_public_project('project-with-issues', with_issue: true) + project_with_issues_and_repo = + create_legacy_license_public_project('project-with-issues-and-repo', repo_size: 1, with_issue: true) + + queries = ActiveRecord::QueryRecorder.new { perform_migration } + + expect(queries.count).to eq(7) + expect(migrated_attribute(project_with_no_issues_no_repo)).to be_falsey + expect(migrated_attribute(project_with_repo)).to be_truthy + expect(migrated_attribute(project_with_issues)).to be_truthy + expect(migrated_attribute(project_with_issues_and_repo)).to be_truthy + end + + def create_legacy_license_public_project(path, repo_size: 0, with_issue: false) + namespace = namespaces_table.create!(name: "namespace-#{path}", path: "namespace-#{path}") + project_namespace = + namespaces_table.create!(name: "-project-namespace-#{path}", path: "project-namespace-#{path}", type: 'Project') + project = projects_table + .create!( + name: path, path: path, namespace_id: namespace.id, + project_namespace_id: project_namespace.id, visibility_level: 20 + ) + + project_statistics_table.create!(project_id: project.id, namespace_id: namespace.id, repository_size: repo_size) + issues_table.create!(project_id: project.id) if with_issue + project_settings_table.create!(project_id: project.id, legacy_open_source_license_available: true) + + project + end + + def migrated_attribute(project) + project_settings_table.find(project.id).legacy_open_source_license_available + end +end diff --git a/spec/lib/gitlab/background_migration/disable_legacy_open_source_license_for_one_member_no_repo_projects_spec.rb b/spec/lib/gitlab/background_migration/disable_legacy_open_source_license_for_one_member_no_repo_projects_spec.rb new file mode 100644 index 00000000000..0dba1d7c8a2 --- /dev/null +++ b/spec/lib/gitlab/background_migration/disable_legacy_open_source_license_for_one_member_no_repo_projects_spec.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::BackgroundMigration::DisableLegacyOpenSourceLicenseForOneMemberNoRepoProjects, + :migration, + schema: 20220721031446 do + let(:namespaces_table) { table(:namespaces) } + let(:projects_table) { table(:projects) } + let(:project_settings_table) { table(:project_settings) } + let(:project_statistics_table) { table(:project_statistics) } + let(:users_table) { table(:users) } + let(:project_authorizations_table) { table(:project_authorizations) } + + subject(:perform_migration) do + described_class.new(start_id: projects_table.minimum(:id), + end_id: projects_table.maximum(:id), + batch_table: :projects, + batch_column: :id, + sub_batch_size: 2, + pause_ms: 0, + connection: ActiveRecord::Base.connection) + .perform + end + + it 'sets `legacy_open_source_license_available` to false only for public projects with 1 member and no repo', + :aggregate_failures do + project_with_no_repo_one_member = create_legacy_license_public_project('project-with-one-member-no-repo') + project_with_repo_one_member = create_legacy_license_public_project('project-with-repo', repo_size: 1) + project_with_no_repo_two_members = create_legacy_license_public_project('project-with-two-members', members: 2) + project_with_repo_two_members = + create_legacy_license_public_project('project-with-repo', repo_size: 1, members: 2) + + queries = ActiveRecord::QueryRecorder.new { perform_migration } + + expect(queries.count).to eq(7) + expect(migrated_attribute(project_with_no_repo_one_member)).to be_falsey + expect(migrated_attribute(project_with_repo_one_member)).to be_truthy + expect(migrated_attribute(project_with_no_repo_two_members)).to be_truthy + expect(migrated_attribute(project_with_repo_two_members)).to be_truthy + end + + def create_legacy_license_public_project(path, repo_size: 0, members: 1) + namespace = namespaces_table.create!(name: "namespace-#{path}", path: "namespace-#{path}") + project_namespace = + namespaces_table.create!(name: "-project-namespace-#{path}", path: "project-namespace-#{path}", type: 'Project') + project = projects_table + .create!( + name: path, path: path, namespace_id: namespace.id, + project_namespace_id: project_namespace.id, visibility_level: 20 + ) + + members.times do |member_id| + user = users_table.create!(email: "user#{member_id}-project-#{project.id}@gitlab.com", projects_limit: 100) + project_authorizations_table.create!(project_id: project.id, user_id: user.id, access_level: 50) + end + project_statistics_table.create!(project_id: project.id, namespace_id: namespace.id, repository_size: repo_size) + project_settings_table.create!(project_id: project.id, legacy_open_source_license_available: true) + + project + end + + def migrated_attribute(project) + project_settings_table.find(project.id).legacy_open_source_license_available + end +end diff --git a/spec/lib/gitlab/background_migration/drop_invalid_security_findings_spec.rb b/spec/lib/gitlab/background_migration/drop_invalid_security_findings_spec.rb index 7cc64889fc8..5fdd8683d06 100644 --- a/spec/lib/gitlab/background_migration/drop_invalid_security_findings_spec.rb +++ b/spec/lib/gitlab/background_migration/drop_invalid_security_findings_spec.rb @@ -1,7 +1,8 @@ # frozen_string_literal: true require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::DropInvalidSecurityFindings, schema: 20211108211434 do +RSpec.describe Gitlab::BackgroundMigration::DropInvalidSecurityFindings, :suppress_gitlab_schemas_validate_connection, + schema: 20211108211434 do let(:namespace) { table(:namespaces).create!(name: 'user', path: 'user', type: Namespaces::UserNamespace.sti_name) } let(:project) { table(:projects).create!(namespace_id: namespace.id) } diff --git a/spec/lib/gitlab/background_migration/extract_project_topics_into_separate_table_spec.rb b/spec/lib/gitlab/background_migration/extract_project_topics_into_separate_table_spec.rb index 65d55f85a98..51a09d50a19 100644 --- a/spec/lib/gitlab/background_migration/extract_project_topics_into_separate_table_spec.rb +++ b/spec/lib/gitlab/background_migration/extract_project_topics_into_separate_table_spec.rb @@ -2,7 +2,8 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::ExtractProjectTopicsIntoSeparateTable, schema: 20210730104800 do +RSpec.describe Gitlab::BackgroundMigration::ExtractProjectTopicsIntoSeparateTable, + :suppress_gitlab_schemas_validate_connection, schema: 20210730104800 do it 'correctly extracts project topics into separate table' do namespaces = table(:namespaces) projects = table(:projects) diff --git a/spec/lib/gitlab/background_migration/migrate_project_taggings_context_from_tags_to_topics_spec.rb b/spec/lib/gitlab/background_migration/migrate_project_taggings_context_from_tags_to_topics_spec.rb index 5e2f32c54be..5495d786a48 100644 --- a/spec/lib/gitlab/background_migration/migrate_project_taggings_context_from_tags_to_topics_spec.rb +++ b/spec/lib/gitlab/background_migration/migrate_project_taggings_context_from_tags_to_topics_spec.rb @@ -2,7 +2,8 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::MigrateProjectTaggingsContextFromTagsToTopics, schema: 20210511095658 do +RSpec.describe Gitlab::BackgroundMigration::MigrateProjectTaggingsContextFromTagsToTopics, + :suppress_gitlab_schemas_validate_connection, schema: 20210511095658 do it 'correctly migrates project taggings context from tags to topics' do taggings = table(:taggings) diff --git a/spec/lib/gitlab/background_migration/nullify_orphan_runner_id_on_ci_builds_spec.rb b/spec/lib/gitlab/background_migration/nullify_orphan_runner_id_on_ci_builds_spec.rb index e38edfc3643..2f0eef3c399 100644 --- a/spec/lib/gitlab/background_migration/nullify_orphan_runner_id_on_ci_builds_spec.rb +++ b/spec/lib/gitlab/background_migration/nullify_orphan_runner_id_on_ci_builds_spec.rb @@ -2,12 +2,13 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::NullifyOrphanRunnerIdOnCiBuilds, :migration, schema: 20220223112304 do +RSpec.describe Gitlab::BackgroundMigration::NullifyOrphanRunnerIdOnCiBuilds, + :suppress_gitlab_schemas_validate_connection, migration: :gitlab_ci, schema: 20220223112304 do let(:namespaces) { table(:namespaces) } let(:projects) { table(:projects) } - let(:ci_runners) { table(:ci_runners, database: :ci) } - let(:ci_pipelines) { table(:ci_pipelines, database: :ci) } - let(:ci_builds) { table(:ci_builds, database: :ci) } + let(:ci_runners) { table(:ci_runners) } + let(:ci_pipelines) { table(:ci_pipelines) } + let(:ci_builds) { table(:ci_builds) } subject { described_class.new } @@ -20,7 +21,9 @@ RSpec.describe Gitlab::BackgroundMigration::NullifyOrphanRunnerIdOnCiBuilds, :mi end after do - helpers.add_concurrent_foreign_key(:ci_builds, :ci_runners, column: :runner_id, on_delete: :nullify, validate: false) + helpers.add_concurrent_foreign_key( + :ci_builds, :ci_runners, column: :runner_id, on_delete: :nullify, validate: false + ) end describe '#perform' do 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 index 2ad561ead87..bff803e2035 100644 --- 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 @@ -5,199 +5,211 @@ require 'spec_helper' RSpec.describe Gitlab::BackgroundMigration::ProjectNamespaces::BackfillProjectNamespaces, :migration, schema: 20220326161803 do include MigrationsHelpers - context 'when migrating data', :aggregate_failures do - let(:projects) { table(:projects) } - let(:namespaces) { table(:namespaces) } + RSpec.shared_examples 'backfills project namespaces' do + 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) { 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(: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(:child_nodes_count) { 2 } + let(:tree_depth) { 3 } - let(:backfilled_namespace) { nil } + 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::SUB_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, nil, nil, nil, 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::SUB_BATCH_SIZE.to_f).ceil - project_namespaces_in_hierarchy = project_namespaces_in_hierarchy(base_ancestor(backfilled_namespace)) + 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::SUB_BATCH_SIZE.to_f).ceil + project_namespaces_count = ::Namespace.where(type: 'Project').count migration = described_class.new - expect(project_namespaces_in_hierarchy.count).to eq(0) + 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(group_projects_count).to eq(14) - expect(project_namespaces_in_hierarchy.count).to eq(0) - - migration.perform(start_id, end_id, nil, nil, nil, nil, backfilled_namespace.id, 'up') + expect { migration.perform(start_id, end_id, nil, nil, nil, nil, nil, 'up') }.to change(Namespace.where(type: 'Project'), :count) - expect(project_namespaces_in_hierarchy.count).to eq(14) - check_projects_in_sync_with(project_namespaces_in_hierarchy) + expect(projects_count).to eq(::Namespace.where(type: 'Project').count) + check_projects_in_sync_with(Namespace.where(type: 'Project')) 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) + context 'when passing specific group as parameter' do + let(:backfilled_namespace) { parent_group1 } - described_class.new.perform(start_id, end_id, nil, nil, nil, nil, parent_group1.id, 'up') - end + 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::SUB_BATCH_SIZE.to_f).ceil + project_namespaces_in_hierarchy = project_namespaces_in_hierarchy(base_ancestor(backfilled_namespace)) - 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::SUB_BATCH_SIZE.to_f).ceil - project_namespaces = ::Namespace.where(type: 'Project') - migration = described_class.new + 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) + 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 - # 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(group_projects_count).to eq(14) + expect(project_namespaces_in_hierarchy.count).to eq(0) - expect { migration.perform(start_id, end_id, nil, nil, nil, nil, nil, 'up') }.to change(project_namespaces, :count).by(14) + migration.perform(start_id, end_id, nil, nil, nil, nil, backfilled_namespace.id, 'up') - expect(projects_count).to eq(project_namespaces.count) + expect(project_namespaces_in_hierarchy.count).to eq(14) + check_projects_in_sync_with(project_namespaces_in_hierarchy) + end 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 + 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, nil, nil, nil, nil, 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::SUB_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, nil, nil, nil, nil, 'up') }.to change(project_namespaces, :count).by(14) + + expect(projects_count).to eq(project_namespaces.count) + end + end + end - 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 + 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 - context 'back-fill project namespaces in a single batch' do - it_behaves_like 'back-fill project namespaces' - end + 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 batches' do - before do - stub_const("#{described_class.name}::SUB_BATCH_SIZE", 2) + context 'back-fill project namespaces in a single batch' do + it_behaves_like 'back-fill project namespaces' end - it_behaves_like 'back-fill project namespaces' - end - end + context 'back-fill project namespaces in batches' do + before do + stub_const("#{described_class.name}::SUB_BATCH_SIZE", 2) + 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, nil, nil, nil, nil, 'up') + it_behaves_like 'back-fill project namespaces' + end end - shared_examples 'cleanup project namespaces' do - it 'removes project namespaces' do - projects_count = ::Project.count + describe '#down' do + before do start_id = ::Project.minimum(:id) end_id = ::Project.maximum(:id) - migration = described_class.new - batches_count = (projects_count / described_class::SUB_BATCH_SIZE.to_f).ceil + # back-fill first + described_class.new.perform(start_id, end_id, nil, nil, nil, nil, nil, 'up') + end - expect(projects_count).to be > 0 - expect(projects_count).to eq(::Namespace.where(type: 'Project').count) + 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::SUB_BATCH_SIZE.to_f).ceil - 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 + expect(projects_count).to be > 0 + expect(projects_count).to eq(::Namespace.where(type: 'Project').count) - migration.perform(start_id, end_id, nil, nil, nil, nil, nil, 'down') + 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 - expect(::Project.count).to be > 0 - expect(::Namespace.where(type: 'Project').count).to eq(0) - end + migration.perform(start_id, end_id, nil, nil, nil, nil, 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 } + 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::SUB_BATCH_SIZE.to_f).ceil - project_namespaces_in_hierarchy = project_namespaces_in_hierarchy(base_ancestor(backfilled_namespace)) - migration = described_class.new + 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::SUB_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 + 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, nil, nil, nil, nil, backfilled_namespace.id, 'down') + migration.perform(start_id, end_id, nil, nil, nil, nil, backfilled_namespace.id, 'down') - expect(::Namespace.where(type: 'Project').count).to be > 0 - expect(project_namespaces_in_hierarchy.count).to eq(0) + expect(::Namespace.where(type: 'Project').count).to be > 0 + expect(project_namespaces_in_hierarchy.count).to eq(0) + end 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}::SUB_BATCH_SIZE", 2) + context 'cleanup project namespaces in a single batch' do + it_behaves_like 'cleanup project namespaces' end - it_behaves_like 'cleanup project namespaces' + context 'cleanup project namespaces in batches' do + before do + stub_const("#{described_class.name}::SUB_BATCH_SIZE", 2) + end + + it_behaves_like 'cleanup project namespaces' + end end end end + it_behaves_like 'backfills project namespaces' + + context 'when namespaces.id is bigint' do + before do + namespaces.connection.execute("ALTER TABLE namespaces ALTER COLUMN id TYPE bigint") + end + + it_behaves_like 'backfills project namespaces' + end + def base_ancestor(ancestor) ::Namespace.where(id: ancestor.id) end @@ -209,7 +221,7 @@ RSpec.describe Gitlab::BackgroundMigration::ProjectNamespaces::BackfillProjectNa 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) + .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 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 8d71b117107..a609227be05 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 @@ -20,7 +20,7 @@ def create_background_migration_job(ids, status) ) end -RSpec.describe Gitlab::BackgroundMigration::RecalculateVulnerabilitiesOccurrencesUuid, schema: 20211124132705 do +RSpec.describe Gitlab::BackgroundMigration::RecalculateVulnerabilitiesOccurrencesUuid, :suppress_gitlab_schemas_validate_connection, schema: 20211124132705 do let(:background_migration_jobs) { table(:background_migration_jobs) } let(:pending_jobs) { background_migration_jobs.where(status: Gitlab::Database::BackgroundMigrationJob.statuses['pending']) } let(:succeeded_jobs) { background_migration_jobs.where(status: Gitlab::Database::BackgroundMigrationJob.statuses['succeeded']) } diff --git a/spec/lib/gitlab/background_migration/remove_all_trace_expiration_dates_spec.rb b/spec/lib/gitlab/background_migration/remove_all_trace_expiration_dates_spec.rb index 8cdcec9621c..eabc012f98b 100644 --- a/spec/lib/gitlab/background_migration/remove_all_trace_expiration_dates_spec.rb +++ b/spec/lib/gitlab/background_migration/remove_all_trace_expiration_dates_spec.rb @@ -2,7 +2,8 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::RemoveAllTraceExpirationDates, :migration, schema: 20220131000001 do +RSpec.describe Gitlab::BackgroundMigration::RemoveAllTraceExpirationDates, :migration, + :suppress_gitlab_schemas_validate_connection, schema: 20220131000001 do subject(:perform) { migration.perform(1, 99) } let(:migration) { described_class.new } diff --git a/spec/lib/gitlab/background_migration/remove_occurrence_pipelines_and_duplicate_vulnerabilities_findings_spec.rb b/spec/lib/gitlab/background_migration/remove_occurrence_pipelines_and_duplicate_vulnerabilities_findings_spec.rb index 07cff32304e..33ad74fbee8 100644 --- a/spec/lib/gitlab/background_migration/remove_occurrence_pipelines_and_duplicate_vulnerabilities_findings_spec.rb +++ b/spec/lib/gitlab/background_migration/remove_occurrence_pipelines_and_duplicate_vulnerabilities_findings_spec.rb @@ -1,7 +1,8 @@ # frozen_string_literal: true require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::RemoveOccurrencePipelinesAndDuplicateVulnerabilitiesFindings, :migration, schema: 20220326161803 do +RSpec.describe Gitlab::BackgroundMigration::RemoveOccurrencePipelinesAndDuplicateVulnerabilitiesFindings, :migration, + :suppress_gitlab_schemas_validate_connection, schema: 20220326161803 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/set_legacy_open_source_license_available_for_non_public_projects_spec.rb b/spec/lib/gitlab/background_migration/set_legacy_open_source_license_available_for_non_public_projects_spec.rb index 035ea6eadcf..e9f73672144 100644 --- a/spec/lib/gitlab/background_migration/set_legacy_open_source_license_available_for_non_public_projects_spec.rb +++ b/spec/lib/gitlab/background_migration/set_legacy_open_source_license_available_for_non_public_projects_spec.rb @@ -4,14 +4,14 @@ require 'spec_helper' RSpec.describe Gitlab::BackgroundMigration::SetLegacyOpenSourceLicenseAvailableForNonPublicProjects, :migration, - schema: 20220520040416 do + schema: 20220722110026 do let(:namespaces_table) { table(:namespaces) } let(:projects_table) { table(:projects) } let(:project_settings_table) { table(:project_settings) } subject(:perform_migration) do - described_class.new(start_id: 1, - end_id: 30, + described_class.new(start_id: projects_table.minimum(:id), + end_id: projects_table.maximum(:id), batch_table: :projects, batch_column: :id, sub_batch_size: 2, @@ -20,35 +20,34 @@ RSpec.describe Gitlab::BackgroundMigration::SetLegacyOpenSourceLicenseAvailableF .perform end - let(:queries) { ActiveRecord::QueryRecorder.new { perform_migration } } + it 'sets `legacy_open_source_license_available` attribute to false for non-public projects', :aggregate_failures do + private_project = create_legacy_license_project('private-project', visibility_level: 0) + internal_project = create_legacy_license_project('internal-project', visibility_level: 10) + public_project = create_legacy_license_project('public-project', visibility_level: 20) - before do - namespaces_table.create!(id: 1, name: 'namespace', path: 'namespace-path-1') - namespaces_table.create!(id: 2, name: 'namespace', path: 'namespace-path-2', type: 'Project') - namespaces_table.create!(id: 3, name: 'namespace', path: 'namespace-path-3', type: 'Project') - namespaces_table.create!(id: 4, name: 'namespace', path: 'namespace-path-4', type: 'Project') + queries = ActiveRecord::QueryRecorder.new { perform_migration } - projects_table - .create!(id: 11, name: 'proj-1', path: 'path-1', namespace_id: 1, project_namespace_id: 2, visibility_level: 0) - projects_table - .create!(id: 12, name: 'proj-2', path: 'path-2', namespace_id: 1, project_namespace_id: 3, visibility_level: 10) - projects_table - .create!(id: 13, name: 'proj-3', path: 'path-3', namespace_id: 1, project_namespace_id: 4, visibility_level: 20) + expect(queries.count).to eq(5) - project_settings_table.create!(project_id: 11, legacy_open_source_license_available: true) - project_settings_table.create!(project_id: 12, legacy_open_source_license_available: true) - project_settings_table.create!(project_id: 13, legacy_open_source_license_available: true) + expect(migrated_attribute(private_project)).to be_falsey + expect(migrated_attribute(internal_project)).to be_falsey + expect(migrated_attribute(public_project)).to be_truthy end - it 'sets `legacy_open_source_license_available` attribute to false for non-public projects', :aggregate_failures do - expect(queries.count).to eq(3) - - expect(migrated_attribute(11)).to be_falsey - expect(migrated_attribute(12)).to be_falsey - expect(migrated_attribute(13)).to be_truthy + def create_legacy_license_project(path, visibility_level:) + namespace = namespaces_table.create!(name: "namespace-#{path}", path: "namespace-#{path}") + project_namespace = namespaces_table.create!(name: "project-namespace-#{path}", path: path, type: 'Project') + project = projects_table.create!(name: path, + path: path, + namespace_id: namespace.id, + project_namespace_id: project_namespace.id, + visibility_level: visibility_level) + project_settings_table.create!(project_id: project.id, legacy_open_source_license_available: true) + + project end - def migrated_attribute(project_id) - project_settings_table.find(project_id).legacy_open_source_license_available + def migrated_attribute(project) + project_settings_table.find(project.id).legacy_open_source_license_available end end diff --git a/spec/lib/gitlab/background_migration/update_jira_tracker_data_deployment_type_based_on_url_spec.rb b/spec/lib/gitlab/background_migration/update_jira_tracker_data_deployment_type_based_on_url_spec.rb index b96d3f7f0b5..c090c1df424 100644 --- a/spec/lib/gitlab/background_migration/update_jira_tracker_data_deployment_type_based_on_url_spec.rb +++ b/spec/lib/gitlab/background_migration/update_jira_tracker_data_deployment_type_based_on_url_spec.rb @@ -2,10 +2,26 @@ require 'spec_helper' -RSpec.describe Gitlab::BackgroundMigration::UpdateJiraTrackerDataDeploymentTypeBasedOnUrl, schema: 20210421163509 do - let(:services_table) { table(:services) } - let(:service_jira_cloud) { services_table.create!(id: 1, type: 'JiraService') } - let(:service_jira_server) { services_table.create!(id: 2, type: 'JiraService') } +RSpec.describe Gitlab::BackgroundMigration::UpdateJiraTrackerDataDeploymentTypeBasedOnUrl do + let(:integrations_table) { table(:integrations) } + let(:service_jira_cloud) { integrations_table.create!(id: 1, type_new: 'JiraService') } + let(:service_jira_server) { integrations_table.create!(id: 2, type_new: 'JiraService') } + let(:service_jira_unknown) { integrations_table.create!(id: 3, type_new: 'JiraService') } + + let(:table_name) { :jira_tracker_data } + let(:batch_column) { :id } + let(:sub_batch_size) { 1 } + let(:pause_ms) { 0 } + let(:migration) do + described_class.new(start_id: 1, end_id: 10, + batch_table: table_name, batch_column: batch_column, + sub_batch_size: sub_batch_size, pause_ms: pause_ms, + connection: ApplicationRecord.connection) + end + + subject(:perform_migration) do + migration.perform + end before do jira_tracker_data = Class.new(ApplicationRecord) do @@ -27,18 +43,21 @@ RSpec.describe Gitlab::BackgroundMigration::UpdateJiraTrackerDataDeploymentTypeB end stub_const('JiraTrackerData', jira_tracker_data) - end - let!(:tracker_data_cloud) { JiraTrackerData.create!(id: 1, service_id: service_jira_cloud.id, url: "https://test-domain.atlassian.net", deployment_type: 0) } - let!(:tracker_data_server) { JiraTrackerData.create!(id: 2, service_id: service_jira_server.id, url: "http://totally-not-jira-server.company.org", deployment_type: 0) } + stub_const('UNKNOWN', 0) + stub_const('SERVER', 1) + stub_const('CLOUD', 2) + end - subject { described_class.new.perform(tracker_data_cloud.id, tracker_data_server.id) } + let!(:tracker_data_cloud) { JiraTrackerData.create!(id: 1, integration_id: service_jira_cloud.id, url: "https://test-domain.atlassian.net", deployment_type: UNKNOWN) } + let!(:tracker_data_server) { JiraTrackerData.create!(id: 2, integration_id: service_jira_server.id, url: "http://totally-not-jira-server.company.org", deployment_type: UNKNOWN) } + let!(:tracker_data_unknown) { JiraTrackerData.create!(id: 3, integration_id: service_jira_unknown.id, url: "", deployment_type: UNKNOWN) } it "changes unknown deployment_types based on URL" do - expect(JiraTrackerData.pluck(:deployment_type)).to eq([0, 0]) + expect(JiraTrackerData.pluck(:deployment_type)).to match_array([UNKNOWN, UNKNOWN, UNKNOWN]) - subject + perform_migration - expect(JiraTrackerData.pluck(:deployment_type)).to eq([2, 1]) + expect(JiraTrackerData.order(:id).pluck(:deployment_type)).to match_array([CLOUD, SERVER, UNKNOWN]) end end |