diff options
Diffstat (limited to 'spec/lib/gitlab/background_migration')
8 files changed, 321 insertions, 254 deletions
diff --git a/spec/lib/gitlab/background_migration/backfill_namespace_traversal_ids_children_spec.rb b/spec/lib/gitlab/background_migration/backfill_namespace_traversal_ids_children_spec.rb new file mode 100644 index 00000000000..35928deff82 --- /dev/null +++ b/spec/lib/gitlab/background_migration/backfill_namespace_traversal_ids_children_spec.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::BackgroundMigration::BackfillNamespaceTraversalIdsChildren, :migration, schema: 20210506065000 do + let(:namespaces_table) { table(:namespaces) } + + let!(:user_namespace) { namespaces_table.create!(id: 1, name: 'user', path: 'user', type: nil) } + let!(:root_group) { namespaces_table.create!(id: 2, name: 'group', path: 'group', type: 'Group', parent_id: nil) } + let!(:sub_group) { namespaces_table.create!(id: 3, name: 'subgroup', path: 'subgroup', type: 'Group', parent_id: 2) } + + describe '#perform' do + it 'backfills traversal_ids for child namespaces' do + described_class.new.perform(1, 3, 5) + + expect(user_namespace.reload.traversal_ids).to eq([]) + expect(root_group.reload.traversal_ids).to eq([]) + expect(sub_group.reload.traversal_ids).to eq([root_group.id, sub_group.id]) + end + end +end diff --git a/spec/lib/gitlab/background_migration/backfill_namespace_traversal_ids_roots_spec.rb b/spec/lib/gitlab/background_migration/backfill_namespace_traversal_ids_roots_spec.rb new file mode 100644 index 00000000000..96e43275972 --- /dev/null +++ b/spec/lib/gitlab/background_migration/backfill_namespace_traversal_ids_roots_spec.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::BackgroundMigration::BackfillNamespaceTraversalIdsRoots, :migration, schema: 20210506065000 do + let(:namespaces_table) { table(:namespaces) } + + let!(:user_namespace) { namespaces_table.create!(id: 1, name: 'user', path: 'user', type: nil) } + let!(:root_group) { namespaces_table.create!(id: 2, name: 'group', path: 'group', type: 'Group', parent_id: nil) } + let!(:sub_group) { namespaces_table.create!(id: 3, name: 'subgroup', path: 'subgroup', type: 'Group', parent_id: 2) } + + describe '#perform' do + it 'backfills traversal_ids for root namespaces' do + described_class.new.perform(1, 3, 5) + + expect(user_namespace.reload.traversal_ids).to eq([user_namespace.id]) + expect(root_group.reload.traversal_ids).to eq([root_group.id]) + expect(sub_group.reload.traversal_ids).to eq([]) + 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 c4c0247ad3e..3e378db04d4 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 @@ -6,6 +6,11 @@ RSpec.describe Gitlab::BackgroundMigration::CopyColumnUsingBackgroundMigrationJo let(:table_name) { :copy_primary_key_test } let(:test_table) { table(table_name) } let(:sub_batch_size) { 1000 } + let(:pause_ms) { 0 } + + let(:helpers) do + ActiveRecord::Migration.new.extend(Gitlab::Database::MigrationHelpers) + end before do ActiveRecord::Base.connection.execute(<<~SQL) @@ -14,8 +19,8 @@ RSpec.describe Gitlab::BackgroundMigration::CopyColumnUsingBackgroundMigrationJo id integer NOT NULL, name character varying, fk integer NOT NULL, - id_convert_to_bigint bigint DEFAULT 0 NOT NULL, - fk_convert_to_bigint bigint DEFAULT 0 NOT NULL, + #{helpers.convert_to_bigint_column(:id)} bigint DEFAULT 0 NOT NULL, + #{helpers.convert_to_bigint_column(:fk)} bigint DEFAULT 0 NOT NULL, name_convert_to_text text DEFAULT 'no name' ); SQL @@ -34,43 +39,85 @@ RSpec.describe Gitlab::BackgroundMigration::CopyColumnUsingBackgroundMigrationJo SQL end - subject { described_class.new } + subject(:copy_columns) { described_class.new } describe '#perform' do let(:migration_class) { described_class.name } it 'copies all primary keys in range' do - subject.perform(12, 15, table_name, 'id', sub_batch_size, 'id', 'id_convert_to_bigint') + temporary_column = helpers.convert_to_bigint_column(:id) + copy_columns.perform(12, 15, table_name, 'id', sub_batch_size, pause_ms, 'id', temporary_column) - 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) + expect(test_table.where("id = #{temporary_column}").pluck(:id)).to contain_exactly(12, 15) + expect(test_table.where(temporary_column => 0).pluck(:id)).to contain_exactly(11, 19) expect(test_table.all.count).to eq(4) end it 'copies all foreign keys in range' do - subject.perform(10, 14, table_name, 'id', sub_batch_size, 'fk', 'fk_convert_to_bigint') + temporary_column = helpers.convert_to_bigint_column(:fk) + copy_columns.perform(10, 14, table_name, 'id', sub_batch_size, pause_ms, 'fk', temporary_column) - 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) + expect(test_table.where("fk = #{temporary_column}").pluck(:id)).to contain_exactly(11, 12) + expect(test_table.where(temporary_column => 0).pluck(:id)).to contain_exactly(15, 19) expect(test_table.all.count).to eq(4) end 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', sub_batch_size, 'name', 'name_convert_to_text') + copy_columns.perform(10, 20, table_name, 'id', sub_batch_size, pause_ms, '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 'copies multiple columns when given' do + columns_to_copy_from = %w[id fk] + id_tmp_column = helpers.convert_to_bigint_column('id') + fk_tmp_column = helpers.convert_to_bigint_column('fk') + columns_to_copy_to = [id_tmp_column, fk_tmp_column] + + subject.perform(10, 15, table_name, 'id', sub_batch_size, pause_ms, columns_to_copy_from, columns_to_copy_to) + + expect(test_table.where("id = #{id_tmp_column} AND fk = #{fk_tmp_column}").pluck(:id)).to contain_exactly(11, 12, 15) + expect(test_table.where(id_tmp_column => 0).where(fk_tmp_column => 0).pluck(:id)).to contain_exactly(19) + expect(test_table.all.count).to eq(4) + end + + it 'raises error when number of source and target columns does not match' do + columns_to_copy_from = %w[id fk] + columns_to_copy_to = [helpers.convert_to_bigint_column(:id)] + + expect do + subject.perform(10, 15, table_name, 'id', sub_batch_size, pause_ms, columns_to_copy_from, columns_to_copy_to) + end.to raise_error(ArgumentError, 'number of source and destination columns must match') + end + it 'tracks timings of queries' do - expect(subject.batch_metrics.timings).to be_empty + expect(copy_columns.batch_metrics.timings).to be_empty + + copy_columns.perform(10, 20, table_name, 'id', sub_batch_size, pause_ms, 'name', 'name_convert_to_text') + + expect(copy_columns.batch_metrics.timings[:update_all]).not_to be_empty + end + + context 'pause interval between sub-batches' do + it 'sleeps for the specified time between sub-batches' do + sub_batch_size = 2 + + expect(copy_columns).to receive(:sleep).with(0.005) + + copy_columns.perform(10, 12, table_name, 'id', sub_batch_size, 5, 'name', 'name_convert_to_text') + end + + it 'treats negative values as 0' do + sub_batch_size = 2 - subject.perform(10, 20, table_name, 'id', sub_batch_size, 'name', 'name_convert_to_text') + expect(copy_columns).to receive(:sleep).with(0) - expect(subject.batch_metrics.timings[:update_all]).not_to be_empty + copy_columns.perform(10, 12, table_name, 'id', sub_batch_size, -5, 'name', 'name_convert_to_text') + end end end end diff --git a/spec/lib/gitlab/background_migration/drop_invalid_vulnerabilities_spec.rb b/spec/lib/gitlab/background_migration/drop_invalid_vulnerabilities_spec.rb new file mode 100644 index 00000000000..c4beb719e1e --- /dev/null +++ b/spec/lib/gitlab/background_migration/drop_invalid_vulnerabilities_spec.rb @@ -0,0 +1,126 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::BackgroundMigration::DropInvalidVulnerabilities, schema: 20201110110454 do + let_it_be(:background_migration_jobs) { table(:background_migration_jobs) } + let_it_be(:namespace) { table(:namespaces).create!(name: 'user', path: 'user') } + let_it_be(:users) { table(:users) } + let_it_be(:user) { create_user! } + let_it_be(:project) { table(:projects).create!(id: 123, namespace_id: namespace.id) } + + let_it_be(:scanners) { table(:vulnerability_scanners) } + let_it_be(:scanner) { scanners.create!(project_id: project.id, external_id: 'test 1', name: 'test scanner 1') } + let_it_be(:different_scanner) { scanners.create!(project_id: project.id, external_id: 'test 2', name: 'test scanner 2') } + + let_it_be(:vulnerabilities) { table(:vulnerabilities) } + let_it_be(:vulnerability_with_finding) do + create_vulnerability!( + project_id: project.id, + author_id: user.id + ) + end + + let_it_be(:vulnerability_without_finding) do + create_vulnerability!( + project_id: project.id, + author_id: user.id + ) + end + + let_it_be(:vulnerability_identifiers) { table(:vulnerability_identifiers) } + let_it_be(:primary_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_it_be(:vulnerabilities_findings) { table(:vulnerability_occurrences) } + let_it_be(:finding) do + create_finding!( + vulnerability_id: vulnerability_with_finding.id, + project_id: project.id, + scanner_id: scanner.id, + primary_identifier_id: primary_identifier.id + ) + end + + let(:succeeded_status) { 1 } + let(:pending_status) { 0 } + + it 'drops Vulnerabilities without any Findings' do + expect(vulnerabilities.pluck(:id)).to eq([vulnerability_with_finding.id, vulnerability_without_finding.id]) + + expect { subject.perform(vulnerability_with_finding.id, vulnerability_without_finding.id) }.to change(vulnerabilities, :count).by(-1) + + expect(vulnerabilities.pluck(:id)).to eq([vulnerability_with_finding.id]) + end + + it 'marks jobs as done' do + background_migration_jobs.create!( + class_name: 'DropInvalidVulnerabilities', + arguments: [vulnerability_with_finding.id, vulnerability_with_finding.id] + ) + + background_migration_jobs.create!( + class_name: 'DropInvalidVulnerabilities', + arguments: [vulnerability_without_finding.id, vulnerability_without_finding.id] + ) + + subject.perform(vulnerability_with_finding.id, vulnerability_with_finding.id) + + expect(background_migration_jobs.first.status).to eq(succeeded_status) + expect(background_migration_jobs.second.status).to eq(pending_status) + 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: primary_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) + users.create!( + name: name, + email: email, + username: name, + projects_limit: 0, + user_type: user_type, + confirmed_at: Time.current + ) + end +end 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 new file mode 100644 index 00000000000..5e2f32c54be --- /dev/null +++ b/spec/lib/gitlab/background_migration/migrate_project_taggings_context_from_tags_to_topics_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::BackgroundMigration::MigrateProjectTaggingsContextFromTagsToTopics, schema: 20210511095658 do + it 'correctly migrates project taggings context from tags to topics' do + taggings = table(:taggings) + + project_old_tagging_1 = taggings.create!(taggable_type: 'Project', context: 'tags') + project_new_tagging_1 = taggings.create!(taggable_type: 'Project', context: 'topics') + project_other_context_tagging_1 = taggings.create!(taggable_type: 'Project', context: 'other') + project_old_tagging_2 = taggings.create!(taggable_type: 'Project', context: 'tags') + project_old_tagging_3 = taggings.create!(taggable_type: 'Project', context: 'tags') + + subject.perform(project_old_tagging_1.id, project_old_tagging_2.id) + + project_old_tagging_1.reload + project_new_tagging_1.reload + project_other_context_tagging_1.reload + project_old_tagging_2.reload + project_old_tagging_3.reload + + expect(project_old_tagging_1.context).to eq('topics') + expect(project_new_tagging_1.context).to eq('topics') + expect(project_other_context_tagging_1.context).to eq('other') + expect(project_old_tagging_2.context).to eq('topics') + expect(project_old_tagging_3.context).to eq('tags') + end +end 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 index 1c62d703a34..b34a57f51f1 100644 --- 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 @@ -31,6 +31,15 @@ RSpec.describe Gitlab::BackgroundMigration::MoveContainerRegistryEnabledToProjec end it 'copies values to project_features' do + table(:background_migration_jobs).create!( + class_name: 'MoveContainerRegistryEnabledToProjectFeature', + arguments: [project1.id, project4.id] + ) + table(:background_migration_jobs).create!( + class_name: 'MoveContainerRegistryEnabledToProjectFeature', + arguments: [-1, -3] + ) + expect(project1.container_registry_enabled).to eq(true) expect(project2.container_registry_enabled).to eq(false) expect(project3.container_registry_enabled).to eq(nil) @@ -57,6 +66,9 @@ RSpec.describe Gitlab::BackgroundMigration::MoveContainerRegistryEnabledToProjec 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) + + expect(table(:background_migration_jobs).first.status).to eq(1) # succeeded + expect(table(:background_migration_jobs).second.status).to eq(0) # pending end context 'when no projects exist in range' do diff --git a/spec/lib/gitlab/background_migration/recalculate_project_authorizations_spec.rb b/spec/lib/gitlab/background_migration/recalculate_project_authorizations_spec.rb deleted file mode 100644 index 1c55b50ea3f..00000000000 --- a/spec/lib/gitlab/background_migration/recalculate_project_authorizations_spec.rb +++ /dev/null @@ -1,241 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Gitlab::BackgroundMigration::RecalculateProjectAuthorizations, schema: 20200204113223 do - let(:users_table) { table(:users) } - let(:namespaces_table) { table(:namespaces) } - let(:projects_table) { table(:projects) } - let(:project_authorizations_table) { table(:project_authorizations) } - let(:members_table) { table(:members) } - let(:group_group_links) { table(:group_group_links) } - let(:project_group_links) { table(:project_group_links) } - - let(:user) { users_table.create!(id: 1, email: 'user@example.com', projects_limit: 10) } - let(:group) { namespaces_table.create!(type: 'Group', name: 'group', path: 'group') } - - subject { described_class.new.perform([user.id]) } - - context 'missing authorization' do - context 'personal project' do - before do - user_namespace = namespaces_table.create!(owner_id: user.id, name: 'User', path: 'user') - projects_table.create!(id: 1, - name: 'personal-project', - path: 'personal-project', - visibility_level: 0, - namespace_id: user_namespace.id) - end - - it 'creates correct authorization' do - expect { subject }.to change { project_authorizations_table.count }.from(0).to(1) - expect(project_authorizations_table.all).to( - match_array([have_attributes(user_id: 1, project_id: 1, access_level: 40)])) - end - end - - context 'group membership' do - before do - projects_table.create!(id: 1, name: 'group-project', path: 'group-project', - visibility_level: 0, namespace_id: group.id) - members_table.create!(user_id: user.id, source_id: group.id, source_type: 'Namespace', - type: 'GroupMember', access_level: 20, notification_level: 3) - end - - it 'creates correct authorization' do - expect { subject }.to change { project_authorizations_table.count }.from(0).to(1) - expect(project_authorizations_table.all).to( - match_array([have_attributes(user_id: 1, project_id: 1, access_level: 20)])) - end - end - - context 'inherited group membership' do - before do - sub_group = namespaces_table.create!(type: 'Group', name: 'subgroup', - path: 'subgroup', parent_id: group.id) - projects_table.create!(id: 1, name: 'group-project', path: 'group-project', - visibility_level: 0, namespace_id: sub_group.id) - members_table.create!(user_id: user.id, source_id: group.id, source_type: 'Namespace', - type: 'GroupMember', access_level: 20, notification_level: 3) - end - - it 'creates correct authorization' do - expect { subject }.to change { project_authorizations_table.count }.from(0).to(1) - expect(project_authorizations_table.all).to( - match_array([have_attributes(user_id: 1, project_id: 1, access_level: 20)])) - end - end - - context 'project membership' do - before do - project = projects_table.create!(id: 1, name: 'group-project', path: 'group-project', - visibility_level: 0, namespace_id: group.id) - members_table.create!(user_id: user.id, source_id: project.id, source_type: 'Project', - type: 'ProjectMember', access_level: 20, notification_level: 3) - end - - it 'creates correct authorization' do - expect { subject }.to change { project_authorizations_table.count }.from(0).to(1) - expect(project_authorizations_table.all).to( - match_array([have_attributes(user_id: 1, project_id: 1, access_level: 20)])) - end - end - - context 'shared group' do - before do - members_table.create!(user_id: user.id, source_id: group.id, source_type: 'Namespace', - type: 'GroupMember', access_level: 30, notification_level: 3) - - shared_group = namespaces_table.create!(type: 'Group', name: 'shared group', - path: 'shared-group') - projects_table.create!(id: 1, name: 'project', path: 'project', visibility_level: 0, - namespace_id: shared_group.id) - - group_group_links.create!(shared_group_id: shared_group.id, shared_with_group_id: group.id, - group_access: 20) - end - - it 'creates correct authorization' do - expect { subject }.to change { project_authorizations_table.count }.from(0).to(1) - expect(project_authorizations_table.all).to( - match_array([have_attributes(user_id: 1, project_id: 1, access_level: 20)])) - end - end - - context 'shared project' do - before do - members_table.create!(user_id: user.id, source_id: group.id, source_type: 'Namespace', - type: 'GroupMember', access_level: 30, notification_level: 3) - - another_group = namespaces_table.create!(type: 'Group', name: 'another group', path: 'another-group') - shared_project = projects_table.create!(id: 1, name: 'shared project', path: 'shared-project', - visibility_level: 0, namespace_id: another_group.id) - - project_group_links.create!(project_id: shared_project.id, group_id: group.id, group_access: 20) - end - - it 'creates correct authorization' do - expect { subject }.to change { project_authorizations_table.count }.from(0).to(1) - expect(project_authorizations_table.all).to( - match_array([have_attributes(user_id: 1, project_id: 1, access_level: 20)])) - end - end - end - - context 'unapproved access requests' do - context 'group membership' do - before do - projects_table.create!(id: 1, name: 'group-project', path: 'group-project', - visibility_level: 0, namespace_id: group.id) - members_table.create!(user_id: user.id, source_id: group.id, source_type: 'Namespace', - type: 'GroupMember', access_level: 20, requested_at: Time.now, notification_level: 3) - end - - it 'does not create authorization' do - expect { subject }.not_to change { project_authorizations_table.count }.from(0) - end - end - - context 'inherited group membership' do - before do - sub_group = namespaces_table.create!(type: 'Group', name: 'subgroup', path: 'subgroup', - parent_id: group.id) - projects_table.create!(id: 1, name: 'group-project', path: 'group-project', - visibility_level: 0, namespace_id: sub_group.id) - members_table.create!(user_id: user.id, source_id: group.id, source_type: 'Namespace', - type: 'GroupMember', access_level: 20, requested_at: Time.now, notification_level: 3) - end - - it 'does not create authorization' do - expect { subject }.not_to change { project_authorizations_table.count }.from(0) - end - end - - context 'project membership' do - before do - project = projects_table.create!(id: 1, name: 'group-project', path: 'group-project', - visibility_level: 0, namespace_id: group.id) - members_table.create!(user_id: user.id, source_id: project.id, source_type: 'Project', - type: 'ProjectMember', access_level: 20, requested_at: Time.now, notification_level: 3) - end - - it 'does not create authorization' do - expect { subject }.not_to change { project_authorizations_table.count }.from(0) - end - end - - context 'shared group' do - before do - members_table.create!(user_id: user.id, source_id: group.id, source_type: 'Namespace', - type: 'GroupMember', access_level: 30, requested_at: Time.now, notification_level: 3) - - shared_group = namespaces_table.create!(type: 'Group', name: 'shared group', - path: 'shared-group') - projects_table.create!(id: 1, name: 'project', path: 'project', visibility_level: 0, - namespace_id: shared_group.id) - - group_group_links.create!(shared_group_id: shared_group.id, shared_with_group_id: group.id, - group_access: 20) - end - - it 'does not create authorization' do - expect { subject }.not_to change { project_authorizations_table.count }.from(0) - end - end - - context 'shared project' do - before do - members_table.create!(user_id: user.id, source_id: group.id, source_type: 'Namespace', - type: 'GroupMember', access_level: 30, requested_at: Time.now, notification_level: 3) - - another_group = namespaces_table.create!(type: 'Group', name: 'another group', path: 'another-group') - shared_project = projects_table.create!(id: 1, name: 'shared project', path: 'shared-project', - visibility_level: 0, namespace_id: another_group.id) - - project_group_links.create!(project_id: shared_project.id, group_id: group.id, group_access: 20) - end - - it 'does not create authorization' do - expect { subject }.not_to change { project_authorizations_table.count }.from(0) - end - end - end - - context 'incorrect authorization' do - before do - project = projects_table.create!(id: 1, name: 'group-project', path: 'group-project', - visibility_level: 0, namespace_id: group.id) - members_table.create!(user_id: user.id, source_id: group.id, source_type: 'Namespace', - type: 'GroupMember', access_level: 30, notification_level: 3) - - project_authorizations_table.create!(user_id: user.id, project_id: project.id, - access_level: 10) - end - - it 'fixes authorization' do - expect { subject }.not_to change { project_authorizations_table.count }.from(1) - expect(project_authorizations_table.all).to( - match_array([have_attributes(user_id: 1, project_id: 1, access_level: 30)])) - end - end - - context 'unwanted authorization' do - before do - project = projects_table.create!(name: 'group-project', path: 'group-project', - visibility_level: 0, namespace_id: group.id) - - project_authorizations_table.create!(user_id: user.id, project_id: project.id, - access_level: 10) - end - - it 'deletes authorization' do - expect { subject }.to change { project_authorizations_table.count }.from(1).to(0) - end - end - - context 'deleted user' do - it 'does not fail' do - expect { described_class.new.perform([non_existing_record_id]) }.not_to raise_error - end - end -end diff --git a/spec/lib/gitlab/background_migration/update_timelogs_project_id_spec.rb b/spec/lib/gitlab/background_migration/update_timelogs_project_id_spec.rb new file mode 100644 index 00000000000..fc4d776b8be --- /dev/null +++ b/spec/lib/gitlab/background_migration/update_timelogs_project_id_spec.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::BackgroundMigration::UpdateTimelogsProjectId, schema: 20210427212034 do + let!(:namespace) { table(:namespaces).create!(name: 'namespace', path: 'namespace') } + let!(:project1) { table(:projects).create!(namespace_id: namespace.id) } + let!(:project2) { table(:projects).create!(namespace_id: namespace.id) } + let!(:issue1) { table(:issues).create!(project_id: project1.id) } + let!(:issue2) { table(:issues).create!(project_id: project2.id) } + let!(:merge_request1) { table(:merge_requests).create!(target_project_id: project1.id, source_branch: 'master', target_branch: 'feature') } + let!(:merge_request2) { table(:merge_requests).create!(target_project_id: project2.id, source_branch: 'master', target_branch: 'feature') } + let!(:timelog1) { table(:timelogs).create!(issue_id: issue1.id, time_spent: 60) } + let!(:timelog2) { table(:timelogs).create!(issue_id: issue1.id, time_spent: 60) } + let!(:timelog3) { table(:timelogs).create!(issue_id: issue2.id, time_spent: 60) } + let!(:timelog4) { table(:timelogs).create!(merge_request_id: merge_request1.id, time_spent: 600) } + let!(:timelog5) { table(:timelogs).create!(merge_request_id: merge_request1.id, time_spent: 600) } + let!(:timelog6) { table(:timelogs).create!(merge_request_id: merge_request2.id, time_spent: 600) } + let!(:timelog7) { table(:timelogs).create!(issue_id: issue2.id, time_spent: 60, project_id: project1.id) } + let!(:timelog8) { table(:timelogs).create!(merge_request_id: merge_request2.id, time_spent: 600, project_id: project1.id) } + + describe '#perform' do + context 'when timelogs belong to issues' do + it 'sets correct project_id' do + subject.perform(timelog1.id, timelog3.id) + + expect(timelog1.reload.project_id).to eq(issue1.project_id) + expect(timelog2.reload.project_id).to eq(issue1.project_id) + expect(timelog3.reload.project_id).to eq(issue2.project_id) + end + end + + context 'when timelogs belong to merge requests' do + it 'sets correct project ids' do + subject.perform(timelog4.id, timelog6.id) + + expect(timelog4.reload.project_id).to eq(merge_request1.target_project_id) + expect(timelog5.reload.project_id).to eq(merge_request1.target_project_id) + expect(timelog6.reload.project_id).to eq(merge_request2.target_project_id) + end + end + + context 'when timelogs already belong to projects' do + it 'does not update the project id' do + subject.perform(timelog7.id, timelog8.id) + + expect(timelog7.reload.project_id).to eq(project1.id) + expect(timelog8.reload.project_id).to eq(project1.id) + end + end + end +end |