From 7021455bd1ed7b125c55eb1b33c5a01f2bc55ee0 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Thu, 17 Nov 2022 11:33:21 +0000 Subject: Add latest changes from gitlab-org/gitlab@15-6-stable-ee --- ...8185845_backfill_projects_with_coverage_spec.rb | 71 ----------------- ...0107064845_populate_vulnerability_reads_spec.rb | 2 +- ...1144258_remove_orphan_group_token_users_spec.rb | 9 +-- ...ective_and_keyresult_to_work_item_types_spec.rb | 66 ++++++++++++++++ ...dule_backfill_project_namespace_details_spec.rb | 37 +++++++++ ..._renaming_background_migration_finished_spec.rb | 91 ++++++++++++++++++++++ ...te_routing_table_for_builds_metadata_v2_spec.rb | 36 +++++++++ ...assword_last_changed_at_to_user_details_spec.rb | 37 +++++++++ ...assword_last_changed_at_to_user_details_spec.rb | 16 ++++ ...ferred_language_to_application_settings_spec.rb | 27 +++++++ ...ferred_language_on_application_settings_spec.rb | 29 +++++++ ...090940_create_next_ci_partitions_record_spec.rb | 63 +++++++++++++++ ...te_second_partition_for_builds_metadata_spec.rb | 61 +++++++++++++++ ...ansitions_with_same_from_state_to_state_spec.rb | 49 ++++++++++++ ...e_migrate_shared_vulnerability_scanners_spec.rb | 69 ++++++++++++++++ .../finalize_invalid_member_cleanup_spec.rb | 72 +++++++++++++++++ .../queue_backfill_user_details_fields_spec.rb | 24 ++++++ .../queue_populate_projects_star_count_spec.rb | 24 ++++++ spec/migrations/recount_epic_cache_counts_spec.rb | 32 ++++++++ ...e_migrate_shared_vulnerability_scanners_spec.rb | 41 ++++++++++ .../sanitize_confidential_note_todos_spec.rb | 33 ++++++++ ...e_migrate_shared_vulnerability_scanners_spec.rb | 59 -------------- ...om_send_user_confirmation_email_setting_spec.rb | 41 ++++++++++ ...nt_used_for_ci_namespace_monthly_usages_spec.rb | 42 ++++++++++ ...ount_used_for_ci_project_monthly_usages_spec.rb | 42 ++++++++++ 25 files changed, 936 insertions(+), 137 deletions(-) delete mode 100644 spec/migrations/20210818185845_backfill_projects_with_coverage_spec.rb create mode 100644 spec/migrations/20221018050323_add_objective_and_keyresult_to_work_item_types_spec.rb create mode 100644 spec/migrations/20221018062308_schedule_backfill_project_namespace_details_spec.rb create mode 100644 spec/migrations/20221018193635_ensure_task_note_renaming_background_migration_finished_spec.rb create mode 100644 spec/migrations/20221021145820_create_routing_table_for_builds_metadata_v2_spec.rb create mode 100644 spec/migrations/20221025043930_change_default_value_on_password_last_changed_at_to_user_details_spec.rb create mode 100644 spec/migrations/20221028022627_add_index_on_password_last_changed_at_to_user_details_spec.rb create mode 100644 spec/migrations/20221101032521_add_default_preferred_language_to_application_settings_spec.rb create mode 100644 spec/migrations/20221101032600_add_text_limit_to_default_preferred_language_on_application_settings_spec.rb create mode 100644 spec/migrations/20221102090940_create_next_ci_partitions_record_spec.rb create mode 100644 spec/migrations/20221102090943_create_second_partition_for_builds_metadata_spec.rb create mode 100644 spec/migrations/cleanup_vulnerability_state_transitions_with_same_from_state_to_state_spec.rb create mode 100644 spec/migrations/delete_migrate_shared_vulnerability_scanners_spec.rb create mode 100644 spec/migrations/finalize_invalid_member_cleanup_spec.rb create mode 100644 spec/migrations/queue_backfill_user_details_fields_spec.rb create mode 100644 spec/migrations/queue_populate_projects_star_count_spec.rb create mode 100644 spec/migrations/recount_epic_cache_counts_spec.rb create mode 100644 spec/migrations/reschedule_migrate_shared_vulnerability_scanners_spec.rb create mode 100644 spec/migrations/sanitize_confidential_note_todos_spec.rb delete mode 100644 spec/migrations/schedule_migrate_shared_vulnerability_scanners_spec.rb create mode 100644 spec/migrations/set_email_confirmation_setting_from_send_user_confirmation_email_setting_spec.rb create mode 100644 spec/migrations/sync_new_amount_used_for_ci_namespace_monthly_usages_spec.rb create mode 100644 spec/migrations/sync_new_amount_used_for_ci_project_monthly_usages_spec.rb (limited to 'spec/migrations') diff --git a/spec/migrations/20210818185845_backfill_projects_with_coverage_spec.rb b/spec/migrations/20210818185845_backfill_projects_with_coverage_spec.rb deleted file mode 100644 index 13a6aa5413e..00000000000 --- a/spec/migrations/20210818185845_backfill_projects_with_coverage_spec.rb +++ /dev/null @@ -1,71 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require_migration! - -RSpec.describe BackfillProjectsWithCoverage, :suppress_gitlab_schemas_validate_connection do - let(:projects) { table(:projects) } - let(:ci_pipelines) { table(:ci_pipelines) } - let(:ci_daily_build_group_report_results) { table(:ci_daily_build_group_report_results) } - let(:group) { table(:namespaces).create!(name: 'user', path: 'user') } - let(:project_1) { projects.create!(namespace_id: group.id) } - let(:project_2) { projects.create!(namespace_id: group.id) } - let(:pipeline_1) { ci_pipelines.create!(project_id: project_1.id) } - let(:pipeline_2) { ci_pipelines.create!(project_id: project_2.id) } - let(:pipeline_3) { ci_pipelines.create!(project_id: project_2.id) } - - describe '#up' do - before do - stub_const("#{described_class}::BATCH_SIZE", 2) - stub_const("#{described_class}::SUB_BATCH_SIZE", 1) - - ci_daily_build_group_report_results.create!( - id: 1, - project_id: project_1.id, - date: 3.days.ago, - last_pipeline_id: pipeline_1.id, - ref_path: 'main', - group_name: 'rspec', - data: { coverage: 95.0 }, - default_branch: true, - group_id: group.id - ) - - ci_daily_build_group_report_results.create!( - id: 2, - project_id: project_2.id, - date: 2.days.ago, - last_pipeline_id: pipeline_2.id, - ref_path: 'main', - group_name: 'rspec', - data: { coverage: 95.0 }, - default_branch: true, - group_id: group.id - ) - - ci_daily_build_group_report_results.create!( - id: 3, - project_id: project_2.id, - date: 1.day.ago, - last_pipeline_id: pipeline_3.id, - ref_path: 'test_branch', - group_name: 'rspec', - data: { coverage: 95.0 }, - default_branch: false, - group_id: group.id - ) - end - - it 'schedules BackfillProjectsWithCoverage background jobs', :aggregate_failures do - Sidekiq::Testing.fake! do - freeze_time do - migrate! - - expect(described_class::MIGRATION).to be_scheduled_delayed_migration(2.minutes, 1, 2, 1) - expect(described_class::MIGRATION).to be_scheduled_delayed_migration(4.minutes, 3, 3, 1) - expect(BackgroundMigrationWorker.jobs.size).to eq(2) - end - end - end - end -end diff --git a/spec/migrations/20220107064845_populate_vulnerability_reads_spec.rb b/spec/migrations/20220107064845_populate_vulnerability_reads_spec.rb index ece971a50c9..063a51227dd 100644 --- a/spec/migrations/20220107064845_populate_vulnerability_reads_spec.rb +++ b/spec/migrations/20220107064845_populate_vulnerability_reads_spec.rb @@ -29,7 +29,7 @@ RSpec.describe PopulateVulnerabilityReads, :migration do project_id: project.id, external_type: 'uuid-v5', external_id: 'uuid-v5', - fingerprint: Digest::SHA1.hexdigest("#{vulnerability.id}"), + fingerprint: Digest::SHA1.hexdigest(vulnerability.id.to_s), name: 'Identifier for UUIDv5') create_finding!( diff --git a/spec/migrations/20220921144258_remove_orphan_group_token_users_spec.rb b/spec/migrations/20220921144258_remove_orphan_group_token_users_spec.rb index 614044657ec..174cfda1a46 100644 --- a/spec/migrations/20220921144258_remove_orphan_group_token_users_spec.rb +++ b/spec/migrations/20220921144258_remove_orphan_group_token_users_spec.rb @@ -34,11 +34,7 @@ RSpec.describe RemoveOrphanGroupTokenUsers, :migration, :sidekiq_inline do let(:members) { table(:members) } let(:namespaces) { table(:namespaces) } - before do - stub_feature_flags(user_destroy_with_limited_execution_time_worker: false) - end - - it 'removes orphan project bot and its tokens', :aggregate_failures do + it 'initiates orphan project bot removal', :aggregate_failures do expect(DeleteUserWorker) .to receive(:perform_async) .with(orphan_bot.id, orphan_bot.id, skip_authorization: true) @@ -46,7 +42,8 @@ RSpec.describe RemoveOrphanGroupTokenUsers, :migration, :sidekiq_inline do migrate! - expect(users.count).to eq 2 + expect(Users::GhostUserMigration.where(user: orphan_bot)).to be_exists + expect(users.count).to eq 3 expect(personal_access_tokens.count).to eq 2 expect(personal_access_tokens.find_by(user_id: orphan_bot.id)).to eq nil end diff --git a/spec/migrations/20221018050323_add_objective_and_keyresult_to_work_item_types_spec.rb b/spec/migrations/20221018050323_add_objective_and_keyresult_to_work_item_types_spec.rb new file mode 100644 index 00000000000..4de897802b9 --- /dev/null +++ b/spec/migrations/20221018050323_add_objective_and_keyresult_to_work_item_types_spec.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe AddObjectiveAndKeyresultToWorkItemTypes, :migration do + include MigrationHelpers::WorkItemTypesHelper + + let_it_be(:work_item_types) { table(:work_item_types) } + + let(:base_types) do + { + issue: 0, + incident: 1, + test_case: 2, + requirement: 3, + task: 4, + objective: 5, + key_result: 6 + } + end + + after(:all) do + # Make sure base types are recreated after running the migration + # because migration specs are not run in a transaction + reset_work_item_types + end + + it 'skips creating both objective & keyresult type record if it already exists' do + reset_db_state_prior_to_migration + work_item_types.find_or_create_by!(name: 'Key Result', namespace_id: nil, base_type: base_types[:key_result], + icon_name: 'issue-type-keyresult') + work_item_types.find_or_create_by!(name: 'Objective', namespace_id: nil, base_type: base_types[:objective], + icon_name: 'issue-type-objective') + + expect do + migrate! + end.to not_change(work_item_types, :count) + end + + it 'adds both objective & keyresult to base work item types' do + reset_db_state_prior_to_migration + + expect do + migrate! + end.to change(work_item_types, :count).from(5).to(7) + + expect(work_item_types.all.pluck(:base_type)).to include(base_types[:objective]) + expect(work_item_types.all.pluck(:base_type)).to include(base_types[:key_result]) + end + + def reset_db_state_prior_to_migration + # Database needs to be in a similar state as when this migration was created + work_item_types.delete_all + work_item_types.find_or_create_by!(name: 'Issue', namespace_id: nil, base_type: base_types[:issue], + icon_name: 'issue-type-issue') + work_item_types.find_or_create_by!(name: 'Incident', namespace_id: nil, base_type: base_types[:incident], + icon_name: 'issue-type-incident') + work_item_types.find_or_create_by!(name: 'Test Case', namespace_id: nil, base_type: base_types[:test_case], + icon_name: 'issue-type-test-case') + work_item_types.find_or_create_by!(name: 'Requirement', namespace_id: nil, base_type: base_types[:requirement], + icon_name: 'issue-type-requirements') + work_item_types.find_or_create_by!(name: 'Task', namespace_id: nil, base_type: base_types[:task], + icon_name: 'issue-type-task') + end +end diff --git a/spec/migrations/20221018062308_schedule_backfill_project_namespace_details_spec.rb b/spec/migrations/20221018062308_schedule_backfill_project_namespace_details_spec.rb new file mode 100644 index 00000000000..4dd6d5757ce --- /dev/null +++ b/spec/migrations/20221018062308_schedule_backfill_project_namespace_details_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe ScheduleBackfillProjectNamespaceDetails, schema: 20221018062308 do + context 'when on gitlab.com' do + let_it_be(:background_migration) { described_class::MIGRATION } + let_it_be(:migration) { described_class.new } + + before do + migration.up + end + + describe '#up' do + it 'schedules background jobs for each batch of projects' do + expect(background_migration).to( + have_scheduled_batched_migration( + table_name: :projects, + column_name: :id, + interval: described_class::INTERVAL, + batch_size: described_class::BATCH_SIZE, + sub_batch_size: described_class::SUB_BATCH_SIZE + ) + ) + end + end + + describe '#down' do + it 'deletes all batched migration records' do + migration.down + + expect(described_class::MIGRATION).not_to have_scheduled_batched_migration + end + end + end +end diff --git a/spec/migrations/20221018193635_ensure_task_note_renaming_background_migration_finished_spec.rb b/spec/migrations/20221018193635_ensure_task_note_renaming_background_migration_finished_spec.rb new file mode 100644 index 00000000000..ea95c34674e --- /dev/null +++ b/spec/migrations/20221018193635_ensure_task_note_renaming_background_migration_finished_spec.rb @@ -0,0 +1,91 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe EnsureTaskNoteRenamingBackgroundMigrationFinished, :migration do + let(:batched_migrations) { table(:batched_background_migrations) } + let(:batch_failed_status) { 2 } + let(:batch_finalized_status) { 3 } + + let_it_be(:migration) { described_class::MIGRATION } + + describe '#up' do + shared_examples 'finalizes the migration' do + it 'finalizes the migration' do + expect do + migrate! + + task_renaming_migration.reload + failed_job.reload + end.to change(task_renaming_migration, :status).from(task_renaming_migration.status).to(3).and( + change(failed_job, :status).from(batch_failed_status).to(batch_finalized_status) + ) + end + end + + context 'when migration is missing' do + it 'warns migration not found' do + expect(Gitlab::AppLogger) + .to receive(:warn).with(/Could not find batched background migration for the given configuration:/) + + migrate! + end + end + + context 'with migration present' do + let!(:task_renaming_migration) do + batched_migrations.create!( + job_class_name: 'RenameTaskSystemNoteToChecklistItem', + table_name: :system_note_metadata, + column_name: :id, + job_arguments: [], + interval: 2.minutes, + min_value: 1, + max_value: 2, + batch_size: 1000, + sub_batch_size: 200, + gitlab_schema: :gitlab_main, + status: 3 # finished + ) + end + + context 'when migration finished successfully' do + it 'does not raise exception' do + expect { migrate! }.not_to raise_error + end + end + + context 'with different migration statuses', :redis do + using RSpec::Parameterized::TableSyntax + + where(:status, :description) do + 0 | 'paused' + 1 | 'active' + 4 | 'failed' + 5 | 'finalizing' + end + + with_them do + let!(:failed_job) do + table(:batched_background_migration_jobs).create!( + batched_background_migration_id: task_renaming_migration.id, + status: batch_failed_status, + min_value: 1, + max_value: 10, + attempts: 2, + batch_size: 100, + sub_batch_size: 10 + ) + end + + before do + task_renaming_migration.update!(status: status) + end + + it_behaves_like 'finalizes the migration' + end + end + end + end +end diff --git a/spec/migrations/20221021145820_create_routing_table_for_builds_metadata_v2_spec.rb b/spec/migrations/20221021145820_create_routing_table_for_builds_metadata_v2_spec.rb new file mode 100644 index 00000000000..48a00df430d --- /dev/null +++ b/spec/migrations/20221021145820_create_routing_table_for_builds_metadata_v2_spec.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe CreateRoutingTableForBuildsMetadataV2, :migration do + let_it_be(:migration) { described_class.new } + + describe '#up' do + context 'when the table is already partitioned' do + before do + # `convert_table_to_first_list_partition` checks if it's being executed + # inside a transaction, but we're using transactional fixtures here so we + # need to tell it that it's not inside a transaction. + # We toggle the behavior depending on how many transactions we have open + # instead of just returning `false` because the migration could have the + # DDL transaction enabled. + # + open_transactions = ActiveRecord::Base.connection.open_transactions + allow(migration).to receive(:transaction_open?) do + ActiveRecord::Base.connection.open_transactions > open_transactions + end + + migration.convert_table_to_first_list_partition( + table_name: :ci_builds_metadata, + partitioning_column: :partition_id, + parent_table_name: :p_ci_builds_metadata, + initial_partitioning_value: 100) + end + + it 'skips the migration' do + expect { migrate! }.not_to raise_error + end + end + end +end diff --git a/spec/migrations/20221025043930_change_default_value_on_password_last_changed_at_to_user_details_spec.rb b/spec/migrations/20221025043930_change_default_value_on_password_last_changed_at_to_user_details_spec.rb new file mode 100644 index 00000000000..4d6f06eb146 --- /dev/null +++ b/spec/migrations/20221025043930_change_default_value_on_password_last_changed_at_to_user_details_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe ChangeDefaultValueOnPasswordLastChangedAtToUserDetails, :migration do + let(:namespace) { table(:namespaces).create!(name: 'user', path: 'user') } + let(:users) { table(:users) } + let(:user_details) { table(:user_details) } + + it 'correctly migrates up and down' do + user = create_user!(email: '1234@abc') + user_details.create!(user_id: user.id, provisioned_by_group_id: namespace.id) + + expect(UserDetail.find_by(user_id: user.id).password_last_changed_at).to be_nil + + migrate! + + user = create_user!(email: 'abc@1234') + user_details.create!(user_id: user.id, provisioned_by_group_id: namespace.id) + + expect(UserDetail.find_by(user_id: user.id).password_last_changed_at).not_to be_nil + end + + private + + 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/migrations/20221028022627_add_index_on_password_last_changed_at_to_user_details_spec.rb b/spec/migrations/20221028022627_add_index_on_password_last_changed_at_to_user_details_spec.rb new file mode 100644 index 00000000000..5f8467f9307 --- /dev/null +++ b/spec/migrations/20221028022627_add_index_on_password_last_changed_at_to_user_details_spec.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe AddIndexOnPasswordLastChangedAtToUserDetails, :migration do + let(:index_name) { 'index_user_details_on_password_last_changed_at' } + + it 'correctly migrates up and down' do + expect(subject).not_to be_index_exists_by_name(:user_details, index_name) + + migrate! + + expect(subject).to be_index_exists_by_name(:user_details, index_name) + end +end diff --git a/spec/migrations/20221101032521_add_default_preferred_language_to_application_settings_spec.rb b/spec/migrations/20221101032521_add_default_preferred_language_to_application_settings_spec.rb new file mode 100644 index 00000000000..3ae4287f3c4 --- /dev/null +++ b/spec/migrations/20221101032521_add_default_preferred_language_to_application_settings_spec.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require 'spec_helper' + +require_migration! + +RSpec.describe AddDefaultPreferredLanguageToApplicationSettings do + let(:application_setting) { table(:application_settings).create! } + + describe "#up" do + it 'allows to read default_preferred_language field' do + migrate! + + expect(application_setting.attributes.keys).to include('default_preferred_language') + expect(application_setting.default_preferred_language).to eq 'en' + end + end + + describe "#down" do + it 'deletes default_preferred_language field' do + migrate! + schema_migrate_down! + + expect(application_setting.attributes.keys).not_to include('default_preferred_language') + end + end +end diff --git a/spec/migrations/20221101032600_add_text_limit_to_default_preferred_language_on_application_settings_spec.rb b/spec/migrations/20221101032600_add_text_limit_to_default_preferred_language_on_application_settings_spec.rb new file mode 100644 index 00000000000..e0370e48db6 --- /dev/null +++ b/spec/migrations/20221101032600_add_text_limit_to_default_preferred_language_on_application_settings_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require 'spec_helper' + +require_migration! + +RSpec.describe AddTextLimitToDefaultPreferredLanguageOnApplicationSettings do + let(:application_setting) { table(:application_settings).create! } + let(:too_long_text) { SecureRandom.alphanumeric(described_class::MAXIMUM_LIMIT + 1) } + + subject { application_setting.update_column(:default_preferred_language, too_long_text) } + + describe "#up" do + it 'adds text limit to default_preferred_language' do + migrate! + + expect { subject }.to raise_error ActiveRecord::StatementInvalid + end + end + + describe "#down" do + it 'deletes text limit to default_preferred_language' do + migrate! + schema_migrate_down! + + expect { subject }.not_to raise_error + end + end +end diff --git a/spec/migrations/20221102090940_create_next_ci_partitions_record_spec.rb b/spec/migrations/20221102090940_create_next_ci_partitions_record_spec.rb new file mode 100644 index 00000000000..c55e4bcfba7 --- /dev/null +++ b/spec/migrations/20221102090940_create_next_ci_partitions_record_spec.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe CreateNextCiPartitionsRecord, migration: :gitlab_ci do + let(:migration) { described_class.new } + let(:partitions) { table(:ci_partitions) } + + describe '#up' do + context 'when on sass' do + before do + allow(Gitlab).to receive(:com?).and_return(true) + end + + it 'creates next partitions record and resets the sequence' do + expect { migrate! } + .to change { partitions.where(id: 101).any? } + .from(false).to(true) + + expect { partitions.create! }.not_to raise_error + end + end + + context 'when self-managed' do + before do + allow(Gitlab).to receive(:com?).and_return(false) + end + + it 'does not create records' do + expect { migrate! }.not_to change(partitions, :count) + end + end + end + + describe '#down' do + context 'when on sass' do + before do + allow(Gitlab).to receive(:com?).and_return(true) + end + + it 'removes the record' do + migrate! + + expect { migration.down } + .to change { partitions.where(id: 101).any? } + .from(true).to(false) + end + end + + context 'when self-managed' do + before do + allow(Gitlab).to receive(:com?).and_return(true, false) + end + + it 'does not remove the record' do + expect { migrate! }.to change(partitions, :count).by(1) + + expect { migration.down }.not_to change(partitions, :count) + end + end + end +end diff --git a/spec/migrations/20221102090943_create_second_partition_for_builds_metadata_spec.rb b/spec/migrations/20221102090943_create_second_partition_for_builds_metadata_spec.rb new file mode 100644 index 00000000000..99754d609ed --- /dev/null +++ b/spec/migrations/20221102090943_create_second_partition_for_builds_metadata_spec.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe CreateSecondPartitionForBuildsMetadata, :migration do + let(:migration) { described_class.new } + let(:partitions) { table(:ci_partitions) } + + describe '#up' do + context 'when on sass' do + before do + allow(Gitlab).to receive(:com?).and_return(true) + end + + it 'creates a new partition' do + expect { migrate! }.to change { partitions_count }.by(1) + end + end + + context 'when self-managed' do + before do + allow(Gitlab).to receive(:com?).and_return(false) + end + + it 'does not create the partition' do + expect { migrate! }.not_to change { partitions_count } + end + end + end + + describe '#down' do + context 'when on sass' do + before do + allow(Gitlab).to receive(:com?).and_return(true) + end + + it 'removes the partition' do + migrate! + + expect { migration.down }.to change { partitions_count }.by(-1) + end + end + + context 'when self-managed' do + before do + allow(Gitlab).to receive(:com?).and_return(false) + end + + it 'does not change the partitions count' do + migrate! + + expect { migration.down }.not_to change { partitions_count } + end + end + end + + def partitions_count + Gitlab::Database::PostgresPartition.for_parent_table(:p_ci_builds_metadata).size + end +end diff --git a/spec/migrations/cleanup_vulnerability_state_transitions_with_same_from_state_to_state_spec.rb b/spec/migrations/cleanup_vulnerability_state_transitions_with_same_from_state_to_state_spec.rb new file mode 100644 index 00000000000..92ece81ffc8 --- /dev/null +++ b/spec/migrations/cleanup_vulnerability_state_transitions_with_same_from_state_to_state_spec.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe CleanupVulnerabilityStateTransitionsWithSameFromStateToState, :migration do + let_it_be(:namespace) { table(:namespaces).create!(name: 'namespace', type: 'Group', path: 'namespace') } + let_it_be(:user) { table(:users).create!(email: 'author@example.com', username: 'author', projects_limit: 10) } + let_it_be(:project) do + table(:projects).create!( + path: 'project', + namespace_id: namespace.id, + project_namespace_id: namespace.id + ) + end + + let_it_be(:vulnerability) do + table(:vulnerabilities).create!( + project_id: project.id, + author_id: user.id, + title: 'test', + severity: 7, + confidence: 7, + report_type: 0 + ) + end + + let_it_be(:state_transitions) { table(:vulnerability_state_transitions) } + + let!(:state_transition_with_no_state_change) do + state_transitions.create!( + vulnerability_id: vulnerability.id, + from_state: 2, + to_state: 2 + ) + end + + let!(:state_transition_with_state_change) do + state_transitions.create!( + vulnerability_id: vulnerability.id, + from_state: 1, + to_state: 2 + ) + end + + it 'deletes state transitions with no state change' do + expect { migrate! }.to change(state_transitions, :count).from(2).to(1) + end +end diff --git a/spec/migrations/delete_migrate_shared_vulnerability_scanners_spec.rb b/spec/migrations/delete_migrate_shared_vulnerability_scanners_spec.rb new file mode 100644 index 00000000000..259b175cd19 --- /dev/null +++ b/spec/migrations/delete_migrate_shared_vulnerability_scanners_spec.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +require "spec_helper" + +require_migration! + +RSpec.describe DeleteMigrateSharedVulnerabilityScanners, :migration do + let(:batched_background_migrations) { table(:batched_background_migrations) } + let(:batched_background_migration_jobs) { table(:batched_background_migration_jobs) } + + let(:migration) do + batched_background_migrations.create!(created_at: Time.zone.now, + updated_at: Time.zone.now, + min_value: 1, + max_value: 1, + batch_size: described_class::BATCH_SIZE, + sub_batch_size: 100, + interval: 300, + status: 3, + job_class_name: described_class::MIGRATION, + batch_class_name: "PrimaryKeyBatchingStrategy", + table_name: described_class::TABLE_NAME, + column_name: described_class::BATCH_COLUMN, + job_arguments: [], + pause_ms: 100, + max_batch_size: 1000, + gitlab_schema: "gitlab_main") + end + + let(:jobs) do + Array.new(10) do + batched_background_migration_jobs.create!(batched_background_migration_id: migration.id, + created_at: Time.zone.now, + updated_at: Time.zone.now, + min_value: 1, + max_value: 1, + batch_size: 1, + sub_batch_size: 1, + status: 0, + attempts: 0, + metrics: {}, + pause_ms: 100) + end + end + + describe "#up" do + it "deletes jobs" do + expect { migrate! }.to change(batched_background_migration_jobs, :count).from(jobs.count).to(0) + end + + it "deletes the migration" do + expect { migrate! }.to change { batched_background_migrations.find_by(id: migration.id) }.from(migration).to(nil) + end + + context "when background migration does not exist" do + before do + migration.destroy! + end + + it "does not delete jobs" do + expect { migrate! }.not_to change(batched_background_migration_jobs, :count) + end + + it "does not delete the migration" do + expect { migrate! }.not_to change { batched_background_migrations.find_by(id: migration.id) } + end + end + end +end diff --git a/spec/migrations/finalize_invalid_member_cleanup_spec.rb b/spec/migrations/finalize_invalid_member_cleanup_spec.rb new file mode 100644 index 00000000000..a29a89c2396 --- /dev/null +++ b/spec/migrations/finalize_invalid_member_cleanup_spec.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe FinalizeInvalidMemberCleanup, :migration do + let(:batched_migrations) { table(:batched_background_migrations) } + + let_it_be(:migration) { described_class::MIGRATION } + + describe '#up' do + shared_examples 'finalizes the migration' do + it 'finalizes the migration' do + allow_next_instance_of(Gitlab::Database::BackgroundMigration::BatchedMigrationRunner) do |runner| + expect(runner).to receive(:finalize).with('DestroyInvalidMembers', :members, :id, []) + end + end + end + + context 'when migration is missing' do + it 'warns migration not found' do + expect(Gitlab::AppLogger) + .to receive(:warn).with(/Could not find batched background migration for the given configuration:/) + + migrate! + end + end + + context 'with migration present' do + let!(:destroy_invalid_member_migration) do + batched_migrations.create!( + job_class_name: 'DestroyInvalidMembers', + table_name: :members, + column_name: :id, + job_arguments: [], + interval: 2.minutes, + min_value: 1, + max_value: 2, + batch_size: 1000, + sub_batch_size: 200, + gitlab_schema: :gitlab_main, + status: 3 # finished + ) + end + + context 'when migration finished successfully' do + it 'does not raise exception' do + expect { migrate! }.not_to raise_error + end + end + + context 'with different migration statuses' do + using RSpec::Parameterized::TableSyntax + + where(:status, :description) do + 0 | 'paused' + 1 | 'active' + 4 | 'failed' + 5 | 'finalizing' + end + + with_them do + before do + destroy_invalid_member_migration.update!(status: status) + end + + it_behaves_like 'finalizes the migration' + end + end + end + end +end diff --git a/spec/migrations/queue_backfill_user_details_fields_spec.rb b/spec/migrations/queue_backfill_user_details_fields_spec.rb new file mode 100644 index 00000000000..388ac6d1bce --- /dev/null +++ b/spec/migrations/queue_backfill_user_details_fields_spec.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe QueueBackfillUserDetailsFields do + let_it_be(:batched_migration) { described_class::MIGRATION } + + it 'schedules a new batched migration' do + reversible_migration do |migration| + migration.before -> { + expect(batched_migration).not_to have_scheduled_batched_migration + } + + migration.after -> { + expect(batched_migration).to have_scheduled_batched_migration( + table_name: :users, + column_name: :id, + interval: described_class::INTERVAL + ) + } + end + end +end diff --git a/spec/migrations/queue_populate_projects_star_count_spec.rb b/spec/migrations/queue_populate_projects_star_count_spec.rb new file mode 100644 index 00000000000..848136d8005 --- /dev/null +++ b/spec/migrations/queue_populate_projects_star_count_spec.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe QueuePopulateProjectsStarCount do + let_it_be(:batched_migration) { described_class::MIGRATION } + + it 'schedules a new batched migration' do + reversible_migration do |migration| + migration.before -> { + expect(batched_migration).not_to have_scheduled_batched_migration + } + + migration.after -> { + expect(batched_migration).to have_scheduled_batched_migration( + table_name: :projects, + column_name: :id, + interval: described_class::DELAY_INTERVAL + ) + } + end + end +end diff --git a/spec/migrations/recount_epic_cache_counts_spec.rb b/spec/migrations/recount_epic_cache_counts_spec.rb new file mode 100644 index 00000000000..56aa96cb40c --- /dev/null +++ b/spec/migrations/recount_epic_cache_counts_spec.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe RecountEpicCacheCounts, :migration do + let(:migration) { described_class::MIGRATION } + + describe '#up' do + it 'schedules a batched background migration' do + migrate! + + expect(migration).to have_scheduled_batched_migration( + table_name: :epics, + column_name: :id, + interval: described_class::DELAY_INTERVAL, + batch_size: described_class::BATCH_SIZE, + max_batch_size: described_class::MAX_BATCH_SIZE, + sub_batch_size: described_class::SUB_BATCH_SIZE + ) + end + end + + describe '#down' do + it 'deletes all batched migration records' do + migrate! + schema_migrate_down! + + expect(migration).not_to have_scheduled_batched_migration + end + end +end diff --git a/spec/migrations/reschedule_migrate_shared_vulnerability_scanners_spec.rb b/spec/migrations/reschedule_migrate_shared_vulnerability_scanners_spec.rb new file mode 100644 index 00000000000..e8253f39c68 --- /dev/null +++ b/spec/migrations/reschedule_migrate_shared_vulnerability_scanners_spec.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require "spec_helper" + +require_migration! + +RSpec.describe RescheduleMigrateSharedVulnerabilityScanners, :migration do + include Gitlab::Database::Migrations::BatchedBackgroundMigrationHelpers + + def connection + ApplicationRecord.connection + end + + describe "#up" do + before do + migrate! + end + + it "schedules" do + expect(described_class::MIGRATION).to have_scheduled_batched_migration( + table_name: described_class::TABLE_NAME, + column_name: described_class::BATCH_COLUMN, + interval: described_class::DELAY_INTERVAL, + batch_size: described_class::BATCH_SIZE, + max_batch_size: described_class::BATCH_SIZE, + sub_batch_size: described_class::SUB_BATCH_SIZE, + gitlab_schema: :gitlab_main + ) + end + end + + describe '#down' do + before do + schema_migrate_down! + end + + it "deletes" do + expect(described_class::MIGRATION).not_to have_scheduled_batched_migration + end + end +end diff --git a/spec/migrations/sanitize_confidential_note_todos_spec.rb b/spec/migrations/sanitize_confidential_note_todos_spec.rb new file mode 100644 index 00000000000..00dece82cc1 --- /dev/null +++ b/spec/migrations/sanitize_confidential_note_todos_spec.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require 'spec_helper' + +require_migration! + +RSpec.describe SanitizeConfidentialNoteTodos do + let(:migration) { described_class::MIGRATION } + + describe '#up' do + it 'schedules a batched background migration' do + migrate! + + expect(migration).to have_scheduled_batched_migration( + table_name: :notes, + column_name: :id, + interval: described_class::DELAY_INTERVAL, + batch_size: described_class::BATCH_SIZE, + max_batch_size: described_class::MAX_BATCH_SIZE, + sub_batch_size: described_class::SUB_BATCH_SIZE + ) + end + end + + describe '#down' do + it 'deletes all batched migration records' do + migrate! + schema_migrate_down! + + expect(migration).not_to have_scheduled_batched_migration + end + end +end diff --git a/spec/migrations/schedule_migrate_shared_vulnerability_scanners_spec.rb b/spec/migrations/schedule_migrate_shared_vulnerability_scanners_spec.rb deleted file mode 100644 index f00d6568b67..00000000000 --- a/spec/migrations/schedule_migrate_shared_vulnerability_scanners_spec.rb +++ /dev/null @@ -1,59 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -require_migration! - -RSpec.describe ScheduleMigrateSharedVulnerabilityScanners, :migration do - describe "#up" do - before do - migrate! - end - - it "schedules" do - expect(described_class::MIGRATION).to have_scheduled_batched_migration( - table_name: described_class::TABLE_NAME, - column_name: described_class::BATCH_COLUMN, - interval: described_class::DELAY_INTERVAL, - batch_size: described_class::BATCH_SIZE, - max_batch_size: described_class::BATCH_SIZE, - sub_batch_size: described_class::SUB_BATCH_SIZE, - gitlab_schema: :gitlab_main - ) - end - - describe "ID range" do - let(:expected_range) do - { min_value: described_class::BATCH_MIN_VALUE, - max_value: described_class::BATCH_MAX_VALUE } - end - - subject do - Gitlab::Database::BackgroundMigration::BatchedMigration - .for_configuration(:gitlab_main, - described_class::MIGRATION, - described_class::TABLE_NAME, - described_class::BATCH_COLUMN, - []) - end - - it "is set" do - # The `have_scheduled_batched_migration` matcher accepts the - # `batch_min_value` and `batch_max_value` keywords. However the respective - # column names are `min_value` and `max_value`. Hence the matcher cannot - # be used in this case, as it asserts the wrong attributes. - expect(subject).to all(have_attributes(expected_range)) - end - end - end - - describe '#down' do - before do - schema_migrate_down! - end - - it "deletes" do - expect(described_class::MIGRATION).not_to have_scheduled_batched_migration - end - end -end diff --git a/spec/migrations/set_email_confirmation_setting_from_send_user_confirmation_email_setting_spec.rb b/spec/migrations/set_email_confirmation_setting_from_send_user_confirmation_email_setting_spec.rb new file mode 100644 index 00000000000..761c0ef2fdb --- /dev/null +++ b/spec/migrations/set_email_confirmation_setting_from_send_user_confirmation_email_setting_spec.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe SetEmailConfirmationSettingFromSendUserConfirmationEmailSetting do + let(:migration) { described_class.new } + let(:application_settings_table) { table(:application_settings) } + + describe '#up' do + context "when 'send_user_confirmation_email' is set to 'true'" do + it "updates 'email_confirmation_setting' to '2' (hard)" do + application_settings_table.create!(send_user_confirmation_email: true, email_confirmation_setting: 0) + + migration.up + + expect(application_settings_table.last.email_confirmation_setting).to eq 2 + end + end + + context "when 'send_user_confirmation_email' is set to 'false'" do + it "updates 'email_confirmation_setting' to '0' (off)" do + application_settings_table.create!(send_user_confirmation_email: false, email_confirmation_setting: 0) + + migration.up + + expect(application_settings_table.last.email_confirmation_setting).to eq 0 + end + end + end + + describe '#down' do + it "updates 'email_confirmation_setting' to default value: '0' (off)" do + application_settings_table.create!(send_user_confirmation_email: true, email_confirmation_setting: 2) + + migration.down + + expect(application_settings_table.last.email_confirmation_setting).to eq 0 + end + end +end diff --git a/spec/migrations/sync_new_amount_used_for_ci_namespace_monthly_usages_spec.rb b/spec/migrations/sync_new_amount_used_for_ci_namespace_monthly_usages_spec.rb new file mode 100644 index 00000000000..9a17f375f82 --- /dev/null +++ b/spec/migrations/sync_new_amount_used_for_ci_namespace_monthly_usages_spec.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +require 'spec_helper' + +require_migration! + +RSpec.describe SyncNewAmountUsedForCiNamespaceMonthlyUsages, migration: :gitlab_ci do + let(:namespace_usages) { table(:ci_namespace_monthly_usages) } + + before do + # Disabling the trigger temporarily to allow records being created with out-of-sync + # `new_amount_used` and `amount_used`. This will simulate existing records before + # we add the trigger. + ActiveRecord::Base.connection + .execute("ALTER TABLE ci_namespace_monthly_usages DISABLE TRIGGER sync_namespaces_amount_used_columns") + + this_month = Time.now.utc.beginning_of_month + last_month = 1.month.ago.utc.beginning_of_month + last_year = 1.year.ago.utc.beginning_of_month + + namespace_usages.create!(namespace_id: 1, date: last_year) + namespace_usages.create!(namespace_id: 1, date: this_month, amount_used: 10, new_amount_used: 0) + namespace_usages.create!(namespace_id: 1, date: last_month, amount_used: 20, new_amount_used: 0) + + namespace_usages.create!(namespace_id: 2, date: last_year) + namespace_usages.create!(namespace_id: 2, date: this_month, amount_used: 30, new_amount_used: 0) + namespace_usages.create!(namespace_id: 2, date: last_month, amount_used: 40, new_amount_used: 0) + + ActiveRecord::Base.connection + .execute("ALTER TABLE ci_namespace_monthly_usages ENABLE TRIGGER sync_namespaces_amount_used_columns") + end + + it 'updates `new_amount_used` with values from `amount_used`' do + expect(namespace_usages.where(new_amount_used: 0).count).to eq(6) + + migrate! + + expect(namespace_usages.where(new_amount_used: 0).count).to eq(2) + expect(namespace_usages.order(:id).pluck(:new_amount_used)) + .to contain_exactly(0, 0, 10, 20, 30, 40) + end +end diff --git a/spec/migrations/sync_new_amount_used_for_ci_project_monthly_usages_spec.rb b/spec/migrations/sync_new_amount_used_for_ci_project_monthly_usages_spec.rb new file mode 100644 index 00000000000..8d45f1107ea --- /dev/null +++ b/spec/migrations/sync_new_amount_used_for_ci_project_monthly_usages_spec.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +require 'spec_helper' + +require_migration! + +RSpec.describe SyncNewAmountUsedForCiProjectMonthlyUsages, migration: :gitlab_ci do + let(:project_usages) { table(:ci_project_monthly_usages) } + + before do + # Disabling the trigger temporarily to allow records being created with out-of-sync + # `new_amount_used` and `amount_used`. This will simulate existing records before + # we add the trigger. + ActiveRecord::Base.connection + .execute("ALTER TABLE ci_project_monthly_usages DISABLE TRIGGER sync_projects_amount_used_columns") + + this_month = Time.now.utc.beginning_of_month + last_month = 1.month.ago.utc.beginning_of_month + last_year = 1.year.ago.utc.beginning_of_month + + project_usages.create!(project_id: 1, date: last_year) + project_usages.create!(project_id: 1, date: this_month, amount_used: 10, new_amount_used: 0) + project_usages.create!(project_id: 1, date: last_month, amount_used: 20, new_amount_used: 0) + + project_usages.create!(project_id: 2, date: last_year) + project_usages.create!(project_id: 2, date: this_month, amount_used: 30, new_amount_used: 0) + project_usages.create!(project_id: 2, date: last_month, amount_used: 40, new_amount_used: 0) + + ActiveRecord::Base.connection + .execute("ALTER TABLE ci_project_monthly_usages ENABLE TRIGGER sync_projects_amount_used_columns") + end + + it 'updates `new_amount_used` with values from `amount_used`' do + expect(project_usages.where(new_amount_used: 0).count).to eq(6) + + migrate! + + expect(project_usages.where(new_amount_used: 0).count).to eq(2) + expect(project_usages.order(:id).pluck(:new_amount_used)) + .to contain_exactly(0, 0, 10, 20, 30, 40) + end +end -- cgit v1.2.3