diff options
Diffstat (limited to 'spec/migrations')
14 files changed, 638 insertions, 0 deletions
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 new file mode 100644 index 00000000000..8cb6ab23fef --- /dev/null +++ b/spec/migrations/20220601152916_add_user_id_and_ip_address_success_index_to_authentication_events_spec.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe AddUserIdAndIpAddressSuccessIndexToAuthenticationEvents do + let(:db) { described_class.new } + let(:old_index) { described_class::OLD_INDEX_NAME } + let(:new_index) { described_class::NEW_INDEX_NAME } + + it 'correctly migrates up and down' do + reversible_migration do |migration| + migration.before -> { + expect(db.connection.indexes(:authentication_events).map(&:name)).to include(old_index) + expect(db.connection.indexes(:authentication_events).map(&:name)).not_to include(new_index) + } + + migration.after -> { + expect(db.connection.indexes(:authentication_events).map(&:name)).to include(new_index) + expect(db.connection.indexes(:authentication_events).map(&:name)).not_to include(old_index) + } + end + end +end 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 new file mode 100644 index 00000000000..1450811b3b9 --- /dev/null +++ b/spec/migrations/20220606082910_add_tmp_index_for_potentially_misassociated_vulnerability_occurrences_spec.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require "spec_helper" + +require_migration! + +RSpec.describe AddTmpIndexForPotentiallyMisassociatedVulnerabilityOccurrences 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/20220620132300_update_last_run_date_for_iterations_cadences_spec.rb b/spec/migrations/20220620132300_update_last_run_date_for_iterations_cadences_spec.rb new file mode 100644 index 00000000000..d23ca8741a2 --- /dev/null +++ b/spec/migrations/20220620132300_update_last_run_date_for_iterations_cadences_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require 'spec_helper' + +require_migration! + +RSpec.describe UpdateLastRunDateForIterationsCadences, :migration do + let(:current_date) { Date.parse(ApplicationRecord.connection.execute("SELECT CURRENT_DATE").first["current_date"]) } + let(:namespaces) { table(:namespaces) } + let(:iterations_cadences) { table(:iterations_cadences) } + + let!(:group) { namespaces.create!(name: 'foo', path: 'foo') } + let!(:cadence_1) do + iterations_cadences.create!(group_id: group.id, title: "cadence 1", last_run_date: Date.today - 5.days) + end + + let!(:cadence_2) { iterations_cadences.create!(group_id: group.id, title: "cadence 2", last_run_date: nil) } + let!(:cadence_3) do + iterations_cadences.create!(group_id: group.id, title: "cadence 2", last_run_date: nil, automatic: false) + end + + it 'sets last_run_date to CURRENT_DATE for iterations cadences with automatic=true', :aggregate_failures do + migrate! + + expect(cadence_1.reload.last_run_date).to eq(current_date) + expect(cadence_2.reload.last_run_date).to eq(current_date) + expect(cadence_3.reload.last_run_date).to eq(nil) + end +end diff --git a/spec/migrations/20220622080547_backfill_project_statistics_with_container_registry_size_spec.rb b/spec/migrations/20220622080547_backfill_project_statistics_with_container_registry_size_spec.rb new file mode 100644 index 00000000000..52b75f0b8a9 --- /dev/null +++ b/spec/migrations/20220622080547_backfill_project_statistics_with_container_registry_size_spec.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe BackfillProjectStatisticsWithContainerRegistrySize do + let_it_be(:batched_migration) { described_class::MIGRATION_CLASS } + + it 'does not schedule background jobs when Gitlab.com is false' do + allow(Gitlab).to receive(:com?).and_return(false) + allow(Gitlab).to receive(:dev_or_test_env?).and_return(false) + + reversible_migration do |migration| + migration.before -> { + expect(batched_migration).not_to have_scheduled_batched_migration + } + + migration.after -> { + expect(batched_migration).not_to have_scheduled_batched_migration + } + end + end + + it 'schedules background jobs for each batch of container_repository' do + allow(Gitlab).to receive(:com?).and_return(true) + + 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: :container_repositories, + column_name: :project_id, + interval: described_class::DELAY_INTERVAL + ) + } + end + end +end diff --git a/spec/migrations/20220627090231_schedule_disable_legacy_open_source_license_for_inactive_public_projects_spec.rb b/spec/migrations/20220627090231_schedule_disable_legacy_open_source_license_for_inactive_public_projects_spec.rb new file mode 100644 index 00000000000..3e7f2a3457b --- /dev/null +++ b/spec/migrations/20220627090231_schedule_disable_legacy_open_source_license_for_inactive_public_projects_spec.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe ScheduleDisableLegacyOpenSourceLicenseForInactivePublicProjects do + context 'on gitlab.com' do + let(:migration) { described_class::MIGRATION } + + before do + allow(Gitlab).to receive(:com?).and_return(true) + end + + describe '#up' do + it 'schedules background jobs for each batch of projects' do + migrate! + + expect(migration).to( + have_scheduled_batched_migration( + table_name: :projects, + column_name: :id, + interval: described_class::INTERVAL, + batch_size: described_class::BATCH_SIZE, + sub_batch_size: described_class::SUB_BATCH_SIZE + ) + ) + end + end + + describe '#down' do + it 'deletes all batched migration records' do + migrate! + schema_migrate_down! + + expect(migration).not_to have_scheduled_batched_migration + end + end + end + + context 'on self-managed instances' do + let(:migration) { described_class.new } + + before do + allow(Gitlab).to receive(:com?).and_return(false) + end + + describe '#up' do + it 'does not schedule background job' do + expect(migration).not_to receive(:queue_batched_background_migration) + + migration.up + end + end + + describe '#down' do + it 'does not delete background job' do + expect(migration).not_to receive(:delete_batched_background_migration) + + migration.down + end + end + end +end diff --git a/spec/migrations/20220627152642_queue_update_delayed_project_removal_to_null_for_user_namespace_spec.rb b/spec/migrations/20220627152642_queue_update_delayed_project_removal_to_null_for_user_namespace_spec.rb new file mode 100644 index 00000000000..190f1c830ae --- /dev/null +++ b/spec/migrations/20220627152642_queue_update_delayed_project_removal_to_null_for_user_namespace_spec.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe QueueUpdateDelayedProjectRemovalToNullForUserNamespace do + let(:migration) { described_class::MIGRATION } + + describe '#up' do + it 'schedules background jobs for each batch of namespace settings' do + migrate! + + expect(migration).to( + have_scheduled_batched_migration( + table_name: :namespace_settings, + column_name: :namespace_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/20220628012902_finalise_project_namespace_members_spec.rb b/spec/migrations/20220628012902_finalise_project_namespace_members_spec.rb new file mode 100644 index 00000000000..1f116cf6a7e --- /dev/null +++ b/spec/migrations/20220628012902_finalise_project_namespace_members_spec.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe FinaliseProjectNamespaceMembers, :migration do + let(:batched_migrations) { table(:batched_background_migrations) } + + let_it_be(:migration) { described_class::MIGRATION } + + describe '#up' do + shared_examples 'finalizes the migration' do + it 'finalizes the migration' do + allow_next_instance_of(Gitlab::Database::BackgroundMigration::BatchedMigrationRunner) do |runner| + expect(runner).to receive(:finalize).with('BackfillProjectMemberNamespaceId', :members, :id, []) + end + end + end + + context 'when migration is missing' do + it 'warns migration not found' do + expect(Gitlab::AppLogger) + .to receive(:warn).with(/Could not find batched background migration for the given configuration:/) + + migrate! + end + end + + context 'with migration present' do + let!(:project_member_namespace_id_backfill) do + batched_migrations.create!( + job_class_name: 'BackfillProjectMemberNamespaceId', + table_name: :members, + column_name: :id, + job_arguments: [], + interval: 2.minutes, + min_value: 1, + max_value: 2, + batch_size: 1000, + sub_batch_size: 200, + gitlab_schema: :gitlab_main, + status: 3 # finished + ) + end + + context 'when migration finished successfully' do + it 'does not raise exception' do + expect { migrate! }.not_to raise_error + end + end + + context 'with different migration statuses' do + using RSpec::Parameterized::TableSyntax + + where(:status, :description) do + 0 | 'paused' + 1 | 'active' + 4 | 'failed' + 5 | 'finalizing' + end + + with_them do + before do + project_member_namespace_id_backfill.update!(status: status) + end + + it_behaves_like 'finalizes the migration' + end + end + end + end +end diff --git a/spec/migrations/20220629184402_unset_escalation_policies_for_alert_incidents_spec.rb b/spec/migrations/20220629184402_unset_escalation_policies_for_alert_incidents_spec.rb new file mode 100644 index 00000000000..bd821714605 --- /dev/null +++ b/spec/migrations/20220629184402_unset_escalation_policies_for_alert_incidents_spec.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe UnsetEscalationPoliciesForAlertIncidents do + let(:namespaces) { table(:namespaces) } + let(:projects) { table(:projects) } + let(:issues) { table(:issues) } + let(:alerts) { table(:alert_management_alerts) } + let(:escalation_policies) { table(:incident_management_escalation_policies) } + let(:escalation_statuses) { table(:incident_management_issuable_escalation_statuses) } + let(:current_time) { Time.current.change(usec: 0) } + + let!(:namespace) { namespaces.create!(name: 'namespace', path: 'namespace') } + let!(:project_namespace) { namespaces.create!(name: 'project', path: 'project', type: 'project') } + let!(:project) { projects.create!(namespace_id: namespace.id, project_namespace_id: project_namespace.id) } + let!(:policy) { escalation_policies.create!(project_id: project.id, name: 'escalation policy') } + + # Escalation status with policy from alert; Policy & escalation start time should be nullified + let!(:issue_1) { create_issue } + let!(:escalation_status_1) { create_status(issue_1, policy, current_time) } + let!(:alert_1) { create_alert(1, issue_1) } + + # Escalation status without policy, but with alert; Should be ignored + let!(:issue_2) { create_issue } + let!(:escalation_status_2) { create_status(issue_2, nil, current_time) } + let!(:alert_2) { create_alert(2, issue_2) } + + # Escalation status without alert, but with policy; Should be ignored + let!(:issue_3) { create_issue } + let!(:escalation_status_3) { create_status(issue_3, policy, current_time) } + + # Alert without issue; Should be ignored + let!(:alert_3) { create_alert(3) } + + it 'removes the escalation policy if the incident corresponds to an alert' do + expect { migrate! } + .to change { escalation_status_1.reload.policy_id }.from(policy.id).to(nil) + .and change { escalation_status_1.escalations_started_at }.from(current_time).to(nil) + .and not_change { policy_attrs(escalation_status_2) } + .and not_change { policy_attrs(escalation_status_3) } + end + + private + + def create_issue + issues.create!(project_id: project.id) + end + + def create_status(issue, policy = nil, escalations_started_at = nil) + escalation_statuses.create!( + issue_id: issue.id, + policy_id: policy&.id, + escalations_started_at: escalations_started_at + ) + end + + def create_alert(iid, issue = nil) + alerts.create!( + project_id: project.id, + started_at: current_time, + title: "alert #{iid}", + iid: iid.to_s, + issue_id: issue&.id + ) + end + + def policy_attrs(escalation_status) + escalation_status.reload.slice(:policy_id, :escalations_started_at) + end +end diff --git a/spec/migrations/20220715163254_update_notes_in_past_spec.rb b/spec/migrations/20220715163254_update_notes_in_past_spec.rb new file mode 100644 index 00000000000..58e6cabc129 --- /dev/null +++ b/spec/migrations/20220715163254_update_notes_in_past_spec.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require 'spec_helper' + +require_migration! + +RSpec.describe UpdateNotesInPast, :migration do + let(:notes) { table(:notes) } + + it 'updates created_at when it is too much in the past' do + notes.create!(id: 10, note: 'note', created_at: '2009-06-01') + notes.create!(id: 11, note: 'note', created_at: '1970-01-01') + notes.create!(id: 12, note: 'note', created_at: '1600-06-01') + + migrate! + + expect(notes.all).to contain_exactly( + an_object_having_attributes(id: 10, created_at: DateTime.parse('2009-06-01')), + an_object_having_attributes(id: 11, created_at: DateTime.parse('1970-01-01')), + an_object_having_attributes(id: 12, created_at: DateTime.parse('1970-01-01')) + ) + end +end diff --git a/spec/migrations/change_public_projects_cost_factor_spec.rb b/spec/migrations/change_public_projects_cost_factor_spec.rb new file mode 100644 index 00000000000..78030736093 --- /dev/null +++ b/spec/migrations/change_public_projects_cost_factor_spec.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe ChangePublicProjectsCostFactor, :migration do + # This is a workaround to force the migration to run against the + # `gitlab_ci` schema. Otherwise it only runs against `gitlab_main`. + around do |example| # rubocop: disable Style/MultilineIfModifier + with_reestablished_active_record_base do + reconfigure_db_connection(name: :ci) + example.run + end + end if Gitlab::Database.has_config?(:ci) + + let(:runners) { table(:ci_runners) } + + let!(:shared_1) { runners.create!(runner_type: 1, public_projects_minutes_cost_factor: 0) } + let!(:shared_2) { runners.create!(runner_type: 1, public_projects_minutes_cost_factor: 0) } + let!(:shared_3) { runners.create!(runner_type: 1, public_projects_minutes_cost_factor: 1) } + let!(:group_1) { runners.create!(runner_type: 2, public_projects_minutes_cost_factor: 0) } + + describe '#up' do + context 'when on SaaS' do + before do + allow(Gitlab).to receive(:com?).and_return(true) + end + + it 'updates the cost factor from 0 only for shared runners', :aggregate_failures do + migrate! + + expect(shared_1.reload.public_projects_minutes_cost_factor).to eq(0.008) + expect(shared_2.reload.public_projects_minutes_cost_factor).to eq(0.008) + expect(shared_3.reload.public_projects_minutes_cost_factor).to eq(1) + expect(group_1.reload.public_projects_minutes_cost_factor).to eq(0) + end + end + + context 'when on self-managed', :aggregate_failures do + it 'skips the migration' do + migrate! + + expect(shared_1.public_projects_minutes_cost_factor).to eq(0) + expect(shared_2.public_projects_minutes_cost_factor).to eq(0) + expect(shared_3.public_projects_minutes_cost_factor).to eq(1) + expect(group_1.public_projects_minutes_cost_factor).to eq(0) + end + end + end + + describe '#down' do + context 'when on SaaS' do + before do + allow(Gitlab).to receive(:com?).and_return(true) + end + + it 'resets the cost factor to 0 only for shared runners that were updated', :aggregate_failures do + migrate! + schema_migrate_down! + + expect(shared_1.public_projects_minutes_cost_factor).to eq(0) + expect(shared_2.public_projects_minutes_cost_factor).to eq(0) + expect(shared_3.public_projects_minutes_cost_factor).to eq(1) + expect(group_1.public_projects_minutes_cost_factor).to eq(0) + end + end + end +end diff --git a/spec/migrations/finalize_orphaned_routes_cleanup_spec.rb b/spec/migrations/finalize_orphaned_routes_cleanup_spec.rb new file mode 100644 index 00000000000..dfc95ed9e63 --- /dev/null +++ b/spec/migrations/finalize_orphaned_routes_cleanup_spec.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe FinalizeOrphanedRoutesCleanup, :migration do + let(:batched_migrations) { table(:batched_background_migrations) } + + let_it_be(:migration) { described_class::MIGRATION } + + describe '#up' do + shared_examples 'finalizes the migration' do + it 'finalizes the migration' do + allow_next_instance_of(Gitlab::Database::BackgroundMigration::BatchedMigrationRunner) do |runner| + expect(runner).to receive(:finalize).with('CleanupOrphanedRoutes', :projects, :id, []) + end + end + end + + context 'when migration is missing' do + it 'warns migration not found' do + expect(Gitlab::AppLogger) + .to receive(:warn).with(/Could not find batched background migration for the given configuration:/) + + migrate! + end + end + + context 'with migration present' do + let!(:project_namespace_backfill) do + batched_migrations.create!( + job_class_name: 'CleanupOrphanedRoutes', + table_name: :routes, + column_name: :id, + job_arguments: [], + interval: 2.minutes, + min_value: 1, + max_value: 2, + batch_size: 1000, + sub_batch_size: 200, + gitlab_schema: :gitlab_main, + status: 3 # finished + ) + end + + context 'when migration finished successfully' do + it 'does not raise exception' do + expect { migrate! }.not_to raise_error + end + end + + context 'with different migration statuses' do + using RSpec::Parameterized::TableSyntax + + where(:status, :description) do + 0 | 'paused' + 1 | 'active' + 4 | 'failed' + 5 | 'finalizing' + end + + with_them do + before do + project_namespace_backfill.update!(status: status) + end + + it_behaves_like 'finalizes the migration' + end + end + end + end +end diff --git a/spec/migrations/populate_operation_visibility_permissions_spec.rb b/spec/migrations/populate_operation_visibility_permissions_spec.rb new file mode 100644 index 00000000000..6737a6f84c3 --- /dev/null +++ b/spec/migrations/populate_operation_visibility_permissions_spec.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +require 'spec_helper' + +require_migration! + +RSpec.describe PopulateOperationVisibilityPermissions, :migration do + let(:migration) { described_class::MIGRATION } + + before do + stub_const("#{described_class.name}::SUB_BATCH_SIZE", 2) + end + + it 'schedules background migrations', :aggregate_failures do + migrate! + + expect(migration).to have_scheduled_batched_migration( + table_name: :project_features, + column_name: :id, + interval: described_class::INTERVAL + ) + end + + describe '#down' do + it 'deletes all batched migration records' do + migrate! + schema_migrate_down! + + expect(migration).not_to have_scheduled_batched_migration + end + end +end diff --git a/spec/migrations/reschedule_backfill_imported_issue_search_data_spec.rb b/spec/migrations/reschedule_backfill_imported_issue_search_data_spec.rb new file mode 100644 index 00000000000..7d1377bbeba --- /dev/null +++ b/spec/migrations/reschedule_backfill_imported_issue_search_data_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe RescheduleBackfillImportedIssueSearchData do + let_it_be(:reschedule_migration) { described_class::MIGRATION } + + context 'when BackfillIssueSearchData.max_value is nil' do + it 'schedules a new batched migration with a default value' do + reversible_migration do |migration| + migration.before -> { + expect(reschedule_migration).not_to have_scheduled_batched_migration + } + migration.after -> { + expect(reschedule_migration).to have_scheduled_batched_migration( + table_name: :issues, + column_name: :id, + interval: described_class::DELAY_INTERVAL, + batch_min_value: described_class::BATCH_MIN_VALUE + ) + } + end + end + end + + context 'when BackfillIssueSearchData.max_value exists' do + before do + Gitlab::Database::BackgroundMigration::BatchedMigration + .create!( + max_value: 200, + batch_size: 200, + sub_batch_size: 20, + interval: 120, + job_class_name: 'BackfillIssueSearchData', + table_name: 'issues', + column_name: 'id', + gitlab_schema: 'glschema' + ) + end + + it 'schedules a new batched migration with a custom max_value' do + reversible_migration do |migration| + migration.after -> { + expect(reschedule_migration).to have_scheduled_batched_migration( + table_name: :issues, + column_name: :id, + interval: described_class::DELAY_INTERVAL, + batch_min_value: 200 + ) + } + end + end + end +end diff --git a/spec/migrations/schedule_set_correct_vulnerability_state_spec.rb b/spec/migrations/schedule_set_correct_vulnerability_state_spec.rb new file mode 100644 index 00000000000..08dccf1f37a --- /dev/null +++ b/spec/migrations/schedule_set_correct_vulnerability_state_spec.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require 'spec_helper' + +require_migration! + +RSpec.describe ScheduleSetCorrectVulnerabilityState do + let_it_be(:migration) { described_class::MIGRATION_NAME } + + describe '#up' do + it 'schedules background jobs for each batch of vulnerabilities' do + migrate! + + expect(migration).to have_scheduled_batched_migration( + table_name: :vulnerabilities, + column_name: :id, + interval: described_class::JOB_INTERVAL, + batch_size: described_class::MAX_BATCH_SIZE, + batch_class_name: described_class::BATCH_CLASS_NAME, + 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 |