diff options
Diffstat (limited to 'spec/migrations')
188 files changed, 4549 insertions, 1880 deletions
diff --git a/spec/migrations/20210831203408_upsert_base_work_item_types_spec.rb b/spec/migrations/20210831203408_upsert_base_work_item_types_spec.rb deleted file mode 100644 index 4c7ef9ac1e8..00000000000 --- a/spec/migrations/20210831203408_upsert_base_work_item_types_spec.rb +++ /dev/null @@ -1,69 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require_migration! - -RSpec.describe UpsertBaseWorkItemTypes, :migration, feature_category: :team_planning do - include MigrationHelpers::WorkItemTypesHelper - - let!(:work_item_types) { table(:work_item_types) } - - let(:base_types) do - { - issue: 0, - incident: 1, - test_case: 2, - requirement: 3 - } - end - - append_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 - - context 'when no default types exist' do - it 'creates default data' do - # Need to delete all as base types are seeded before entire test suite - work_item_types.delete_all - - expect(work_item_types.count).to eq(0) - - reversible_migration do |migration| - migration.before -> { - # Depending on whether the migration has been run before, - # the size could be 4, or 0, so we don't set any expectations - # as we don't delete base types on migration reverse - } - - migration.after -> { - expect(work_item_types.count).to eq(4) - expect(work_item_types.all.pluck(:base_type)).to match_array(base_types.values) - } - end - end - end - - context 'when default types already exist' do - it 'does not create default types again' do - # 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') - - reversible_migration do |migration| - migration.before -> { - expect(work_item_types.all.pluck(:base_type)).to match_array(base_types.values) - } - - migration.after -> { - expect(work_item_types.count).to eq(4) - expect(work_item_types.all.pluck(:base_type)).to match_array(base_types.values) - } - end - end - end -end diff --git a/spec/migrations/20210902144144_drop_temporary_columns_and_triggers_for_ci_build_needs_spec.rb b/spec/migrations/20210902144144_drop_temporary_columns_and_triggers_for_ci_build_needs_spec.rb deleted file mode 100644 index 0d89851cac1..00000000000 --- a/spec/migrations/20210902144144_drop_temporary_columns_and_triggers_for_ci_build_needs_spec.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require_migration! - -RSpec.describe DropTemporaryColumnsAndTriggersForCiBuildNeeds, feature_category: :pipeline_authoring do - let(:ci_build_needs_table) { table(:ci_build_needs) } - - it 'correctly migrates up and down' do - reversible_migration do |migration| - migration.before -> { - expect(ci_build_needs_table.column_names).to include('build_id_convert_to_bigint') - } - - migration.after -> { - ci_build_needs_table.reset_column_information - expect(ci_build_needs_table.column_names).not_to include('build_id_convert_to_bigint') - } - end - end -end diff --git a/spec/migrations/20210906100316_drop_temporary_columns_and_triggers_for_ci_build_trace_chunks_spec.rb b/spec/migrations/20210906100316_drop_temporary_columns_and_triggers_for_ci_build_trace_chunks_spec.rb deleted file mode 100644 index eef4c7bc9fd..00000000000 --- a/spec/migrations/20210906100316_drop_temporary_columns_and_triggers_for_ci_build_trace_chunks_spec.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require_migration! - -RSpec.describe DropTemporaryColumnsAndTriggersForCiBuildTraceChunks, feature_category: :continuous_integration do - let(:ci_build_trace_chunks_table) { table(:ci_build_trace_chunks) } - - it 'correctly migrates up and down' do - reversible_migration do |migration| - migration.before -> { - expect(ci_build_trace_chunks_table.column_names).to include('build_id_convert_to_bigint') - } - - migration.after -> { - ci_build_trace_chunks_table.reset_column_information - expect(ci_build_trace_chunks_table.column_names).not_to include('build_id_convert_to_bigint') - } - end - end -end diff --git a/spec/migrations/20210906130643_drop_temporary_columns_and_triggers_for_taggings_spec.rb b/spec/migrations/20210906130643_drop_temporary_columns_and_triggers_for_taggings_spec.rb deleted file mode 100644 index 208cbac2ae9..00000000000 --- a/spec/migrations/20210906130643_drop_temporary_columns_and_triggers_for_taggings_spec.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require_migration! - -RSpec.describe DropTemporaryColumnsAndTriggersForTaggings, feature_category: :continuous_integration do - let(:taggings_table) { table(:taggings) } - - it 'correctly migrates up and down' do - reversible_migration do |migration| - migration.before -> { - expect(taggings_table.column_names).to include('id_convert_to_bigint') - expect(taggings_table.column_names).to include('taggable_id_convert_to_bigint') - } - - migration.after -> { - taggings_table.reset_column_information - expect(taggings_table.column_names).not_to include('id_convert_to_bigint') - expect(taggings_table.column_names).not_to include('taggable_id_convert_to_bigint') - } - end - end -end diff --git a/spec/migrations/20210907013944_cleanup_bigint_conversion_for_ci_builds_metadata_spec.rb b/spec/migrations/20210907013944_cleanup_bigint_conversion_for_ci_builds_metadata_spec.rb deleted file mode 100644 index 63664803fba..00000000000 --- a/spec/migrations/20210907013944_cleanup_bigint_conversion_for_ci_builds_metadata_spec.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require_migration! - -RSpec.describe CleanupBigintConversionForCiBuildsMetadata, feature_category: :continuous_integration do - let(:ci_builds_metadata) { table(:ci_builds_metadata) } - - it 'correctly migrates up and down' do - reversible_migration do |migration| - migration.before -> { - expect(ci_builds_metadata.column_names).to include('id_convert_to_bigint') - expect(ci_builds_metadata.column_names).to include('build_id_convert_to_bigint') - } - - migration.after -> { - ci_builds_metadata.reset_column_information - expect(ci_builds_metadata.column_names).not_to include('id_convert_to_bigint') - expect(ci_builds_metadata.column_names).not_to include('build_id_convert_to_bigint') - } - end - end -end diff --git a/spec/migrations/20210907211557_finalize_ci_builds_bigint_conversion_spec.rb b/spec/migrations/20210907211557_finalize_ci_builds_bigint_conversion_spec.rb deleted file mode 100644 index 663b90f3fa7..00000000000 --- a/spec/migrations/20210907211557_finalize_ci_builds_bigint_conversion_spec.rb +++ /dev/null @@ -1,18 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require_migration! - -RSpec.describe FinalizeCiBuildsBigintConversion, :migration, schema: 20210907182359, feature_category: :continuous_integration do - context 'with an unexpected FK fk_3f0c88d7dc' do - it 'removes the FK and migrates successfully' do - # Add the unexpected FK - subject.add_foreign_key(:ci_sources_pipelines, :ci_builds, column: :source_job_id, name: 'fk_3f0c88d7dc') - - expect { migrate! }.to change { subject.foreign_key_exists?(:ci_sources_pipelines, :ci_builds, column: :source_job_id, name: 'fk_3f0c88d7dc') }.from(true).to(false) - - # Additional check: The actually expected FK should still exist - expect(subject.foreign_key_exists?(:ci_sources_pipelines, :ci_builds, column: :source_job_id, name: 'fk_be5624bf37')).to be_truthy - end - end -end diff --git a/spec/migrations/20210910194952_update_report_type_for_existing_approval_project_rules_spec.rb b/spec/migrations/20210910194952_update_report_type_for_existing_approval_project_rules_spec.rb deleted file mode 100644 index e9d34fad76d..00000000000 --- a/spec/migrations/20210910194952_update_report_type_for_existing_approval_project_rules_spec.rb +++ /dev/null @@ -1,48 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require_migration! - -RSpec.describe UpdateReportTypeForExistingApprovalProjectRules, :migration, feature_category: :source_code_management do - using RSpec::Parameterized::TableSyntax - - let(:group) { table(:namespaces).create!(name: 'user', path: 'user') } - let(:project) { table(:projects).create!(namespace_id: group.id) } - let(:approval_project_rule) { table(:approval_project_rules).create!(name: rule_name, rule_type: rule_type, project_id: project.id) } - let(:rule_type) { 2 } - let(:rule_name) { 'Vulnerability-Check' } - - context 'with rule_type set to :report_approver' do - where(:rule_name, :report_type) do - [ - ['Vulnerability-Check', 1], - ['License-Check', 2], - ['Coverage-Check', 3] - ] - end - - with_them do - context "with names associated with report type" do - it 'updates report_type' do - expect { migrate! }.to change { approval_project_rule.reload.report_type }.from(nil).to(report_type) - end - end - end - end - - context 'with rule_type set to another value (e.g., :regular)' do - let(:rule_type) { 0 } - - it 'does not update report_type' do - expect { migrate! }.not_to change { approval_project_rule.reload.report_type } - end - end - - context 'with the rule name set to another value (e.g., Test Rule)' do - let(:rule_name) { 'Test Rule' } - - it 'does not update report_type' do - expect { migrate! }.not_to change { approval_project_rule.reload.report_type } - end - end -end diff --git a/spec/migrations/20210914095310_cleanup_orphan_project_access_tokens_spec.rb b/spec/migrations/20210914095310_cleanup_orphan_project_access_tokens_spec.rb deleted file mode 100644 index a198ae9e473..00000000000 --- a/spec/migrations/20210914095310_cleanup_orphan_project_access_tokens_spec.rb +++ /dev/null @@ -1,47 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require_migration! - -RSpec.describe CleanupOrphanProjectAccessTokens, :migration, feature_category: :user_profile do - def create_user(**extra_options) - defaults = { state: 'active', projects_limit: 0, email: "#{extra_options[:username]}@example.com" } - - table(:users).create!(defaults.merge(extra_options)) - end - - def create_membership(**extra_options) - defaults = { access_level: 30, notification_level: 0, source_id: 1, source_type: 'Project' } - - table(:members).create!(defaults.merge(extra_options)) - end - - let!(:regular_user) { create_user(username: 'regular') } - let!(:orphan_bot) { create_user(username: 'orphaned_bot', user_type: 6) } - let!(:used_bot) do - create_user(username: 'used_bot', user_type: 6).tap do |bot| - create_membership(user_id: bot.id) - end - end - - it 'marks all bots without memberships as deactivated' do - expect do - migrate! - regular_user.reload - orphan_bot.reload - used_bot.reload - end.to change { - [regular_user.state, orphan_bot.state, used_bot.state] - }.from(%w[active active active]).to(%w[active deactivated active]) - end - - it 'schedules for deletion all bots without memberships' do - job_class = 'DeleteUserWorker'.safe_constantize - - if job_class - expect(job_class).to receive(:bulk_perform_async).with([[orphan_bot.id, orphan_bot.id, skip_authorization: true]]) - - migrate! - end - end -end diff --git a/spec/migrations/20210915022415_cleanup_bigint_conversion_for_ci_builds_spec.rb b/spec/migrations/20210915022415_cleanup_bigint_conversion_for_ci_builds_spec.rb deleted file mode 100644 index 808c5371018..00000000000 --- a/spec/migrations/20210915022415_cleanup_bigint_conversion_for_ci_builds_spec.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require_migration! - -RSpec.describe CleanupBigintConversionForCiBuilds, feature_category: :continuous_integration do - let(:ci_builds) { table(:ci_builds) } - - it 'correctly migrates up and down' do - reversible_migration do |migration| - migration.before -> { - expect(ci_builds.column_names).to include('id_convert_to_bigint') - expect(ci_builds.column_names).to include('stage_id_convert_to_bigint') - } - - migration.after -> { - ci_builds.reset_column_information - expect(ci_builds.column_names).not_to include('id_convert_to_bigint') - expect(ci_builds.column_names).not_to include('stage_id_convert_to_bigint') - } - end - end -end diff --git a/spec/migrations/20210918201050_remove_old_pending_jobs_for_recalculate_vulnerabilities_occurrences_uuid_spec.rb b/spec/migrations/20210918201050_remove_old_pending_jobs_for_recalculate_vulnerabilities_occurrences_uuid_spec.rb deleted file mode 100644 index b3d1b41c330..00000000000 --- a/spec/migrations/20210918201050_remove_old_pending_jobs_for_recalculate_vulnerabilities_occurrences_uuid_spec.rb +++ /dev/null @@ -1,47 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require_migration! - -def create_background_migration_jobs(ids, status, created_at) - proper_status = case status - when :pending - Gitlab::Database::BackgroundMigrationJob.statuses['pending'] - when :succeeded - Gitlab::Database::BackgroundMigrationJob.statuses['succeeded'] - else - raise ArgumentError - end - - background_migration_jobs.create!( - class_name: 'RecalculateVulnerabilitiesOccurrencesUuid', - arguments: Array(ids), - status: proper_status, - created_at: created_at - ) -end - -RSpec.describe RemoveOldPendingJobsForRecalculateVulnerabilitiesOccurrencesUuid, :migration, -feature_category: :vulnerability_management do - let!(:background_migration_jobs) { table(:background_migration_jobs) } - let!(:before_target_date) { -Float::INFINITY..(DateTime.new(2021, 8, 17, 23, 59, 59)) } - let!(:after_target_date) { (DateTime.new(2021, 8, 18, 0, 0, 0))..Float::INFINITY } - - context 'when old RecalculateVulnerabilitiesOccurrencesUuid jobs are pending' do - before do - create_background_migration_jobs([1, 2, 3], :succeeded, DateTime.new(2021, 5, 5, 0, 2)) - create_background_migration_jobs([4, 5, 6], :pending, DateTime.new(2021, 5, 5, 0, 4)) - - create_background_migration_jobs([1, 2, 3], :succeeded, DateTime.new(2021, 8, 18, 0, 0)) - create_background_migration_jobs([4, 5, 6], :pending, DateTime.new(2021, 8, 18, 0, 2)) - create_background_migration_jobs([7, 8, 9], :pending, DateTime.new(2021, 8, 18, 0, 4)) - end - - it 'removes old, pending jobs' do - migrate! - - expect(background_migration_jobs.where(created_at: before_target_date).count).to eq(1) - expect(background_migration_jobs.where(created_at: after_target_date).count).to eq(3) - end - end -end diff --git a/spec/migrations/20210922021816_drop_int4_columns_for_ci_job_artifacts_spec.rb b/spec/migrations/20210922021816_drop_int4_columns_for_ci_job_artifacts_spec.rb deleted file mode 100644 index c463f69c80c..00000000000 --- a/spec/migrations/20210922021816_drop_int4_columns_for_ci_job_artifacts_spec.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require_migration! - -RSpec.describe DropInt4ColumnsForCiJobArtifacts, feature_category: :build_artifacts do - let(:ci_job_artifacts) { table(:ci_job_artifacts) } - - it 'correctly migrates up and down' do - reversible_migration do |migration| - migration.before -> { - expect(ci_job_artifacts.column_names).to include('id_convert_to_bigint') - expect(ci_job_artifacts.column_names).to include('job_id_convert_to_bigint') - } - - migration.after -> { - ci_job_artifacts.reset_column_information - expect(ci_job_artifacts.column_names).not_to include('id_convert_to_bigint') - expect(ci_job_artifacts.column_names).not_to include('job_id_convert_to_bigint') - } - end - end -end diff --git a/spec/migrations/20210922025631_drop_int4_column_for_ci_sources_pipelines_spec.rb b/spec/migrations/20210922025631_drop_int4_column_for_ci_sources_pipelines_spec.rb deleted file mode 100644 index 6b0c3a6db9a..00000000000 --- a/spec/migrations/20210922025631_drop_int4_column_for_ci_sources_pipelines_spec.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require_migration! - -RSpec.describe DropInt4ColumnForCiSourcesPipelines, feature_category: :pipeline_authoring do - let(:ci_sources_pipelines) { table(:ci_sources_pipelines) } - - it 'correctly migrates up and down' do - reversible_migration do |migration| - migration.before -> { - expect(ci_sources_pipelines.column_names).to include('source_job_id_convert_to_bigint') - } - - migration.after -> { - ci_sources_pipelines.reset_column_information - expect(ci_sources_pipelines.column_names).not_to include('source_job_id_convert_to_bigint') - } - end - end -end diff --git a/spec/migrations/20210922082019_drop_int4_column_for_events_spec.rb b/spec/migrations/20210922082019_drop_int4_column_for_events_spec.rb deleted file mode 100644 index 49cf1a01f2a..00000000000 --- a/spec/migrations/20210922082019_drop_int4_column_for_events_spec.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require_migration! - -RSpec.describe DropInt4ColumnForEvents, feature_category: :user_profile do - let(:events) { table(:events) } - - it 'correctly migrates up and down' do - reversible_migration do |migration| - migration.before -> { - expect(events.column_names).to include('id_convert_to_bigint') - } - - migration.after -> { - events.reset_column_information - expect(events.column_names).not_to include('id_convert_to_bigint') - } - end - end -end diff --git a/spec/migrations/20210922091402_drop_int4_column_for_push_event_payloads_spec.rb b/spec/migrations/20210922091402_drop_int4_column_for_push_event_payloads_spec.rb deleted file mode 100644 index 3e241438339..00000000000 --- a/spec/migrations/20210922091402_drop_int4_column_for_push_event_payloads_spec.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require_migration! - -RSpec.describe DropInt4ColumnForPushEventPayloads, feature_category: :user_profile do - let(:push_event_payloads) { table(:push_event_payloads) } - - it 'correctly migrates up and down' do - reversible_migration do |migration| - migration.before -> { - expect(push_event_payloads.column_names).to include('event_id_convert_to_bigint') - } - - migration.after -> { - push_event_payloads.reset_column_information - expect(push_event_payloads.column_names).not_to include('event_id_convert_to_bigint') - } - end - end -end diff --git a/spec/migrations/20211006060436_schedule_populate_topics_total_projects_count_cache_spec.rb b/spec/migrations/20211006060436_schedule_populate_topics_total_projects_count_cache_spec.rb deleted file mode 100644 index 2f3903a20a9..00000000000 --- a/spec/migrations/20211006060436_schedule_populate_topics_total_projects_count_cache_spec.rb +++ /dev/null @@ -1,29 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require_migration! - -RSpec.describe SchedulePopulateTopicsTotalProjectsCountCache, feature_category: :projects do - let(:topics) { table(:topics) } - let!(:topic_1) { topics.create!(name: 'Topic1') } - let!(:topic_2) { topics.create!(name: 'Topic2') } - let!(:topic_3) { topics.create!(name: 'Topic3') } - - describe '#up' do - before do - stub_const("#{described_class}::BATCH_SIZE", 2) - 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, topic_1.id, topic_2.id) - expect(described_class::MIGRATION).to be_scheduled_delayed_migration(4.minutes, topic_3.id, topic_3.id) - expect(BackgroundMigrationWorker.jobs.size).to eq(2) - end - end - end - end -end diff --git a/spec/migrations/20211012134316_clean_up_migrate_merge_request_diff_commit_users_spec.rb b/spec/migrations/20211012134316_clean_up_migrate_merge_request_diff_commit_users_spec.rb deleted file mode 100644 index a61e450d9ab..00000000000 --- a/spec/migrations/20211012134316_clean_up_migrate_merge_request_diff_commit_users_spec.rb +++ /dev/null @@ -1,48 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require_migration! 'clean_up_migrate_merge_request_diff_commit_users' - -RSpec.describe CleanUpMigrateMergeRequestDiffCommitUsers, :migration, feature_category: :code_review_workflow do - describe '#up' do - context 'when there are pending jobs' do - it 'processes the jobs immediately' do - Gitlab::Database::BackgroundMigrationJob.create!( - class_name: 'MigrateMergeRequestDiffCommitUsers', - status: :pending, - arguments: [10, 20] - ) - - spy = Gitlab::BackgroundMigration::MigrateMergeRequestDiffCommitUsers - migration = described_class.new - - allow(Gitlab::BackgroundMigration::MigrateMergeRequestDiffCommitUsers) - .to receive(:new) - .and_return(spy) - - expect(migration).to receive(:say) - expect(spy).to receive(:perform).with(10, 20) - - migration.up - end - end - - context 'when all jobs are completed' do - it 'does nothing' do - Gitlab::Database::BackgroundMigrationJob.create!( - class_name: 'MigrateMergeRequestDiffCommitUsers', - status: :succeeded, - arguments: [10, 20] - ) - - migration = described_class.new - - expect(migration).not_to receive(:say) - expect(Gitlab::BackgroundMigration::MigrateMergeRequestDiffCommitUsers) - .not_to receive(:new) - - migration.up - end - end - end -end diff --git a/spec/migrations/20211018152654_schedule_remove_duplicate_vulnerabilities_findings3_spec.rb b/spec/migrations/20211018152654_schedule_remove_duplicate_vulnerabilities_findings3_spec.rb deleted file mode 100644 index 3e8176a36a1..00000000000 --- a/spec/migrations/20211018152654_schedule_remove_duplicate_vulnerabilities_findings3_spec.rb +++ /dev/null @@ -1,166 +0,0 @@ -# frozen_string_literal: true -require 'spec_helper' -require_migration!('schedule_remove_duplicate_vulnerabilities_findings3') - -RSpec.describe ScheduleRemoveDuplicateVulnerabilitiesFindings3, :migration, feature_category: :vulnerability_management do - let(:namespace) { table(:namespaces).create!(name: 'user', path: 'user') } - let(:users) { table(:users) } - let(:user) { create_user! } - let(:project) { table(:projects).create!(id: 14219619, namespace_id: namespace.id) } - let(:scanners) { table(:vulnerability_scanners) } - let!(:scanner1) { scanners.create!(project_id: project.id, external_id: 'test 1', name: 'test scanner 1') } - let!(:scanner2) { scanners.create!(project_id: project.id, external_id: 'test 2', name: 'test scanner 2') } - let!(:scanner3) { scanners.create!(project_id: project.id, external_id: 'test 3', name: 'test scanner 3') } - let!(:unrelated_scanner) { scanners.create!(project_id: project.id, external_id: 'unreleated_scanner', name: 'unrelated scanner') } - let(:vulnerabilities) { table(:vulnerabilities) } - let(:vulnerability_findings) { table(:vulnerability_occurrences) } - let(:vulnerability_identifiers) { table(:vulnerability_identifiers) } - let(:vulnerability_identifier) do - vulnerability_identifiers.create!( - id: 1244459, - project_id: project.id, - external_type: 'vulnerability-identifier', - external_id: 'vulnerability-identifier', - fingerprint: '0a203e8cd5260a1948edbedc76c7cb91ad6a2e45', - name: 'vulnerability identifier') - end - - let!(:vulnerability_for_first_duplicate) do - create_vulnerability!( - project_id: project.id, - author_id: user.id - ) - end - - let!(:first_finding_duplicate) do - create_finding!( - id: 5606961, - uuid: "bd95c085-71aa-51d7-9bb6-08ae669c262e", - vulnerability_id: vulnerability_for_first_duplicate.id, - report_type: 0, - location_fingerprint: '00049d5119c2cb3bfb3d1ee1f6e031fe925aed75', - primary_identifier_id: vulnerability_identifier.id, - scanner_id: scanner1.id, - project_id: project.id - ) - end - - let!(:vulnerability_for_second_duplicate) do - create_vulnerability!( - project_id: project.id, - author_id: user.id - ) - end - - let!(:second_finding_duplicate) do - create_finding!( - id: 8765432, - uuid: "5b714f58-1176-5b26-8fd5-e11dfcb031b5", - vulnerability_id: vulnerability_for_second_duplicate.id, - report_type: 0, - location_fingerprint: '00049d5119c2cb3bfb3d1ee1f6e031fe925aed75', - primary_identifier_id: vulnerability_identifier.id, - scanner_id: scanner2.id, - project_id: project.id - ) - end - - let!(:vulnerability_for_third_duplicate) do - create_vulnerability!( - project_id: project.id, - author_id: user.id - ) - end - - let!(:third_finding_duplicate) do - create_finding!( - id: 8832995, - uuid: "cfe435fa-b25b-5199-a56d-7b007cc9e2d4", - vulnerability_id: vulnerability_for_third_duplicate.id, - report_type: 0, - location_fingerprint: '00049d5119c2cb3bfb3d1ee1f6e031fe925aed75', - primary_identifier_id: vulnerability_identifier.id, - scanner_id: scanner3.id, - project_id: project.id - ) - end - - let!(:unrelated_finding) do - create_finding!( - id: 9999999, - vulnerability_id: nil, - report_type: 1, - location_fingerprint: 'random_location_fingerprint', - primary_identifier_id: vulnerability_identifier.id, - scanner_id: unrelated_scanner.id, - project_id: project.id - ) - end - - before do - stub_const("#{described_class}::BATCH_SIZE", 1) - end - - around do |example| - freeze_time { Sidekiq::Testing.fake! { example.run } } - end - - it 'schedules background migration' do - migrate! - - expect(BackgroundMigrationWorker.jobs.size).to eq(4) - expect(described_class::MIGRATION).to be_scheduled_migration(first_finding_duplicate.id, first_finding_duplicate.id) - expect(described_class::MIGRATION).to be_scheduled_migration(second_finding_duplicate.id, second_finding_duplicate.id) - expect(described_class::MIGRATION).to be_scheduled_migration(third_finding_duplicate.id, third_finding_duplicate.id) - expect(described_class::MIGRATION).to be_scheduled_migration(unrelated_finding.id, unrelated_finding.id) - 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:, id: nil, - name: "test", severity: 7, confidence: 7, report_type: 0, - project_fingerprint: '123qweasdzxc', location_fingerprint: 'test', - metadata_version: 'test', raw_metadata: 'test', uuid: SecureRandom.uuid) - vulnerability_findings.create!({ - id: id, - vulnerability_id: vulnerability_id, - project_id: project_id, - name: name, - severity: severity, - confidence: confidence, - report_type: report_type, - project_fingerprint: project_fingerprint, - scanner_id: scanner_id, - primary_identifier_id: vulnerability_identifier.id, - location_fingerprint: location_fingerprint, - metadata_version: metadata_version, - raw_metadata: raw_metadata, - uuid: uuid - }.compact) - end - # rubocop:enable Metrics/ParameterLists - - def create_user!(name: "Example User", email: "user@example.com", user_type: nil, created_at: Time.zone.now, confirmed_at: Time.zone.now) - users.create!( - name: name, - email: email, - username: name, - projects_limit: 0, - user_type: user_type, - confirmed_at: confirmed_at - ) - end -end diff --git a/spec/migrations/20211028155449_schedule_fix_merge_request_diff_commit_users_migration_spec.rb b/spec/migrations/20211028155449_schedule_fix_merge_request_diff_commit_users_migration_spec.rb deleted file mode 100644 index 968d9cf176c..00000000000 --- a/spec/migrations/20211028155449_schedule_fix_merge_request_diff_commit_users_migration_spec.rb +++ /dev/null @@ -1,63 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require_migration! 'schedule_fix_merge_request_diff_commit_users_migration' - -RSpec.describe ScheduleFixMergeRequestDiffCommitUsersMigration, :migration, feature_category: :code_review_workflow do - let(:migration) { described_class.new } - let(:namespaces) { table(:namespaces) } - let(:projects) { table(:projects) } - let(:namespace) { namespaces.create!(name: 'foo', path: 'foo') } - - describe '#up' do - it 'does nothing when there are no projects to correct' do - migration.up - - expect(Gitlab::Database::BackgroundMigrationJob.count).to be_zero - end - - it 'schedules imported projects created after July' do - project = projects.create!( - namespace_id: namespace.id, - import_type: 'gitlab_project', - created_at: '2021-08-01' - ) - - expect(migration) - .to receive(:migrate_in) - .with(2.minutes, 'FixMergeRequestDiffCommitUsers', [project.id]) - - migration.up - - expect(Gitlab::Database::BackgroundMigrationJob.count).to eq(1) - - job = Gitlab::Database::BackgroundMigrationJob.first - - expect(job.class_name).to eq('FixMergeRequestDiffCommitUsers') - expect(job.arguments).to eq([project.id]) - end - - it 'ignores projects imported before July' do - projects.create!( - namespace_id: namespace.id, - import_type: 'gitlab_project', - created_at: '2020-08-01' - ) - - migration.up - - expect(Gitlab::Database::BackgroundMigrationJob.count).to be_zero - end - - it 'ignores projects that are not imported' do - projects.create!( - namespace_id: namespace.id, - created_at: '2021-08-01' - ) - - migration.up - - expect(Gitlab::Database::BackgroundMigrationJob.count).to be_zero - end - end -end diff --git a/spec/migrations/20211101222614_consume_remaining_user_namespace_jobs_spec.rb b/spec/migrations/20211101222614_consume_remaining_user_namespace_jobs_spec.rb deleted file mode 100644 index 1688ebf7cb1..00000000000 --- a/spec/migrations/20211101222614_consume_remaining_user_namespace_jobs_spec.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require_migration! - -RSpec.describe ConsumeRemainingUserNamespaceJobs, feature_category: :subgroups do - let(:namespaces) { table(:namespaces) } - let!(:namespace) { namespaces.create!(name: 'gitlab', path: 'gitlab-org', type: nil) } - - context 'when Namespaces with nil `type` still exist' do - it 'steals sidekiq jobs from BackfillUserNamespace background migration' do - expect(Gitlab::BackgroundMigration).to receive(:steal).with('BackfillUserNamespace') - - migrate! - end - - it 'migrates namespaces without type' do - expect { migrate! }.to change { namespaces.where(type: 'User').count }.from(0).to(1) - end - end -end diff --git a/spec/migrations/20211110143306_add_not_null_constraint_to_security_findings_uuid_spec.rb b/spec/migrations/20211110143306_add_not_null_constraint_to_security_findings_uuid_spec.rb deleted file mode 100644 index 3b69169b2d6..00000000000 --- a/spec/migrations/20211110143306_add_not_null_constraint_to_security_findings_uuid_spec.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true -require 'spec_helper' -require_migration! - -RSpec.describe AddNotNullConstraintToSecurityFindingsUuid, feature_category: :vulnerability_management do - let!(:security_findings) { table(:security_findings) } - let!(:migration) { described_class.new } - - before do - allow(migration).to receive(:transaction_open?).and_return(false) - allow(migration).to receive(:with_lock_retries).and_yield - end - - it 'adds a check constraint' do - constraint = security_findings.connection.check_constraints(:security_findings).find { |constraint| constraint.expression == "uuid IS NOT NULL" } - expect(constraint).to be_nil - - migration.up - - constraint = security_findings.connection.check_constraints(:security_findings).find { |constraint| constraint.expression == "uuid IS NOT NULL" } - expect(constraint).to be_a(ActiveRecord::ConnectionAdapters::CheckConstraintDefinition) - end -end diff --git a/spec/migrations/20211110151350_schedule_drop_invalid_security_findings_spec.rb b/spec/migrations/20211110151350_schedule_drop_invalid_security_findings_spec.rb deleted file mode 100644 index d05828112e6..00000000000 --- a/spec/migrations/20211110151350_schedule_drop_invalid_security_findings_spec.rb +++ /dev/null @@ -1,72 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require_migration! - -RSpec.describe ScheduleDropInvalidSecurityFindings, :migration, :suppress_gitlab_schemas_validate_connection, schema: 20211108211434, - feature_category: :vulnerability_management do - let!(:background_migration_jobs) { table(:background_migration_jobs) } - - let!(:namespace) { table(:namespaces).create!(name: 'user', path: 'user', type: Namespaces::UserNamespace.sti_name) } - let!(:project) { table(:projects).create!(namespace_id: namespace.id) } - - let!(:pipelines) { table(:ci_pipelines) } - let!(:pipeline) { pipelines.create!(project_id: project.id) } - - let!(:ci_builds) { table(:ci_builds) } - let!(:ci_build) { ci_builds.create! } - - let!(:security_scans) { table(:security_scans) } - let!(:security_scan) do - security_scans.create!( - scan_type: 1, - status: 1, - build_id: ci_build.id, - project_id: project.id, - pipeline_id: pipeline.id - ) - end - - let!(:vulnerability_scanners) { table(:vulnerability_scanners) } - let!(:vulnerability_scanner) { vulnerability_scanners.create!(project_id: project.id, external_id: 'test 1', name: 'test scanner 1') } - - let!(:security_findings) { table(:security_findings) } - let!(:security_finding_without_uuid) do - security_findings.create!( - severity: 1, - confidence: 1, - scan_id: security_scan.id, - scanner_id: vulnerability_scanner.id, - uuid: nil - ) - end - - let!(:security_finding_with_uuid) do - security_findings.create!( - severity: 1, - confidence: 1, - scan_id: security_scan.id, - scanner_id: vulnerability_scanner.id, - uuid: 'bd95c085-71aa-51d7-9bb6-08ae669c262e' - ) - end - - before do - stub_const("#{described_class}::BATCH_SIZE", 1) - stub_const("#{described_class}::SUB_BATCH_SIZE", 1) - end - - around do |example| - freeze_time { Sidekiq::Testing.fake! { example.run } } - end - - it 'schedules background migrations' do - migrate! - - expect(background_migration_jobs.count).to eq(1) - expect(background_migration_jobs.first.arguments).to match_array([security_finding_without_uuid.id, security_finding_without_uuid.id, described_class::SUB_BATCH_SIZE]) - - expect(BackgroundMigrationWorker.jobs.size).to eq(1) - expect(described_class::MIGRATION).to be_scheduled_delayed_migration(2.minutes, security_finding_without_uuid.id, security_finding_without_uuid.id, described_class::SUB_BATCH_SIZE) - end -end diff --git a/spec/migrations/20211116091751_change_namespace_type_default_to_user_spec.rb b/spec/migrations/20211116091751_change_namespace_type_default_to_user_spec.rb deleted file mode 100644 index deba6f9b87c..00000000000 --- a/spec/migrations/20211116091751_change_namespace_type_default_to_user_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -# frozen_string_literal: true - -# With https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73495, we no longer allow -# a Namespace type to be nil. There is nothing left to test for this migration, -# but we'll keep this file here as a tombstone. diff --git a/spec/migrations/20211116111644_schedule_remove_occurrence_pipelines_and_duplicate_vulnerabilities_findings_spec.rb b/spec/migrations/20211116111644_schedule_remove_occurrence_pipelines_and_duplicate_vulnerabilities_findings_spec.rb deleted file mode 100644 index 18513656029..00000000000 --- a/spec/migrations/20211116111644_schedule_remove_occurrence_pipelines_and_duplicate_vulnerabilities_findings_spec.rb +++ /dev/null @@ -1,190 +0,0 @@ -# frozen_string_literal: true -require 'spec_helper' - -require_migration! - -RSpec.describe ScheduleRemoveOccurrencePipelinesAndDuplicateVulnerabilitiesFindings, - :suppress_gitlab_schemas_validate_connection, :migration, feature_category: :vulnerability_management do - let!(:background_migration_jobs) { table(:background_migration_jobs) } - let!(:namespace) { table(:namespaces).create!(name: 'user', path: 'user') } - let!(:users) { table(:users) } - let!(:user) { create_user! } - let!(:project) { table(:projects).create!(id: 14219619, namespace_id: namespace.id) } - let!(:pipelines) { table(:ci_pipelines) } - let!(:scanners) { table(:vulnerability_scanners) } - let!(:scanner1) { scanners.create!(project_id: project.id, external_id: 'test 1', name: 'test scanner 1') } - let!(:scanner2) { scanners.create!(project_id: project.id, external_id: 'test 2', name: 'test scanner 2') } - let!(:scanner3) { scanners.create!(project_id: project.id, external_id: 'test 3', name: 'test scanner 3') } - let!(:unrelated_scanner) { scanners.create!(project_id: project.id, external_id: 'unreleated_scanner', name: 'unrelated scanner') } - let!(:vulnerabilities) { table(:vulnerabilities) } - let!(:vulnerability_findings) { table(:vulnerability_occurrences) } - let!(:vulnerability_finding_pipelines) { table(:vulnerability_occurrence_pipelines) } - let!(:vulnerability_identifiers) { table(:vulnerability_identifiers) } - let!(:vulnerability_identifier) do - vulnerability_identifiers.create!( - id: 1244459, - project_id: project.id, - external_type: 'vulnerability-identifier', - external_id: 'vulnerability-identifier', - fingerprint: '0a203e8cd5260a1948edbedc76c7cb91ad6a2e45', - name: 'vulnerability identifier') - end - - let!(:vulnerability_for_first_duplicate) do - create_vulnerability!( - project_id: project.id, - author_id: user.id - ) - end - - let!(:first_finding_duplicate) do - create_finding!( - id: 5606961, - uuid: "bd95c085-71aa-51d7-9bb6-08ae669c262e", - vulnerability_id: vulnerability_for_first_duplicate.id, - report_type: 0, - location_fingerprint: '00049d5119c2cb3bfb3d1ee1f6e031fe925aed75', - primary_identifier_id: vulnerability_identifier.id, - scanner_id: scanner1.id, - project_id: project.id - ) - end - - let!(:vulnerability_for_second_duplicate) do - create_vulnerability!( - project_id: project.id, - author_id: user.id - ) - end - - let!(:second_finding_duplicate) do - create_finding!( - id: 8765432, - uuid: "5b714f58-1176-5b26-8fd5-e11dfcb031b5", - vulnerability_id: vulnerability_for_second_duplicate.id, - report_type: 0, - location_fingerprint: '00049d5119c2cb3bfb3d1ee1f6e031fe925aed75', - primary_identifier_id: vulnerability_identifier.id, - scanner_id: scanner2.id, - project_id: project.id - ) - end - - let!(:vulnerability_for_third_duplicate) do - create_vulnerability!( - project_id: project.id, - author_id: user.id - ) - end - - let!(:third_finding_duplicate) do - create_finding!( - id: 8832995, - uuid: "cfe435fa-b25b-5199-a56d-7b007cc9e2d4", - vulnerability_id: vulnerability_for_third_duplicate.id, - report_type: 0, - location_fingerprint: '00049d5119c2cb3bfb3d1ee1f6e031fe925aed75', - primary_identifier_id: vulnerability_identifier.id, - scanner_id: scanner3.id, - project_id: project.id - ) - end - - let!(:unrelated_finding) do - create_finding!( - id: 9999999, - vulnerability_id: nil, - report_type: 1, - location_fingerprint: 'random_location_fingerprint', - primary_identifier_id: vulnerability_identifier.id, - scanner_id: unrelated_scanner.id, - project_id: project.id - ) - end - - before do - stub_const("#{described_class}::BATCH_SIZE", 1) - - 4.times do - create_finding_pipeline!(project_id: project.id, finding_id: first_finding_duplicate.id) - create_finding_pipeline!(project_id: project.id, finding_id: second_finding_duplicate.id) - create_finding_pipeline!(project_id: project.id, finding_id: third_finding_duplicate.id) - create_finding_pipeline!(project_id: project.id, finding_id: unrelated_finding.id) - end - end - - around do |example| - freeze_time { Sidekiq::Testing.fake! { example.run } } - end - - it 'schedules background migrations' do - migrate! - - expect(background_migration_jobs.count).to eq(4) - expect(background_migration_jobs.first.arguments).to match_array([first_finding_duplicate.id, first_finding_duplicate.id]) - expect(background_migration_jobs.second.arguments).to match_array([second_finding_duplicate.id, second_finding_duplicate.id]) - expect(background_migration_jobs.third.arguments).to match_array([third_finding_duplicate.id, third_finding_duplicate.id]) - expect(background_migration_jobs.fourth.arguments).to match_array([unrelated_finding.id, unrelated_finding.id]) - - expect(BackgroundMigrationWorker.jobs.size).to eq(4) - expect(described_class::MIGRATION).to be_scheduled_delayed_migration(2.minutes, first_finding_duplicate.id, first_finding_duplicate.id) - expect(described_class::MIGRATION).to be_scheduled_delayed_migration(4.minutes, second_finding_duplicate.id, second_finding_duplicate.id) - expect(described_class::MIGRATION).to be_scheduled_delayed_migration(6.minutes, third_finding_duplicate.id, third_finding_duplicate.id) - expect(described_class::MIGRATION).to be_scheduled_delayed_migration(8.minutes, unrelated_finding.id, unrelated_finding.id) - 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:, id: nil, - name: "test", severity: 7, confidence: 7, report_type: 0, - project_fingerprint: '123qweasdzxc', location_fingerprint: 'test', - metadata_version: 'test', raw_metadata: 'test', uuid: SecureRandom.uuid) - params = { - vulnerability_id: vulnerability_id, - project_id: project_id, - name: name, - severity: severity, - confidence: confidence, - report_type: report_type, - project_fingerprint: project_fingerprint, - scanner_id: scanner_id, - primary_identifier_id: vulnerability_identifier.id, - location_fingerprint: location_fingerprint, - metadata_version: metadata_version, - raw_metadata: raw_metadata, - uuid: uuid - } - params[:id] = id unless id.nil? - vulnerability_findings.create!(params) - end - # rubocop:enable Metrics/ParameterLists - - def create_user!(name: "Example User", email: "user@example.com", user_type: nil, created_at: Time.zone.now, confirmed_at: Time.zone.now) - users.create!( - name: name, - email: email, - username: name, - projects_limit: 0, - user_type: user_type, - confirmed_at: confirmed_at - ) - end - - def create_finding_pipeline!(project_id:, finding_id:) - pipeline = pipelines.create!(project_id: project_id) - vulnerability_finding_pipelines.create!(pipeline_id: pipeline.id, occurrence_id: finding_id) - end -end diff --git a/spec/migrations/20211117084814_migrate_remaining_u2f_registrations_spec.rb b/spec/migrations/20211117084814_migrate_remaining_u2f_registrations_spec.rb deleted file mode 100644 index bfe2b661a31..00000000000 --- a/spec/migrations/20211117084814_migrate_remaining_u2f_registrations_spec.rb +++ /dev/null @@ -1,43 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require_migration! - -RSpec.describe MigrateRemainingU2fRegistrations, :migration, feature_category: :authentication_and_authorization do - let(:u2f_registrations) { table(:u2f_registrations) } - let(:webauthn_registrations) { table(:webauthn_registrations) } - let(:users) { table(:users) } - - let(:user) { users.create!(email: 'email@email.com', name: 'foo', username: 'foo', projects_limit: 0) } - - before do - create_u2f_registration(1, 'reg1') - create_u2f_registration(2, 'reg2') - create_u2f_registration(3, '') - create_u2f_registration(4, nil) - webauthn_registrations.create!({ name: 'reg1', u2f_registration_id: 1, credential_xid: '', public_key: '', user_id: user.id }) - end - - it 'correctly migrates u2f registrations previously not migrated' do - expect { migrate! }.to change { webauthn_registrations.count }.from(1).to(4) - end - - it 'migrates all valid u2f registrations depite errors' do - create_u2f_registration(5, 'reg3', 'invalid!') - create_u2f_registration(6, 'reg4') - - expect { migrate! }.to change { webauthn_registrations.count }.from(1).to(5) - end - - def create_u2f_registration(id, name, public_key = nil) - device = U2F::FakeU2F.new(FFaker::BaconIpsum.characters(5), { key_handle: SecureRandom.random_bytes(255) }) - public_key ||= Base64.strict_encode64(device.origin_public_key_raw) - u2f_registrations.create!({ id: id, - certificate: Base64.strict_encode64(device.cert_raw), - key_handle: U2F.urlsafe_encode64(device.key_handle_raw), - public_key: public_key, - counter: 5, - name: name, - user_id: user.id }) - end -end diff --git a/spec/migrations/20211126115449_encrypt_static_objects_external_storage_auth_token_spec.rb b/spec/migrations/20211126115449_encrypt_static_objects_external_storage_auth_token_spec.rb deleted file mode 100644 index 09a8bb44d88..00000000000 --- a/spec/migrations/20211126115449_encrypt_static_objects_external_storage_auth_token_spec.rb +++ /dev/null @@ -1,78 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require_migration! - -RSpec.describe EncryptStaticObjectsExternalStorageAuthToken, :migration, feature_category: :source_code_management do - let(:application_settings) do - Class.new(ActiveRecord::Base) do - self.table_name = 'application_settings' - end - end - - context 'when static_objects_external_storage_auth_token is not set' do - it 'does nothing' do - application_settings.create! - - reversible_migration do |migration| - migration.before -> { - settings = application_settings.first - - expect(settings.static_objects_external_storage_auth_token).to be_nil - expect(settings.static_objects_external_storage_auth_token_encrypted).to be_nil - } - - migration.after -> { - settings = application_settings.first - - expect(settings.static_objects_external_storage_auth_token).to be_nil - expect(settings.static_objects_external_storage_auth_token_encrypted).to be_nil - } - end - end - end - - context 'when static_objects_external_storage_auth_token is set' do - it 'encrypts static_objects_external_storage_auth_token' do - settings = application_settings.create! - settings.update_column(:static_objects_external_storage_auth_token, 'Test') - - reversible_migration do |migration| - migration.before -> { - settings = application_settings.first - - expect(settings.static_objects_external_storage_auth_token).to eq('Test') - expect(settings.static_objects_external_storage_auth_token_encrypted).to be_nil - } - migration.after -> { - settings = application_settings.first - - expect(settings.static_objects_external_storage_auth_token).to eq('Test') - expect(settings.static_objects_external_storage_auth_token_encrypted).to be_present - } - end - end - end - - context 'when static_objects_external_storage_auth_token is empty string' do - it 'does not break' do - settings = application_settings.create! - settings.update_column(:static_objects_external_storage_auth_token, '') - - reversible_migration do |migration| - migration.before -> { - settings = application_settings.first - - expect(settings.static_objects_external_storage_auth_token).to eq('') - expect(settings.static_objects_external_storage_auth_token_encrypted).to be_nil - } - migration.after -> { - settings = application_settings.first - - expect(settings.static_objects_external_storage_auth_token).to eq('') - expect(settings.static_objects_external_storage_auth_token_encrypted).to be_nil - } - end - end - end -end diff --git a/spec/migrations/20211126204445_add_task_to_work_item_types_spec.rb b/spec/migrations/20211126204445_add_task_to_work_item_types_spec.rb deleted file mode 100644 index db68e895b61..00000000000 --- a/spec/migrations/20211126204445_add_task_to_work_item_types_spec.rb +++ /dev/null @@ -1,54 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require_migration! - -RSpec.describe AddTaskToWorkItemTypes, :migration, feature_category: :team_planning do - include MigrationHelpers::WorkItemTypesHelper - - let!(:work_item_types) { table(:work_item_types) } - - let(:base_types) do - { - issue: 0, - incident: 1, - test_case: 2, - requirement: 3, - task: 4 - } - end - - append_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 the record if it already exists' do - reset_db_state_prior_to_migration - work_item_types.find_or_create_by!(name: 'Task', namespace_id: nil, base_type: base_types[:task], icon_name: 'issue-type-task') - - expect do - migrate! - end.to not_change(work_item_types, :count) - end - - it 'adds task to base work item types' do - reset_db_state_prior_to_migration - - expect do - migrate! - end.to change(work_item_types, :count).from(4).to(5) - - expect(work_item_types.all.pluck(:base_type)).to include(base_types[:task]) - 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') - end -end diff --git a/spec/migrations/20211130165043_backfill_sequence_column_for_sprints_table_spec.rb b/spec/migrations/20211130165043_backfill_sequence_column_for_sprints_table_spec.rb deleted file mode 100644 index 91646da4791..00000000000 --- a/spec/migrations/20211130165043_backfill_sequence_column_for_sprints_table_spec.rb +++ /dev/null @@ -1,42 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -require_migration! - -RSpec.describe BackfillSequenceColumnForSprintsTable, :migration, schema: 20211126042235, feature_category: :team_planning do - let(:migration) { described_class.new } - let(:namespaces) { table(:namespaces) } - let(:sprints) { table(:sprints) } - let(:iterations_cadences) { table(:iterations_cadences) } - - let!(:group) { namespaces.create!(name: 'foo', path: 'foo') } - let!(:cadence_1) { iterations_cadences.create!(group_id: group.id, title: "cadence 1") } - let!(:cadence_2) { iterations_cadences.create!(group_id: group.id, title: "cadence 2") } - let!(:iteration_1) { sprints.create!(id: 1, group_id: group.id, iterations_cadence_id: cadence_1.id, start_date: Date.new(2021, 11, 1), due_date: Date.new(2021, 11, 5), iid: 1, title: 'a' ) } - let!(:iteration_2) { sprints.create!(id: 2, group_id: group.id, iterations_cadence_id: cadence_1.id, start_date: Date.new(2021, 12, 1), due_date: Date.new(2021, 12, 5), iid: 2, title: 'b') } - let!(:iteration_3) { sprints.create!(id: 3, group_id: group.id, iterations_cadence_id: cadence_2.id, start_date: Date.new(2021, 12, 1), due_date: Date.new(2021, 12, 5), iid: 4, title: 'd') } - let!(:iteration_4) { sprints.create!(id: 4, group_id: group.id, iterations_cadence_id: nil, start_date: Date.new(2021, 11, 15), due_date: Date.new(2021, 11, 20), iid: 3, title: 'c') } - - describe '#up' do - it "correctly sets the sequence attribute with idempotency" do - migration.up - - expect(iteration_1.reload.sequence).to be 1 - expect(iteration_2.reload.sequence).to be 2 - expect(iteration_3.reload.sequence).to be 1 - expect(iteration_4.reload.sequence).to be nil - - iteration_5 = sprints.create!(id: 5, group_id: group.id, iterations_cadence_id: cadence_1.id, start_date: Date.new(2022, 1, 1), due_date: Date.new(2022, 1, 5), iid: 1, title: 'e' ) - - migration.down - migration.up - - expect(iteration_1.reload.sequence).to be 1 - expect(iteration_2.reload.sequence).to be 2 - expect(iteration_5.reload.sequence).to be 3 - expect(iteration_3.reload.sequence).to be 1 - expect(iteration_4.reload.sequence).to be nil - end - end -end diff --git a/spec/migrations/20211207125331_remove_jobs_for_recalculate_vulnerabilities_occurrences_uuid_spec.rb b/spec/migrations/20211207125331_remove_jobs_for_recalculate_vulnerabilities_occurrences_uuid_spec.rb index be89ee9d2aa..9fa2ac2313a 100644 --- a/spec/migrations/20211207125331_remove_jobs_for_recalculate_vulnerabilities_occurrences_uuid_spec.rb +++ b/spec/migrations/20211207125331_remove_jobs_for_recalculate_vulnerabilities_occurrences_uuid_spec.rb @@ -21,7 +21,7 @@ def create_background_migration_jobs(ids, status, created_at) end RSpec.describe RemoveJobsForRecalculateVulnerabilitiesOccurrencesUuid, :migration, -feature_category: :vulnerability_management do + feature_category: :vulnerability_management do let!(:background_migration_jobs) { table(:background_migration_jobs) } context 'when RecalculateVulnerabilitiesOccurrencesUuid jobs are present' do diff --git a/spec/migrations/20220124130028_dedup_runner_projects_spec.rb b/spec/migrations/20220124130028_dedup_runner_projects_spec.rb index ee468f40908..b9189cbae7f 100644 --- a/spec/migrations/20220124130028_dedup_runner_projects_spec.rb +++ b/spec/migrations/20220124130028_dedup_runner_projects_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' require_migration! RSpec.describe DedupRunnerProjects, :migration, :suppress_gitlab_schemas_validate_connection, -schema: 20220120085655, feature_category: :runner do + schema: 20220120085655, feature_category: :runner do let(:namespaces) { table(:namespaces) } let(:projects) { table(:projects) } let(:runners) { table(:ci_runners) } diff --git a/spec/migrations/20220128155251_remove_dangling_running_builds_spec.rb b/spec/migrations/20220128155251_remove_dangling_running_builds_spec.rb index ea88cf1a2ce..3abe173196f 100644 --- a/spec/migrations/20220128155251_remove_dangling_running_builds_spec.rb +++ b/spec/migrations/20220128155251_remove_dangling_running_builds_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' require_migration!('remove_dangling_running_builds') RSpec.describe RemoveDanglingRunningBuilds, :suppress_gitlab_schemas_validate_connection, -feature_category: :continuous_integration do + feature_category: :continuous_integration do let(:namespace) { table(:namespaces).create!(name: 'user', path: 'user') } let(:project) { table(:projects).create!(namespace_id: namespace.id) } let(:runner) { table(:ci_runners).create!(runner_type: 1) } diff --git a/spec/migrations/20220307192610_remove_duplicate_project_tag_releases_spec.rb b/spec/migrations/20220307192610_remove_duplicate_project_tag_releases_spec.rb index 3bdd6e5fab9..98e2ba4816b 100644 --- a/spec/migrations/20220307192610_remove_duplicate_project_tag_releases_spec.rb +++ b/spec/migrations/20220307192610_remove_duplicate_project_tag_releases_spec.rb @@ -14,9 +14,7 @@ RSpec.describe RemoveDuplicateProjectTagReleases, feature_category: :release_orc let(:dup_releases) do Array.new(4).fill do |i| - rel = releases.new(project_id: project.id, - tag: "duplicate tag", - released_at: (DateTime.now + i.days)) + rel = releases.new(project_id: project.id, tag: "duplicate tag", released_at: (DateTime.now + i.days)) rel.save!(validate: false) rel end diff --git a/spec/migrations/20220309084954_remove_leftover_external_pull_request_deletions_spec.rb b/spec/migrations/20220309084954_remove_leftover_external_pull_request_deletions_spec.rb index c0b94313d4d..8df9907643e 100644 --- a/spec/migrations/20220309084954_remove_leftover_external_pull_request_deletions_spec.rb +++ b/spec/migrations/20220309084954_remove_leftover_external_pull_request_deletions_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' require_migration! -RSpec.describe RemoveLeftoverExternalPullRequestDeletions, feature_category: :pods do +RSpec.describe RemoveLeftoverExternalPullRequestDeletions, feature_category: :cell do let(:deleted_records) { table(:loose_foreign_keys_deleted_records) } let(:pending_record1) { deleted_records.create!(id: 1, fully_qualified_table_name: 'public.external_pull_requests', primary_key_value: 1, status: 1) } diff --git a/spec/migrations/20220310141349_remove_dependency_list_usage_data_from_redis_spec.rb b/spec/migrations/20220310141349_remove_dependency_list_usage_data_from_redis_spec.rb index f40f9c70833..5d9be79e768 100644 --- a/spec/migrations/20220310141349_remove_dependency_list_usage_data_from_redis_spec.rb +++ b/spec/migrations/20220310141349_remove_dependency_list_usage_data_from_redis_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' require_migration! RSpec.describe RemoveDependencyListUsageDataFromRedis, :migration, :clean_gitlab_redis_shared_state, -feature_category: :dependency_management do + feature_category: :dependency_management do let(:key) { "DEPENDENCY_LIST_USAGE_COUNTER" } describe "#up" do diff --git a/spec/migrations/20220324032250_migrate_shimo_confluence_service_category_spec.rb b/spec/migrations/20220324032250_migrate_shimo_confluence_service_category_spec.rb index 15c16a2b232..6f9e70aa8c8 100644 --- a/spec/migrations/20220324032250_migrate_shimo_confluence_service_category_spec.rb +++ b/spec/migrations/20220324032250_migrate_shimo_confluence_service_category_spec.rb @@ -11,8 +11,9 @@ RSpec.describe MigrateShimoConfluenceServiceCategory, :migration, feature_catego before do namespace = namespaces.create!(name: 'test', path: 'test') projects.create!(id: 1, namespace_id: namespace.id, name: 'gitlab', path: 'gitlab') - integrations.create!(id: 1, active: true, type_new: "Integrations::SlackSlashCommands", - category: 'chat', project_id: 1) + integrations.create!( + id: 1, active: true, type_new: "Integrations::SlackSlashCommands", category: 'chat', project_id: 1 + ) integrations.create!(id: 3, active: true, type_new: "Integrations::Confluence", category: 'common', project_id: 1) integrations.create!(id: 5, active: true, type_new: "Integrations::Shimo", category: 'common', project_id: 1) end diff --git a/spec/migrations/20220329175119_remove_leftover_ci_job_artifact_deletions_spec.rb b/spec/migrations/20220329175119_remove_leftover_ci_job_artifact_deletions_spec.rb index e9bca42f37f..ca2ee6d8aba 100644 --- a/spec/migrations/20220329175119_remove_leftover_ci_job_artifact_deletions_spec.rb +++ b/spec/migrations/20220329175119_remove_leftover_ci_job_artifact_deletions_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' require_migration! -RSpec.describe RemoveLeftoverCiJobArtifactDeletions, feature_category: :pods do +RSpec.describe RemoveLeftoverCiJobArtifactDeletions, feature_category: :cell do let(:deleted_records) { table(:loose_foreign_keys_deleted_records) } target_table_name = Ci::JobArtifact.table_name diff --git a/spec/migrations/20220505044348_fix_automatic_iterations_cadences_start_date_spec.rb b/spec/migrations/20220505044348_fix_automatic_iterations_cadences_start_date_spec.rb index 3a6a8f5dbe5..16258eeb0fb 100644 --- a/spec/migrations/20220505044348_fix_automatic_iterations_cadences_start_date_spec.rb +++ b/spec/migrations/20220505044348_fix_automatic_iterations_cadences_start_date_spec.rb @@ -28,19 +28,19 @@ RSpec.describe FixAutomaticIterationsCadencesStartDate, feature_category: :team_ before do sprints.create!(id: 2, start_date: jan2022, due_date: jan2022 + 1.week, iterations_cadence_id: cadence1.id, - group_id: group1.id, iid: 1) + group_id: group1.id, iid: 1) sprints.create!(id: 1, start_date: dec2022, due_date: dec2022 + 1.week, iterations_cadence_id: cadence1.id, - group_id: group1.id, iid: 2) + group_id: group1.id, iid: 2) sprints.create!(id: 4, start_date: feb2022, due_date: feb2022 + 1.week, iterations_cadence_id: cadence3.id, - group_id: group2.id, iid: 1) + group_id: group2.id, iid: 1) sprints.create!(id: 3, start_date: may2022, due_date: may2022 + 1.week, iterations_cadence_id: cadence3.id, - group_id: group2.id, iid: 2) + group_id: group2.id, iid: 2) sprints.create!(id: 5, start_date: may2022, due_date: may2022 + 1.week, iterations_cadence_id: cadence4.id, - group_id: group2.id, iid: 4) + group_id: group2.id, iid: 4) sprints.create!(id: 6, start_date: feb2022, due_date: feb2022 + 1.week, iterations_cadence_id: cadence4.id, - group_id: group2.id, iid: 3) + group_id: group2.id, iid: 3) end describe '#up' do diff --git a/spec/migrations/20220513043344_reschedule_expire_o_auth_tokens_spec.rb b/spec/migrations/20220513043344_reschedule_expire_o_auth_tokens_spec.rb index 735232dfac7..b03849b61a2 100644 --- a/spec/migrations/20220513043344_reschedule_expire_o_auth_tokens_spec.rb +++ b/spec/migrations/20220513043344_reschedule_expire_o_auth_tokens_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' require_migration! -RSpec.describe RescheduleExpireOAuthTokens, feature_category: :authentication_and_authorization do +RSpec.describe RescheduleExpireOAuthTokens, feature_category: :system_access do let!(:migration) { described_class::MIGRATION } describe '#up' do diff --git a/spec/migrations/20220601152916_add_user_id_and_ip_address_success_index_to_authentication_events_spec.rb b/spec/migrations/20220601152916_add_user_id_and_ip_address_success_index_to_authentication_events_spec.rb index 1b8ec47f61b..c01d982c34e 100644 --- a/spec/migrations/20220601152916_add_user_id_and_ip_address_success_index_to_authentication_events_spec.rb +++ b/spec/migrations/20220601152916_add_user_id_and_ip_address_success_index_to_authentication_events_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' require_migration! RSpec.describe AddUserIdAndIpAddressSuccessIndexToAuthenticationEvents, -feature_category: :authentication_and_authorization do + feature_category: :system_access do let(:db) { described_class.new } let(:old_index) { described_class::OLD_INDEX_NAME } let(:new_index) { described_class::NEW_INDEX_NAME } diff --git a/spec/migrations/20220606082910_add_tmp_index_for_potentially_misassociated_vulnerability_occurrences_spec.rb b/spec/migrations/20220606082910_add_tmp_index_for_potentially_misassociated_vulnerability_occurrences_spec.rb index b74e15d804f..4ae40933541 100644 --- a/spec/migrations/20220606082910_add_tmp_index_for_potentially_misassociated_vulnerability_occurrences_spec.rb +++ b/spec/migrations/20220606082910_add_tmp_index_for_potentially_misassociated_vulnerability_occurrences_spec.rb @@ -5,7 +5,7 @@ require "spec_helper" require_migration! RSpec.describe AddTmpIndexForPotentiallyMisassociatedVulnerabilityOccurrences, -feature_category: :vulnerability_management do + feature_category: :vulnerability_management do let(:async_index) { Gitlab::Database::AsyncIndexes::PostgresAsyncIndex } let(:index_name) { described_class::INDEX_NAME } diff --git a/spec/migrations/20220607082910_add_sync_tmp_index_for_potentially_misassociated_vulnerability_occurrences_spec.rb b/spec/migrations/20220607082910_add_sync_tmp_index_for_potentially_misassociated_vulnerability_occurrences_spec.rb index 8d3ef9a46d7..d4a800eb1db 100644 --- a/spec/migrations/20220607082910_add_sync_tmp_index_for_potentially_misassociated_vulnerability_occurrences_spec.rb +++ b/spec/migrations/20220607082910_add_sync_tmp_index_for_potentially_misassociated_vulnerability_occurrences_spec.rb @@ -5,7 +5,7 @@ require "spec_helper" require_migration! RSpec.describe AddSyncTmpIndexForPotentiallyMisassociatedVulnerabilityOccurrences, -feature_category: :vulnerability_management do + feature_category: :vulnerability_management do let(:table) { "vulnerability_occurrences" } let(:index) { described_class::INDEX_NAME } diff --git a/spec/migrations/20220628012902_finalise_project_namespace_members_spec.rb b/spec/migrations/20220628012902_finalise_project_namespace_members_spec.rb index 55cabc21997..fb1a4782f3b 100644 --- a/spec/migrations/20220628012902_finalise_project_namespace_members_spec.rb +++ b/spec/migrations/20220628012902_finalise_project_namespace_members_spec.rb @@ -12,12 +12,16 @@ RSpec.describe FinaliseProjectNamespaceMembers, :migration, feature_category: :s 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('BackfillProjectMemberNamespaceId', :members, :id, []) + expect(runner).to receive(:finalize).with(migration, :members, :id, []) end end end context 'when migration is missing' do + before do + batched_migrations.where(job_class_name: migration).delete_all + end + it 'warns migration not found' do expect(Gitlab::AppLogger) .to receive(:warn).with(/Could not find batched background migration for the given configuration:/) @@ -29,7 +33,7 @@ RSpec.describe FinaliseProjectNamespaceMembers, :migration, feature_category: :s context 'with migration present' do let!(:project_member_namespace_id_backfill) do batched_migrations.create!( - job_class_name: 'BackfillProjectMemberNamespaceId', + job_class_name: migration, table_name: :members, column_name: :id, job_arguments: [], diff --git a/spec/migrations/20220801155858_schedule_disable_legacy_open_source_licence_for_recent_public_projects_spec.rb b/spec/migrations/20220801155858_schedule_disable_legacy_open_source_licence_for_recent_public_projects_spec.rb index f8f1565fe4c..a9f0bdc8487 100644 --- a/spec/migrations/20220801155858_schedule_disable_legacy_open_source_licence_for_recent_public_projects_spec.rb +++ b/spec/migrations/20220801155858_schedule_disable_legacy_open_source_licence_for_recent_public_projects_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' require_migration! -RSpec.describe ScheduleDisableLegacyOpenSourceLicenceForRecentPublicProjects, schema: 20220801155858, - feature_category: :projects do +RSpec.describe ScheduleDisableLegacyOpenSourceLicenceForRecentPublicProjects, + schema: 20220801155858, feature_category: :projects do context 'when on gitlab.com' do let(:background_migration) { described_class::MIGRATION } let(:migration) { described_class.new } diff --git a/spec/migrations/20220802204737_remove_deactivated_user_highest_role_stats_spec.rb b/spec/migrations/20220802204737_remove_deactivated_user_highest_role_stats_spec.rb index 36c65612bb9..b731a8c8c18 100644 --- a/spec/migrations/20220802204737_remove_deactivated_user_highest_role_stats_spec.rb +++ b/spec/migrations/20220802204737_remove_deactivated_user_highest_role_stats_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' require_migration! -RSpec.describe RemoveDeactivatedUserHighestRoleStats, feature_category: :subscription_cost_management do +RSpec.describe RemoveDeactivatedUserHighestRoleStats, feature_category: :seat_cost_management do let!(:users) { table(:users) } let!(:user_highest_roles) { table(:user_highest_roles) } diff --git a/spec/migrations/20220816163444_update_start_date_for_iterations_cadences_spec.rb b/spec/migrations/20220816163444_update_start_date_for_iterations_cadences_spec.rb index 25b2b5c2e18..0807f5d4e38 100644 --- a/spec/migrations/20220816163444_update_start_date_for_iterations_cadences_spec.rb +++ b/spec/migrations/20220816163444_update_start_date_for_iterations_cadences_spec.rb @@ -31,31 +31,31 @@ RSpec.describe UpdateStartDateForIterationsCadences, :freeze_time, feature_categ before do # Past iteratioin sprints.create!(id: 1, iid: 1, **cadence_params(auto_cadence1), - start_date: Date.current - 1.week, due_date: Date.current - 1.day) + start_date: Date.current - 1.week, due_date: Date.current - 1.day) # Current iteraition sprints.create!(id: 3, iid: 5, **cadence_params(auto_cadence1), - start_date: Date.current, due_date: Date.current + 1.week) + start_date: Date.current, due_date: Date.current + 1.week) # First upcoming iteration sprints.create!(id: 4, iid: 8, **cadence_params(auto_cadence1), - start_date: first_upcoming_start_date, due_date: first_upcoming_start_date + 1.week) + start_date: first_upcoming_start_date, due_date: first_upcoming_start_date + 1.week) # Second upcoming iteration sprints.create!(id: 5, iid: 9, **cadence_params(auto_cadence1), - start_date: first_upcoming_start_date + 2.weeks, due_date: first_upcoming_start_date + 3.weeks) + start_date: first_upcoming_start_date + 2.weeks, due_date: first_upcoming_start_date + 3.weeks) sprints.create!(id: 6, iid: 1, **cadence_params(manual_cadence2), - start_date: Date.current, due_date: Date.current + 1.week) + start_date: Date.current, due_date: Date.current + 1.week) sprints.create!(id: 7, iid: 5, **cadence_params(manual_cadence2), - start_date: Date.current + 2.weeks, due_date: Date.current + 3.weeks) + start_date: Date.current + 2.weeks, due_date: Date.current + 3.weeks) end describe '#up' do it "updates the start date of an automatic cadence to the start date of its first upcoming sprint record." do expect { migration.up } - .to change { auto_cadence1.reload.start_date }.to(first_upcoming_start_date) - .and not_change { auto_cadence2.reload.start_date } # the cadence doesn't have any upcoming iteration. - .and not_change { auto_cadence3.reload.start_date } # the cadence is empty; it has no iterations. - .and not_change { manual_cadence1.reload.start_date } # manual cadence don't need to be touched. - .and not_change { manual_cadence2.reload.start_date } # manual cadence don't need to be touched. + .to change { auto_cadence1.reload.start_date }.to(first_upcoming_start_date) + .and not_change { auto_cadence2.reload.start_date } # the cadence doesn't have any upcoming iteration. + .and not_change { auto_cadence3.reload.start_date } # the cadence is empty; it has no iterations. + .and not_change { manual_cadence1.reload.start_date } # manual cadence don't need to be touched. + .and not_change { manual_cadence2.reload.start_date } # manual cadence don't need to be touched. end end @@ -64,10 +64,10 @@ RSpec.describe UpdateStartDateForIterationsCadences, :freeze_time, feature_categ migration.up expect { migration.down } - .to change { auto_cadence1.reload.start_date }.to(original_cadence_start_date) - .and not_change { auto_cadence2.reload.start_date } # the cadence is empty; it has no iterations. - .and not_change { manual_cadence1.reload.start_date } # manual cadence don't need to be touched. - .and not_change { manual_cadence2.reload.start_date } # manual cadence don't need to be touched. + .to change { auto_cadence1.reload.start_date }.to(original_cadence_start_date) + .and not_change { auto_cadence2.reload.start_date } # the cadence is empty; it has no iterations. + .and not_change { manual_cadence1.reload.start_date } # manual cadence don't need to be touched. + .and not_change { manual_cadence2.reload.start_date } # manual cadence don't need to be touched. end end end diff --git a/spec/migrations/20220819153725_add_vulnerability_advisory_foreign_key_to_sbom_vulnerable_component_versions_spec.rb b/spec/migrations/20220819153725_add_vulnerability_advisory_foreign_key_to_sbom_vulnerable_component_versions_spec.rb index 5a61f49485c..1d18862c8ee 100644 --- a/spec/migrations/20220819153725_add_vulnerability_advisory_foreign_key_to_sbom_vulnerable_component_versions_spec.rb +++ b/spec/migrations/20220819153725_add_vulnerability_advisory_foreign_key_to_sbom_vulnerable_component_versions_spec.rb @@ -5,7 +5,7 @@ require "spec_helper" require_migration! RSpec.describe AddVulnerabilityAdvisoryForeignKeyToSbomVulnerableComponentVersions, -feature_category: :dependency_management do + feature_category: :dependency_management do let(:table) { described_class::SOURCE_TABLE } let(:column) { described_class::COLUMN } let(:foreign_key) { -> { described_class.new.foreign_keys_for(table, column).first } } diff --git a/spec/migrations/20220819162852_add_sbom_component_version_foreign_key_to_sbom_vulnerable_component_versions_spec.rb b/spec/migrations/20220819162852_add_sbom_component_version_foreign_key_to_sbom_vulnerable_component_versions_spec.rb index 999c833f9e3..a280795380d 100644 --- a/spec/migrations/20220819162852_add_sbom_component_version_foreign_key_to_sbom_vulnerable_component_versions_spec.rb +++ b/spec/migrations/20220819162852_add_sbom_component_version_foreign_key_to_sbom_vulnerable_component_versions_spec.rb @@ -5,7 +5,7 @@ require "spec_helper" require_migration! RSpec.describe AddSbomComponentVersionForeignKeyToSbomVulnerableComponentVersions, -feature_category: :dependency_management do + feature_category: :dependency_management do let(:table) { described_class::SOURCE_TABLE } let(:column) { described_class::COLUMN } let(:foreign_key) { -> { described_class.new.foreign_keys_for(table, column).first } } 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 19cf3b2fb69..5cfcb2eb3dd 100644 --- a/spec/migrations/20220921144258_remove_orphan_group_token_users_spec.rb +++ b/spec/migrations/20220921144258_remove_orphan_group_token_users_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' require_migration! RSpec.describe RemoveOrphanGroupTokenUsers, :migration, :sidekiq_inline, -feature_category: :authentication_and_authorization do + feature_category: :system_access do subject(:migration) { described_class.new } let(:users) { table(:users) } @@ -18,12 +18,14 @@ feature_category: :authentication_and_authorization do let!(:valid_used_bot) do create_bot(username: 'used_bot', email: 'used_bot@bot.com').tap do |bot| group = namespaces.create!(type: 'Group', path: 'used_bot_group', name: 'used_bot_group') - members.create!(user_id: bot.id, - source_id: group.id, - member_namespace_id: group.id, - source_type: 'Group', - access_level: 10, - notification_level: 0) + members.create!( + user_id: bot.id, + source_id: group.id, + member_namespace_id: group.id, + source_type: 'Group', + access_level: 10, + notification_level: 0 + ) end end diff --git a/spec/migrations/20220928225711_schedule_update_ci_pipeline_artifacts_locked_status_spec.rb b/spec/migrations/20220928225711_schedule_update_ci_pipeline_artifacts_locked_status_spec.rb index 5c1b5c8f2a7..085e9726663 100644 --- a/spec/migrations/20220928225711_schedule_update_ci_pipeline_artifacts_locked_status_spec.rb +++ b/spec/migrations/20220928225711_schedule_update_ci_pipeline_artifacts_locked_status_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' require_migration! -RSpec.describe ScheduleUpdateCiPipelineArtifactsLockedStatus, migration: :gitlab_ci, - feature_category: :build_artifacts do +RSpec.describe ScheduleUpdateCiPipelineArtifactsLockedStatus, + migration: :gitlab_ci, feature_category: :build_artifacts do let!(:migration) { described_class::MIGRATION } describe '#up' do diff --git a/spec/migrations/20221002234454_finalize_group_member_namespace_id_migration_spec.rb b/spec/migrations/20221002234454_finalize_group_member_namespace_id_migration_spec.rb index 4ff16111417..632b23a8384 100644 --- a/spec/migrations/20221002234454_finalize_group_member_namespace_id_migration_spec.rb +++ b/spec/migrations/20221002234454_finalize_group_member_namespace_id_migration_spec.rb @@ -12,12 +12,16 @@ RSpec.describe FinalizeGroupMemberNamespaceIdMigration, :migration, feature_cate 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('BackfillMemberNamespaceForGroupMembers', :members, :id, []) + expect(runner).to receive(:finalize).with(migration, :members, :id, []) end end end context 'when migration is missing' do + before do + batched_migrations.where(job_class_name: migration).delete_all + end + it 'warns migration not found' do expect(Gitlab::AppLogger) .to receive(:warn).with(/Could not find batched background migration for the given configuration:/) @@ -29,7 +33,7 @@ RSpec.describe FinalizeGroupMemberNamespaceIdMigration, :migration, feature_cate context 'with migration present' do let!(:group_member_namespace_id_backfill) do batched_migrations.create!( - job_class_name: 'BackfillMemberNamespaceForGroupMembers', + job_class_name: migration, table_name: :members, column_name: :id, job_arguments: [], 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 index 6284608becb..d591b370d65 100644 --- 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 @@ -28,10 +28,12 @@ RSpec.describe AddObjectiveAndKeyresultToWorkItemTypes, :migration, feature_cate 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') + 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! @@ -52,15 +54,20 @@ RSpec.describe AddObjectiveAndKeyresultToWorkItemTypes, :migration, feature_cate 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') + 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/20221018193635_ensure_task_note_renaming_background_migration_finished_spec.rb b/spec/migrations/20221018193635_ensure_task_note_renaming_background_migration_finished_spec.rb index 8b599881359..da1df92691e 100644 --- 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 @@ -25,6 +25,10 @@ RSpec.describe EnsureTaskNoteRenamingBackgroundMigrationFinished, :migration, fe end context 'when migration is missing' do + before do + batched_migrations.where(job_class_name: migration).delete_all + end + it 'warns migration not found' do expect(Gitlab::AppLogger) .to receive(:warn).with(/Could not find batched background migration for the given configuration:/) @@ -36,7 +40,7 @@ RSpec.describe EnsureTaskNoteRenamingBackgroundMigrationFinished, :migration, fe context 'with migration present' do let!(:task_renaming_migration) do batched_migrations.create!( - job_class_name: 'RenameTaskSystemNoteToChecklistItem', + job_class_name: migration, table_name: :system_note_metadata, column_name: :id, job_arguments: [], diff --git a/spec/migrations/20221102231130_finalize_backfill_user_details_fields_spec.rb b/spec/migrations/20221102231130_finalize_backfill_user_details_fields_spec.rb index 37bff128edd..da2f4364e5c 100644 --- a/spec/migrations/20221102231130_finalize_backfill_user_details_fields_spec.rb +++ b/spec/migrations/20221102231130_finalize_backfill_user_details_fields_spec.rb @@ -26,6 +26,10 @@ RSpec.describe FinalizeBackfillUserDetailsFields, :migration, feature_category: end context 'when migration is missing' do + before do + batched_migrations.where(job_class_name: migration).delete_all + end + it 'warns migration not found' do expect(Gitlab::AppLogger) .to receive(:warn).with(/Could not find batched background migration for the given configuration:/) diff --git a/spec/migrations/20221104115712_backfill_project_statistics_storage_size_without_uploads_size_spec.rb b/spec/migrations/20221104115712_backfill_project_statistics_storage_size_without_uploads_size_spec.rb index d86720365c4..9658b5a699a 100644 --- a/spec/migrations/20221104115712_backfill_project_statistics_storage_size_without_uploads_size_spec.rb +++ b/spec/migrations/20221104115712_backfill_project_statistics_storage_size_without_uploads_size_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' require_migration! RSpec.describe BackfillProjectStatisticsStorageSizeWithoutUploadsSize, - feature_category: :subscription_cost_management do + feature_category: :consumables_cost_management do let!(:batched_migration) { described_class::MIGRATION_CLASS } it 'does not schedule background jobs when Gitlab.org_or_com? is false' do diff --git a/spec/migrations/20221115173607_ensure_work_item_type_backfill_migration_finished_spec.rb b/spec/migrations/20221115173607_ensure_work_item_type_backfill_migration_finished_spec.rb index e9250625832..d560da40c21 100644 --- a/spec/migrations/20221115173607_ensure_work_item_type_backfill_migration_finished_spec.rb +++ b/spec/migrations/20221115173607_ensure_work_item_type_backfill_migration_finished_spec.rb @@ -13,6 +13,10 @@ RSpec.describe EnsureWorkItemTypeBackfillMigrationFinished, :migration, feature_ describe '#up', :redis do context 'when migration is missing' do + before do + batched_migrations.where(job_class_name: migration_class).delete_all + end + it 'warns migration not found' do expect(Gitlab::AppLogger) .to receive(:warn).with(/Could not find batched background migration for the given configuration:/) diff --git a/spec/migrations/20221209235940_cleanup_o_auth_access_tokens_with_null_expires_in_spec.rb b/spec/migrations/20221209235940_cleanup_o_auth_access_tokens_with_null_expires_in_spec.rb index da6532a822a..e5890ffce17 100644 --- a/spec/migrations/20221209235940_cleanup_o_auth_access_tokens_with_null_expires_in_spec.rb +++ b/spec/migrations/20221209235940_cleanup_o_auth_access_tokens_with_null_expires_in_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' require_migration! -RSpec.describe CleanupOAuthAccessTokensWithNullExpiresIn, feature_category: :authentication_and_authorization do +RSpec.describe CleanupOAuthAccessTokensWithNullExpiresIn, feature_category: :system_access do let(:batched_migration) { described_class::MIGRATION } it 'schedules background jobs for each batch of oauth_access_tokens' do diff --git a/spec/migrations/20221215151822_schedule_backfill_releases_author_id_spec.rb b/spec/migrations/20221215151822_schedule_backfill_releases_author_id_spec.rb index d7aa53ec35b..7cc0bd96a0d 100644 --- a/spec/migrations/20221215151822_schedule_backfill_releases_author_id_spec.rb +++ b/spec/migrations/20221215151822_schedule_backfill_releases_author_id_spec.rb @@ -10,21 +10,27 @@ RSpec.describe ScheduleBackfillReleasesAuthorId, feature_category: :release_orch let(:date_time) { DateTime.now } let!(:batched_migration) { described_class::MIGRATION } let!(:test_user) do - user_table.create!(name: 'test', - email: 'test@example.com', - username: 'test', - projects_limit: 10) + user_table.create!( + name: 'test', + email: 'test@example.com', + username: 'test', + projects_limit: 10 + ) end before do - releases_table.create!(tag: 'tag1', name: 'tag1', - released_at: (date_time - 1.minute), author_id: test_user.id) - releases_table.create!(tag: 'tag2', name: 'tag2', - released_at: (date_time - 2.minutes), author_id: test_user.id) - releases_table.new(tag: 'tag3', name: 'tag3', - released_at: (date_time - 3.minutes), author_id: nil).save!(validate: false) - releases_table.new(tag: 'tag4', name: 'tag4', - released_at: (date_time - 4.minutes), author_id: nil).save!(validate: false) + releases_table.create!( + tag: 'tag1', name: 'tag1', released_at: (date_time - 1.minute), author_id: test_user.id + ) + releases_table.create!( + tag: 'tag2', name: 'tag2', released_at: (date_time - 2.minutes), author_id: test_user.id + ) + releases_table.new( + tag: 'tag3', name: 'tag3', released_at: (date_time - 3.minutes), author_id: nil + ).save!(validate: false) + releases_table.new( + tag: 'tag4', name: 'tag4', released_at: (date_time - 4.minutes), author_id: nil + ).save!(validate: false) end it 'schedules a new batched migration' do diff --git a/spec/migrations/20221221110733_remove_temp_index_for_project_statistics_upload_size_migration_spec.rb b/spec/migrations/20221221110733_remove_temp_index_for_project_statistics_upload_size_migration_spec.rb index 6f9cfe4764a..440a932c76b 100644 --- a/spec/migrations/20221221110733_remove_temp_index_for_project_statistics_upload_size_migration_spec.rb +++ b/spec/migrations/20221221110733_remove_temp_index_for_project_statistics_upload_size_migration_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' require_migration! RSpec.describe RemoveTempIndexForProjectStatisticsUploadSizeMigration, -feature_category: :subscription_cost_management do + feature_category: :consumables_cost_management do let(:table_name) { 'project_statistics' } let(:index_name) { described_class::INDEX_NAME } diff --git a/spec/migrations/20230105172120_sync_new_amount_used_with_amount_used_on_ci_namespace_monthly_usages_table_spec.rb b/spec/migrations/20230105172120_sync_new_amount_used_with_amount_used_on_ci_namespace_monthly_usages_table_spec.rb index aa82ca2661b..70c9c1333b8 100644 --- a/spec/migrations/20230105172120_sync_new_amount_used_with_amount_used_on_ci_namespace_monthly_usages_table_spec.rb +++ b/spec/migrations/20230105172120_sync_new_amount_used_with_amount_used_on_ci_namespace_monthly_usages_table_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' require_migration! RSpec.describe SyncNewAmountUsedWithAmountUsedOnCiNamespaceMonthlyUsagesTable, migration: :gitlab_ci, -feature_category: :continuous_integration do + feature_category: :continuous_integration do let(:namespace_usages) { table(:ci_namespace_monthly_usages) } let(:migration) { described_class.new } diff --git a/spec/migrations/20230118144623_schedule_migration_for_remediation_spec.rb b/spec/migrations/20230118144623_schedule_migration_for_remediation_spec.rb new file mode 100644 index 00000000000..f6d0f32b87c --- /dev/null +++ b/spec/migrations/20230118144623_schedule_migration_for_remediation_spec.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe ScheduleMigrationForRemediation, :migration, feature_category: :vulnerability_management do + let(:migration) { described_class::MIGRATION } + + describe '#up' do + it 'schedules a batched background migration' do + migrate! + + expect(migration).not_to have_scheduled_batched_migration + 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/20230125195503_queue_backfill_compliance_violations_spec.rb b/spec/migrations/20230125195503_queue_backfill_compliance_violations_spec.rb new file mode 100644 index 00000000000..a70f9820855 --- /dev/null +++ b/spec/migrations/20230125195503_queue_backfill_compliance_violations_spec.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe QueueBackfillComplianceViolations, feature_category: :compliance_management do + let(:migration) { described_class::MIGRATION } + + describe '#up' do + it 'schedules background jobs for each batch of merge_request_compliance_violations' do + migrate! + + expect(migration).to( + have_scheduled_batched_migration( + table_name: :merge_requests_compliance_violations, + column_name: :id, + interval: described_class::INTERVAL, + batch_size: described_class::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/backfill_user_namespace_spec.rb b/spec/migrations/20230130182412_schedule_create_vulnerability_links_migration_spec.rb index a58030803b1..58e27379ef7 100644 --- a/spec/migrations/backfill_user_namespace_spec.rb +++ b/spec/migrations/20230130182412_schedule_create_vulnerability_links_migration_spec.rb @@ -3,17 +3,18 @@ require 'spec_helper' require_migration! -RSpec.describe BackfillUserNamespace, feature_category: :subgroups do - let!(:migration) { described_class::MIGRATION } +RSpec.describe ScheduleCreateVulnerabilityLinksMigration, feature_category: :vulnerability_management do + let(:migration) { described_class::MIGRATION } describe '#up' do - it 'schedules background jobs for each batch of namespaces' do + it 'schedules background jobs for each batch of Vulnerabilities::Feedback' do migrate! expect(migration).to have_scheduled_batched_migration( - table_name: :namespaces, + table_name: :vulnerability_feedback, column_name: :id, - interval: described_class::INTERVAL + interval: described_class::DELAY_INTERVAL, + batch_size: described_class::BATCH_SIZE ) end end diff --git a/spec/migrations/20230201171450_finalize_backfill_environment_tier_migration_spec.rb b/spec/migrations/20230201171450_finalize_backfill_environment_tier_migration_spec.rb index 3fc9c7d8af7..e7a78f11f16 100644 --- a/spec/migrations/20230201171450_finalize_backfill_environment_tier_migration_spec.rb +++ b/spec/migrations/20230201171450_finalize_backfill_environment_tier_migration_spec.rb @@ -18,6 +18,10 @@ RSpec.describe FinalizeBackfillEnvironmentTierMigration, :migration, feature_cat end context 'when migration is missing' do + before do + batched_migrations.where(job_class_name: migration).delete_all + end + it 'warns migration not found' do expect(Gitlab::AppLogger) .to receive(:warn).with(/Could not find batched background migration for the given configuration:/) @@ -29,7 +33,7 @@ RSpec.describe FinalizeBackfillEnvironmentTierMigration, :migration, feature_cat context 'with migration present' do let!(:group_member_namespace_id_backfill) do batched_migrations.create!( - job_class_name: 'BackfillEnvironmentTiers', + job_class_name: migration, table_name: :environments, column_name: :id, job_arguments: [], diff --git a/spec/migrations/20230202131928_encrypt_ci_trigger_token_spec.rb b/spec/migrations/20230202131928_encrypt_ci_trigger_token_spec.rb index a8896e7d3cf..597cd7c1581 100644 --- a/spec/migrations/20230202131928_encrypt_ci_trigger_token_spec.rb +++ b/spec/migrations/20230202131928_encrypt_ci_trigger_token_spec.rb @@ -9,14 +9,6 @@ RSpec.describe EncryptCiTriggerToken, migration: :gitlab_ci, feature_category: : let!(: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('EncryptCiTriggerToken', :ci_triggers, :id, []) - end - end - end - context 'with migration present' do let!(:ci_trigger_token_encryption_migration) do batched_migrations.create!( @@ -51,25 +43,6 @@ RSpec.describe EncryptCiTriggerToken, migration: :gitlab_ci, feature_category: : ) 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 - ci_trigger_token_encryption_migration.update!(status: status) - end - - it_behaves_like 'finalizes the migration' - end - end end end diff --git a/spec/migrations/20230202211434_migrate_redis_slot_keys_spec.rb b/spec/migrations/20230202211434_migrate_redis_slot_keys_spec.rb new file mode 100644 index 00000000000..ca2c50241bf --- /dev/null +++ b/spec/migrations/20230202211434_migrate_redis_slot_keys_spec.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe MigrateRedisSlotKeys, :migration, feature_category: :service_ping do + let(:date) { Date.yesterday.strftime('%G-%j') } + let(:week) { Date.yesterday.strftime('%G-%V') } + + before do + allow(described_class::BackupHLLRedisCounter).to receive(:known_events).and_return([{ + redis_slot: 'analytics', + aggregation: 'daily', + name: 'users_viewing_analytics_group_devops_adoption' + }, { + aggregation: 'weekly', + name: 'wiki_action' + }]) + end + + describe "#up" do + it 'rename keys', :aggregate_failures do + expiry_daily = described_class::BackupHLLRedisCounter::DEFAULT_DAILY_KEY_EXPIRY_LENGTH + expiry_weekly = described_class::BackupHLLRedisCounter::DEFAULT_WEEKLY_KEY_EXPIRY_LENGTH + + default_slot = described_class::BackupHLLRedisCounter::REDIS_SLOT + + old_slot_a = "#{date}-users_viewing_{analytics}_group_devops_adoption" + old_slot_b = "{wiki_action}-#{week}" + + new_slot_a = "#{date}-{#{default_slot}}_users_viewing_analytics_group_devops_adoption" + new_slot_b = "{#{default_slot}}_wiki_action-#{week}" + + Gitlab::Redis::HLL.add(key: old_slot_a, value: 1, expiry: expiry_daily) + Gitlab::Redis::HLL.add(key: old_slot_b, value: 1, expiry: expiry_weekly) + + # check that we merge values during migration + # i.e. we dont drop keys created after code deploy but before the migration + Gitlab::Redis::HLL.add(key: new_slot_a, value: 2, expiry: expiry_daily) + Gitlab::Redis::HLL.add(key: new_slot_b, value: 2, expiry: expiry_weekly) + + migrate! + + expect(Gitlab::Redis::HLL.count(keys: new_slot_a)).to eq(2) + expect(Gitlab::Redis::HLL.count(keys: new_slot_b)).to eq(2) + expect(with_redis { |r| r.ttl(new_slot_a) }).to be_within(600).of(expiry_daily) + expect(with_redis { |r| r.ttl(new_slot_b) }).to be_within(600).of(expiry_weekly) + end + end + + def with_redis(&block) + Gitlab::Redis::SharedState.with(&block) + end +end diff --git a/spec/migrations/20230208125736_schedule_migration_for_links_spec.rb b/spec/migrations/20230208125736_schedule_migration_for_links_spec.rb new file mode 100644 index 00000000000..035f13b8309 --- /dev/null +++ b/spec/migrations/20230208125736_schedule_migration_for_links_spec.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe ScheduleMigrationForLinks, :migration, feature_category: :vulnerability_management do + let(:migration) { described_class::MIGRATION } + + describe '#up' do + it 'schedules a batched background migration' do + migrate! + + expect(migration).not_to have_scheduled_batched_migration + 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/20230209222452_schedule_remove_project_group_link_with_missing_groups_spec.rb b/spec/migrations/20230209222452_schedule_remove_project_group_link_with_missing_groups_spec.rb new file mode 100644 index 00000000000..13ae12b2774 --- /dev/null +++ b/spec/migrations/20230209222452_schedule_remove_project_group_link_with_missing_groups_spec.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe ScheduleRemoveProjectGroupLinkWithMissingGroups, feature_category: :subgroups do + let!(:migration) { described_class::MIGRATION } + + describe '#up' do + it 'schedules background migration' do + migrate! + + expect(migration).to have_scheduled_batched_migration( + table_name: :project_group_links, + 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 'removes scheduled background migrations' do + migrate! + schema_migrate_down! + + expect(migration).not_to have_scheduled_batched_migration + end + end +end diff --git a/spec/migrations/20230214181633_finalize_ci_build_needs_big_int_conversion_spec.rb b/spec/migrations/20230214181633_finalize_ci_build_needs_big_int_conversion_spec.rb new file mode 100644 index 00000000000..638fe2a12d5 --- /dev/null +++ b/spec/migrations/20230214181633_finalize_ci_build_needs_big_int_conversion_spec.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe FinalizeCiBuildNeedsBigIntConversion, migration: :gitlab_ci, feature_category: :continuous_integration do + describe '#up' do + using RSpec::Parameterized::TableSyntax + + where(:dot_com, :dev_or_test, :jh, :expectation) do + true | true | true | :not_to + true | false | true | :not_to + false | true | true | :not_to + false | false | true | :not_to + true | true | false | :to + true | false | false | :to + false | true | false | :to + false | false | false | :not_to + end + + with_them do + it 'ensures the migration is completed for GitLab.com, dev, or test' do + allow(Gitlab).to receive(:com?).and_return(dot_com) + allow(Gitlab).to receive(:dev_or_test_env?).and_return(dev_or_test) + allow(Gitlab).to receive(:jh?).and_return(jh) + + migration_arguments = { + job_class_name: 'CopyColumnUsingBackgroundMigrationJob', + table_name: 'ci_build_needs', + column_name: 'id', + job_arguments: [['id'], ['id_convert_to_bigint']] + } + + expect(described_class).send( + expectation, + ensure_batched_background_migration_is_finished_for(migration_arguments) + ) + + migrate! + end + end + end +end diff --git a/spec/migrations/20230220102212_swap_columns_ci_build_needs_big_int_conversion_spec.rb b/spec/migrations/20230220102212_swap_columns_ci_build_needs_big_int_conversion_spec.rb new file mode 100644 index 00000000000..1c21047c0c3 --- /dev/null +++ b/spec/migrations/20230220102212_swap_columns_ci_build_needs_big_int_conversion_spec.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe SwapColumnsCiBuildNeedsBigIntConversion, feature_category: :continuous_integration do + describe '#up' do + using RSpec::Parameterized::TableSyntax + + where(:dot_com, :dev_or_test, :jh, :swap) do + true | true | true | false + true | false | true | false + false | true | true | false + false | false | true | false + true | true | false | true + true | false | false | true + false | true | false | true + false | false | false | false + end + + with_them do + before do + connection = described_class.new.connection + connection.execute('ALTER TABLE ci_build_needs ALTER COLUMN id TYPE integer') + connection.execute('ALTER TABLE ci_build_needs ALTER COLUMN id_convert_to_bigint TYPE bigint') + end + + it 'swaps the integer and bigint columns for GitLab.com, dev, or test' do + allow(Gitlab).to receive(:com?).and_return(dot_com) + allow(Gitlab).to receive(:dev_or_test_env?).and_return(dev_or_test) + allow(Gitlab).to receive(:jh?).and_return(jh) + + ci_build_needs = table(:ci_build_needs) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + ci_build_needs.reset_column_information + + expect(ci_build_needs.columns.find { |c| c.name == 'id' }.sql_type).to eq('integer') + expect(ci_build_needs.columns.find { |c| c.name == 'id_convert_to_bigint' }.sql_type).to eq('bigint') + } + + migration.after -> { + ci_build_needs.reset_column_information + + if swap + expect(ci_build_needs.columns.find { |c| c.name == 'id' }.sql_type).to eq('bigint') + expect(ci_build_needs.columns.find { |c| c.name == 'id_convert_to_bigint' }.sql_type).to eq('integer') + else + expect(ci_build_needs.columns.find { |c| c.name == 'id' }.sql_type).to eq('integer') + expect(ci_build_needs.columns.find { |c| c.name == 'id_convert_to_bigint' }.sql_type).to eq('bigint') + end + } + end + end + end + end + end +end diff --git a/spec/migrations/20230221093533_add_tmp_partial_index_on_vulnerability_report_types_spec.rb b/spec/migrations/20230221093533_add_tmp_partial_index_on_vulnerability_report_types_spec.rb new file mode 100644 index 00000000000..cbf6b2882c4 --- /dev/null +++ b/spec/migrations/20230221093533_add_tmp_partial_index_on_vulnerability_report_types_spec.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require "spec_helper" + +require_migration! + +RSpec.describe AddTmpPartialIndexOnVulnerabilityReportTypes, feature_category: :vulnerability_management do + let(:async_index) { Gitlab::Database::AsyncIndexes::PostgresAsyncIndex } + let(:index_name) { described_class::INDEX_NAME } + + it "schedules the index" do + reversible_migration do |migration| + migration.before -> do + expect(async_index.where(name: index_name).count).to be(0) + end + + migration.after -> do + expect(async_index.where(name: index_name).count).to be(1) + end + end + end +end diff --git a/spec/migrations/20230221214519_remove_incorrectly_onboarded_namespaces_from_onboarding_progress_spec.rb b/spec/migrations/20230221214519_remove_incorrectly_onboarded_namespaces_from_onboarding_progress_spec.rb new file mode 100644 index 00000000000..be49a3e919d --- /dev/null +++ b/spec/migrations/20230221214519_remove_incorrectly_onboarded_namespaces_from_onboarding_progress_spec.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe RemoveIncorrectlyOnboardedNamespacesFromOnboardingProgress, feature_category: :onboarding do + let(:onboarding_progresses) { table(:onboarding_progresses) } + let(:namespaces) { table(:namespaces) } + let(:projects) { table(:projects) } + + # namespace to keep with name Learn Gitlab + let(:namespace1) { namespaces.create!(name: 'namespace1', type: 'Group', path: 'namespace1') } + let!(:onboard_keep_1) { onboarding_progresses.create!(namespace_id: namespace1.id) } + let!(:proj1) do + proj_namespace = namespaces.create!(name: 'proj1', path: 'proj1', type: 'Project', parent_id: namespace1.id) + projects.create!(name: 'project', namespace_id: namespace1.id, project_namespace_id: proj_namespace.id) + end + + let!(:learn_gitlab) do + proj_namespace = namespaces.create!(name: 'projlg1', path: 'projlg1', type: 'Project', parent_id: namespace1.id) + projects.create!(name: 'Learn GitLab', namespace_id: namespace1.id, project_namespace_id: proj_namespace.id) + end + + # namespace to keep with name Learn GitLab - Ultimate trial + let(:namespace2) { namespaces.create!(name: 'namespace2', type: 'Group', path: 'namespace2') } + let!(:onboard_keep_2) { onboarding_progresses.create!(namespace_id: namespace2.id) } + let!(:proj2) do + proj_namespace = namespaces.create!(name: 'proj2', path: 'proj2', type: 'Project', parent_id: namespace2.id) + projects.create!(name: 'project', namespace_id: namespace2.id, project_namespace_id: proj_namespace.id) + end + + let!(:learn_gitlab2) do + proj_namespace = namespaces.create!(name: 'projlg2', path: 'projlg2', type: 'Project', parent_id: namespace2.id) + projects.create!( + name: 'Learn GitLab - Ultimate trial', + namespace_id: namespace2.id, + project_namespace_id: proj_namespace.id + ) + end + + # namespace to remove without learn gitlab project + let(:namespace3) { namespaces.create!(name: 'namespace3', type: 'Group', path: 'namespace3') } + let!(:onboarding_to_delete) { onboarding_progresses.create!(namespace_id: namespace3.id) } + let!(:proj3) do + proj_namespace = namespaces.create!(name: 'proj3', path: 'proj3', type: 'Project', parent_id: namespace3.id) + projects.create!(name: 'project', namespace_id: namespace3.id, project_namespace_id: proj_namespace.id) + end + + # namespace to remove without any projects + let(:namespace4) { namespaces.create!(name: 'namespace4', type: 'Group', path: 'namespace4') } + let!(:onboarding_to_delete_without_project) { onboarding_progresses.create!(namespace_id: namespace4.id) } + + describe '#up' do + it 'deletes the onboarding for namespaces without learn gitlab' do + expect { migrate! }.to change { onboarding_progresses.count }.by(-2) + expect(onboarding_progresses.all).to contain_exactly(onboard_keep_1, onboard_keep_2) + end + end +end diff --git a/spec/migrations/20230223065753_finalize_nullify_creator_id_of_orphaned_projects_spec.rb b/spec/migrations/20230223065753_finalize_nullify_creator_id_of_orphaned_projects_spec.rb new file mode 100644 index 00000000000..e4adf3ca540 --- /dev/null +++ b/spec/migrations/20230223065753_finalize_nullify_creator_id_of_orphaned_projects_spec.rb @@ -0,0 +1,97 @@ +# frozen_string_literal: true + +require 'spec_helper' + +require_migration! + +RSpec.describe FinalizeNullifyCreatorIdOfOrphanedProjects, :migration, feature_category: :projects do + let(:batched_migrations) { table(:batched_background_migrations) } + let(:batch_failed_status) { 2 } + let(:batch_finalized_status) { 3 } + + let!(:migration) { described_class::MIGRATION } + + describe '#up' do + shared_examples 'finalizes the migration' do + it 'finalizes the migration' do + expect do + migrate! + + migration_record.reload + failed_job.reload + end.to change { migration_record.status }.from(migration_record.status).to(3).and( + change { failed_job.status }.from(batch_failed_status).to(batch_finalized_status) + ) + end + end + + context 'when migration is missing' do + before do + batched_migrations.where(job_class_name: migration).delete_all + end + + 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!(:migration_record) do + batched_migrations.create!( + job_class_name: migration, + table_name: :projects, + column_name: :id, + job_arguments: [], + interval: 2.minutes, + min_value: 1, + max_value: 2, + batch_size: 1000, + sub_batch_size: 500, + max_batch_size: 5000, + 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: migration_record.id, + status: batch_failed_status, + min_value: 1, + max_value: 10, + attempts: 2, + batch_size: 100, + sub_batch_size: 10 + ) + end + + before do + migration_record.update!(status: status) + end + + it_behaves_like 'finalizes the migration' + end + end + end + end +end diff --git a/spec/migrations/20230224085743_update_issues_internal_id_scope_spec.rb b/spec/migrations/20230224085743_update_issues_internal_id_scope_spec.rb new file mode 100644 index 00000000000..7c7b58c7f0e --- /dev/null +++ b/spec/migrations/20230224085743_update_issues_internal_id_scope_spec.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe UpdateIssuesInternalIdScope, feature_category: :team_planning do + describe '#up' do + it 'schedules background migration' do + migrate! + + expect(described_class::MIGRATION).to have_scheduled_batched_migration( + table_name: :internal_ids, + column_name: :id, + interval: described_class::INTERVAL) + end + end + + describe '#down' do + it 'does not schedule background migration' do + schema_migrate_down! + + expect(described_class::MIGRATION).not_to have_scheduled_batched_migration( + table_name: :internal_ids, + column_name: :id, + interval: described_class::INTERVAL) + end + end +end diff --git a/spec/migrations/20230224144233_migrate_evidences_from_raw_metadata_spec.rb b/spec/migrations/20230224144233_migrate_evidences_from_raw_metadata_spec.rb new file mode 100644 index 00000000000..6610f70be2b --- /dev/null +++ b/spec/migrations/20230224144233_migrate_evidences_from_raw_metadata_spec.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe MigrateEvidencesFromRawMetadata, :migration, feature_category: :vulnerability_management do + let(:migration) { described_class::MIGRATION } + + describe '#up' do + it 'schedules a batched background migration' do + migrate! + + expect(migration).not_to have_scheduled_batched_migration + 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/20230228142350_add_notifications_work_item_widget_spec.rb b/spec/migrations/20230228142350_add_notifications_work_item_widget_spec.rb new file mode 100644 index 00000000000..7161ca35edd --- /dev/null +++ b/spec/migrations/20230228142350_add_notifications_work_item_widget_spec.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe AddNotificationsWorkItemWidget, :migration, feature_category: :team_planning do + it_behaves_like 'migration that adds widget to work items definitions', widget_name: 'Notifications' +end diff --git a/spec/migrations/20230302185739_queue_fix_vulnerability_reads_has_issues_spec.rb b/spec/migrations/20230302185739_queue_fix_vulnerability_reads_has_issues_spec.rb new file mode 100644 index 00000000000..54b1e231db2 --- /dev/null +++ b/spec/migrations/20230302185739_queue_fix_vulnerability_reads_has_issues_spec.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe QueueFixVulnerabilityReadsHasIssues, feature_category: :vulnerability_management do + let!(: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: :vulnerability_issue_links, + column_name: :vulnerability_id, + interval: described_class::DELAY_INTERVAL, + batch_size: described_class::BATCH_SIZE, + sub_batch_size: described_class::SUB_BATCH_SIZE, + max_batch_size: described_class::MAX_BATCH_SIZE + ) + } + end + end +end diff --git a/spec/migrations/20230302811133_re_migrate_redis_slot_keys_spec.rb b/spec/migrations/20230302811133_re_migrate_redis_slot_keys_spec.rb new file mode 100644 index 00000000000..4c6d4907c29 --- /dev/null +++ b/spec/migrations/20230302811133_re_migrate_redis_slot_keys_spec.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe ReMigrateRedisSlotKeys, :migration, feature_category: :service_ping do + let(:date) { Date.yesterday.strftime('%G-%j') } + let(:week) { Date.yesterday.strftime('%G-%V') } + let(:known_events) do + [ + { + redis_slot: 'analytics', + aggregation: 'daily', + name: 'users_viewing_analytics_group_devops_adoption' + }, { + aggregation: 'weekly', + name: 'wiki_action' + }, { + aggregation: 'weekly', + name: 'non_existing_event' + }, { + aggregation: 'weekly', + name: 'event_without_expiry' + } + ] + end + + describe "#up" do + it 'rename keys', :aggregate_failures do + allow(Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:known_events) + .and_return(known_events) + + expiry_daily = Gitlab::UsageDataCounters::HLLRedisCounter::DEFAULT_DAILY_KEY_EXPIRY_LENGTH + expiry_weekly = Gitlab::UsageDataCounters::HLLRedisCounter::DEFAULT_WEEKLY_KEY_EXPIRY_LENGTH + + default_slot = Gitlab::UsageDataCounters::HLLRedisCounter::REDIS_SLOT + + old_slot_a = "#{date}-users_viewing_{analytics}_group_devops_adoption" + old_slot_b = "{wiki_action}-#{week}" + old_slot_without_expiry = "{event_without_expiry}-#{week}" + + new_slot_a = "#{date}-{#{default_slot}}_users_viewing_analytics_group_devops_adoption" + new_slot_b = "{#{default_slot}}_wiki_action-#{week}" + new_slot_without_expiry = "{#{default_slot}}_event_without_expiry-#{week}" + + Gitlab::Redis::HLL.add(key: old_slot_a, value: 1, expiry: expiry_daily) + Gitlab::Redis::HLL.add(key: old_slot_b, value: 1, expiry: expiry_weekly) + Gitlab::Redis::HLL.add(key: old_slot_a, value: 2, expiry: expiry_daily) + Gitlab::Redis::HLL.add(key: old_slot_b, value: 2, expiry: expiry_weekly) + Gitlab::Redis::HLL.add(key: old_slot_b, value: 2, expiry: expiry_weekly) + Gitlab::Redis::SharedState.with { |redis| redis.pfadd(old_slot_without_expiry, 1) } + + # check that we merge values during migration + # i.e. we dont drop keys created after code deploy but before the migration + Gitlab::Redis::HLL.add(key: new_slot_a, value: 3, expiry: expiry_daily) + Gitlab::Redis::HLL.add(key: new_slot_b, value: 3, expiry: expiry_weekly) + Gitlab::Redis::HLL.add(key: new_slot_without_expiry, value: 2, expiry: expiry_weekly) + + migrate! + + expect(Gitlab::Redis::HLL.count(keys: new_slot_a)).to eq(3) + expect(Gitlab::Redis::HLL.count(keys: new_slot_b)).to eq(3) + expect(Gitlab::Redis::HLL.count(keys: new_slot_without_expiry)).to eq(2) + expect(with_redis { |r| r.ttl(new_slot_a) }).to be_within(600).of(expiry_daily) + expect(with_redis { |r| r.ttl(new_slot_b) }).to be_within(600).of(expiry_weekly) + expect(with_redis { |r| r.ttl(new_slot_without_expiry) }).to be_within(600).of(expiry_weekly) + end + + it 'runs without errors' do + expect { migrate! }.not_to raise_error + end + end + + def with_redis(&block) + Gitlab::Redis::SharedState.with(&block) + end +end diff --git a/spec/migrations/20230303105806_queue_delete_orphaned_packages_dependencies_spec.rb b/spec/migrations/20230303105806_queue_delete_orphaned_packages_dependencies_spec.rb new file mode 100644 index 00000000000..7fe90a08763 --- /dev/null +++ b/spec/migrations/20230303105806_queue_delete_orphaned_packages_dependencies_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe QueueDeleteOrphanedPackagesDependencies, feature_category: :package_registry do + let!(: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: :packages_dependencies, + column_name: :id, + interval: described_class::DELAY_INTERVAL, + batch_size: described_class::BATCH_SIZE, + sub_batch_size: described_class::SUB_BATCH_SIZE + ) + } + end + end +end diff --git a/spec/migrations/20230309071242_delete_security_policy_bot_users_spec.rb b/spec/migrations/20230309071242_delete_security_policy_bot_users_spec.rb new file mode 100644 index 00000000000..4dd44cad158 --- /dev/null +++ b/spec/migrations/20230309071242_delete_security_policy_bot_users_spec.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe DeleteSecurityPolicyBotUsers, feature_category: :security_policy_management do + let(:users) { table(:users) } + + before do + users.create!(user_type: 10, projects_limit: 0, email: 'security_policy_bot@example.com') + users.create!(user_type: 1, projects_limit: 0, email: 'support_bot@example.com') + users.create!(projects_limit: 0, email: 'human@example.com') + end + + describe '#up' do + it 'deletes security_policy_bot users' do + expect { migrate! }.to change { users.count }.by(-1) + + expect(users.where(user_type: 10).count).to eq(0) + expect(users.where(user_type: 1).count).to eq(1) + expect(users.where(user_type: nil).count).to eq(1) + end + end +end diff --git a/spec/migrations/20230313142631_backfill_ml_candidates_package_id_spec.rb b/spec/migrations/20230313142631_backfill_ml_candidates_package_id_spec.rb new file mode 100644 index 00000000000..57ddb0504ec --- /dev/null +++ b/spec/migrations/20230313142631_backfill_ml_candidates_package_id_spec.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +require 'spec_helper' + +require_migration! + +RSpec.describe BackfillMlCandidatesPackageId, feature_category: :mlops do + let(:migration) { described_class.new } + + let(:projects) { table(:projects) } + let(:namespaces) { table(:namespaces) } + let(:ml_experiments) { table(:ml_experiments) } + let(:ml_candidates) { table(:ml_candidates) } + let(:packages_packages) { table(:packages_packages) } + + let(:namespace) { namespaces.create!(name: 'foo', path: 'foo') } + let(:project) { projects.create!(project_namespace_id: namespace.id, namespace_id: namespace.id) } + let(:experiment) { ml_experiments.create!(project_id: project.id, iid: 1, name: 'experiment') } + let!(:candidate1) { ml_candidates.create!(experiment_id: experiment.id, iid: SecureRandom.uuid) } + let!(:candidate2) { ml_candidates.create!(experiment_id: experiment.id, iid: SecureRandom.uuid) } + let!(:package1) do + packages_packages.create!( + project_id: project.id, + name: "ml_candidate_#{candidate1.id}", + version: "-", + package_type: 7 + ) + end + + let!(:package2) do + packages_packages.create!( + project_id: project.id, + name: "ml_candidate_1000", + version: "-", + package_type: 7) + end + + let!(:package3) do + packages_packages.create!( + project_id: project.id, + name: "ml_candidate_abcde", + version: "-", + package_type: 7 + ) + end + + describe '#up' do + it 'sets the correct package_ids with idempotency', :aggregate_failures do + migration.up + + expect(candidate1.reload.package_id).to be(package1.id) + expect(candidate2.reload.package_id).to be(nil) + + migration.down + migration.up + + expect(candidate1.reload.package_id).to be(package1.id) + expect(candidate2.reload.package_id).to be(nil) + end + end +end diff --git a/spec/migrations/20230313150531_reschedule_migration_for_remediation_spec.rb b/spec/migrations/20230313150531_reschedule_migration_for_remediation_spec.rb new file mode 100644 index 00000000000..00f0836285b --- /dev/null +++ b/spec/migrations/20230313150531_reschedule_migration_for_remediation_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe RescheduleMigrationForRemediation, :migration, feature_category: :vulnerability_management 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: :vulnerability_occurrences, + column_name: :id, + interval: described_class::DELAY_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 + migrate! + schema_migrate_down! + + expect(migration).not_to have_scheduled_batched_migration + end + end +end diff --git a/spec/migrations/20230314144640_reschedule_migration_for_links_spec.rb b/spec/migrations/20230314144640_reschedule_migration_for_links_spec.rb new file mode 100644 index 00000000000..b28b1ea0730 --- /dev/null +++ b/spec/migrations/20230314144640_reschedule_migration_for_links_spec.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe RescheduleMigrationForLinks, :migration, feature_category: :vulnerability_management do + let(:migration) { described_class::MIGRATION } + + describe '#up' do + it 'schedules a batched background migration' do + migrate! + + expect(migration).not_to have_scheduled_batched_migration + 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/20230317004428_migrate_daily_redis_hll_events_to_weekly_aggregation_spec.rb b/spec/migrations/20230317004428_migrate_daily_redis_hll_events_to_weekly_aggregation_spec.rb new file mode 100644 index 00000000000..86787273fbc --- /dev/null +++ b/spec/migrations/20230317004428_migrate_daily_redis_hll_events_to_weekly_aggregation_spec.rb @@ -0,0 +1,124 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe MigrateDailyRedisHllEventsToWeeklyAggregation, :migration, :clean_gitlab_redis_cache, feature_category: :service_ping do + it 'calls HLLRedisCounter.known_events to get list of events' do + expect(Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:known_events).and_call_original.at_least(1).time + + migrate! + end + + describe '#redis_key' do + let(:date) { Date.today } + + context 'with daily aggregation' do + let(:date_formatted) { date.strftime('%G-%j') } + let(:event) { { aggregation: 'daily', name: 'wiki_action' } } + + it 'returns correct key' do + existing_key = "#{date_formatted}-{hll_counters}_wiki_action" + + expect(described_class.new.redis_key(event, date, event[:aggregation])).to eq(existing_key) + end + end + + context 'with weekly aggregation' do + let(:event) { { aggregation: 'weekly', name: 'wiki_action' } } + + it 'returns correct key' do + existing_key = Gitlab::UsageDataCounters::HLLRedisCounter.send(:redis_key, event, date) + + expect(described_class.new.redis_key(event, date, event[:aggregation])).to eq(existing_key) + end + end + end + + context 'with weekly events' do + let(:events) { [{ aggregation: 'weekly', name: 'wiki_action' }] } + + before do + allow(Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:known_events).and_return(events) + end + + it 'does not migrate weekly events' do + Gitlab::Redis::SharedState.with do |redis| + expect(redis).not_to receive(:pfmerge) + expect(redis).not_to receive(:expire) + end + + migrate! + end + end + + context 'with daily events' do + let(:daily_expiry) { Gitlab::UsageDataCounters::HLLRedisCounter::DEFAULT_DAILY_KEY_EXPIRY_LENGTH } + let(:weekly_expiry) { Gitlab::UsageDataCounters::HLLRedisCounter::DEFAULT_WEEKLY_KEY_EXPIRY_LENGTH } + + it 'doesnt override events from migrated keys (code deployed before migration)' do + events = [{ aggregation: 'daily', name: 'users_viewing_analytics' }, + { aggregation: 'weekly', name: 'users_viewing_analytics' }] + allow(Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:known_events).and_return(events) + + day = (Date.today - 1.week).beginning_of_week + daily_event = events.first + key_daily1 = Gitlab::UsageDataCounters::HLLRedisCounter.send(:redis_key, daily_event, day) + Gitlab::Redis::HLL.add(key: key_daily1, value: 1, expiry: daily_expiry) + key_daily2 = Gitlab::UsageDataCounters::HLLRedisCounter.send(:redis_key, daily_event, day + 2.days) + Gitlab::Redis::HLL.add(key: key_daily2, value: 2, expiry: daily_expiry) + key_daily3 = Gitlab::UsageDataCounters::HLLRedisCounter.send(:redis_key, daily_event, day + 5.days) + Gitlab::Redis::HLL.add(key: key_daily3, value: 3, expiry: daily_expiry) + + # the same event but with weekly aggregation and pre-Redis migration + weekly_event = events.second + key_weekly = Gitlab::UsageDataCounters::HLLRedisCounter.send(:redis_key, weekly_event, day + 5.days) + Gitlab::Redis::HLL.add(key: key_weekly, value: 3, expiry: weekly_expiry) + + migrate! + + expect(Gitlab::Redis::HLL.count(keys: key_weekly)).to eq(3) + end + + it 'migrates with correct parameters', :aggregate_failures do + events = [{ aggregation: 'daily', name: 'users_viewing_analytics_group_devops_adoption' }] + allow(Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:known_events).and_return(events) + + event = events.first.dup.tap { |e| e[:aggregation] = 'weekly' } + # For every day in the last 30 days, add a value to the daily key with daily expiry (including today) + 31.times do |i| + key = Gitlab::UsageDataCounters::HLLRedisCounter.send(:redis_key, event, Date.today - i.days) + Gitlab::Redis::HLL.add(key: key, value: i, expiry: daily_expiry) + end + + migrate! + + new_key = Gitlab::UsageDataCounters::HLLRedisCounter.send(:redis_key, event, Date.today) + # for the current week we should have value eq to the day of the week (ie. 1 for Monday, 2 for Tuesday, etc.) + first_week_days = Date.today.cwday + expect(Gitlab::Redis::HLL.count(keys: new_key)).to eq(first_week_days) + expect(with_redis { |r| r.ttl(new_key) }).to be_within(600).of(weekly_expiry) + + full_weeks = (31 - first_week_days) / 7 + # for the next full weeks we should have value eq to 7 (ie. 7 days in a week) + (1..full_weeks).each do |i| + new_key = Gitlab::UsageDataCounters::HLLRedisCounter.send(:redis_key, event, Date.today - i.weeks) + expect(Gitlab::Redis::HLL.count(keys: new_key)).to eq(7) + expect(with_redis { |r| r.ttl(new_key) }).to be_within(600).of(weekly_expiry) + end + + # for the last week we should have value eq to amount of rest of the days affected + last_week_days = 31 - ((full_weeks * 7) + first_week_days) + unless last_week_days.zero? + last_week = full_weeks + 1 + new_key = Gitlab::UsageDataCounters::HLLRedisCounter.send(:redis_key, event, Date.today - last_week.weeks) + expect(Gitlab::Redis::HLL.count(keys: new_key)).to eq(last_week_days) + expect(with_redis { |r| r.ttl(new_key) }).to be_within(600).of(weekly_expiry) + end + end + end + + def with_redis(&block) + Gitlab::Redis::SharedState.with(&block) + end +end diff --git a/spec/migrations/20230317162059_add_current_user_todos_work_item_widget_spec.rb b/spec/migrations/20230317162059_add_current_user_todos_work_item_widget_spec.rb new file mode 100644 index 00000000000..1df80a519f2 --- /dev/null +++ b/spec/migrations/20230317162059_add_current_user_todos_work_item_widget_spec.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe AddCurrentUserTodosWorkItemWidget, :migration, feature_category: :team_planning do + it_behaves_like 'migration that adds widget to work items definitions', widget_name: 'Current user todos' +end diff --git a/spec/migrations/20230321153035_add_package_id_created_at_desc_index_to_package_files_spec.rb b/spec/migrations/20230321153035_add_package_id_created_at_desc_index_to_package_files_spec.rb new file mode 100644 index 00000000000..68f3b1f23a9 --- /dev/null +++ b/spec/migrations/20230321153035_add_package_id_created_at_desc_index_to_package_files_spec.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe AddPackageIdCreatedAtDescIndexToPackageFiles, feature_category: :package_registry do + it 'correctly migrates up and down' do + reversible_migration do |migration| + migration.before -> { + expect(ActiveRecord::Base.connection.indexes('packages_package_files').map(&:name)) + .not_to include('index_packages_package_files_on_package_id_and_created_at_desc') + } + + migration.after -> { + expect(ActiveRecord::Base.connection.indexes('packages_package_files').map(&:name)) + .to include('index_packages_package_files_on_package_id_and_created_at_desc') + } + end + end +end diff --git a/spec/migrations/20230321163947_backfill_ml_candidates_project_id_spec.rb b/spec/migrations/20230321163947_backfill_ml_candidates_project_id_spec.rb new file mode 100644 index 00000000000..da76794a74c --- /dev/null +++ b/spec/migrations/20230321163947_backfill_ml_candidates_project_id_spec.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +require 'spec_helper' + +require_migration! + +RSpec.describe BackfillMlCandidatesProjectId, feature_category: :mlops do + let(:migration) { described_class.new } + + let(:projects) { table(:projects) } + let(:namespaces) { table(:namespaces) } + let(:ml_experiments) { table(:ml_experiments) } + let(:ml_candidates) { table(:ml_candidates) } + + let(:namespace1) { namespaces.create!(name: 'foo', path: 'foo') } + let(:namespace2) { namespaces.create!(name: 'bar', path: 'bar') } + let(:project1) { projects.create!(project_namespace_id: namespace1.id, namespace_id: namespace1.id) } + let(:project2) { projects.create!(project_namespace_id: namespace2.id, namespace_id: namespace2.id) } + let(:experiment1) { ml_experiments.create!(project_id: project1.id, iid: 1, name: 'experiment') } + let(:experiment2) { ml_experiments.create!(project_id: project2.id, iid: 1, name: 'experiment') } + let!(:candidate1) do + ml_candidates.create!(experiment_id: experiment1.id, project_id: nil, eid: SecureRandom.uuid) + end + + let!(:candidate2) do + ml_candidates.create!(experiment_id: experiment2.id, project_id: nil, eid: SecureRandom.uuid) + end + + let!(:candidate3) do + ml_candidates.create!(experiment_id: experiment1.id, project_id: project1.id, eid: SecureRandom.uuid) + end + + describe '#up' do + it 'sets the correct project_id with idempotency', :aggregate_failures do + migration.up + + expect(candidate1.reload.project_id).to be(project1.id) + expect(candidate2.reload.project_id).to be(project2.id) + # in case we have candidates added between the column addition and the migration + expect(candidate3.reload.project_id).to be(project1.id) + + migration.down + migration.up + + expect(candidate1.reload.project_id).to be(project1.id) + expect(candidate2.reload.project_id).to be(project2.id) + expect(candidate3.reload.project_id).to be(project1.id) + end + end +end diff --git a/spec/migrations/20230321170823_backfill_ml_candidates_internal_id_spec.rb b/spec/migrations/20230321170823_backfill_ml_candidates_internal_id_spec.rb new file mode 100644 index 00000000000..c8f7b19490a --- /dev/null +++ b/spec/migrations/20230321170823_backfill_ml_candidates_internal_id_spec.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +require 'spec_helper' + +require_migration! + +RSpec.describe BackfillMlCandidatesInternalId, feature_category: :mlops do + let(:migration) { described_class.new } + + let(:projects) { table(:projects) } + let(:namespaces) { table(:namespaces) } + let(:ml_experiments) { table(:ml_experiments) } + let(:ml_candidates) { table(:ml_candidates) } + + let(:namespace1) { namespaces.create!(name: 'foo', path: 'foo') } + let(:namespace2) { namespaces.create!(name: 'bar', path: 'bar') } + let(:project1) { projects.create!(project_namespace_id: namespace1.id, namespace_id: namespace1.id) } + let(:project2) { projects.create!(project_namespace_id: namespace2.id, namespace_id: namespace2.id) } + let(:experiment1) { ml_experiments.create!(project_id: project1.id, iid: 1, name: 'experiment1') } + let(:experiment2) { ml_experiments.create!(project_id: project1.id, iid: 2, name: 'experiment2') } + let(:experiment3) { ml_experiments.create!(project_id: project2.id, iid: 1, name: 'experiment3') } + + let!(:candidate1) do + ml_candidates.create!(experiment_id: experiment1.id, project_id: project1.id, eid: SecureRandom.uuid) + end + + let!(:candidate2) do + ml_candidates.create!(experiment_id: experiment2.id, project_id: project1.id, eid: SecureRandom.uuid) + end + + let!(:candidate3) do + ml_candidates.create!(experiment_id: experiment1.id, project_id: project1.id, eid: SecureRandom.uuid) + end + + let!(:candidate4) do + ml_candidates.create!(experiment_id: experiment1.id, project_id: project1.id, internal_id: 1, + eid: SecureRandom.uuid) + end + + let!(:candidate5) do + ml_candidates.create!(experiment_id: experiment3.id, project_id: project2.id, eid: SecureRandom.uuid) + end + + describe '#up' do + it 'sets the correct project_id with idempotency', :aggregate_failures do + migration.up + + expect(candidate4.reload.internal_id).to be(1) # candidate 4 already has an internal_id + expect(candidate1.reload.internal_id).to be(2) + expect(candidate2.reload.internal_id).to be(3) + expect(candidate3.reload.internal_id).to be(4) + expect(candidate5.reload.internal_id).to be(1) # candidate 5 is a different project + + migration.down + migration.up + + expect(candidate4.reload.internal_id).to be(1) + expect(candidate1.reload.internal_id).to be(2) + expect(candidate2.reload.internal_id).to be(3) + expect(candidate3.reload.internal_id).to be(4) + expect(candidate5.reload.internal_id).to be(1) + end + end +end diff --git a/spec/migrations/20230322085041_remove_user_namespace_records_from_vsa_aggregation_spec.rb b/spec/migrations/20230322085041_remove_user_namespace_records_from_vsa_aggregation_spec.rb new file mode 100644 index 00000000000..e5f64ef2e70 --- /dev/null +++ b/spec/migrations/20230322085041_remove_user_namespace_records_from_vsa_aggregation_spec.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe RemoveUserNamespaceRecordsFromVsaAggregation, + migration: :gitlab_main, + feature_category: :value_stream_management do + let(:migration) { described_class::MIGRATION } + let!(:namespaces) { table(:namespaces) } + let!(:aggregations) { table(:analytics_cycle_analytics_aggregations) } + + let!(:group) { namespaces.create!(name: 'aaa', path: 'aaa', type: 'Group') } + let!(:user_namespace) { namespaces.create!(name: 'ccc', path: 'ccc', type: 'User') } + let!(:project_namespace) { namespaces.create!(name: 'bbb', path: 'bbb', type: 'Project') } + + let!(:group_aggregation) { aggregations.create!(group_id: group.id) } + let!(:user_namespace_aggregation) { aggregations.create!(group_id: user_namespace.id) } + let!(:project_namespace_aggregation) { aggregations.create!(group_id: project_namespace.id) } + + describe '#up' do + it 'deletes the non-group namespace aggregation records' do + stub_const('RemoveUserNamespaceRecordsFromVsaAggregation::BATCH_SIZE', 1) + + expect { migrate! }.to change { + aggregations.order(:group_id) + }.from([group_aggregation, user_namespace_aggregation, + project_namespace_aggregation]).to([group_aggregation]) + end + end + + describe '#down' do + it 'does nothing' do + migrate! + + expect { schema_migrate_down! }.not_to change { + aggregations.order(:group_id).pluck(:group_id) + }.from([group_aggregation.id]) + end + end +end diff --git a/spec/migrations/20230322145403_add_project_id_foreign_key_to_packages_npm_metadata_caches_spec.rb b/spec/migrations/20230322145403_add_project_id_foreign_key_to_packages_npm_metadata_caches_spec.rb new file mode 100644 index 00000000000..647c583aa39 --- /dev/null +++ b/spec/migrations/20230322145403_add_project_id_foreign_key_to_packages_npm_metadata_caches_spec.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require 'spec_helper' + +require_migration! + +RSpec.describe AddProjectIdForeignKeyToPackagesNpmMetadataCaches, + feature_category: :package_registry do + let(:table) { described_class::SOURCE_TABLE } + let(:column) { described_class::COLUMN } + let(:foreign_key) { -> { described_class.new.foreign_keys_for(table, column).first } } + + it 'creates and drops the foreign key' do + reversible_migration do |migration| + migration.before -> do + expect(foreign_key.call).to be(nil) + end + + migration.after -> do + expect(foreign_key.call).to have_attributes(column: column.to_s) + end + end + end +end diff --git a/spec/migrations/20230323101138_add_award_emoji_work_item_widget_spec.rb b/spec/migrations/20230323101138_add_award_emoji_work_item_widget_spec.rb new file mode 100644 index 00000000000..16a205c5da5 --- /dev/null +++ b/spec/migrations/20230323101138_add_award_emoji_work_item_widget_spec.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe AddAwardEmojiWorkItemWidget, :migration, feature_category: :team_planning do + it_behaves_like 'migration that adds widget to work items definitions', widget_name: 'Award emoji' +end diff --git a/spec/migrations/20230327103401_queue_migrate_human_user_type_spec.rb b/spec/migrations/20230327103401_queue_migrate_human_user_type_spec.rb new file mode 100644 index 00000000000..e5852c93471 --- /dev/null +++ b/spec/migrations/20230327103401_queue_migrate_human_user_type_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe QueueMigrateHumanUserType, feature_category: :user_management do + let(: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::DELAY_INTERVAL, + batch_size: described_class::BATCH_SIZE, + sub_batch_size: described_class::SUB_BATCH_SIZE + ) + } + end + end +end diff --git a/spec/migrations/20230327123333_backfill_product_analytics_data_collector_host_spec.rb b/spec/migrations/20230327123333_backfill_product_analytics_data_collector_host_spec.rb new file mode 100644 index 00000000000..253512c9194 --- /dev/null +++ b/spec/migrations/20230327123333_backfill_product_analytics_data_collector_host_spec.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +require "spec_helper" +require_migration! + +RSpec.describe BackfillProductAnalyticsDataCollectorHost, feature_category: :product_analytics do + let!(:application_settings) { table(:application_settings) } + + describe '#up' do + before do + create_application_settings!(id: 1, jitsu_host: "https://configurator.testing.my-product-analytics.com", + product_analytics_data_collector_host: nil) + create_application_settings!(id: 2, jitsu_host: "https://config-urator_1.testing.my-product-analytics.com", + product_analytics_data_collector_host: nil) + create_application_settings!(id: 3, jitsu_host: "https://configurator.testing.my-product-analytics.com", + product_analytics_data_collector_host: "https://existingcollector.my-product-analytics.com") + create_application_settings!(id: 4, jitsu_host: nil, product_analytics_data_collector_host: nil) + migrate! + end + + describe 'when jitsu host is present' do + it 'backfills missing product_analytics_data_collector_host' do + expect(application_settings.find(1).product_analytics_data_collector_host).to eq("https://collector.testing.my-product-analytics.com") + expect(application_settings.find(2).product_analytics_data_collector_host).to eq("https://collector.testing.my-product-analytics.com") + end + + it 'does not modify existing product_analytics_data_collector_host' do + expect(application_settings.find(3).product_analytics_data_collector_host).to eq("https://existingcollector.my-product-analytics.com") + end + end + + describe 'when jitsu host is not present' do + it 'does not backfill product_analytics_data_collector_host' do + expect(application_settings.find(4).product_analytics_data_collector_host).to be_nil + end + end + end + + def create_application_settings!(id:, jitsu_host:, product_analytics_data_collector_host:) + params = { + id: id, + jitsu_host: jitsu_host, + product_analytics_data_collector_host: product_analytics_data_collector_host + } + application_settings.create!(params) + end +end diff --git a/spec/migrations/20230328030101_add_secureflag_training_provider_spec.rb b/spec/migrations/20230328030101_add_secureflag_training_provider_spec.rb new file mode 100644 index 00000000000..774ea89937a --- /dev/null +++ b/spec/migrations/20230328030101_add_secureflag_training_provider_spec.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe AddSecureflagTrainingProvider, :migration, feature_category: :vulnerability_management do + include MigrationHelpers::WorkItemTypesHelper + + let!(:security_training_providers) { table(:security_training_providers) } + + it 'adds additional provider' do + # Need to delete all as security training providers are seeded before entire test suite + security_training_providers.delete_all + + reversible_migration do |migration| + migration.before -> { + expect(security_training_providers.count).to eq(0) + } + + migration.after -> { + expect(security_training_providers.count).to eq(1) + } + end + end +end diff --git a/spec/migrations/20230328100534_truncate_error_tracking_tables_spec.rb b/spec/migrations/20230328100534_truncate_error_tracking_tables_spec.rb new file mode 100644 index 00000000000..efbbe22fd1b --- /dev/null +++ b/spec/migrations/20230328100534_truncate_error_tracking_tables_spec.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe TruncateErrorTrackingTables, :migration, feature_category: :redis do + let(:migration) { described_class.new } + + context 'when on GitLab.com' do + before do + allow(Gitlab).to receive(:com?).and_return(true) + end + + context 'when using Main db' do + it 'truncates the table' do + expect(described_class.connection).to receive(:execute).with('TRUNCATE table error_tracking_errors CASCADE') + + migration.up + end + end + + context 'when uses CI db', migration: :gitlab_ci do + before do + skip_if_multiple_databases_not_setup(:ci) + end + + it 'does not truncate the table' do + expect(described_class.connection).not_to receive(:execute).with('TRUNCATE table error_tracking_errors CASCADE') + + migration.up + end + end + end + + context 'when on self-managed' do + before do + allow(Gitlab).to receive(:com?).and_return(false) + end + + context 'when using Main db' do + it 'does not truncate the table' do + expect(described_class.connection).not_to receive(:execute).with('TRUNCATE table error_tracking_errors CASCADE') + + migration.up + end + end + + context 'when uses CI db', migration: :gitlab_ci do + it 'does not truncate the table' do + expect(described_class.connection).not_to receive(:execute).with('TRUNCATE table error_tracking_errors CASCADE') + + migration.up + end + end + end +end diff --git a/spec/migrations/20230329100222_drop_software_licenses_temp_index_spec.rb b/spec/migrations/20230329100222_drop_software_licenses_temp_index_spec.rb new file mode 100644 index 00000000000..d4d276980f8 --- /dev/null +++ b/spec/migrations/20230329100222_drop_software_licenses_temp_index_spec.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe DropSoftwareLicensesTempIndex, feature_category: :security_policy_management do + it 'correctly migrates up and down' do + reversible_migration do |migration| + migration.before -> { + expect(ActiveRecord::Base.connection.indexes('software_licenses').map(&:name)) + .to include(described_class::INDEX_NAME) + } + + migration.after -> { + expect(ActiveRecord::Base.connection.indexes('software_licenses').map(&:name)) + .not_to include(described_class::INDEX_NAME) + } + end + end +end diff --git a/spec/migrations/20230330103104_reschedule_migrate_evidences_spec.rb b/spec/migrations/20230330103104_reschedule_migrate_evidences_spec.rb new file mode 100644 index 00000000000..8dc8cd68acb --- /dev/null +++ b/spec/migrations/20230330103104_reschedule_migrate_evidences_spec.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe RescheduleMigrateEvidences, :migration, feature_category: :vulnerability_management do + let(:migration) { described_class::MIGRATION } + + describe '#up' do + it 'does not schedule a batched background migration' do + migrate! + + expect(migration).not_to have_scheduled_batched_migration + 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/20230403085957_add_tmp_partial_index_on_vulnerability_report_types2_spec.rb b/spec/migrations/20230403085957_add_tmp_partial_index_on_vulnerability_report_types2_spec.rb new file mode 100644 index 00000000000..5203e772d15 --- /dev/null +++ b/spec/migrations/20230403085957_add_tmp_partial_index_on_vulnerability_report_types2_spec.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +require "spec_helper" + +require_migration! + +RSpec.describe AddTmpPartialIndexOnVulnerabilityReportTypes2, feature_category: :vulnerability_management do + let(:async_index) { Gitlab::Database::AsyncIndexes::PostgresAsyncIndex } + let(:index_name) { described_class::INDEX_NAME } + + before do + allow_any_instance_of(ActiveRecord::ConnectionAdapters::SchemaStatements) # rubocop:disable RSpec/AnyInstanceOf + .to receive(:index_exists?) + .with("vulnerability_occurrences", :id, hash_including(name: index_name)) + .and_return(index_exists) + end + + context "with index absent" do + let(:index_exists) { false } + + it "schedules the index" do + reversible_migration do |migration| + migration.before -> do + expect(async_index.where(name: index_name).count).to be(0) + end + + migration.after -> do + expect(async_index.where(name: index_name).count).to be(1) + end + end + end + end + + context "with index present" do + let(:index_exists) { true } + + it "does not schedule the index" do + reversible_migration do |migration| + migration.before -> do + expect(async_index.where(name: index_name).count).to be(0) + end + + migration.after -> do + expect(async_index.where(name: index_name).count).to be(0) + end + end + end + end +end diff --git a/spec/migrations/20230405200858_requeue_backfill_project_wiki_repositories_spec.rb b/spec/migrations/20230405200858_requeue_backfill_project_wiki_repositories_spec.rb new file mode 100644 index 00000000000..cf42818152f --- /dev/null +++ b/spec/migrations/20230405200858_requeue_backfill_project_wiki_repositories_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe RequeueBackfillProjectWikiRepositories, feature_category: :geo_replication do + let!(: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, + batch_size: described_class::BATCH_SIZE, + sub_batch_size: described_class::SUB_BATCH_SIZE + ) + } + end + end +end diff --git a/spec/migrations/20230406121544_queue_backfill_design_management_repositories_spec.rb b/spec/migrations/20230406121544_queue_backfill_design_management_repositories_spec.rb new file mode 100644 index 00000000000..39ef769fd11 --- /dev/null +++ b/spec/migrations/20230406121544_queue_backfill_design_management_repositories_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe QueueBackfillDesignManagementRepositories, feature_category: :geo_replication do + let!(: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, + batch_size: described_class::BATCH_SIZE, + sub_batch_size: described_class::SUB_BATCH_SIZE + ) + } + end + end +end diff --git a/spec/migrations/20230411153310_cleanup_bigint_conversion_for_sent_notifications_spec.rb b/spec/migrations/20230411153310_cleanup_bigint_conversion_for_sent_notifications_spec.rb new file mode 100644 index 00000000000..5780aa365da --- /dev/null +++ b/spec/migrations/20230411153310_cleanup_bigint_conversion_for_sent_notifications_spec.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration!('cleanup_bigint_conversion_for_sent_notifications') + +RSpec.describe CleanupBigintConversionForSentNotifications, feature_category: :database do + let(:sent_notifications) { table(:sent_notifications) } + + it 'correctly migrates up and down' do + reversible_migration do |migration| + migration.before -> { + expect(sent_notifications.column_names).to include('id_convert_to_bigint') + } + + migration.after -> { + sent_notifications.reset_column_information + expect(sent_notifications.column_names).not_to include('id_convert_to_bigint') + } + end + end +end diff --git a/spec/migrations/20230412141541_reschedule_links_avoiding_duplication_spec.rb b/spec/migrations/20230412141541_reschedule_links_avoiding_duplication_spec.rb new file mode 100644 index 00000000000..06eccf03ca4 --- /dev/null +++ b/spec/migrations/20230412141541_reschedule_links_avoiding_duplication_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe RescheduleLinksAvoidingDuplication, :migration, feature_category: :vulnerability_management 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: :vulnerability_occurrences, + column_name: :id, + interval: described_class::DELAY_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 + migrate! + schema_migrate_down! + + expect(migration).not_to have_scheduled_batched_migration + end + end +end diff --git a/spec/migrations/20230412185837_queue_populate_vulnerability_dismissal_fields_spec.rb b/spec/migrations/20230412185837_queue_populate_vulnerability_dismissal_fields_spec.rb new file mode 100644 index 00000000000..d39936abb90 --- /dev/null +++ b/spec/migrations/20230412185837_queue_populate_vulnerability_dismissal_fields_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe QueuePopulateVulnerabilityDismissalFields, feature_category: :vulnerability_management do + let!(:batched_migration) { described_class::MIGRATION } + + describe '#up' do + 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: :vulnerabilities, + column_name: :id, + interval: described_class::DELAY_INTERVAL, + batch_size: described_class::BATCH_SIZE, + sub_batch_size: described_class::SUB_BATCH_SIZE + ) + } + end + end + end + + describe '#down' do + it 'deletes all batched migration records' do + migrate! + schema_migrate_down! + + expect(batched_migration).not_to have_scheduled_batched_migration + end + end +end diff --git a/spec/migrations/20230412214119_finalize_encrypt_ci_trigger_token_spec.rb b/spec/migrations/20230412214119_finalize_encrypt_ci_trigger_token_spec.rb new file mode 100644 index 00000000000..c30cafc915d --- /dev/null +++ b/spec/migrations/20230412214119_finalize_encrypt_ci_trigger_token_spec.rb @@ -0,0 +1,96 @@ +# frozen_string_literal: true + +require 'spec_helper' + +require_migration! + +RSpec.describe FinalizeEncryptCiTriggerToken, migration: :gitlab_ci, feature_category: :continuous_integration do + let(:batched_migrations) { table(:batched_background_migrations) } + let(:batch_failed_status) { 2 } + let(:batch_finalized_status) { 3 } + + let!(:migration) { described_class::MIGRATION } + + describe '#up' do + context 'when migration is missing' do + before do + batched_migrations.where(job_class_name: migration).delete_all + end + + 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!(:migration_record) do + batched_migrations.create!( + job_class_name: migration, + table_name: :ci_triggers, + column_name: :id, + job_arguments: [], + interval: 2.minutes, + min_value: 1, + max_value: 2, + batch_size: 1000, + sub_batch_size: 100, + max_batch_size: 2000, + gitlab_schema: :gitlab_ci, + status: batch_finalized_status + ) + 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: migration_record.id, + status: batch_failed_status, + min_value: 1, + max_value: 10, + attempts: 2, + batch_size: 100, + sub_batch_size: 10 + ) + end + + before do + migration_record.update!(status: status) + end + + it 'finalizes the migration' do + expect do + migrate! + + migration_record.reload + failed_job.reload + end.to( + change { migration_record.status }.from(status).to(batch_finalized_status) + .and( + change { failed_job.status }.from(batch_failed_status).to(batch_finalized_status) + ) + ) + end + end + end + end + end +end diff --git a/spec/migrations/20230418215853_add_assignee_widget_to_incidents_spec.rb b/spec/migrations/20230418215853_add_assignee_widget_to_incidents_spec.rb new file mode 100644 index 00000000000..d809d0e6a54 --- /dev/null +++ b/spec/migrations/20230418215853_add_assignee_widget_to_incidents_spec.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe AddAssigneeWidgetToIncidents, :migration, feature_category: :team_planning do + let(:migration) { described_class.new } + let(:work_item_definitions) { table(:work_item_widget_definitions) } + let(:work_item_types) { table(:work_item_types) } + + let(:widget_name) { 'Assignees' } + let(:work_item_type) { 'Incident' } + + describe '#up' do + it 'creates widget definition' do + type = work_item_types.find_by_name_and_namespace_id(work_item_type, nil) + work_item_definitions.where(work_item_type_id: type, name: widget_name).delete_all if type + + expect { migrate! }.to change { work_item_definitions.count }.by(1) + + type = work_item_types.find_by_name_and_namespace_id(work_item_type, nil) + + expect(work_item_definitions.where(work_item_type_id: type, name: widget_name).count).to eq 1 + end + + it 'logs a warning if the type is missing' do + allow(described_class::WorkItemType).to receive(:find_by_name_and_namespace_id).and_call_original + allow(described_class::WorkItemType).to receive(:find_by_name_and_namespace_id) + .with(work_item_type, nil).and_return(nil) + + expect(Gitlab::AppLogger).to receive(:warn).with(AddAssigneeWidgetToIncidents::FAILURE_MSG) + migrate! + end + end + + describe '#down' do + it 'removes definitions for widget' do + migrate! + + expect { migration.down }.to change { work_item_definitions.count }.by(-1) + + type = work_item_types.find_by_name_and_namespace_id(work_item_type, nil) + + expect(work_item_definitions.where(work_item_type_id: type, name: widget_name).count).to eq 0 + end + end +end diff --git a/spec/migrations/20230419105225_remove_phabricator_from_application_settings_spec.rb b/spec/migrations/20230419105225_remove_phabricator_from_application_settings_spec.rb new file mode 100644 index 00000000000..df84c8efd05 --- /dev/null +++ b/spec/migrations/20230419105225_remove_phabricator_from_application_settings_spec.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe RemovePhabricatorFromApplicationSettings, feature_category: :importers do + let(:settings) { table(:application_settings) } + let(:import_sources_with_phabricator) { %w[phabricator github git bitbucket bitbucket_server] } + let(:import_sources_without_phabricator) { %w[github git bitbucket bitbucket_server] } + + describe "#up" do + it 'removes phabricator and preserves existing valid import sources' do + record = settings.create!(import_sources: import_sources_with_phabricator) + + migrate! + + expect(record.reload.import_sources).to start_with('---') + + expect(ApplicationSetting.last.import_sources).to eq(import_sources_without_phabricator) + end + end +end diff --git a/spec/migrations/20230426102200_fix_import_sources_on_application_settings_after_phabricator_removal_spec.rb b/spec/migrations/20230426102200_fix_import_sources_on_application_settings_after_phabricator_removal_spec.rb new file mode 100644 index 00000000000..aa5ec462871 --- /dev/null +++ b/spec/migrations/20230426102200_fix_import_sources_on_application_settings_after_phabricator_removal_spec.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe FixImportSourcesOnApplicationSettingsAfterPhabricatorRemoval, feature_category: :importers do + let(:settings) { table(:application_settings) } + let(:import_sources) { %w[github git bitbucket bitbucket_server] } + + describe "#up" do + shared_examples 'fixes import_sources on application_settings' do + it 'ensures YAML is stored' do + record = settings.create!(import_sources: data) + + migrate! + + expect(record.reload.import_sources).to start_with('---') + expect(ApplicationSetting.last.import_sources).to eq(import_sources) + end + end + + context 'when import_sources is a String' do + let(:data) { import_sources.to_s } + + it_behaves_like 'fixes import_sources on application_settings' + end + + context 'when import_sources is already YAML' do + let(:data) { import_sources.to_yaml } + + it_behaves_like 'fixes import_sources on application_settings' + end + end +end diff --git a/spec/migrations/20230428085332_remove_shimo_zentao_integration_records_spec.rb b/spec/migrations/20230428085332_remove_shimo_zentao_integration_records_spec.rb new file mode 100644 index 00000000000..1d2fbb6b95d --- /dev/null +++ b/spec/migrations/20230428085332_remove_shimo_zentao_integration_records_spec.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +require 'spec_helper' + +require_migration! + +RSpec.describe RemoveShimoZentaoIntegrationRecords, feature_category: :integrations do + let(:integrations) { table(:integrations) } + let(:zentao_tracker_data) { table(:zentao_tracker_data) } + + before do + integrations.create!(id: 1, type_new: 'Integrations::MockMonitoring') + integrations.create!(id: 2, type_new: 'Integrations::Redmine') + integrations.create!(id: 3, type_new: 'Integrations::Confluence') + + integrations.create!(id: 4, type_new: 'Integrations::Shimo') + integrations.create!(id: 5, type_new: 'Integrations::Zentao') + integrations.create!(id: 6, type_new: 'Integrations::Zentao') + zentao_tracker_data.create!(id: 1, integration_id: 5) + zentao_tracker_data.create!(id: 2, integration_id: 6) + end + + context 'with CE/EE env' do + it 'destroys all shimo and zentao integrations' do + migrate! + + expect(integrations.count).to eq(3) # keep other integrations + expect(integrations.where(type_new: described_class::TYPES).count).to eq(0) + expect(zentao_tracker_data.count).to eq(0) + end + end + + context 'with JiHu env' do + before do + allow(Gitlab).to receive(:jh?).and_return(true) + end + + it 'keeps shimo and zentao integrations' do + migrate! + + expect(integrations.count).to eq(6) + expect(integrations.where(type_new: described_class::TYPES).count).to eq(3) + expect(zentao_tracker_data.count).to eq(2) + end + end +end diff --git a/spec/migrations/20230502102832_schedule_index_to_members_on_source_and_type_and_access_level_spec.rb b/spec/migrations/20230502102832_schedule_index_to_members_on_source_and_type_and_access_level_spec.rb new file mode 100644 index 00000000000..34d69642802 --- /dev/null +++ b/spec/migrations/20230502102832_schedule_index_to_members_on_source_and_type_and_access_level_spec.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require "spec_helper" + +require_migration! + +RSpec.describe ScheduleIndexToMembersOnSourceAndTypeAndAccessLevel, feature_category: :security_policy_management do + let(:async_index) { Gitlab::Database::AsyncIndexes::PostgresAsyncIndex } + let(:index_name) { described_class::INDEX_NAME } + + it "schedules the index" do + reversible_migration do |migration| + migration.before -> do + expect(async_index.where(name: index_name).count).to be(0) + end + + migration.after -> do + expect(async_index.where(name: index_name).count).to be(1) + end + end + end +end diff --git a/spec/migrations/20230502120021_schedule_index_to_project_authorizations_on_project_user_access_level_spec.rb b/spec/migrations/20230502120021_schedule_index_to_project_authorizations_on_project_user_access_level_spec.rb new file mode 100644 index 00000000000..9759fa7862d --- /dev/null +++ b/spec/migrations/20230502120021_schedule_index_to_project_authorizations_on_project_user_access_level_spec.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require "spec_helper" + +require_migration! + +RSpec.describe ScheduleIndexToProjectAuthorizationsOnProjectUserAccessLevel, feature_category: :security_policy_management do + let(:async_index) { Gitlab::Database::AsyncIndexes::PostgresAsyncIndex } + let(:index_name) { described_class::INDEX_NAME } + + it "schedules the index" do + reversible_migration do |migration| + migration.before -> do + expect(async_index.where(name: index_name).count).to be(0) + end + + migration.after -> do + expect(async_index.where(name: index_name).count).to be(1) + end + end + end +end diff --git a/spec/migrations/20230504084524_remove_gitlab_import_source_spec.rb b/spec/migrations/20230504084524_remove_gitlab_import_source_spec.rb new file mode 100644 index 00000000000..b2442359e87 --- /dev/null +++ b/spec/migrations/20230504084524_remove_gitlab_import_source_spec.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe RemoveGitlabImportSource, feature_category: :importers do + let(:settings) { table(:application_settings) } + let(:import_sources_with_gitlab) { %w[github git gitlab bitbucket bitbucket_server] } + let(:import_sources_without_gitlab) { %w[github git bitbucket bitbucket_server] } + + describe "#up" do + it 'removes gitlab and preserves existing valid import sources' do + record = settings.create!(import_sources: import_sources_with_gitlab) + + migrate! + + expect(record.reload.import_sources).to start_with('---') + + expect(ApplicationSetting.last.import_sources).to eq(import_sources_without_gitlab) + end + end +end diff --git a/spec/migrations/20230508150219_reschedule_evidences_handling_unicode_spec.rb b/spec/migrations/20230508150219_reschedule_evidences_handling_unicode_spec.rb new file mode 100644 index 00000000000..9ba44984372 --- /dev/null +++ b/spec/migrations/20230508150219_reschedule_evidences_handling_unicode_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe RescheduleEvidencesHandlingUnicode, :migration, feature_category: :vulnerability_management 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: :vulnerability_occurrences, + column_name: :id, + interval: described_class::DELAY_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 + migrate! + schema_migrate_down! + + expect(migration).not_to have_scheduled_batched_migration + end + end +end diff --git a/spec/migrations/20230508175057_backfill_corrected_secure_files_expirations_spec.rb b/spec/migrations/20230508175057_backfill_corrected_secure_files_expirations_spec.rb new file mode 100644 index 00000000000..570be0e02c7 --- /dev/null +++ b/spec/migrations/20230508175057_backfill_corrected_secure_files_expirations_spec.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require 'spec_helper' + +require_migration! + +RSpec.describe BackfillCorrectedSecureFilesExpirations, migration: :gitlab_ci, feature_category: :mobile_devops do + let(:migration) { described_class.new } + let(:ci_secure_files) { table(:ci_secure_files) } + + let!(:file1) { ci_secure_files.create!(project_id: 1, name: "file.cer", file: "foo", checksum: 'bar') } + let!(:file2) { ci_secure_files.create!(project_id: 1, name: "file.p12", file: "foo", checksum: 'bar') } + let!(:file3) { ci_secure_files.create!(project_id: 1, name: "file.jks", file: "foo", checksum: 'bar') } + + describe '#up' do + it 'enqueues the ParseSecureFileMetadataWorker job for relevant file types', :aggregate_failures do + expect(::Ci::ParseSecureFileMetadataWorker).to receive(:perform_async).with(file1.id) + expect(::Ci::ParseSecureFileMetadataWorker).to receive(:perform_async).with(file2.id) + expect(::Ci::ParseSecureFileMetadataWorker).not_to receive(:perform_async).with(file3.id) + + migration.up + end + end +end diff --git a/spec/migrations/20230509131736_add_default_organization_spec.rb b/spec/migrations/20230509131736_add_default_organization_spec.rb new file mode 100644 index 00000000000..539216c57ee --- /dev/null +++ b/spec/migrations/20230509131736_add_default_organization_spec.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +require 'spec_helper' + +require_migration! + +RSpec.describe AddDefaultOrganization, feature_category: :cell do + let(:organization) { table(:organizations) } + + it "correctly migrates up and down" do + reversible_migration do |migration| + migration.before -> { + expect(organization.where(id: 1, name: 'Default')).to be_empty + } + migration.after -> { + expect(organization.where(id: 1, name: 'Default')).not_to be_empty + } + end + end +end diff --git a/spec/migrations/20230510062502_queue_cleanup_personal_access_tokens_with_nil_expires_at_spec.rb b/spec/migrations/20230510062502_queue_cleanup_personal_access_tokens_with_nil_expires_at_spec.rb new file mode 100644 index 00000000000..45ef85a49cf --- /dev/null +++ b/spec/migrations/20230510062502_queue_cleanup_personal_access_tokens_with_nil_expires_at_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe QueueCleanupPersonalAccessTokensWithNilExpiresAt, feature_category: :system_access do + let!(: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: :personal_access_tokens, + column_name: :id, + interval: described_class::DELAY_INTERVAL, + batch_size: described_class::BATCH_SIZE, + sub_batch_size: described_class::SUB_BATCH_SIZE + ) + } + end + end +end diff --git a/spec/migrations/add_open_source_plan_spec.rb b/spec/migrations/add_open_source_plan_spec.rb deleted file mode 100644 index f5d68f455e6..00000000000 --- a/spec/migrations/add_open_source_plan_spec.rb +++ /dev/null @@ -1,86 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -require_migration! - -RSpec.describe AddOpenSourcePlan, :migration, feature_category: :purchase do - describe '#up' do - before do - allow(Gitlab).to receive(:com?).and_return true - end - - it 'creates 1 entry within the plans table' do - expect { migrate! }.to change { AddOpenSourcePlan::Plan.count }.by 1 - expect(AddOpenSourcePlan::Plan.last.name).to eql('opensource') - end - - it 'creates 1 entry for plan limits' do - expect { migrate! }.to change { AddOpenSourcePlan::PlanLimits.count }.by 1 - end - - context 'when the plan limits for gold and silver exists' do - before do - table(:plans).create!(id: 1, name: 'ultimate', title: 'Ultimate') - table(:plan_limits).create!(id: 1, plan_id: 1, storage_size_limit: 2000) - end - - it 'duplicates the gold and silvers plan limits entries' do - migrate! - - opensource_limits = AddOpenSourcePlan::Plan.find_by(name: 'opensource').limits - expect(opensource_limits.storage_size_limit).to be 2000 - end - end - - context 'when the instance is not SaaS' do - before do - allow(Gitlab).to receive(:com?).and_return false - end - - it 'does not create plans and plan limits and returns' do - expect { migrate! }.not_to change { AddOpenSourcePlan::Plan.count } - end - end - end - - describe '#down' do - before do - table(:plans).create!(id: 3, name: 'other') - table(:plan_limits).create!(plan_id: 3) - end - - context 'when the instance is SaaS' do - before do - allow(Gitlab).to receive(:com?).and_return true - end - - it 'removes the newly added opensource entry' do - migrate! - - expect { described_class.new.down }.to change { AddOpenSourcePlan::Plan.count }.by(-1) - expect(AddOpenSourcePlan::Plan.find_by(name: 'opensource')).to be_nil - - other_plan = AddOpenSourcePlan::Plan.find_by(name: 'other') - expect(other_plan).to be_persisted - expect(AddOpenSourcePlan::PlanLimits.count).to eq(1) - expect(AddOpenSourcePlan::PlanLimits.first.plan_id).to eq(other_plan.id) - end - end - - context 'when the instance is not SaaS' do - before do - allow(Gitlab).to receive(:com?).and_return false - table(:plans).create!(id: 1, name: 'opensource', title: 'Open Source Program') - table(:plan_limits).create!(id: 1, plan_id: 1) - end - - it 'does not delete plans and plan limits and returns' do - migrate! - - expect { described_class.new.down }.not_to change { AddOpenSourcePlan::Plan.count } - expect(AddOpenSourcePlan::PlanLimits.count).to eq(2) - end - end - end -end diff --git a/spec/migrations/backfill_current_value_with_progress_work_item_progresses_spec.rb b/spec/migrations/backfill_current_value_with_progress_work_item_progresses_spec.rb new file mode 100644 index 00000000000..632925b23b2 --- /dev/null +++ b/spec/migrations/backfill_current_value_with_progress_work_item_progresses_spec.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe BackfillCurrentValueWithProgressWorkItemProgresses, :migration, feature_category: :team_planning do + let(:namespaces) { table(:namespaces) } + let(:users) { table(:users) } + let(:projects) { table(:projects) } + let(:issues) { table(:issues) } + let(:progresses) { table(:work_item_progresses) } + let(:issue_base_type_enum_value) { 5 } + let(:issue_type) { table(:work_item_types).find_by!(namespace_id: nil, base_type: issue_base_type_enum_value) } + + let(:namespace) { namespaces.create!(name: 'foo', path: 'foo') } + let(:user) { users.create!(name: 'test', email: 'test@example.com', projects_limit: 5) } + let(:project) do + projects.create!(namespace_id: namespace.id, project_namespace_id: namespace.id, name: 'Alpha Gamma', + path: 'alpha-gamma') + end + + let(:work_item1) do + issues.create!( + id: 1, project_id: project.id, namespace_id: project.project_namespace_id, + title: 'issue1', author_id: user.id, work_item_type_id: issue_type.id + ) + end + + let(:work_item2) do + issues.create!( + id: 2, project_id: project.id, namespace_id: project.project_namespace_id, + title: 'issue2', author_id: user.id, work_item_type_id: issue_type.id + ) + end + + let(:progress1) { progresses.create!(issue_id: work_item1.id, progress: 10) } + let(:progress2) { progresses.create!(issue_id: work_item2.id, progress: 60) } + + describe '#up' do + it 'back fills current_value from progress columns' do + expect { migrate! } + .to change { progress1.reload.current_value }.from(0).to(10) + .and change { progress2.reload.current_value }.from(0).to(60) + .and not_change(progress1, :progress) + .and not_change(progress2, :progress) + end + end +end diff --git a/spec/migrations/backfill_integrations_enable_ssl_verification_spec.rb b/spec/migrations/backfill_integrations_enable_ssl_verification_spec.rb index 5029a861d31..83b47da3065 100644 --- a/spec/migrations/backfill_integrations_enable_ssl_verification_spec.rb +++ b/spec/migrations/backfill_integrations_enable_ssl_verification_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' require_migration! -RSpec.describe BackfillIntegrationsEnableSslVerification, feature_category: :authentication_and_authorization do +RSpec.describe BackfillIntegrationsEnableSslVerification, feature_category: :system_access do let!(:migration) { described_class::MIGRATION } let!(:integrations) { described_class::Integration } diff --git a/spec/migrations/bulk_insert_cluster_enabled_grants_spec.rb b/spec/migrations/bulk_insert_cluster_enabled_grants_spec.rb index e85489198ee..71ffdd66d62 100644 --- a/spec/migrations/bulk_insert_cluster_enabled_grants_spec.rb +++ b/spec/migrations/bulk_insert_cluster_enabled_grants_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' require_migration! -RSpec.describe BulkInsertClusterEnabledGrants, :migration, feature_category: :kubernetes_management do +RSpec.describe BulkInsertClusterEnabledGrants, :migration, feature_category: :deployment_management do let(:migration) { described_class.new } let(:cluster_enabled_grants) { table(:cluster_enabled_grants) } diff --git a/spec/migrations/cleanup_backfill_integrations_enable_ssl_verification_spec.rb b/spec/migrations/cleanup_backfill_integrations_enable_ssl_verification_spec.rb index 7aaa90ee985..01c85f85e0b 100644 --- a/spec/migrations/cleanup_backfill_integrations_enable_ssl_verification_spec.rb +++ b/spec/migrations/cleanup_backfill_integrations_enable_ssl_verification_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' require_migration! RSpec.describe CleanupBackfillIntegrationsEnableSslVerification, :migration, -feature_category: :authentication_and_authorization do + feature_category: :system_access do let(:job_class_name) { 'BackfillIntegrationsEnableSslVerification' } before do 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 index b808f03428d..b270f2b100f 100644 --- 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 @@ -4,7 +4,7 @@ require 'spec_helper' require_migration! RSpec.describe CleanupVulnerabilityStateTransitionsWithSameFromStateToState, :migration, -feature_category: :vulnerability_management do + feature_category: :vulnerability_management do let!(:namespace) { table(:namespaces).create!(name: 'namespace', type: 'Group', path: 'namespace') } let!(:user) { table(:users).create!(email: 'author@example.com', username: 'author', projects_limit: 10) } let!(:project) do diff --git a/spec/migrations/delete_migrate_shared_vulnerability_scanners_spec.rb b/spec/migrations/delete_migrate_shared_vulnerability_scanners_spec.rb index 562b1e25db4..8a0c0250cdf 100644 --- a/spec/migrations/delete_migrate_shared_vulnerability_scanners_spec.rb +++ b/spec/migrations/delete_migrate_shared_vulnerability_scanners_spec.rb @@ -9,37 +9,41 @@ RSpec.describe DeleteMigrateSharedVulnerabilityScanners, :migration, feature_cat 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") + 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) + 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 diff --git a/spec/migrations/disable_job_token_scope_when_unused_spec.rb b/spec/migrations/disable_job_token_scope_when_unused_spec.rb deleted file mode 100644 index fddf3594e2b..00000000000 --- a/spec/migrations/disable_job_token_scope_when_unused_spec.rb +++ /dev/null @@ -1,10 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require_migration! - -RSpec.describe DisableJobTokenScopeWhenUnused, feature_category: :continuous_integration do - it 'is a no-op' do - migrate! - end -end diff --git a/spec/migrations/drop_packages_events_table_spec.rb b/spec/migrations/drop_packages_events_table_spec.rb new file mode 100644 index 00000000000..539a3b88196 --- /dev/null +++ b/spec/migrations/drop_packages_events_table_spec.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require "spec_helper" + +require_migration! + +RSpec.describe DropPackagesEventsTable, feature_category: :package_registry do + let(:table) { described_class::SOURCE_TABLE } + let(:column) { described_class::COLUMN } + + subject { described_class.new } + + it 'drops and creates the packages_events table' do + reversible_migration do |migration| + migration.before -> do + expect(subject.table_exists?(:packages_events)).to eq(true) + end + + migration.after -> do + expect(subject.table_exists?(:packages_events)).to eq(false) + end + end + end +end diff --git a/spec/migrations/ensure_award_emoji_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb b/spec/migrations/ensure_award_emoji_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb new file mode 100644 index 00000000000..826320ec6c2 --- /dev/null +++ b/spec/migrations/ensure_award_emoji_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe EnsureAwardEmojiBigintBackfillIsFinishedForGitlabDotCom, feature_category: :database do + describe '#up' do + let(:migration_arguments) do + { + job_class_name: 'CopyColumnUsingBackgroundMigrationJob', + table_name: 'award_emoji', + column_name: 'id', + job_arguments: [['awardable_id'], ['awardable_id_convert_to_bigint']] + } + end + + it 'ensures the migration is completed for GitLab.com, dev, or test' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true) + expect(instance).to receive(:ensure_batched_background_migration_is_finished).with(migration_arguments) + end + + migrate! + end + + it 'skips the check for other instances' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + expect(instance).not_to receive(:ensure_batched_background_migration_is_finished) + end + + migrate! + end + end +end diff --git a/spec/migrations/ensure_commit_user_mentions_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb b/spec/migrations/ensure_commit_user_mentions_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb new file mode 100644 index 00000000000..89e14650034 --- /dev/null +++ b/spec/migrations/ensure_commit_user_mentions_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe EnsureCommitUserMentionsNoteIdBigintBackfillIsFinishedForGitlabDotCom, feature_category: :database do + describe '#up' do + let(:migration_arguments) do + { + job_class_name: 'CopyColumnUsingBackgroundMigrationJob', + table_name: 'commit_user_mentions', + column_name: 'id', + job_arguments: [['note_id'], ['note_id_convert_to_bigint']] + } + end + + it 'ensures the migration is completed for GitLab.com, dev, or test' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true) + expect(instance).to receive(:ensure_batched_background_migration_is_finished).with(migration_arguments) + end + + migrate! + end + + it 'skips the check for other instances' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + expect(instance).not_to receive(:ensure_batched_background_migration_is_finished) + end + + migrate! + end + end +end diff --git a/spec/migrations/ensure_design_user_mentions_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb b/spec/migrations/ensure_design_user_mentions_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb new file mode 100644 index 00000000000..ac763af1a70 --- /dev/null +++ b/spec/migrations/ensure_design_user_mentions_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe EnsureDesignUserMentionsNoteIdBigintBackfillIsFinishedForGitlabDotCom, feature_category: :database do + describe '#up' do + let(:migration_arguments) do + { + job_class_name: 'CopyColumnUsingBackgroundMigrationJob', + table_name: 'design_user_mentions', + column_name: 'id', + job_arguments: [['note_id'], ['note_id_convert_to_bigint']] + } + end + + it 'ensures the migration is completed for GitLab.com, dev, or test' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true) + expect(instance).to receive(:ensure_batched_background_migration_is_finished).with(migration_arguments) + end + + migrate! + end + + it 'skips the check for other instances' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + expect(instance).not_to receive(:ensure_batched_background_migration_is_finished) + end + + migrate! + end + end +end diff --git a/spec/migrations/ensure_epic_user_mentions_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb b/spec/migrations/ensure_epic_user_mentions_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb new file mode 100644 index 00000000000..a6b2f751b3b --- /dev/null +++ b/spec/migrations/ensure_epic_user_mentions_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe EnsureEpicUserMentionsBigintBackfillIsFinishedForGitlabDotCom, feature_category: :database do + describe '#up' do + let(:migration_arguments) do + { + job_class_name: 'CopyColumnUsingBackgroundMigrationJob', + table_name: 'epic_user_mentions', + column_name: 'id', + job_arguments: [['note_id'], ['note_id_convert_to_bigint']] + } + end + + it 'ensures the migration is completed for GitLab.com, dev, or test' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true) + expect(instance).to receive(:ensure_batched_background_migration_is_finished).with(migration_arguments) + end + + migrate! + end + + it 'skips the check for other instances' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + expect(instance).not_to receive(:ensure_batched_background_migration_is_finished) + end + + migrate! + end + end +end diff --git a/spec/migrations/ensure_issue_user_mentions_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb b/spec/migrations/ensure_issue_user_mentions_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb new file mode 100644 index 00000000000..602dd87c593 --- /dev/null +++ b/spec/migrations/ensure_issue_user_mentions_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe EnsureIssueUserMentionsBigintBackfillIsFinishedForGitlabDotCom, feature_category: :database do + describe '#up' do + let(:migration_arguments) do + { + job_class_name: 'CopyColumnUsingBackgroundMigrationJob', + table_name: 'issue_user_mentions', + column_name: 'id', + job_arguments: [['note_id'], ['note_id_convert_to_bigint']] + } + end + + it 'ensures the migration is completed for GitLab.com, dev, or test' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true) + expect(instance).to receive(:ensure_batched_background_migration_is_finished).with(migration_arguments) + end + + migrate! + end + + it 'skips the check for other instances' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + expect(instance).not_to receive(:ensure_batched_background_migration_is_finished) + end + + migrate! + end + end +end diff --git a/spec/migrations/ensure_merge_request_metrics_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb b/spec/migrations/ensure_merge_request_metrics_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb new file mode 100644 index 00000000000..118e0058922 --- /dev/null +++ b/spec/migrations/ensure_merge_request_metrics_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe EnsureMergeRequestMetricsIdBigintBackfillIsFinishedForGitlabDotCom, feature_category: :database do + describe '#up' do + using RSpec::Parameterized::TableSyntax + + let(:migration_arguments) do + { + job_class_name: 'CopyColumnUsingBackgroundMigrationJob', + table_name: 'merge_request_metrics', + column_name: 'id', + job_arguments: [['id'], ['id_convert_to_bigint']] + } + end + + it 'ensures the migration is completed for GitLab.com, dev, or test' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true) + expect(instance).to receive(:ensure_batched_background_migration_is_finished).with(migration_arguments) + end + + migrate! + end + + it 'skips the check for other instances' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + expect(instance).not_to receive(:ensure_batched_background_migration_is_finished) + end + + migrate! + end + end +end diff --git a/spec/migrations/ensure_merge_request_metrics_id_bigint_backfill_is_finished_for_self_hosts_spec.rb b/spec/migrations/ensure_merge_request_metrics_id_bigint_backfill_is_finished_for_self_hosts_spec.rb new file mode 100644 index 00000000000..b946f816f3b --- /dev/null +++ b/spec/migrations/ensure_merge_request_metrics_id_bigint_backfill_is_finished_for_self_hosts_spec.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe EnsureMergeRequestMetricsIdBigintBackfillIsFinishedForSelfHosts, feature_category: :database do + describe '#up' do + let(:migration_arguments) do + { + job_class_name: 'CopyColumnUsingBackgroundMigrationJob', + table_name: 'merge_request_metrics', + column_name: 'id', + job_arguments: [['id'], ['id_convert_to_bigint']] + } + end + + it 'ensures the migration is completed' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:ensure_batched_background_migration_is_finished).with(migration_arguments) + end + + migrate! + end + end +end diff --git a/spec/migrations/ensure_mr_user_mentions_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb b/spec/migrations/ensure_mr_user_mentions_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb new file mode 100644 index 00000000000..af9fc3f3b07 --- /dev/null +++ b/spec/migrations/ensure_mr_user_mentions_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe EnsureMrUserMentionsNoteIdBigintBackfillIsFinishedForGitlabDotCom, feature_category: :database do + describe '#up' do + let(:migration_arguments) do + { + job_class_name: 'CopyColumnUsingBackgroundMigrationJob', + table_name: 'merge_request_user_mentions', + column_name: 'id', + job_arguments: [['note_id'], ['note_id_convert_to_bigint']] + } + end + + it 'ensures the migration is completed for GitLab.com, dev, or test' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true) + expect(instance).to receive(:ensure_batched_background_migration_is_finished).with(migration_arguments) + end + + migrate! + end + + it 'skips the check for other instances' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + expect(instance).not_to receive(:ensure_batched_background_migration_is_finished) + end + + migrate! + end + end +end diff --git a/spec/migrations/ensure_note_diff_files_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb b/spec/migrations/ensure_note_diff_files_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb new file mode 100644 index 00000000000..acafc211e8c --- /dev/null +++ b/spec/migrations/ensure_note_diff_files_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe EnsureNoteDiffFilesBigintBackfillIsFinishedForGitlabDotCom, feature_category: :database do + describe '#up' do + let(:migration_arguments) do + { + job_class_name: 'CopyColumnUsingBackgroundMigrationJob', + table_name: 'note_diff_files', + column_name: 'id', + job_arguments: [['diff_note_id'], ['diff_note_id_convert_to_bigint']] + } + end + + it 'ensures the migration is completed for GitLab.com, dev, or test' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true) + expect(instance).to receive(:ensure_batched_background_migration_is_finished).with(migration_arguments) + end + + migrate! + end + + it 'skips the check for other instances' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + expect(instance).not_to receive(:ensure_batched_background_migration_is_finished) + end + + migrate! + end + end +end diff --git a/spec/migrations/ensure_notes_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb b/spec/migrations/ensure_notes_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb new file mode 100644 index 00000000000..2832be38f9d --- /dev/null +++ b/spec/migrations/ensure_notes_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe EnsureNotesBigintBackfillIsFinishedForGitlabDotCom, feature_category: :database do + describe '#up' do + let(:migration_arguments) do + { + job_class_name: 'CopyColumnUsingBackgroundMigrationJob', + table_name: 'notes', + column_name: 'id', + job_arguments: [['id'], ['id_convert_to_bigint']] + } + end + + it 'ensures the migration is completed for GitLab.com, dev, or test' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true) + expect(instance).to receive(:ensure_batched_background_migration_is_finished).with(migration_arguments) + end + + migrate! + end + + it 'skips the check for other instances' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + expect(instance).not_to receive(:ensure_batched_background_migration_is_finished) + end + + migrate! + end + end +end diff --git a/spec/migrations/ensure_snippet_user_mentions_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb b/spec/migrations/ensure_snippet_user_mentions_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb new file mode 100644 index 00000000000..b942a9a67a3 --- /dev/null +++ b/spec/migrations/ensure_snippet_user_mentions_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe EnsureSnippetUserMentionsBigintBackfillIsFinishedForGitlabDotCom, feature_category: :database do + describe '#up' do + let(:migration_arguments) do + { + job_class_name: 'CopyColumnUsingBackgroundMigrationJob', + table_name: 'snippet_user_mentions', + column_name: 'id', + job_arguments: [['note_id'], ['note_id_convert_to_bigint']] + } + end + + it 'ensures the migration is completed for GitLab.com, dev, or test' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true) + expect(instance).to receive(:ensure_batched_background_migration_is_finished).with(migration_arguments) + end + + migrate! + end + + it 'skips the check for other instances' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + expect(instance).not_to receive(:ensure_batched_background_migration_is_finished) + end + + migrate! + end + end +end diff --git a/spec/migrations/ensure_suggestions_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb b/spec/migrations/ensure_suggestions_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb new file mode 100644 index 00000000000..f8dd700b160 --- /dev/null +++ b/spec/migrations/ensure_suggestions_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe EnsureSuggestionsNoteIdBigintBackfillIsFinishedForGitlabDotCom, feature_category: :database do + describe '#up' do + let(:migration_arguments) do + { + job_class_name: 'CopyColumnUsingBackgroundMigrationJob', + table_name: 'suggestions', + column_name: 'id', + job_arguments: [['note_id'], ['note_id_convert_to_bigint']] + } + end + + it 'ensures the migration is completed for GitLab.com, dev, or test' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true) + expect(instance).to receive(:ensure_batched_background_migration_is_finished).with(migration_arguments) + end + + migrate! + end + + it 'skips the check for other instances' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + expect(instance).not_to receive(:ensure_batched_background_migration_is_finished) + end + + migrate! + end + end +end diff --git a/spec/migrations/ensure_system_note_metadata_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb b/spec/migrations/ensure_system_note_metadata_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb new file mode 100644 index 00000000000..11e087b63e2 --- /dev/null +++ b/spec/migrations/ensure_system_note_metadata_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe EnsureSystemNoteMetadataBigintBackfillIsFinishedForGitlabDotCom, feature_category: :database do + describe '#up' do + let(:migration_arguments) do + { + job_class_name: 'CopyColumnUsingBackgroundMigrationJob', + table_name: 'system_note_metadata', + column_name: 'id', + job_arguments: [['note_id'], ['note_id_convert_to_bigint']] + } + end + + it 'ensures the migration is completed for GitLab.com, dev, or test' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true) + expect(instance).to receive(:ensure_batched_background_migration_is_finished).with(migration_arguments) + end + + migrate! + end + + it 'skips the check for other instances' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + expect(instance).not_to receive(:ensure_batched_background_migration_is_finished) + end + + migrate! + end + end +end diff --git a/spec/migrations/ensure_timelogs_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb b/spec/migrations/ensure_timelogs_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb new file mode 100644 index 00000000000..9f733f1e1f4 --- /dev/null +++ b/spec/migrations/ensure_timelogs_note_id_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe EnsureTimelogsNoteIdBigintBackfillIsFinishedForGitlabDotCom, feature_category: :database do + describe '#up' do + let(:migration_arguments) do + { + job_class_name: 'CopyColumnUsingBackgroundMigrationJob', + table_name: 'timelogs', + column_name: 'id', + job_arguments: [['note_id'], ['note_id_convert_to_bigint']] + } + end + + it 'ensures the migration is completed for GitLab.com, dev, or test' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true) + expect(instance).to receive(:ensure_batched_background_migration_is_finished).with(migration_arguments) + end + + migrate! + end + + it 'skips the check for other instances' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + expect(instance).not_to receive(:ensure_batched_background_migration_is_finished) + end + + migrate! + end + end +end diff --git a/spec/migrations/ensure_todos_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb b/spec/migrations/ensure_todos_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb new file mode 100644 index 00000000000..2b9d319be08 --- /dev/null +++ b/spec/migrations/ensure_todos_bigint_backfill_is_finished_for_gitlab_dot_com_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe EnsureTodosBigintBackfillIsFinishedForGitlabDotCom, feature_category: :database do + describe '#up' do + let(:migration_arguments) do + { + job_class_name: 'CopyColumnUsingBackgroundMigrationJob', + table_name: 'todos', + column_name: 'id', + job_arguments: [['note_id'], ['note_id_convert_to_bigint']] + } + end + + it 'ensures the migration is completed for GitLab.com, dev, or test' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true) + expect(instance).to receive(:ensure_batched_background_migration_is_finished).with(migration_arguments) + end + + migrate! + end + + it 'skips the check for other instances' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + expect(instance).not_to receive(:ensure_batched_background_migration_is_finished) + end + + migrate! + end + end +end diff --git a/spec/migrations/ensure_unique_debian_packages_spec.rb b/spec/migrations/ensure_unique_debian_packages_spec.rb new file mode 100644 index 00000000000..eaa87ebd45e --- /dev/null +++ b/spec/migrations/ensure_unique_debian_packages_spec.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +require 'spec_helper' + +require_migration! +require_migration! 'add_unique_packages_index_when_debian' +require_migration! 'add_tmp_unique_packages_index_when_debian' + +RSpec.describe EnsureUniqueDebianPackages, feature_category: :package_registry do + let(:namespaces) { table(:namespaces) } + let(:projects) { table(:projects) } + let(:packages) { table(:packages_packages) } + + let!(:group) { namespaces.create!(name: 'group', path: 'group_path') } + let!(:project_namespace1) { namespaces.create!(name: 'name1', path: 'path1') } + let!(:project_namespace2) { namespaces.create!(name: 'name2', path: 'path2') } + + let!(:project1) { projects.create!(namespace_id: group.id, project_namespace_id: project_namespace1.id) } + let!(:project2) { projects.create!(namespace_id: group.id, project_namespace_id: project_namespace2.id) } + + let!(:debian_package1_1) do + packages.create!(project_id: project1.id, package_type: 9, name: FFaker::Lorem.word, version: 'v1.0') + end + + let(:debian_package1_2) do + packages.create!(project_id: project1.id, package_type: 9, name: debian_package1_1.name, + version: debian_package1_1.version) + end + + let!(:pypi_package1_3) do + packages.create!(project_id: project1.id, package_type: 5, name: debian_package1_1.name, + version: debian_package1_1.version) + end + + let!(:debian_package2_1) do + packages.create!(project_id: project2.id, package_type: 9, name: debian_package1_1.name, + version: debian_package1_1.version) + end + + before do + # Remove unique indices + AddUniquePackagesIndexWhenDebian.new.down + AddTmpUniquePackagesIndexWhenDebian.new.down + # Then create the duplicate packages + debian_package1_2 + end + + it 'marks as pending destruction the duplicated packages', :aggregate_failures do + expect { migrate! } + .to change { packages.where(status: 0).count }.from(4).to(3) + .and not_change { packages.where(status: 1).count } + .and not_change { packages.where(status: 2).count } + .and not_change { packages.where(status: 3).count } + .and change { packages.where(status: 4).count }.from(0).to(1) + end +end diff --git a/spec/migrations/ensure_vum_bigint_backfill_is_finished_for_gl_dot_com_spec.rb b/spec/migrations/ensure_vum_bigint_backfill_is_finished_for_gl_dot_com_spec.rb new file mode 100644 index 00000000000..d582a8a9460 --- /dev/null +++ b/spec/migrations/ensure_vum_bigint_backfill_is_finished_for_gl_dot_com_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe EnsureVumBigintBackfillIsFinishedForGlDotCom, feature_category: :database do + describe '#up' do + let(:migration_arguments) do + { + job_class_name: 'CopyColumnUsingBackgroundMigrationJob', + table_name: 'vulnerability_user_mentions', + column_name: 'id', + job_arguments: [['note_id'], ['note_id_convert_to_bigint']] + } + end + + it 'ensures the migration is completed for GitLab.com, dev, or test' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true) + expect(instance).to receive(:ensure_batched_background_migration_is_finished).with(migration_arguments) + end + + migrate! + end + + it 'skips the check for other instances' do + expect_next_instance_of(described_class) do |instance| + expect(instance).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + expect(instance).not_to receive(:ensure_batched_background_migration_is_finished) + end + + migrate! + end + end +end diff --git a/spec/migrations/finalize_invalid_member_cleanup_spec.rb b/spec/migrations/finalize_invalid_member_cleanup_spec.rb index 29d03f8983c..c039edcc319 100644 --- a/spec/migrations/finalize_invalid_member_cleanup_spec.rb +++ b/spec/migrations/finalize_invalid_member_cleanup_spec.rb @@ -18,6 +18,10 @@ RSpec.describe FinalizeInvalidMemberCleanup, :migration, feature_category: :subg end context 'when migration is missing' do + before do + batched_migrations.where(job_class_name: migration).delete_all + end + it 'warns migration not found' do expect(Gitlab::AppLogger) .to receive(:warn).with(/Could not find batched background migration for the given configuration:/) diff --git a/spec/migrations/finalize_issues_iid_scoping_to_namespace_spec.rb b/spec/migrations/finalize_issues_iid_scoping_to_namespace_spec.rb new file mode 100644 index 00000000000..1834e8c6e0e --- /dev/null +++ b/spec/migrations/finalize_issues_iid_scoping_to_namespace_spec.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe FinalizeIssuesIidScopingToNamespace, :migration, feature_category: :team_planning do + let(:batched_migrations) { table(:batched_background_migrations) } + + let!(: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('"IssuesInternalIdScopeUpdater"', :internal_ids, :id, [nil, "up"]) + 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!(:migration) do + batched_migrations.create!( + job_class_name: 'IssuesInternalIdScopeUpdater', + table_name: :internal_ids, + column_name: :id, + job_arguments: [nil, 'up'], + 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 + migration.update!(status: status) + end + + it_behaves_like 'finalizes the migration' + end + end + end + end +end diff --git a/spec/migrations/finalize_issues_namespace_id_backfilling_spec.rb b/spec/migrations/finalize_issues_namespace_id_backfilling_spec.rb index d0c25fb3dd6..0800a049767 100644 --- a/spec/migrations/finalize_issues_namespace_id_backfilling_spec.rb +++ b/spec/migrations/finalize_issues_namespace_id_backfilling_spec.rb @@ -12,12 +12,16 @@ RSpec.describe FinalizeIssuesNamespaceIdBackfilling, :migration, feature_categor 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('BackfillProjectNamespaceOnIssues', :projects, :id, []) + expect(runner).to receive(:finalize).with(migration, :projects, :id, []) end end end context 'when routes backfilling migration is missing' do + before do + batched_migrations.where(job_class_name: migration).delete_all + end + it 'warns migration not found' do expect(Gitlab::AppLogger) .to receive(:warn).with(/Could not find batched background migration for the given configuration:/) @@ -29,7 +33,7 @@ RSpec.describe FinalizeIssuesNamespaceIdBackfilling, :migration, feature_categor context 'with backfilling migration present' do let!(:project_namespace_backfill) do batched_migrations.create!( - job_class_name: 'BackfillProjectNamespaceOnIssues', + job_class_name: migration, table_name: :routes, column_name: :id, job_arguments: [], diff --git a/spec/migrations/finalize_orphaned_routes_cleanup_spec.rb b/spec/migrations/finalize_orphaned_routes_cleanup_spec.rb index 78546806039..215fdbb05ad 100644 --- a/spec/migrations/finalize_orphaned_routes_cleanup_spec.rb +++ b/spec/migrations/finalize_orphaned_routes_cleanup_spec.rb @@ -12,12 +12,16 @@ RSpec.describe FinalizeOrphanedRoutesCleanup, :migration, feature_category: :pro 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('CleanupOrphanedRoutes', :projects, :id, []) + expect(runner).to receive(:finalize).with(migration, :projects, :id, []) end end end context 'when migration is missing' do + before do + batched_migrations.where(job_class_name: migration).delete_all + end + it 'warns migration not found' do expect(Gitlab::AppLogger) .to receive(:warn).with(/Could not find batched background migration for the given configuration:/) @@ -29,7 +33,7 @@ RSpec.describe FinalizeOrphanedRoutesCleanup, :migration, feature_category: :pro context 'with migration present' do let!(:project_namespace_backfill) do batched_migrations.create!( - job_class_name: 'CleanupOrphanedRoutes', + job_class_name: migration, table_name: :routes, column_name: :id, job_arguments: [], diff --git a/spec/migrations/finalize_project_namespaces_backfill_spec.rb b/spec/migrations/finalize_project_namespaces_backfill_spec.rb index 6cc3a694de8..880bb6661a4 100644 --- a/spec/migrations/finalize_project_namespaces_backfill_spec.rb +++ b/spec/migrations/finalize_project_namespaces_backfill_spec.rb @@ -12,12 +12,16 @@ RSpec.describe FinalizeProjectNamespacesBackfill, :migration, feature_category: 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('"ProjectNamespaces::BackfillProjectNamespaces"', :projects, :id, [nil, "up"]) + expect(runner).to receive(:finalize).with(migration, :projects, :id, [nil, "up"]) end end end context 'when project namespace backfilling migration is missing' do + before do + batched_migrations.where(job_class_name: migration).delete_all + end + it 'warns migration not found' do expect(Gitlab::AppLogger) .to receive(:warn).with(/Could not find batched background migration for the given configuration:/) @@ -29,7 +33,7 @@ RSpec.describe FinalizeProjectNamespacesBackfill, :migration, feature_category: context 'with backfilling migration present' do let!(:project_namespace_backfill) do batched_migrations.create!( - job_class_name: 'ProjectNamespaces::BackfillProjectNamespaces', + job_class_name: migration, table_name: :projects, column_name: :id, job_arguments: [nil, 'up'], diff --git a/spec/migrations/finalize_routes_backfilling_for_projects_spec.rb b/spec/migrations/finalize_routes_backfilling_for_projects_spec.rb index b79fdc98425..7618957d2f7 100644 --- a/spec/migrations/finalize_routes_backfilling_for_projects_spec.rb +++ b/spec/migrations/finalize_routes_backfilling_for_projects_spec.rb @@ -12,12 +12,16 @@ RSpec.describe FinalizeRoutesBackfillingForProjects, :migration, feature_categor 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('BackfillNamespaceIdForProjectRoute', :projects, :id, []) + expect(runner).to receive(:finalize).with(migration, :projects, :id, []) end end end context 'when routes backfilling migration is missing' do + before do + batched_migrations.where(job_class_name: migration).delete_all + end + it 'warns migration not found' do expect(Gitlab::AppLogger) .to receive(:warn).with(/Could not find batched background migration for the given configuration:/) @@ -29,7 +33,7 @@ RSpec.describe FinalizeRoutesBackfillingForProjects, :migration, feature_categor context 'with backfilling migration present' do let!(:project_namespace_backfill) do batched_migrations.create!( - job_class_name: 'BackfillNamespaceIdForProjectRoute', + job_class_name: migration, table_name: :routes, column_name: :id, job_arguments: [], diff --git a/spec/migrations/finalize_traversal_ids_background_migrations_spec.rb b/spec/migrations/finalize_traversal_ids_background_migrations_spec.rb deleted file mode 100644 index 0cebe7b9f91..00000000000 --- a/spec/migrations/finalize_traversal_ids_background_migrations_spec.rb +++ /dev/null @@ -1,60 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require_migration!('finalize_traversal_ids_background_migrations') - -RSpec.describe FinalizeTraversalIdsBackgroundMigrations, :migration, feature_category: :database do - shared_context 'incomplete background migration' do - before do - # Jobs enqueued in Sidekiq. - Sidekiq::Testing.disable! do - BackgroundMigrationWorker.perform_in(10, job_class_name, [1, 2, 100]) - BackgroundMigrationWorker.perform_in(20, job_class_name, [3, 4, 100]) - end - - # Jobs tracked in the database. - # table(:background_migration_jobs).create!( - Gitlab::Database::BackgroundMigrationJob.create!( - class_name: job_class_name, - arguments: [5, 6, 100], - status: Gitlab::Database::BackgroundMigrationJob.statuses['pending'] - ) - # table(:background_migration_jobs).create!( - Gitlab::Database::BackgroundMigrationJob.create!( - class_name: job_class_name, - arguments: [7, 8, 100], - status: Gitlab::Database::BackgroundMigrationJob.statuses['succeeded'] - ) - end - end - - context 'BackfillNamespaceTraversalIdsRoots background migration' do - let(:job_class_name) { 'BackfillNamespaceTraversalIdsRoots' } - - include_context 'incomplete background migration' - - before do - migrate! - end - - it_behaves_like( - 'finalized tracked background migration', - Gitlab::BackgroundMigration::BackfillNamespaceTraversalIdsRoots - ) - end - - context 'BackfillNamespaceTraversalIdsChildren background migration' do - let(:job_class_name) { 'BackfillNamespaceTraversalIdsChildren' } - - include_context 'incomplete background migration' - - before do - migrate! - end - - it_behaves_like( - 'finalized tracked background migration', - Gitlab::BackgroundMigration::BackfillNamespaceTraversalIdsChildren - ) - end -end diff --git a/spec/migrations/insert_daily_invites_trial_plan_limits_spec.rb b/spec/migrations/insert_daily_invites_trial_plan_limits_spec.rb new file mode 100644 index 00000000000..ea1476b94a9 --- /dev/null +++ b/spec/migrations/insert_daily_invites_trial_plan_limits_spec.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe InsertDailyInvitesTrialPlanLimits, feature_category: :subgroups do + let(:plans) { table(:plans) } + let(:plan_limits) { table(:plan_limits) } + let!(:premium_trial_plan) { plans.create!(name: 'premium_trial') } + let!(:ultimate_trial_plan) { plans.create!(name: 'ultimate_trial') } + + context 'when on gitlab.com' do + before do + allow(Gitlab).to receive(:com?).and_return(true) + end + + it 'correctly migrates up and down' do + reversible_migration do |migration| + migration.before -> { + trial_plan_ids = [premium_trial_plan.id, ultimate_trial_plan.id] + expect(plan_limits.where(plan_id: trial_plan_ids).where.not(daily_invites: 0)).to be_empty + } + + migration.after -> { + expect(plan_limits.pluck(:plan_id, :daily_invites)) + .to contain_exactly([premium_trial_plan.id, 50], [ultimate_trial_plan.id, 50]) + } + end + end + end + + context 'when on self-managed' do + before do + allow(Gitlab).to receive(:com?).and_return(false) + end + + it 'correctly migrates up and down' do + reversible_migration do |migration| + trial_plan_ids = [premium_trial_plan.id, ultimate_trial_plan.id] + + migration.before -> { + expect(plan_limits.where(plan_id: trial_plan_ids).where.not(daily_invites: 0)).to be_empty + } + + migration.after -> { + expect(plan_limits.where(plan_id: trial_plan_ids).where.not(daily_invites: 0)).to be_empty + } + end + end + end +end diff --git a/spec/migrations/queue_backfill_admin_mode_scope_for_personal_access_tokens_spec.rb b/spec/migrations/queue_backfill_admin_mode_scope_for_personal_access_tokens_spec.rb deleted file mode 100644 index 8209f317550..00000000000 --- a/spec/migrations/queue_backfill_admin_mode_scope_for_personal_access_tokens_spec.rb +++ /dev/null @@ -1,18 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require_migration! - -RSpec.describe QueueBackfillAdminModeScopeForPersonalAccessTokens, - feature_category: :authentication_and_authorization do - describe '#up' do - it 'schedules background migration' do - migrate! - - expect(described_class::MIGRATION).to have_scheduled_batched_migration( - table_name: :personal_access_tokens, - column_name: :id, - interval: described_class::DELAY_INTERVAL) - end - end -end diff --git a/spec/migrations/queue_backfill_prepared_at_data_spec.rb b/spec/migrations/queue_backfill_prepared_at_data_spec.rb new file mode 100644 index 00000000000..ac3ea2f59c5 --- /dev/null +++ b/spec/migrations/queue_backfill_prepared_at_data_spec.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe QueueBackfillPreparedAtData, feature_category: :code_review_workflow do + let!(: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: :merge_requests, + column_name: :id, + interval: described_class::DELAY_INTERVAL + ) + } + end + end +end diff --git a/spec/migrations/recreate_index_security_ci_builds_on_name_and_id_parser_features_spec.rb b/spec/migrations/recreate_index_security_ci_builds_on_name_and_id_parser_features_spec.rb deleted file mode 100644 index 80ecc23dfbe..00000000000 --- a/spec/migrations/recreate_index_security_ci_builds_on_name_and_id_parser_features_spec.rb +++ /dev/null @@ -1,28 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -require_migration! - -RSpec.describe RecreateIndexSecurityCiBuildsOnNameAndIdParserFeatures, :migration, feature_category: :database do - let(:db) { described_class.new } - let(:pg_class) { table(:pg_class) } - let(:pg_index) { table(:pg_index) } - let(:async_indexes) { table(:postgres_async_indexes) } - - it "recreates index" do - reversible_migration do |migration| - migration.before -> { - expect(async_indexes.where(name: described_class::OLD_INDEX_NAME).exists?).to be false - expect(db.index_exists?(described_class::TABLE, described_class::COLUMNS, name: described_class::OLD_INDEX_NAME)).to be true - expect(db.index_exists?(described_class::TABLE, described_class::COLUMNS, name: described_class::NEW_INDEX_NAME)).to be false - } - - migration.after -> { - expect(async_indexes.where(name: described_class::OLD_INDEX_NAME).exists?).to be true - expect(db.index_exists?(described_class::TABLE, described_class::COLUMNS, name: described_class::OLD_INDEX_NAME)).to be false - expect(db.index_exists?(described_class::TABLE, described_class::COLUMNS, name: described_class::NEW_INDEX_NAME)).to be true - } - end - end -end diff --git a/spec/migrations/remove_invalid_deploy_access_level_spec.rb b/spec/migrations/remove_invalid_deploy_access_level_spec.rb deleted file mode 100644 index cc0f5679dda..00000000000 --- a/spec/migrations/remove_invalid_deploy_access_level_spec.rb +++ /dev/null @@ -1,48 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -require_migration! - -RSpec.describe RemoveInvalidDeployAccessLevel, :migration, feature_category: :continuous_integration do - let(:users) { table(:users) } - let(:groups) { table(:namespaces) } - let(:protected_environments) { table(:protected_environments) } - let(:deploy_access_levels) { table(:protected_environment_deploy_access_levels) } - - let(:user) { users.create!(email: 'email@email.com', name: 'foo', username: 'foo', projects_limit: 0) } - let(:group) { groups.create!(name: 'test-group', path: 'test-group') } - let(:pe) do - protected_environments.create!(name: 'test-pe', group_id: group.id) - end - - let!(:invalid_access_level) do - deploy_access_levels.create!( - access_level: 40, - user_id: user.id, - group_id: group.id, - protected_environment_id: pe.id) - end - - let!(:group_access_level) do - deploy_access_levels.create!( - group_id: group.id, - protected_environment_id: pe.id) - end - - let!(:user_access_level) do - deploy_access_levels.create!( - user_id: user.id, - protected_environment_id: pe.id) - end - - it 'removes invalid access_level entries' do - expect { migrate! }.to change { - deploy_access_levels.where( - protected_environment_id: pe.id, - access_level: nil).count - }.from(2).to(3) - - expect(invalid_access_level.reload.access_level).to be_nil - end -end diff --git a/spec/migrations/remove_packages_events_package_id_fk_spec.rb b/spec/migrations/remove_packages_events_package_id_fk_spec.rb new file mode 100644 index 00000000000..13e73de88bd --- /dev/null +++ b/spec/migrations/remove_packages_events_package_id_fk_spec.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require "spec_helper" + +require_migration! + +RSpec.describe RemovePackagesEventsPackageIdFk, feature_category: :package_registry do + let(:table) { described_class::SOURCE_TABLE } + let(:column) { described_class::COLUMN } + let(:foreign_key) { -> { described_class.new.foreign_keys_for(table, column).first } } + + it 'drops and creates the foreign key' do + reversible_migration do |migration| + migration.before -> do + expect(foreign_key.call).to have_attributes(column: column.to_s) + end + + migration.after -> do + expect(foreign_key.call).to be(nil) + end + end + end +end diff --git a/spec/migrations/remove_saml_provider_and_identities_non_root_group_spec.rb b/spec/migrations/remove_saml_provider_and_identities_non_root_group_spec.rb new file mode 100644 index 00000000000..07873d0ce79 --- /dev/null +++ b/spec/migrations/remove_saml_provider_and_identities_non_root_group_spec.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe RemoveSamlProviderAndIdentitiesNonRootGroup, feature_category: :system_access do + let(:namespaces) { table(:namespaces) } + let(:saml_providers) { table(:saml_providers) } + let(:identities) { table(:identities) } + let(:root_group) do + namespaces.create!(name: 'root_group', path: 'foo', parent_id: nil, type: 'Group') + end + + let(:non_root_group) do + namespaces.create!(name: 'non_root_group', path: 'non_root', parent_id: root_group.id, type: 'Group') + end + + it 'removes saml_providers that belong to non-root group and related identities' do + provider_root_group = saml_providers.create!( + group_id: root_group.id, + sso_url: 'https://saml.example.com/adfs/ls', + certificate_fingerprint: '55:44:33:22:11:aa:bb:cc:dd:ee:ff:11:22:33:44:55:66:77:88:99', + default_membership_role: ::Gitlab::Access::GUEST, + enabled: true + ) + + identity_root_group = identities.create!( + saml_provider_id: provider_root_group.id, + extern_uid: "12345" + ) + + provider_non_root_group = saml_providers.create!( + group_id: non_root_group.id, + sso_url: 'https://saml.example.com/adfs/ls', + certificate_fingerprint: '55:44:33:22:11:aa:bb:cc:dd:ee:ff:11:22:33:44:55:66:77:88:99', + default_membership_role: ::Gitlab::Access::GUEST, + enabled: true + ) + + identity_non_root_group = identities.create!( + saml_provider_id: provider_non_root_group.id, + extern_uid: "12345" + ) + + expect { migrate! }.to change { saml_providers.count }.from(2).to(1) + + expect(identities.find_by_id(identity_non_root_group.id)).to be_nil + expect(saml_providers.find_by_id(provider_non_root_group.id)).to be_nil + + expect(identities.find_by_id(identity_root_group.id)).not_to be_nil + expect(saml_providers.find_by_id(provider_root_group.id)).not_to be_nil + end +end diff --git a/spec/migrations/remove_schedule_and_status_from_pending_alert_escalations_spec.rb b/spec/migrations/remove_schedule_and_status_from_pending_alert_escalations_spec.rb deleted file mode 100644 index 86e161cea43..00000000000 --- a/spec/migrations/remove_schedule_and_status_from_pending_alert_escalations_spec.rb +++ /dev/null @@ -1,37 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require_migration! - -RSpec.describe RemoveScheduleAndStatusFromPendingAlertEscalations, feature_category: :incident_management do - let(:escalations) { table(:incident_management_pending_alert_escalations) } - let(:schedule_index) { 'index_incident_management_pending_alert_escalations_on_schedule' } - let(:schedule_foreign_key) { 'fk_rails_fcbfd9338b' } - - it 'correctly migrates up and down' do - reversible_migration do |migration| - migration.before -> { - expect(escalations.column_names).to include('schedule_id', 'status') - expect(escalations_indexes).to include(schedule_index) - expect(escalations_constraints).to include(schedule_foreign_key) - } - - migration.after -> { - escalations.reset_column_information - expect(escalations.column_names).not_to include('schedule_id', 'status') - expect(escalations_indexes).not_to include(schedule_index) - expect(escalations_constraints).not_to include(schedule_foreign_key) - } - end - end - - private - - def escalations_indexes - ActiveRecord::Base.connection.indexes(:incident_management_pending_alert_escalations).collect(&:name) - end - - def escalations_constraints - ActiveRecord::Base.connection.foreign_keys(:incident_management_pending_alert_escalations).collect(&:name) - end -end diff --git a/spec/migrations/remove_scim_token_and_scim_identity_non_root_group_spec.rb b/spec/migrations/remove_scim_token_and_scim_identity_non_root_group_spec.rb new file mode 100644 index 00000000000..31915365c91 --- /dev/null +++ b/spec/migrations/remove_scim_token_and_scim_identity_non_root_group_spec.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe RemoveScimTokenAndScimIdentityNonRootGroup, feature_category: :system_access do + let(:namespaces) { table(:namespaces) } + let(:scim_oauth_access_tokens) { table(:scim_oauth_access_tokens) } + let(:scim_identities) { table(:scim_identities) } + let(:users) { table(:users) } + let(:root_group) do + namespaces.create!(name: 'root_group', path: 'foo', parent_id: nil, type: 'Group') + end + + let(:non_root_group) do + namespaces.create!(name: 'non_root_group', path: 'non_root', parent_id: root_group.id, type: 'Group') + end + + let(:root_group_user) do + users.create!(name: 'Example User', email: 'user@example.com', projects_limit: 0) + end + + let(:non_root_group_user) do + users.create!(username: 'user2', email: 'user2@example.com', projects_limit: 10) + end + + it 'removes scim_oauth_access_tokens that belong to non-root group and related scim_identities' do + scim_oauth_access_token_root_group = scim_oauth_access_tokens.create!( + group_id: root_group.id, + token_encrypted: Gitlab::CryptoHelper.aes256_gcm_encrypt(SecureRandom.hex(50)) + ) + scim_oauth_access_token_non_root_group = scim_oauth_access_tokens.create!( + group_id: non_root_group.id, + token_encrypted: Gitlab::CryptoHelper.aes256_gcm_encrypt(SecureRandom.hex(50)) + ) + + scim_identity_root_group = scim_identities.create!( + group_id: root_group.id, + extern_uid: "12345", + user_id: root_group_user.id, + active: true + ) + + scim_identity_non_root_group = scim_identities.create!( + group_id: non_root_group.id, + extern_uid: "12345", + user_id: non_root_group_user.id, + active: true + ) + + expect { migrate! }.to change { scim_oauth_access_tokens.count }.from(2).to(1) + expect(scim_oauth_access_tokens.find_by_id(scim_oauth_access_token_non_root_group.id)).to be_nil + expect(scim_identities.find_by_id(scim_identity_non_root_group.id)).to be_nil + + expect(scim_oauth_access_tokens.find_by_id(scim_oauth_access_token_root_group.id)).not_to be_nil + expect(scim_identities.find_by_id(scim_identity_root_group.id)).not_to be_nil + end +end diff --git a/spec/migrations/requeue_backfill_admin_mode_scope_for_personal_access_tokens_spec.rb b/spec/migrations/requeue_backfill_admin_mode_scope_for_personal_access_tokens_spec.rb new file mode 100644 index 00000000000..b9af6d98beb --- /dev/null +++ b/spec/migrations/requeue_backfill_admin_mode_scope_for_personal_access_tokens_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe RequeueBackfillAdminModeScopeForPersonalAccessTokens, feature_category: :system_access do + describe '#up' do + it 'schedules background migration' do + migrate! + + expect(described_class::MIGRATION).to( + have_scheduled_batched_migration( + table_name: :personal_access_tokens, + column_name: :id, + interval: described_class::DELAY_INTERVAL) + ) + end + end +end diff --git a/spec/migrations/rerun_remove_invalid_deploy_access_level_spec.rb b/spec/migrations/rerun_remove_invalid_deploy_access_level_spec.rb new file mode 100644 index 00000000000..72663e63996 --- /dev/null +++ b/spec/migrations/rerun_remove_invalid_deploy_access_level_spec.rb @@ -0,0 +1,86 @@ +# frozen_string_literal: true + +require 'spec_helper' + +require_migration! + +RSpec.describe RerunRemoveInvalidDeployAccessLevel, :migration, feature_category: :continuous_integration do + let(:users) { table(:users) } + let(:groups) { table(:namespaces) } + let(:protected_environments) { table(:protected_environments) } + let(:deploy_access_levels) { table(:protected_environment_deploy_access_levels) } + + let(:user) { users.create!(email: 'email@email.com', name: 'foo', username: 'foo', projects_limit: 0) } + let(:group) { groups.create!(name: 'test-group', path: 'test-group') } + let(:pe) do + protected_environments.create!(name: 'test-pe', group_id: group.id) + end + + let!(:invalid_access_level) do + deploy_access_levels.create!( + access_level: 40, + user_id: user.id, + group_id: group.id, + protected_environment_id: pe.id) + end + + let!(:access_level) do + deploy_access_levels.create!( + access_level: 40, + user_id: nil, + group_id: nil, + protected_environment_id: pe.id) + end + + let!(:group_access_level) do + deploy_access_levels.create!( + group_id: group.id, + protected_environment_id: pe.id) + end + + let!(:user_access_level) do + deploy_access_levels.create!( + user_id: user.id, + protected_environment_id: pe.id) + end + + let!(:user_and_group_access_level) do + deploy_access_levels.create!( + user_id: user.id, + group_id: group.id, + protected_environment_id: pe.id) + end + + it 'fixes invalid access_level entries and does not affect others' do + expect { migrate! }.to change { + deploy_access_levels.where(protected_environment_id: pe.id) + .where("num_nonnulls(user_id, group_id, access_level) = 1").count + }.from(3).to(5) + + invalid_access_level.reload + access_level.reload + group_access_level.reload + user_access_level.reload + user_and_group_access_level.reload + + expect(invalid_access_level.access_level).to be_nil + expect(invalid_access_level.user_id).to eq(user.id) + expect(invalid_access_level.group_id).to be_nil + + expect(access_level.access_level).to eq(40) + expect(access_level.user_id).to be_nil + expect(access_level.group_id).to be_nil + + expect(group_access_level.access_level).to be_nil + expect(group_access_level.user_id).to be_nil + expect(group_access_level.group_id).to eq(group.id) + + expect(user_access_level.access_level).to be_nil + expect(user_access_level.user_id).to eq(user.id) + expect(user_access_level.group_id).to be_nil + + expect(user_and_group_access_level.access_level).to be_nil + expect(user_and_group_access_level.user_id).to eq(user.id) + expect(user_and_group_access_level.group_id).to be_nil + end +end diff --git a/spec/migrations/reschedule_incident_work_item_type_id_backfill_spec.rb b/spec/migrations/reschedule_incident_work_item_type_id_backfill_spec.rb new file mode 100644 index 00000000000..cb8773e9a9f --- /dev/null +++ b/spec/migrations/reschedule_incident_work_item_type_id_backfill_spec.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe RescheduleIncidentWorkItemTypeIdBackfill, :migration, feature_category: :team_planning do + include MigrationHelpers::WorkItemTypesHelper + + let!(:migration) { described_class::MIGRATION } + let!(:interval) { 2.minutes } + let!(:incident_type_enum) { 1 } + let!(:issue_type_enum) { 0 } + let!(:incident_work_item_type) do + table(:work_item_types).find_by!(namespace_id: nil, base_type: incident_type_enum) + end + + let!(:issue_work_item_type) do + table(:work_item_types).find_by!(namespace_id: nil, base_type: issue_type_enum) + end + + describe '#up' do + let!(:existing_incident_migration) { create_backfill_migration(incident_type_enum, incident_work_item_type.id) } + let!(:existing_issue_migration) { create_backfill_migration(issue_type_enum, issue_work_item_type.id) } + + it 'correctly reschedules background migration only for incidents' do + migrate! + + migration_ids = table(:batched_background_migrations).pluck(:id) + + expect(migration).to have_scheduled_batched_migration( + table_name: :issues, + column_name: :id, + job_arguments: [incident_type_enum, incident_work_item_type.id], + interval: interval, + batch_size: described_class::BATCH_SIZE, + max_batch_size: described_class::MAX_BATCH_SIZE, + sub_batch_size: described_class::SUB_BATCH_SIZE + ) + expect(migration_ids.count).to eq(2) + expect(migration_ids).not_to include(existing_incident_migration.id) + expect(migration_ids).to include(existing_issue_migration.id) + end + + it "doesn't fail if work item types don't exist on the DB" do + table(:work_item_types).delete_all + + migrate! + + # Since migration specs run outside of a transaction, we need to make + # sure we recreate default types since this spec deletes them all + reset_work_item_types + end + end + + def create_backfill_migration(base_type, type_id) + table(:batched_background_migrations).create!( + job_class_name: migration, + table_name: :issues, + column_name: :id, + job_arguments: [base_type, type_id], + interval: 2.minutes, + min_value: 1, + max_value: 2, + batch_size: 1000, + sub_batch_size: 200, + gitlab_schema: :gitlab_main, + status: 3 + ) + end +end diff --git a/spec/migrations/schedule_backfill_draft_status_on_merge_requests_corrected_regex_spec.rb b/spec/migrations/schedule_backfill_draft_status_on_merge_requests_corrected_regex_spec.rb index a3bec40c3f0..abcdde7f075 100644 --- a/spec/migrations/schedule_backfill_draft_status_on_merge_requests_corrected_regex_spec.rb +++ b/spec/migrations/schedule_backfill_draft_status_on_merge_requests_corrected_regex_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' require_migration! RSpec.describe ScheduleBackfillDraftStatusOnMergeRequestsCorrectedRegex, - :sidekiq, feature_category: :code_review_workflow do + :sidekiq, feature_category: :code_review_workflow do let(:namespaces) { table(:namespaces) } let(:projects) { table(:projects) } let(:merge_requests) { table(:merge_requests) } diff --git a/spec/migrations/schedule_fixing_security_scan_statuses_spec.rb b/spec/migrations/schedule_fixing_security_scan_statuses_spec.rb index c4c7819bda7..56d30e71676 100644 --- a/spec/migrations/schedule_fixing_security_scan_statuses_spec.rb +++ b/spec/migrations/schedule_fixing_security_scan_statuses_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' require_migration! -RSpec.describe ScheduleFixingSecurityScanStatuses, :suppress_gitlab_schemas_validate_connection, - feature_category: :vulnerability_management do +RSpec.describe ScheduleFixingSecurityScanStatuses, + :suppress_gitlab_schemas_validate_connection, feature_category: :vulnerability_management do let!(:namespaces) { table(:namespaces) } let!(:projects) { table(:projects) } let!(:pipelines) { table(:ci_pipelines) } diff --git a/spec/migrations/schedule_migrate_shared_vulnerability_identifiers_spec.rb b/spec/migrations/schedule_migrate_shared_vulnerability_identifiers_spec.rb new file mode 100644 index 00000000000..c1802a1a339 --- /dev/null +++ b/spec/migrations/schedule_migrate_shared_vulnerability_identifiers_spec.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +require "spec_helper" + +require_migration! + +RSpec.describe ScheduleMigrateSharedVulnerabilityIdentifiers, :migration, feature_category: :vulnerability_management do + describe "#up" do + before do + migrate! + end + + it "schedules" do + Gitlab::Database::BackgroundMigration::BatchedMigration.find_by!( + job_class_name: described_class::MIGRATION, + table_name: described_class::TABLE_NAME, + column_name: described_class::BATCH_COLUMN, + batch_size: described_class::BATCH_SIZE, + sub_batch_size: described_class::SUB_BATCH_SIZE) + 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/schedule_purging_stale_security_scans_spec.rb b/spec/migrations/schedule_purging_stale_security_scans_spec.rb index b39baa145ff..906dc90bcc4 100644 --- a/spec/migrations/schedule_purging_stale_security_scans_spec.rb +++ b/spec/migrations/schedule_purging_stale_security_scans_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' require_migration! RSpec.describe SchedulePurgingStaleSecurityScans, :suppress_gitlab_schemas_validate_connection, -feature_category: :vulnerability_management do + feature_category: :vulnerability_management do let!(:namespaces) { table(:namespaces) } let!(:projects) { table(:projects) } let!(:pipelines) { table(:ci_pipelines) } diff --git a/spec/migrations/schedule_recalculate_vulnerability_finding_signatures_for_findings_spec.rb b/spec/migrations/schedule_recalculate_vulnerability_finding_signatures_for_findings_spec.rb deleted file mode 100644 index 8903a32285e..00000000000 --- a/spec/migrations/schedule_recalculate_vulnerability_finding_signatures_for_findings_spec.rb +++ /dev/null @@ -1,90 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require_migration! - -RSpec.describe ScheduleRecalculateVulnerabilityFindingSignaturesForFindings, :migration, -feature_category: :vulnerability_management do - before do - allow(Gitlab).to receive(:ee?).and_return(ee?) - stub_const("#{described_class.name}::BATCH_SIZE", 2) - end - - context 'when the Gitlab instance is FOSS' do - let(:ee?) { false } - - it 'does not run the migration' do - expect { migrate! }.not_to change { BackgroundMigrationWorker.jobs.size } - end - end - - context 'when the Gitlab instance is EE' do - let(:ee?) { true } - - let!(:namespaces) { table(:namespaces) } - let!(:projects) { table(:projects) } - let!(:findings) { table(:vulnerability_occurrences) } - let!(:scanners) { table(:vulnerability_scanners) } - let!(:identifiers) { table(:vulnerability_identifiers) } - let!(:vulnerability_finding_signatures) { table(:vulnerability_finding_signatures) } - - let!(:namespace) { namespaces.create!(name: 'test', path: 'test') } - let!(:project) { projects.create!(namespace_id: namespace.id, name: 'gitlab', path: 'gitlab') } - - let!(:scanner) do - scanners.create!(project_id: project.id, external_id: 'trivy', name: 'Security Scanner') - end - - let!(:identifier) do - identifiers.create!(project_id: project.id, - fingerprint: 'd432c2ad2953e8bd587a3a43b3ce309b5b0154c123', - external_type: 'SECURITY_ID', - external_id: 'SECURITY_0', - name: 'SECURITY_IDENTIFIER 0') - end - - let!(:finding1) { findings.create!(finding_params) } - let!(:signature1) { vulnerability_finding_signatures.create!(finding_id: finding1.id, algorithm_type: 0, signature_sha: ::Digest::SHA1.digest(SecureRandom.hex(50))) } - - let!(:finding2) { findings.create!(finding_params) } - let!(:signature2) { vulnerability_finding_signatures.create!(finding_id: finding2.id, algorithm_type: 0, signature_sha: ::Digest::SHA1.digest(SecureRandom.hex(50))) } - - let!(:finding3) { findings.create!(finding_params) } - let!(:signature3) { vulnerability_finding_signatures.create!(finding_id: finding3.id, algorithm_type: 0, signature_sha: ::Digest::SHA1.digest(SecureRandom.hex(50))) } - - # this migration is now a no-op - it 'does not schedule the background jobs', :aggregate_failure do - Sidekiq::Testing.fake! do - freeze_time do - migrate! - - expect(BackgroundMigrationWorker.jobs.size).to eq(0) - expect(described_class::MIGRATION) - .not_to be_scheduled_migration_with_multiple_args(signature1.id, signature2.id) - expect(described_class::MIGRATION) - .not_to be_scheduled_migration_with_multiple_args(signature3.id, signature3.id) - end - end - end - - def finding_params - uuid = SecureRandom.uuid - - { - severity: 0, - confidence: 5, - report_type: 2, - project_id: project.id, - scanner_id: scanner.id, - primary_identifier_id: identifier.id, - location: nil, - project_fingerprint: SecureRandom.hex(20), - location_fingerprint: Digest::SHA1.hexdigest(SecureRandom.hex(10)), - uuid: uuid, - name: "Vulnerability Finding #{uuid}", - metadata_version: '1.3', - raw_metadata: '{}' - } - end - end -end diff --git a/spec/migrations/set_email_confirmation_setting_before_removing_send_user_confirmation_email_column_spec.rb b/spec/migrations/set_email_confirmation_setting_before_removing_send_user_confirmation_email_column_spec.rb index 8e00fbe4b89..02ecbe90ee0 100644 --- a/spec/migrations/set_email_confirmation_setting_before_removing_send_user_confirmation_email_column_spec.rb +++ b/spec/migrations/set_email_confirmation_setting_before_removing_send_user_confirmation_email_column_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' require_migration! RSpec.describe SetEmailConfirmationSettingBeforeRemovingSendUserConfirmationEmailColumn, - feature_category: :user_profile do + feature_category: :user_profile do let(:migration) { described_class.new } let(:application_settings_table) { table(:application_settings) } diff --git a/spec/migrations/set_email_confirmation_setting_from_soft_email_confirmation_ff_spec.rb b/spec/migrations/set_email_confirmation_setting_from_soft_email_confirmation_ff_spec.rb new file mode 100644 index 00000000000..202baebf1da --- /dev/null +++ b/spec/migrations/set_email_confirmation_setting_from_soft_email_confirmation_ff_spec.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe SetEmailConfirmationSettingFromSoftEmailConfirmationFf, feature_category: :feature_flags do + let(:migration) { described_class.new } + let(:application_settings_table) { table(:application_settings) } + let(:feature_gates_table) { table(:feature_gates) } + + describe '#up' do + context 'when feature gate for `soft_email_confirmation` does not exist' do + it 'does not update `email_confirmation_setting`' do + application_settings_table.create!(email_confirmation_setting: 0) + + migration.up + + expect(application_settings_table.last.email_confirmation_setting).to eq 0 + end + end + + context 'when feature gate for `soft_email_confirmation` does exist' do + context 'when feature gate value is `false`' do + before do + feature_gates_table.create!(feature_key: 'soft_email_confirmation', key: 'boolean', value: 'false') + end + + it 'does not update `email_confirmation_setting`' do + application_settings_table.create!(email_confirmation_setting: 0) + + migration.up + + expect(application_settings_table.last.email_confirmation_setting).to eq 0 + end + end + + context 'when feature gate value is `true`' do + before do + feature_gates_table.create!(feature_key: 'soft_email_confirmation', key: 'boolean', value: 'true') + end + + it "updates `email_confirmation_setting` to '1' (soft)" do + application_settings_table.create!(email_confirmation_setting: 0) + + migration.up + + expect(application_settings_table.last.email_confirmation_setting).to eq 1 + end + end + end + end + + describe '#down' do + it "updates 'email_confirmation_setting' to default value: '0' (off)" do + application_settings_table.create!(email_confirmation_setting: 1) + + migration.down + + expect(application_settings_table.last.email_confirmation_setting).to eq 0 + end + end +end diff --git a/spec/migrations/slice_merge_request_diff_commit_migrations_spec.rb b/spec/migrations/slice_merge_request_diff_commit_migrations_spec.rb deleted file mode 100644 index ffd25152a45..00000000000 --- a/spec/migrations/slice_merge_request_diff_commit_migrations_spec.rb +++ /dev/null @@ -1,70 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require_migration! - -RSpec.describe SliceMergeRequestDiffCommitMigrations, :migration, feature_category: :code_review_workflow do - let(:migration) { described_class.new } - - describe '#up' do - context 'when there are no jobs to process' do - it 'does nothing' do - expect(migration).not_to receive(:migrate_in) - expect(Gitlab::Database::BackgroundMigrationJob).not_to receive(:create!) - - migration.up - end - end - - context 'when there are pending jobs' do - let!(:job1) do - Gitlab::Database::BackgroundMigrationJob.create!( - class_name: described_class::MIGRATION_CLASS, - arguments: [1, 10_001] - ) - end - - let!(:job2) do - Gitlab::Database::BackgroundMigrationJob.create!( - class_name: described_class::MIGRATION_CLASS, - arguments: [10_001, 20_001] - ) - end - - it 'marks the old jobs as finished' do - migration.up - - job1.reload - job2.reload - - expect(job1).to be_succeeded - expect(job2).to be_succeeded - end - - it 'the jobs are slices into smaller ranges' do - migration.up - - new_jobs = Gitlab::Database::BackgroundMigrationJob - .for_migration_class(described_class::MIGRATION_CLASS) - .pending - .to_a - - expect(new_jobs.map(&:arguments)).to eq( - [ - [1, 5_001], - [5_001, 10_001], - [10_001, 15_001], - [15_001, 20_001] - ]) - end - - it 'schedules a background migration for the first job' do - expect(migration) - .to receive(:migrate_in) - .with(1.hour, described_class::STEAL_MIGRATION_CLASS, [1, 5_001]) - - migration.up - end - end - end -end diff --git a/spec/migrations/start_backfill_ci_queuing_tables_spec.rb b/spec/migrations/start_backfill_ci_queuing_tables_spec.rb index c308a16d5b8..0a189b58c94 100644 --- a/spec/migrations/start_backfill_ci_queuing_tables_spec.rb +++ b/spec/migrations/start_backfill_ci_queuing_tables_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' require_migration! RSpec.describe StartBackfillCiQueuingTables, :suppress_gitlab_schemas_validate_connection, -feature_category: :continuous_integration do + feature_category: :continuous_integration do let(:namespaces) { table(:namespaces) } let(:projects) { table(:projects) } let(:builds) { table(:ci_builds) } diff --git a/spec/migrations/swap_award_emoji_note_id_to_bigint_for_gitlab_dot_com_spec.rb b/spec/migrations/swap_award_emoji_note_id_to_bigint_for_gitlab_dot_com_spec.rb new file mode 100644 index 00000000000..c133deaf250 --- /dev/null +++ b/spec/migrations/swap_award_emoji_note_id_to_bigint_for_gitlab_dot_com_spec.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe SwapAwardEmojiNoteIdToBigintForGitlabDotCom, feature_category: :database do + describe '#up' do + before do + # A we call `schema_migrate_down!` before each example, and for this migration + # `#down` is same as `#up`, we need to ensure we start from the expected state. + connection = described_class.new.connection + connection.execute('ALTER TABLE award_emoji ALTER COLUMN awardable_id TYPE integer') + connection.execute('ALTER TABLE award_emoji ALTER COLUMN awardable_id_convert_to_bigint TYPE bigint') + end + + # rubocop: disable RSpec/AnyInstanceOf + it 'swaps the integer and bigint columns for GitLab.com, dev, or test' do + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true) + + award_emoji = table(:award_emoji) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + award_emoji.reset_column_information + + expect(award_emoji.columns.find { |c| c.name == 'awardable_id' }.sql_type).to eq('integer') + expect(award_emoji.columns.find { |c| c.name == 'awardable_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + + migration.after -> { + award_emoji.reset_column_information + + expect(award_emoji.columns.find { |c| c.name == 'awardable_id' }.sql_type).to eq('bigint') + expect(award_emoji.columns.find { |c| c.name == 'awardable_id_convert_to_bigint' }.sql_type) + .to eq('integer') + } + end + end + end + + it 'is a no-op for other instances' do + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + + award_emoji = table(:award_emoji) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + award_emoji.reset_column_information + + expect(award_emoji.columns.find { |c| c.name == 'awardable_id' }.sql_type).to eq('integer') + expect(award_emoji.columns.find { |c| c.name == 'awardable_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + + migration.after -> { + award_emoji.reset_column_information + + expect(award_emoji.columns.find { |c| c.name == 'awardable_id' }.sql_type).to eq('integer') + expect(award_emoji.columns.find { |c| c.name == 'awardable_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + end + end + end + # rubocop: enable RSpec/AnyInstanceOf + end +end diff --git a/spec/migrations/swap_commit_user_mentions_note_id_to_bigint_for_gitlab_dot_com_spec.rb b/spec/migrations/swap_commit_user_mentions_note_id_to_bigint_for_gitlab_dot_com_spec.rb new file mode 100644 index 00000000000..d219d544033 --- /dev/null +++ b/spec/migrations/swap_commit_user_mentions_note_id_to_bigint_for_gitlab_dot_com_spec.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe SwapCommitUserMentionsNoteIdToBigintForGitlabDotCom, feature_category: :database do + describe '#up' do + before do + # A we call `schema_migrate_down!` before each example, and for this migration + # `#down` is same as `#up`, we need to ensure we start from the expected state. + connection = described_class.new.connection + connection.execute('ALTER TABLE commit_user_mentions ALTER COLUMN note_id TYPE integer') + connection.execute('ALTER TABLE commit_user_mentions ALTER COLUMN note_id_convert_to_bigint TYPE bigint') + end + + # rubocop: disable RSpec/AnyInstanceOf + it 'swaps the integer and bigint columns for GitLab.com, dev, or test' do + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true) + + user_mentions = table(:commit_user_mentions) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + user_mentions.reset_column_information + + expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + + migration.after -> { + user_mentions.reset_column_information + + expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('bigint') + expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('integer') + } + end + end + end + + it 'is a no-op for other instances' do + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + + user_mentions = table(:commit_user_mentions) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + user_mentions.reset_column_information + + expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + + migration.after -> { + user_mentions.reset_column_information + + expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + end + end + end + # rubocop: enable RSpec/AnyInstanceOf + end +end diff --git a/spec/migrations/swap_design_user_mentions_note_id_to_bigint_for_gitlab_dot_com_spec.rb b/spec/migrations/swap_design_user_mentions_note_id_to_bigint_for_gitlab_dot_com_spec.rb new file mode 100644 index 00000000000..c7cbf7bfe2a --- /dev/null +++ b/spec/migrations/swap_design_user_mentions_note_id_to_bigint_for_gitlab_dot_com_spec.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe SwapDesignUserMentionsNoteIdToBigintForGitlabDotCom, feature_category: :database do + describe '#up' do + before do + # A we call `schema_migrate_down!` before each example, and for this migration + # `#down` is same as `#up`, we need to ensure we start from the expected state. + connection = described_class.new.connection + connection.execute('ALTER TABLE design_user_mentions ALTER COLUMN note_id TYPE integer') + connection.execute('ALTER TABLE design_user_mentions ALTER COLUMN note_id_convert_to_bigint TYPE bigint') + end + + # rubocop: disable RSpec/AnyInstanceOf + it 'swaps the integer and bigint columns for GitLab.com, dev, or test' do + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true) + + user_mentions = table(:design_user_mentions) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + user_mentions.reset_column_information + + expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + + migration.after -> { + user_mentions.reset_column_information + + expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('bigint') + expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('integer') + } + end + end + end + + it 'is a no-op for other instances' do + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + + user_mentions = table(:design_user_mentions) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + user_mentions.reset_column_information + + expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + + migration.after -> { + user_mentions.reset_column_information + + expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + end + end + end + # rubocop: enable RSpec/AnyInstanceOf + end +end diff --git a/spec/migrations/swap_epic_user_mentions_note_id_to_bigint_for_gitlab_dot_com_spec.rb b/spec/migrations/swap_epic_user_mentions_note_id_to_bigint_for_gitlab_dot_com_spec.rb new file mode 100644 index 00000000000..41cc75672e1 --- /dev/null +++ b/spec/migrations/swap_epic_user_mentions_note_id_to_bigint_for_gitlab_dot_com_spec.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe SwapEpicUserMentionsNoteIdToBigintForGitlabDotCom, feature_category: :database do + describe '#up' do + before do + # A we call `schema_migrate_down!` before each example, and for this migration + # `#down` is same as `#up`, we need to ensure we start from the expected state. + connection = described_class.new.connection + connection.execute('ALTER TABLE epic_user_mentions ALTER COLUMN note_id TYPE integer') + connection.execute('ALTER TABLE epic_user_mentions ALTER COLUMN note_id_convert_to_bigint TYPE bigint') + end + + # rubocop: disable RSpec/AnyInstanceOf + it 'swaps the integer and bigint columns for GitLab.com, dev, or test' do + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true) + + user_mentions = table(:epic_user_mentions) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + user_mentions.reset_column_information + + expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + + migration.after -> { + user_mentions.reset_column_information + + expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('bigint') + expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('integer') + } + end + end + end + + it 'is a no-op for other instances' do + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + + user_mentions = table(:epic_user_mentions) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + user_mentions.reset_column_information + + expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + + migration.after -> { + user_mentions.reset_column_information + + expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + end + end + end + # rubocop: enable RSpec/AnyInstanceOf + end +end diff --git a/spec/migrations/swap_issue_user_mentions_note_id_to_bigint_for_gitlab_dot_com_2_spec.rb b/spec/migrations/swap_issue_user_mentions_note_id_to_bigint_for_gitlab_dot_com_2_spec.rb new file mode 100644 index 00000000000..2c561730d95 --- /dev/null +++ b/spec/migrations/swap_issue_user_mentions_note_id_to_bigint_for_gitlab_dot_com_2_spec.rb @@ -0,0 +1,84 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +# rubocop: disable RSpec/FilePath +RSpec.describe SwapIssueUserMentionsNoteIdToBigintForGitlabDotCom2, feature_category: :database do + describe '#up' do + before do + # A we call `schema_migrate_down!` before each example, and for this migration + # `#down` is same as `#up`, we need to ensure we start from the expected state. + connection = described_class.new.connection + connection.execute('ALTER TABLE issue_user_mentions ALTER COLUMN note_id TYPE integer') + connection.execute('ALTER TABLE issue_user_mentions ALTER COLUMN note_id_convert_to_bigint TYPE bigint') + end + + # rubocop: disable RSpec/AnyInstanceOf + it 'swaps the integer and bigint columns for GitLab.com, dev, or test' do + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true) + + user_mentions = table(:issue_user_mentions) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + user_mentions.reset_column_information + + expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + + migration.after -> { + user_mentions.reset_column_information + + expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('bigint') + expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('integer') + } + end + end + end + + it 'is a no-op for other instances' do + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + + user_mentions = table(:issue_user_mentions) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + user_mentions.reset_column_information + + expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + + migration.after -> { + user_mentions.reset_column_information + + expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + end + end + end + + it 'is a no-op if columns are already swapped' do + connection = described_class.new.connection + connection.execute('ALTER TABLE issue_user_mentions ALTER COLUMN note_id TYPE bigint') + connection.execute('ALTER TABLE issue_user_mentions ALTER COLUMN note_id_convert_to_bigint TYPE integer') + + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true) + + migrate! + + user_mentions = table(:issue_user_mentions) + user_mentions.reset_column_information + + expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('bigint') + expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('integer') + end + # rubocop: enable RSpec/AnyInstanceOf + end +end +# rubocop: enable RSpec/FilePath diff --git a/spec/migrations/swap_merge_request_metrics_id_to_bigint_for_gitlab_dot_com_spec.rb b/spec/migrations/swap_merge_request_metrics_id_to_bigint_for_gitlab_dot_com_spec.rb new file mode 100644 index 00000000000..b819495aa89 --- /dev/null +++ b/spec/migrations/swap_merge_request_metrics_id_to_bigint_for_gitlab_dot_com_spec.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe SwapMergeRequestMetricsIdToBigintForGitlabDotCom, feature_category: :database do + describe '#up' do + before do + # As we call `schema_migrate_down!` before each example, and for this migration + # `#down` is same as `#up`, we need to ensure we start from the expected state. + connection = described_class.new.connection + connection.execute('ALTER TABLE merge_request_metrics ALTER COLUMN id TYPE integer') + connection.execute('ALTER TABLE merge_request_metrics ALTER COLUMN id_convert_to_bigint TYPE bigint') + end + + it 'swaps the integer and bigint columns for GitLab.com, dev, or test' do + # rubocop: disable RSpec/AnyInstanceOf + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true) + # rubocop: enable RSpec/AnyInstanceOf + + merge_request_metrics = table(:merge_request_metrics) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + merge_request_metrics.reset_column_information + + expect(merge_request_metrics.columns.find { |c| c.name == 'id' }.sql_type).to eq('integer') + expect(merge_request_metrics.columns.find do |c| + c.name == 'id_convert_to_bigint' + end.sql_type).to eq('bigint') + } + + migration.after -> { + merge_request_metrics.reset_column_information + + expect(merge_request_metrics.columns.find { |c| c.name == 'id' }.sql_type).to eq('bigint') + expect(merge_request_metrics.columns.find do |c| + c.name == 'id_convert_to_bigint' + end.sql_type).to eq('integer') + } + end + end + end + + it 'is a no-op for other instances' do + # rubocop: disable RSpec/AnyInstanceOf + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + # rubocop: enable RSpec/AnyInstanceOf + + merge_request_metrics = table(:merge_request_metrics) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + merge_request_metrics.reset_column_information + + expect(merge_request_metrics.columns.find { |c| c.name == 'id' }.sql_type).to eq('integer') + expect(merge_request_metrics.columns.find do |c| + c.name == 'id_convert_to_bigint' + end.sql_type).to eq('bigint') + } + + migration.after -> { + merge_request_metrics.reset_column_information + + expect(merge_request_metrics.columns.find { |c| c.name == 'id' }.sql_type).to eq('integer') + expect(merge_request_metrics.columns.find do |c| + c.name == 'id_convert_to_bigint' + end.sql_type).to eq('bigint') + } + end + end + end + end +end diff --git a/spec/migrations/swap_merge_request_metrics_id_to_bigint_for_self_hosts_spec.rb b/spec/migrations/swap_merge_request_metrics_id_to_bigint_for_self_hosts_spec.rb new file mode 100644 index 00000000000..a2d9887a6c0 --- /dev/null +++ b/spec/migrations/swap_merge_request_metrics_id_to_bigint_for_self_hosts_spec.rb @@ -0,0 +1,155 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe SwapMergeRequestMetricsIdToBigintForSelfHosts, feature_category: :database do + after do + connection = described_class.new.connection + connection.execute('ALTER TABLE merge_request_metrics DROP COLUMN IF EXISTS id_convert_to_bigint') + end + + describe '#up' do + context 'when is GitLab.com, dev, or test' do + before do + # As we call `schema_migrate_down!` before each example, and for this migration + # `#down` is same as `#up`, we need to ensure we start from the expected state. + connection = described_class.new.connection + connection.execute('ALTER TABLE merge_request_metrics ALTER COLUMN id TYPE bigint') + connection.execute('ALTER TABLE merge_request_metrics DROP COLUMN IF EXISTS id_convert_to_bigint') + end + + it 'does not swap the columns' do + # rubocop: disable RSpec/AnyInstanceOf + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true) + # rubocop: enable RSpec/AnyInstanceOf + + merge_request_metrics = table(:merge_request_metrics) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + merge_request_metrics.reset_column_information + + expect(merge_request_metrics.columns.find { |c| c.name == 'id' }.sql_type).to eq('bigint') + expect(merge_request_metrics.columns.find { |c| c.name == 'id_convert_to_bigint' }).to be nil + } + + migration.after -> { + merge_request_metrics.reset_column_information + + expect(merge_request_metrics.columns.find { |c| c.name == 'id' }.sql_type).to eq('bigint') + expect(merge_request_metrics.columns.find { |c| c.name == 'id_convert_to_bigint' }).to be nil + } + end + end + end + end + + context 'when is a self-host customer with the swapped already completed' do + before do + # As we call `schema_migrate_down!` before each example, and for this migration + # `#down` is same as `#up`, we need to ensure we start from the expected state. + connection = described_class.new.connection + connection.execute('ALTER TABLE merge_request_metrics ALTER COLUMN id TYPE bigint') + connection.execute('ALTER TABLE merge_request_metrics ADD COLUMN IF NOT EXISTS id_convert_to_bigint integer') + end + + it 'does not swap the columns' do + # rubocop: disable RSpec/AnyInstanceOf + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + # rubocop: enable RSpec/AnyInstanceOf + + merge_request_metrics = table(:merge_request_metrics) + + migrate! + + expect(merge_request_metrics.columns.find { |c| c.name == 'id' }.sql_type).to eq('bigint') + expect(merge_request_metrics.columns.find do |c| + c.name == 'id_convert_to_bigint' + end.sql_type).to eq('integer') + end + end + + context 'when is a self-host customer with the `id_convert_to_bigint` column already dropped ' do + before do + # As we call `schema_migrate_down!` before each example, and for this migration + # `#down` is same as `#up`, we need to ensure we start from the expected state. + connection = described_class.new.connection + connection.execute('ALTER TABLE merge_request_metrics ALTER COLUMN id TYPE bigint') + connection.execute('ALTER TABLE merge_request_metrics DROP COLUMN IF EXISTS id_convert_to_bigint') + end + + it 'does not swap the columns' do + # rubocop: disable RSpec/AnyInstanceOf + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + # rubocop: enable RSpec/AnyInstanceOf + + merge_request_metrics = table(:merge_request_metrics) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + merge_request_metrics.reset_column_information + + expect(merge_request_metrics.columns.find { |c| c.name == 'id' }.sql_type).to eq('bigint') + expect(merge_request_metrics.columns.find { |c| c.name == 'id_convert_to_bigint' }).to be nil + } + + migration.after -> { + merge_request_metrics.reset_column_information + + expect(merge_request_metrics.columns.find { |c| c.name == 'id' }.sql_type).to eq('bigint') + expect(merge_request_metrics.columns.find { |c| c.name == 'id_convert_to_bigint' }).to be nil + } + end + end + end + end + + context 'when is a self-host customer' do + before do + # As we call `schema_migrate_down!` before each example, and for this migration + # `#down` is same as `#up`, we need to ensure we start from the expected state. + connection = described_class.new.connection + connection.execute('ALTER TABLE merge_request_metrics ALTER COLUMN id TYPE integer') + connection.execute('ALTER TABLE merge_request_metrics ADD COLUMN IF NOT EXISTS id_convert_to_bigint bigint') + connection.execute('ALTER TABLE merge_request_metrics ALTER COLUMN id_convert_to_bigint TYPE bigint') + connection.execute('DROP INDEX IF EXISTS index_merge_request_metrics_on_id_convert_to_bigint') + connection.execute('DROP INDEX IF EXISTS tmp_index_mr_metrics_on_target_project_id_merged_at_nulls_last') + connection.execute('CREATE OR REPLACE FUNCTION trigger_c7107f30d69d() RETURNS trigger LANGUAGE plpgsql AS $$ + BEGIN NEW."id_convert_to_bigint" := NEW."id"; RETURN NEW; END; $$;') + end + + it 'swaps the columns' do + # rubocop: disable RSpec/AnyInstanceOf + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + # rubocop: enable RSpec/AnyInstanceOf + + merge_request_metrics = table(:merge_request_metrics) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + merge_request_metrics.reset_column_information + + expect(merge_request_metrics.columns.find { |c| c.name == 'id' }.sql_type).to eq('integer') + expect(merge_request_metrics.columns.find do |c| + c.name == 'id_convert_to_bigint' + end.sql_type).to eq('bigint') + } + + migration.after -> { + merge_request_metrics.reset_column_information + + expect(merge_request_metrics.columns.find { |c| c.name == 'id' }.sql_type).to eq('bigint') + expect(merge_request_metrics.columns.find do |c| + c.name == 'id_convert_to_bigint' + end.sql_type).to eq('integer') + } + end + end + end + end + end +end diff --git a/spec/migrations/swap_merge_request_user_mentions_note_id_to_bigint_spec.rb b/spec/migrations/swap_merge_request_user_mentions_note_id_to_bigint_spec.rb new file mode 100644 index 00000000000..15b21d34714 --- /dev/null +++ b/spec/migrations/swap_merge_request_user_mentions_note_id_to_bigint_spec.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe SwapMergeRequestUserMentionsNoteIdToBigint, feature_category: :database do + describe '#up' do + before do + # A we call `schema_migrate_down!` before each example, and for this migration + # `#down` is same as `#up`, we need to ensure we start from the expected state. + connection = described_class.new.connection + connection.execute('ALTER TABLE merge_request_user_mentions ALTER COLUMN note_id TYPE integer') + connection.execute('ALTER TABLE merge_request_user_mentions ALTER COLUMN note_id_convert_to_bigint TYPE bigint') + end + + # rubocop: disable RSpec/AnyInstanceOf + it 'swaps the integer and bigint columns for GitLab.com, dev, or test' do + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true) + + user_mentions = table(:merge_request_user_mentions) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + user_mentions.reset_column_information + + expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + + migration.after -> { + user_mentions.reset_column_information + + expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('bigint') + expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('integer') + } + end + end + end + + it 'is a no-op for other instances' do + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + + user_mentions = table(:merge_request_user_mentions) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + user_mentions.reset_column_information + + expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + + migration.after -> { + user_mentions.reset_column_information + + expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + end + end + end + # rubocop: enable RSpec/AnyInstanceOf + end +end diff --git a/spec/migrations/swap_note_diff_files_note_id_to_bigint_for_gitlab_dot_com_spec.rb b/spec/migrations/swap_note_diff_files_note_id_to_bigint_for_gitlab_dot_com_spec.rb new file mode 100644 index 00000000000..b0147f3ef58 --- /dev/null +++ b/spec/migrations/swap_note_diff_files_note_id_to_bigint_for_gitlab_dot_com_spec.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe SwapNoteDiffFilesNoteIdToBigintForGitlabDotCom, feature_category: :database do + describe '#up' do + before do + # A we call `schema_migrate_down!` before each example, and for this migration + # `#down` is same as `#up`, we need to ensure we start from the expected state. + connection = described_class.new.connection + connection.execute('ALTER TABLE note_diff_files ALTER COLUMN diff_note_id TYPE integer') + connection.execute('ALTER TABLE note_diff_files ALTER COLUMN diff_note_id_convert_to_bigint TYPE bigint') + end + + # rubocop: disable RSpec/AnyInstanceOf + it 'swaps the integer and bigint columns for GitLab.com, dev, or test' do + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true) + + ndf = table(:note_diff_files) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + ndf.reset_column_information + + expect(ndf.columns.find { |c| c.name == 'diff_note_id' }.sql_type).to eq('integer') + expect(ndf.columns.find { |c| c.name == 'diff_note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + + migration.after -> { + ndf.reset_column_information + + expect(ndf.columns.find { |c| c.name == 'diff_note_id' }.sql_type).to eq('bigint') + expect(ndf.columns.find { |c| c.name == 'diff_note_id_convert_to_bigint' }.sql_type).to eq('integer') + } + end + end + end + + it 'is a no-op for other instances' do + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + + ndf = table(:note_diff_files) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + ndf.reset_column_information + + expect(ndf.columns.find { |c| c.name == 'diff_note_id' }.sql_type).to eq('integer') + expect(ndf.columns.find { |c| c.name == 'diff_note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + + migration.after -> { + ndf.reset_column_information + + expect(ndf.columns.find { |c| c.name == 'diff_note_id' }.sql_type).to eq('integer') + expect(ndf.columns.find { |c| c.name == 'diff_note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + end + end + end + # rubocop: enable RSpec/AnyInstanceOf + end +end diff --git a/spec/migrations/swap_sent_notifications_id_columns_spec.rb b/spec/migrations/swap_sent_notifications_id_columns_spec.rb new file mode 100644 index 00000000000..2f681a2a587 --- /dev/null +++ b/spec/migrations/swap_sent_notifications_id_columns_spec.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe SwapSentNotificationsIdColumns, feature_category: :database do + describe '#up' do + before do + # A we call `schema_migrate_down!` before each example, and for this migration + # `#down` is same as `#up`, we need to ensure we start from the expected state. + connection = described_class.new.connection + connection.execute('ALTER TABLE sent_notifications ALTER COLUMN id TYPE integer') + connection.execute('ALTER TABLE sent_notifications ALTER COLUMN id_convert_to_bigint TYPE bigint') + # rubocop: disable RSpec/AnyInstanceOf + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(run_migration?) + # rubocop: enable RSpec/AnyInstanceOf + end + + context 'when we are GitLab.com, dev, or test' do + let(:run_migration?) { true } + + it 'swaps the integer and bigint columns' do + sent_notifications = table(:sent_notifications) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + sent_notifications.reset_column_information + + expect(sent_notifications.columns.find { |c| c.name == 'id' }.sql_type).to eq('integer') + expect(sent_notifications.columns.find { |c| c.name == 'id_convert_to_bigint' }.sql_type).to eq('bigint') + } + + migration.after -> { + sent_notifications.reset_column_information + + expect(sent_notifications.columns.find { |c| c.name == 'id' }.sql_type).to eq('bigint') + expect(sent_notifications.columns.find { |c| c.name == 'id_convert_to_bigint' }.sql_type).to eq('integer') + } + end + end + end + end + + context 'when we are NOT GitLab.com, dev, or test' do + let(:run_migration?) { false } + + it 'does not swap the integer and bigint columns' do + sent_notifications = table(:sent_notifications) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + sent_notifications.reset_column_information + + expect(sent_notifications.columns.find { |c| c.name == 'id' }.sql_type).to eq('integer') + expect(sent_notifications.columns.find { |c| c.name == 'id_convert_to_bigint' }.sql_type).to eq('bigint') + } + + migration.after -> { + sent_notifications.reset_column_information + + expect(sent_notifications.columns.find { |c| c.name == 'id' }.sql_type).to eq('integer') + expect(sent_notifications.columns.find { |c| c.name == 'id_convert_to_bigint' }.sql_type).to eq('bigint') + } + end + end + end + end + end +end diff --git a/spec/migrations/swap_snippet_user_mentions_note_id_to_bigint_for_gitlab_dot_com_spec.rb b/spec/migrations/swap_snippet_user_mentions_note_id_to_bigint_for_gitlab_dot_com_spec.rb new file mode 100644 index 00000000000..628c0fba528 --- /dev/null +++ b/spec/migrations/swap_snippet_user_mentions_note_id_to_bigint_for_gitlab_dot_com_spec.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe SwapSnippetUserMentionsNoteIdToBigintForGitlabDotCom, feature_category: :database do + describe '#up' do + before do + # A we call `schema_migrate_down!` before each example, and for this migration + # `#down` is same as `#up`, we need to ensure we start from the expected state. + connection = described_class.new.connection + connection.execute('ALTER TABLE snippet_user_mentions ALTER COLUMN note_id TYPE integer') + connection.execute('ALTER TABLE snippet_user_mentions ALTER COLUMN note_id_convert_to_bigint TYPE bigint') + end + + # rubocop: disable RSpec/AnyInstanceOf + it 'swaps the integer and bigint columns for GitLab.com, dev, or test' do + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true) + + user_mentions = table(:snippet_user_mentions) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + user_mentions.reset_column_information + + expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + + migration.after -> { + user_mentions.reset_column_information + + expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('bigint') + expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('integer') + } + end + end + end + + it 'is a no-op for other instances' do + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + + user_mentions = table(:snippet_user_mentions) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + user_mentions.reset_column_information + + expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + + migration.after -> { + user_mentions.reset_column_information + + expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + end + end + end + # rubocop: enable RSpec/AnyInstanceOf + end +end diff --git a/spec/migrations/swap_suggestions_note_id_to_bigint_for_gitlab_dot_com_spec.rb b/spec/migrations/swap_suggestions_note_id_to_bigint_for_gitlab_dot_com_spec.rb new file mode 100644 index 00000000000..48d72ec151e --- /dev/null +++ b/spec/migrations/swap_suggestions_note_id_to_bigint_for_gitlab_dot_com_spec.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe SwapSuggestionsNoteIdToBigintForGitlabDotCom, feature_category: :database do + describe '#up' do + before do + # A we call `schema_migrate_down!` before each example, and for this migration + # `#down` is same as `#up`, we need to ensure we start from the expected state. + connection = described_class.new.connection + connection.execute('ALTER TABLE suggestions ALTER COLUMN note_id TYPE integer') + connection.execute('ALTER TABLE suggestions ALTER COLUMN note_id_convert_to_bigint TYPE bigint') + end + + # rubocop: disable RSpec/AnyInstanceOf + it 'swaps the integer and bigint columns for GitLab.com, dev, or test' do + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true) + + suggestions = table(:suggestions) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + suggestions.reset_column_information + + expect(suggestions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(suggestions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + + migration.after -> { + suggestions.reset_column_information + + expect(suggestions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('bigint') + expect(suggestions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('integer') + } + end + end + end + + it 'is a no-op for other instances' do + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + + suggestions = table(:suggestions) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + suggestions.reset_column_information + + expect(suggestions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(suggestions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + + migration.after -> { + suggestions.reset_column_information + + expect(suggestions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(suggestions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + end + end + end + # rubocop: enable RSpec/AnyInstanceOf + end +end diff --git a/spec/migrations/swap_system_note_metadata_note_id_to_bigint_for_gitlab_dot_com_spec.rb b/spec/migrations/swap_system_note_metadata_note_id_to_bigint_for_gitlab_dot_com_spec.rb new file mode 100644 index 00000000000..4fa5814986a --- /dev/null +++ b/spec/migrations/swap_system_note_metadata_note_id_to_bigint_for_gitlab_dot_com_spec.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe SwapSystemNoteMetadataNoteIdToBigintForGitlabDotCom, feature_category: :database do + describe '#up' do + before do + # A we call `schema_migrate_down!` before each example, and for this migration + # `#down` is same as `#up`, we need to ensure we start from the expected state. + connection = described_class.new.connection + connection.execute('ALTER TABLE system_note_metadata ALTER COLUMN note_id TYPE integer') + connection.execute('ALTER TABLE system_note_metadata ALTER COLUMN note_id_convert_to_bigint TYPE bigint') + end + + # rubocop: disable RSpec/AnyInstanceOf + it 'swaps the integer and bigint columns for GitLab.com, dev, or test' do + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true) + + metadata = table(:system_note_metadata) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + metadata.reset_column_information + + expect(metadata.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(metadata.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + + migration.after -> { + metadata.reset_column_information + + expect(metadata.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('bigint') + expect(metadata.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('integer') + } + end + end + end + + it 'is a no-op for other instances' do + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + + metadata = table(:system_note_metadata) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + metadata.reset_column_information + + expect(metadata.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(metadata.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + + migration.after -> { + metadata.reset_column_information + + expect(metadata.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(metadata.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + end + end + end + # rubocop: enable RSpec/AnyInstanceOf + end +end diff --git a/spec/migrations/swap_timelogs_note_id_to_bigint_for_gitlab_dot_com_spec.rb b/spec/migrations/swap_timelogs_note_id_to_bigint_for_gitlab_dot_com_spec.rb new file mode 100644 index 00000000000..708688ec446 --- /dev/null +++ b/spec/migrations/swap_timelogs_note_id_to_bigint_for_gitlab_dot_com_spec.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe SwapTimelogsNoteIdToBigintForGitlabDotCom, feature_category: :database do + describe '#up' do + before do + # A we call `schema_migrate_down!` before each example, and for this migration + # `#down` is same as `#up`, we need to ensure we start from the expected state. + connection = described_class.new.connection + connection.execute('ALTER TABLE timelogs ALTER COLUMN note_id TYPE integer') + connection.execute('ALTER TABLE timelogs ALTER COLUMN note_id_convert_to_bigint TYPE bigint') + end + + # rubocop: disable RSpec/AnyInstanceOf + it 'swaps the integer and bigint columns for GitLab.com, dev, or test' do + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true) + + timelogs = table(:timelogs) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + timelogs.reset_column_information + + expect(timelogs.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(timelogs.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + + migration.after -> { + timelogs.reset_column_information + + expect(timelogs.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('bigint') + expect(timelogs.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('integer') + } + end + end + end + + it 'is a no-op for other instances' do + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + + timelogs = table(:timelogs) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + timelogs.reset_column_information + + expect(timelogs.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(timelogs.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + + migration.after -> { + timelogs.reset_column_information + + expect(timelogs.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(timelogs.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + end + end + end + # rubocop: enable RSpec/AnyInstanceOf + end +end diff --git a/spec/migrations/swap_todos_note_id_to_bigint_for_gitlab_dot_com_spec.rb b/spec/migrations/swap_todos_note_id_to_bigint_for_gitlab_dot_com_spec.rb new file mode 100644 index 00000000000..e71c921998a --- /dev/null +++ b/spec/migrations/swap_todos_note_id_to_bigint_for_gitlab_dot_com_spec.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe SwapTodosNoteIdToBigintForGitlabDotCom, feature_category: :database do + describe '#up' do + before do + # A we call `schema_migrate_down!` before each example, and for this migration + # `#down` is same as `#up`, we need to ensure we start from the expected state. + connection = described_class.new.connection + connection.execute('ALTER TABLE todos ALTER COLUMN note_id TYPE integer') + connection.execute('ALTER TABLE todos ALTER COLUMN note_id_convert_to_bigint TYPE bigint') + end + + # rubocop: disable RSpec/AnyInstanceOf + it 'swaps the integer and bigint columns for GitLab.com, dev, or test' do + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true) + + todos = table(:todos) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + todos.reset_column_information + + expect(todos.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(todos.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + + migration.after -> { + todos.reset_column_information + + expect(todos.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('bigint') + expect(todos.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('integer') + } + end + end + end + + it 'is a no-op for other instances' do + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + + todos = table(:todos) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + todos.reset_column_information + + expect(todos.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(todos.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + + migration.after -> { + todos.reset_column_information + + expect(todos.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(todos.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + end + end + end + # rubocop: enable RSpec/AnyInstanceOf + end +end diff --git a/spec/migrations/swap_vulnerability_user_mentions_note_id_to_bigint_for_gitlab_dot_com_spec.rb b/spec/migrations/swap_vulnerability_user_mentions_note_id_to_bigint_for_gitlab_dot_com_spec.rb new file mode 100644 index 00000000000..1e358387536 --- /dev/null +++ b/spec/migrations/swap_vulnerability_user_mentions_note_id_to_bigint_for_gitlab_dot_com_spec.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe SwapVulnerabilityUserMentionsNoteIdToBigintForGitlabDotCom, feature_category: :database do + describe '#up' do + before do + # A we call `schema_migrate_down!` before each example, and for this migration + # `#down` is same as `#up`, we need to ensure we start from the expected state. + connection = described_class.new.connection + connection.execute('ALTER TABLE vulnerability_user_mentions ALTER COLUMN note_id TYPE integer') + connection.execute('ALTER TABLE vulnerability_user_mentions ALTER COLUMN note_id_convert_to_bigint TYPE bigint') + end + + # rubocop: disable RSpec/AnyInstanceOf + it 'swaps the integer and bigint columns for GitLab.com, dev, or test' do + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(true) + + user_mentions = table(:vulnerability_user_mentions) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + user_mentions.reset_column_information + + expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + + migration.after -> { + user_mentions.reset_column_information + + expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('bigint') + expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('integer') + } + end + end + end + + it 'is a no-op for other instances' do + allow_any_instance_of(described_class).to receive(:com_or_dev_or_test_but_not_jh?).and_return(false) + + user_mentions = table(:vulnerability_user_mentions) + + disable_migrations_output do + reversible_migration do |migration| + migration.before -> { + user_mentions.reset_column_information + + expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + + migration.after -> { + user_mentions.reset_column_information + + expect(user_mentions.columns.find { |c| c.name == 'note_id' }.sql_type).to eq('integer') + expect(user_mentions.columns.find { |c| c.name == 'note_id_convert_to_bigint' }.sql_type).to eq('bigint') + } + end + end + end + # rubocop: enable RSpec/AnyInstanceOf + 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 index da8790f4450..c60447d04a1 100644 --- 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 @@ -5,7 +5,7 @@ require 'spec_helper' require_migration! RSpec.describe SyncNewAmountUsedForCiNamespaceMonthlyUsages, migration: :gitlab_ci, - feature_category: :continuous_integration do + feature_category: :continuous_integration do let(:namespace_usages) { table(:ci_namespace_monthly_usages) } before do 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 index 1c9b2711687..d7add66a97f 100644 --- 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 @@ -5,7 +5,7 @@ require 'spec_helper' require_migration! RSpec.describe SyncNewAmountUsedForCiProjectMonthlyUsages, migration: :gitlab_ci, - feature_category: :continuous_integration do + feature_category: :continuous_integration do let(:project_usages) { table(:ci_project_monthly_usages) } before do diff --git a/spec/migrations/update_application_settings_container_registry_exp_pol_worker_capacity_default_spec.rb b/spec/migrations/update_application_settings_container_registry_exp_pol_worker_capacity_default_spec.rb index d249fcecf66..66da9e6653d 100644 --- a/spec/migrations/update_application_settings_container_registry_exp_pol_worker_capacity_default_spec.rb +++ b/spec/migrations/update_application_settings_container_registry_exp_pol_worker_capacity_default_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' require_migration! RSpec.describe UpdateApplicationSettingsContainerRegistryExpPolWorkerCapacityDefault, -feature_category: :container_registry do + feature_category: :container_registry do let(:settings) { table(:application_settings) } context 'with no rows in the application_settings table' do diff --git a/spec/migrations/update_application_settings_protected_paths_spec.rb b/spec/migrations/update_application_settings_protected_paths_spec.rb index d61eadf9f9c..c2bd4e8727d 100644 --- a/spec/migrations/update_application_settings_protected_paths_spec.rb +++ b/spec/migrations/update_application_settings_protected_paths_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' require_migration! RSpec.describe UpdateApplicationSettingsProtectedPaths, :aggregate_failures, -feature_category: :authentication_and_authorization do + feature_category: :system_access do subject(:migration) { described_class.new } let!(:application_settings) { table(:application_settings) } diff --git a/spec/migrations/update_default_scan_method_of_dast_site_profile_spec.rb b/spec/migrations/update_default_scan_method_of_dast_site_profile_spec.rb index ac7a4171063..15a8e79a610 100644 --- a/spec/migrations/update_default_scan_method_of_dast_site_profile_spec.rb +++ b/spec/migrations/update_default_scan_method_of_dast_site_profile_spec.rb @@ -14,13 +14,23 @@ RSpec.describe UpdateDefaultScanMethodOfDastSiteProfile, feature_category: :dyna project = projects.create!(id: 12, namespace_id: namespace.id, name: 'gitlab', path: 'gitlab') dast_site = dast_sites.create!(id: 1, url: 'https://www.gitlab.com', project_id: project.id) - dast_site_profiles.create!(id: 1, project_id: project.id, dast_site_id: dast_site.id, - name: "#{FFaker::Product.product_name.truncate(192)} #{SecureRandom.hex(4)} - 0", - scan_method: 0, target_type: 0) + dast_site_profiles.create!( + id: 1, + project_id: project.id, + dast_site_id: dast_site.id, + name: "#{FFaker::Product.product_name.truncate(192)} #{SecureRandom.hex(4)} - 0", + scan_method: 0, + target_type: 0 + ) - dast_site_profiles.create!(id: 2, project_id: project.id, dast_site_id: dast_site.id, - name: "#{FFaker::Product.product_name.truncate(192)} #{SecureRandom.hex(4)} - 1", - scan_method: 0, target_type: 1) + dast_site_profiles.create!( + id: 2, + project_id: project.id, + dast_site_id: dast_site.id, + name: "#{FFaker::Product.product_name.truncate(192)} #{SecureRandom.hex(4)} - 1", + scan_method: 0, + target_type: 1 + ) end it 'updates the scan_method to 1 for profiles with target_type 1' do |