Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-07-20 12:55:51 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-07-20 12:55:51 +0300
commite8d2c2579383897a1dd7f9debd359abe8ae8373d (patch)
treec42be41678c2586d49a75cabce89322082698334 /spec/migrations
parentfc845b37ec3a90aaa719975f607740c22ba6a113 (diff)
Add latest changes from gitlab-org/gitlab@14-1-stable-eev14.1.0-rc42
Diffstat (limited to 'spec/migrations')
-rw-r--r--spec/migrations/20190924152703_migrate_issue_trackers_data_spec.rb12
-rw-r--r--spec/migrations/20200130145430_reschedule_migrate_issue_trackers_data_spec.rb12
-rw-r--r--spec/migrations/20200728080250_replace_unique_index_on_cycle_analytics_stages_spec.rb2
-rw-r--r--spec/migrations/20210610153556_delete_legacy_operations_feature_flags_spec.rb45
-rw-r--r--spec/migrations/2021061716138_cascade_delete_freeze_periods_spec.rb22
-rw-r--r--spec/migrations/20210708130419_reschedule_merge_request_diff_users_background_migration_spec.rb75
-rw-r--r--spec/migrations/active_record/schema_spec.rb6
-rw-r--r--spec/migrations/add_premium_and_ultimate_plan_limits_spec.rb86
-rw-r--r--spec/migrations/add_upvotes_count_index_to_issues_spec.rb22
-rw-r--r--spec/migrations/backfill_issues_upvotes_count_spec.rb35
-rw-r--r--spec/migrations/delete_template_services_duplicated_by_type_spec.rb6
-rw-r--r--spec/migrations/fix_batched_migrations_old_format_job_arguments_spec.rb63
-rw-r--r--spec/migrations/re_schedule_latest_pipeline_id_population_spec.rb61
-rw-r--r--spec/migrations/rename_services_to_integrations_spec.rb255
-rw-r--r--spec/migrations/reset_job_token_scope_enabled_spec.rb25
-rw-r--r--spec/migrations/schedule_backfill_draft_status_on_merge_requests_spec.rb59
-rw-r--r--spec/migrations/schedule_delete_orphaned_deployments_spec.rb48
17 files changed, 815 insertions, 19 deletions
diff --git a/spec/migrations/20190924152703_migrate_issue_trackers_data_spec.rb b/spec/migrations/20190924152703_migrate_issue_trackers_data_spec.rb
index 2999332509a..dad95760306 100644
--- a/spec/migrations/20190924152703_migrate_issue_trackers_data_spec.rb
+++ b/spec/migrations/20190924152703_migrate_issue_trackers_data_spec.rb
@@ -14,11 +14,11 @@ RSpec.describe MigrateIssueTrackersData do
}
end
- let!(:jira_service) do
+ let!(:jira_integration) do
services.create!(type: 'JiraService', properties: properties, category: 'issue_tracker')
end
- let!(:jira_service_nil) do
+ let!(:jira_integration_nil) do
services.create!(type: 'JiraService', properties: nil, category: 'issue_tracker')
end
@@ -26,11 +26,11 @@ RSpec.describe MigrateIssueTrackersData do
services.create!(type: 'BugzillaService', properties: properties, category: 'issue_tracker')
end
- let!(:youtrack_service) do
+ let!(:youtrack_integration) do
services.create!(type: 'YoutrackService', properties: properties, category: 'issue_tracker')
end
- let!(:youtrack_service_empty) do
+ let!(:youtrack_integration_empty) do
services.create!(type: 'YoutrackService', properties: '', category: 'issue_tracker')
end
@@ -55,8 +55,8 @@ RSpec.describe MigrateIssueTrackersData do
freeze_time do
migrate!
- expect(migration_name).to be_scheduled_delayed_migration(3.minutes, jira_service.id, bugzilla_integration.id)
- expect(migration_name).to be_scheduled_delayed_migration(6.minutes, youtrack_service.id, gitlab_service.id)
+ expect(migration_name).to be_scheduled_delayed_migration(3.minutes, jira_integration.id, bugzilla_integration.id)
+ expect(migration_name).to be_scheduled_delayed_migration(6.minutes, youtrack_integration.id, gitlab_service.id)
expect(BackgroundMigrationWorker.jobs.size).to eq(2)
end
end
diff --git a/spec/migrations/20200130145430_reschedule_migrate_issue_trackers_data_spec.rb b/spec/migrations/20200130145430_reschedule_migrate_issue_trackers_data_spec.rb
index 5516e2af3f1..cf8bc608483 100644
--- a/spec/migrations/20200130145430_reschedule_migrate_issue_trackers_data_spec.rb
+++ b/spec/migrations/20200130145430_reschedule_migrate_issue_trackers_data_spec.rb
@@ -14,11 +14,11 @@ RSpec.describe RescheduleMigrateIssueTrackersData do
}
end
- let!(:jira_service) do
+ let!(:jira_integration) do
services.create!(id: 10, type: 'JiraService', properties: properties, category: 'issue_tracker')
end
- let!(:jira_service_nil) do
+ let!(:jira_integration_nil) do
services.create!(id: 11, type: 'JiraService', properties: nil, category: 'issue_tracker')
end
@@ -26,11 +26,11 @@ RSpec.describe RescheduleMigrateIssueTrackersData do
services.create!(id: 12, type: 'BugzillaService', properties: properties, category: 'issue_tracker')
end
- let!(:youtrack_service) do
+ let!(:youtrack_integration) do
services.create!(id: 13, type: 'YoutrackService', properties: properties, category: 'issue_tracker')
end
- let!(:youtrack_service_empty) do
+ let!(:youtrack_integration_empty) do
services.create!(id: 14, type: 'YoutrackService', properties: '', category: 'issue_tracker')
end
@@ -56,8 +56,8 @@ RSpec.describe RescheduleMigrateIssueTrackersData do
freeze_time do
migrate!
- expect(migration_name).to be_scheduled_delayed_migration(3.minutes, jira_service.id, bugzilla_integration.id)
- expect(migration_name).to be_scheduled_delayed_migration(6.minutes, youtrack_service.id, gitlab_service.id)
+ expect(migration_name).to be_scheduled_delayed_migration(3.minutes, jira_integration.id, bugzilla_integration.id)
+ expect(migration_name).to be_scheduled_delayed_migration(6.minutes, youtrack_integration.id, gitlab_service.id)
expect(BackgroundMigrationWorker.jobs.size).to eq(2)
end
end
diff --git a/spec/migrations/20200728080250_replace_unique_index_on_cycle_analytics_stages_spec.rb b/spec/migrations/20200728080250_replace_unique_index_on_cycle_analytics_stages_spec.rb
index 761168ae609..a632065946d 100644
--- a/spec/migrations/20200728080250_replace_unique_index_on_cycle_analytics_stages_spec.rb
+++ b/spec/migrations/20200728080250_replace_unique_index_on_cycle_analytics_stages_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require_migration!('replace_unique_index_on_cycle_analytics_stages')
-RSpec.describe ReplaceUniqueIndexOnCycleAnalyticsStages, :migration, schema: 20200728080250 do
+RSpec.describe ReplaceUniqueIndexOnCycleAnalyticsStages, :migration, schema: 20200727142337 do
let(:namespaces) { table(:namespaces) }
let(:group_value_streams) { table(:analytics_cycle_analytics_group_value_streams) }
let(:group_stages) { table(:analytics_cycle_analytics_group_stages) }
diff --git a/spec/migrations/20210610153556_delete_legacy_operations_feature_flags_spec.rb b/spec/migrations/20210610153556_delete_legacy_operations_feature_flags_spec.rb
new file mode 100644
index 00000000000..4f621d0670c
--- /dev/null
+++ b/spec/migrations/20210610153556_delete_legacy_operations_feature_flags_spec.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require_migration!('delete_legacy_operations_feature_flags')
+
+RSpec.describe DeleteLegacyOperationsFeatureFlags do
+ let(:namespace) { table(:namespaces).create!(name: 'foo', path: 'bar') }
+ let(:project) { table(:projects).create!(namespace_id: namespace.id) }
+ let(:issue) { table(:issues).create!(id: 123, project_id: project.id) }
+ let(:operations_feature_flags) { table(:operations_feature_flags) }
+ let(:operations_feature_flag_scopes) { table(:operations_feature_flag_scopes) }
+ let(:operations_strategies) { table(:operations_strategies) }
+ let(:operations_scopes) { table(:operations_scopes) }
+ let(:operations_feature_flags_issues) { table(:operations_feature_flags_issues) }
+
+ it 'correctly deletes legacy feature flags' do
+ # Legacy version of a feature flag - dropped support in GitLab 14.0.
+ legacy_flag = operations_feature_flags.create!(project_id: project.id, version: 1, name: 'flag_a', active: true, iid: 1)
+ operations_feature_flag_scopes.create!(feature_flag_id: legacy_flag.id, active: true)
+ operations_feature_flags_issues.create!(feature_flag_id: legacy_flag.id, issue_id: issue.id)
+ # New version of a feature flag.
+ new_flag = operations_feature_flags.create!(project_id: project.id, version: 2, name: 'flag_b', active: true, iid: 2)
+ new_strategy = operations_strategies.create!(feature_flag_id: new_flag.id, name: 'default')
+ operations_scopes.create!(strategy_id: new_strategy.id, environment_scope: '*')
+ operations_feature_flags_issues.create!(feature_flag_id: new_flag.id, issue_id: issue.id)
+
+ expect(operations_feature_flags.all.pluck(:version)).to contain_exactly(1, 2)
+ expect(operations_feature_flag_scopes.count).to eq(1)
+ expect(operations_strategies.count).to eq(1)
+ expect(operations_scopes.count).to eq(1)
+ expect(operations_feature_flags_issues.all.pluck(:feature_flag_id)).to contain_exactly(legacy_flag.id, new_flag.id)
+
+ migrate!
+
+ # Legacy flag is deleted.
+ expect(operations_feature_flags.all.pluck(:version)).to contain_exactly(2)
+ # The associated entries of the legacy flag are deleted too.
+ expect(operations_feature_flag_scopes.count).to eq(0)
+ # The associated entries of the new flag stay instact.
+ expect(operations_strategies.count).to eq(1)
+ expect(operations_scopes.count).to eq(1)
+ expect(operations_feature_flags_issues.all.pluck(:feature_flag_id)).to contain_exactly(new_flag.id)
+ end
+end
diff --git a/spec/migrations/2021061716138_cascade_delete_freeze_periods_spec.rb b/spec/migrations/2021061716138_cascade_delete_freeze_periods_spec.rb
new file mode 100644
index 00000000000..fd664d99f06
--- /dev/null
+++ b/spec/migrations/2021061716138_cascade_delete_freeze_periods_spec.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require_migration!('cascade_delete_freeze_periods')
+
+RSpec.describe CascadeDeleteFreezePeriods do
+ let(:namespace) { table(:namespaces).create!(name: 'deploy_freeze', path: 'deploy_freeze') }
+ let(:project) { table(:projects).create!(id: 1, namespace_id: namespace.id) }
+ let(:freeze_periods) { table(:ci_freeze_periods) }
+
+ describe "#up" do
+ it 'allows for a project to be deleted' do
+ freeze_periods.create!(id: 1, project_id: project.id, freeze_start: '5 * * * *', freeze_end: '6 * * * *', cron_timezone: 'UTC')
+ migrate!
+
+ project.delete
+
+ expect(freeze_periods.where(project_id: project.id).count).to be_zero
+ end
+ end
+end
diff --git a/spec/migrations/20210708130419_reschedule_merge_request_diff_users_background_migration_spec.rb b/spec/migrations/20210708130419_reschedule_merge_request_diff_users_background_migration_spec.rb
new file mode 100644
index 00000000000..9cc454662f9
--- /dev/null
+++ b/spec/migrations/20210708130419_reschedule_merge_request_diff_users_background_migration_spec.rb
@@ -0,0 +1,75 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration! 'reschedule_merge_request_diff_users_background_migration'
+
+RSpec.describe RescheduleMergeRequestDiffUsersBackgroundMigration, :migration do
+ let(:migration) { described_class.new }
+
+ describe '#up' do
+ before do
+ allow(described_class::MergeRequestDiff)
+ .to receive(:minimum)
+ .with(:id)
+ .and_return(42)
+
+ allow(described_class::MergeRequestDiff)
+ .to receive(:maximum)
+ .with(:id)
+ .and_return(85_123)
+ end
+
+ it 'deletes existing background migration job records' do
+ args = [150_000, 300_000]
+
+ Gitlab::Database::BackgroundMigrationJob
+ .create!(class_name: described_class::MIGRATION_NAME, arguments: args)
+
+ migration.up
+
+ found = Gitlab::Database::BackgroundMigrationJob
+ .where(class_name: described_class::MIGRATION_NAME, arguments: args)
+ .count
+
+ expect(found).to eq(0)
+ end
+
+ it 'schedules the migrations in batches' do
+ expect(migration)
+ .to receive(:migrate_in)
+ .ordered
+ .with(2.minutes.to_i, described_class::MIGRATION_NAME, [42, 40_042])
+
+ expect(migration)
+ .to receive(:migrate_in)
+ .ordered
+ .with(4.minutes.to_i, described_class::MIGRATION_NAME, [40_042, 80_042])
+
+ expect(migration)
+ .to receive(:migrate_in)
+ .ordered
+ .with(6.minutes.to_i, described_class::MIGRATION_NAME, [80_042, 120_042])
+
+ migration.up
+ end
+
+ it 'creates rows to track the background migration jobs' do
+ expect(Gitlab::Database::BackgroundMigrationJob)
+ .to receive(:create!)
+ .ordered
+ .with(class_name: described_class::MIGRATION_NAME, arguments: [42, 40_042])
+
+ expect(Gitlab::Database::BackgroundMigrationJob)
+ .to receive(:create!)
+ .ordered
+ .with(class_name: described_class::MIGRATION_NAME, arguments: [40_042, 80_042])
+
+ expect(Gitlab::Database::BackgroundMigrationJob)
+ .to receive(:create!)
+ .ordered
+ .with(class_name: described_class::MIGRATION_NAME, arguments: [80_042, 120_042])
+
+ migration.up
+ end
+ end
+end
diff --git a/spec/migrations/active_record/schema_spec.rb b/spec/migrations/active_record/schema_spec.rb
index 8199f55f5fc..4a505c51a16 100644
--- a/spec/migrations/active_record/schema_spec.rb
+++ b/spec/migrations/active_record/schema_spec.rb
@@ -7,10 +7,10 @@ require 'spec_helper'
RSpec.describe ActiveRecord::Schema, schema: :latest do
let(:all_migrations) do
- migrations_paths = %w[db/migrate db/post_migrate]
- .map { |path| Rails.root.join(*path, '*') }
+ migrations_directories = %w[db/migrate db/post_migrate].map { |path| Rails.root.join(path).to_s }
+ migrations_paths = migrations_directories.map { |path| File.join(path, '*') }
- migrations = Dir[*migrations_paths]
+ migrations = Dir[*migrations_paths] - migrations_directories
migrations.map { |migration| File.basename(migration).split('_').first.to_i }.sort
end
diff --git a/spec/migrations/add_premium_and_ultimate_plan_limits_spec.rb b/spec/migrations/add_premium_and_ultimate_plan_limits_spec.rb
new file mode 100644
index 00000000000..fb62fc3ca02
--- /dev/null
+++ b/spec/migrations/add_premium_and_ultimate_plan_limits_spec.rb
@@ -0,0 +1,86 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require_migration!
+
+RSpec.describe AddPremiumAndUltimatePlanLimits, :migration do
+ shared_examples_for 'a migration that does not alter plans or plan limits' do
+ it do
+ expect { migrate! }.not_to change {
+ [
+ AddPremiumAndUltimatePlanLimits::Plan.count,
+ AddPremiumAndUltimatePlanLimits::PlanLimits.count
+ ]
+ }
+ end
+ end
+
+ describe '#up' do
+ context 'when not .com?' do
+ before do
+ allow(Gitlab).to receive(:com?).and_return false
+ end
+
+ it_behaves_like 'a migration that does not alter plans or plan limits'
+ end
+
+ context 'when .com?' do
+ before do
+ allow(Gitlab).to receive(:com?).and_return true
+ end
+
+ context 'when source plan does not exist' do
+ it_behaves_like 'a migration that does not alter plans or plan limits'
+ end
+
+ context 'when target plan does not exist' do
+ before do
+ table(:plans).create!(name: 'silver', title: 'Silver')
+ table(:plans).create!(name: 'gold', title: 'Gold')
+ end
+
+ it_behaves_like 'a migration that does not alter plans or plan limits'
+ end
+
+ context 'when source and target plans exist' do
+ let!(:silver) { table(:plans).create!(name: 'silver', title: 'Silver') }
+ let!(:gold) { table(:plans).create!(name: 'gold', title: 'Gold') }
+ let!(:premium) { table(:plans).create!(name: 'premium', title: 'Premium') }
+ let!(:ultimate) { table(:plans).create!(name: 'ultimate', title: 'Ultimate') }
+
+ let!(:silver_limits) { table(:plan_limits).create!(plan_id: silver.id, storage_size_limit: 111) }
+ let!(:gold_limits) { table(:plan_limits).create!(plan_id: gold.id, storage_size_limit: 222) }
+
+ context 'when target has plan limits' do
+ before do
+ table(:plan_limits).create!(plan_id: premium.id, storage_size_limit: 999)
+ table(:plan_limits).create!(plan_id: ultimate.id, storage_size_limit: 999)
+ end
+
+ it 'does not overwrite the limits' do
+ expect { migrate! }.not_to change {
+ [
+ AddPremiumAndUltimatePlanLimits::Plan.count,
+ AddPremiumAndUltimatePlanLimits::PlanLimits.pluck(:id, :storage_size_limit).sort
+ ]
+ }
+ end
+ end
+
+ context 'when target has no plan limits' do
+ it 'creates plan limits from the source plan' do
+ migrate!
+
+ expect(AddPremiumAndUltimatePlanLimits::PlanLimits.pluck(:plan_id, :storage_size_limit)).to match_array([
+ [silver.id, silver_limits.storage_size_limit],
+ [gold.id, gold_limits.storage_size_limit],
+ [premium.id, silver_limits.storage_size_limit],
+ [ultimate.id, gold_limits.storage_size_limit]
+ ])
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/migrations/add_upvotes_count_index_to_issues_spec.rb b/spec/migrations/add_upvotes_count_index_to_issues_spec.rb
new file mode 100644
index 00000000000..c04cb98a107
--- /dev/null
+++ b/spec/migrations/add_upvotes_count_index_to_issues_spec.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe AddUpvotesCountIndexToIssues do
+ let(:migration_instance) { described_class.new }
+
+ describe '#up' do
+ it 'adds index' do
+ expect { migrate! }.to change { migration_instance.index_exists?(:issues, [:project_id, :upvotes_count], name: described_class::INDEX_NAME) }.from(false).to(true)
+ end
+ end
+
+ describe '#down' do
+ it 'removes index' do
+ migrate!
+
+ expect { schema_migrate_down! }.to change { migration_instance.index_exists?(:issues, [:project_id, :upvotes_count], name: described_class::INDEX_NAME) }.from(true).to(false)
+ end
+ end
+end
diff --git a/spec/migrations/backfill_issues_upvotes_count_spec.rb b/spec/migrations/backfill_issues_upvotes_count_spec.rb
new file mode 100644
index 00000000000..f2bea0edea0
--- /dev/null
+++ b/spec/migrations/backfill_issues_upvotes_count_spec.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe BackfillIssuesUpvotesCount do
+ let(:migration) { described_class.new }
+ let(:issues) { table(:issues) }
+ let(:award_emoji) { table(:award_emoji) }
+
+ let!(:issue1) { issues.create! }
+ let!(:issue2) { issues.create! }
+ let!(:issue3) { issues.create! }
+ let!(:issue4) { issues.create! }
+ let!(:issue4_without_thumbsup) { issues.create! }
+
+ let!(:award_emoji1) { award_emoji.create!( name: 'thumbsup', awardable_type: 'Issue', awardable_id: issue1.id) }
+ let!(:award_emoji2) { award_emoji.create!( name: 'thumbsup', awardable_type: 'Issue', awardable_id: issue2.id) }
+ let!(:award_emoji3) { award_emoji.create!( name: 'thumbsup', awardable_type: 'Issue', awardable_id: issue3.id) }
+ let!(:award_emoji4) { award_emoji.create!( name: 'thumbsup', awardable_type: 'Issue', awardable_id: issue4.id) }
+
+ it 'correctly schedules background migrations' do
+ stub_const("#{described_class.name}::BATCH_SIZE", 2)
+
+ Sidekiq::Testing.fake! do
+ freeze_time do
+ migrate!
+
+ expect(described_class::MIGRATION).to be_scheduled_migration(issue1.id, issue2.id)
+ expect(described_class::MIGRATION).to be_scheduled_migration(issue3.id, issue4.id)
+ expect(BackgroundMigrationWorker.jobs.size).to eq(2)
+ end
+ end
+ end
+end
diff --git a/spec/migrations/delete_template_services_duplicated_by_type_spec.rb b/spec/migrations/delete_template_services_duplicated_by_type_spec.rb
index b5a29436159..577fea984da 100644
--- a/spec/migrations/delete_template_services_duplicated_by_type_spec.rb
+++ b/spec/migrations/delete_template_services_duplicated_by_type_spec.rb
@@ -14,11 +14,11 @@ RSpec.describe DeleteTemplateServicesDuplicatedByType do
end
it 'deletes service templates duplicated by type except the one with the lowest ID' do
- jenkins_service_id = services.where(type: 'JenkinsService').order(:id).pluck(:id).first
- jira_service_id = services.where(type: 'JiraService').pluck(:id).first
+ jenkins_integration_id = services.where(type: 'JenkinsService').order(:id).pluck(:id).first
+ jira_integration_id = services.where(type: 'JiraService').pluck(:id).first
migrate!
- expect(services.pluck(:id)).to contain_exactly(jenkins_service_id, jira_service_id)
+ expect(services.pluck(:id)).to contain_exactly(jenkins_integration_id, jira_integration_id)
end
end
diff --git a/spec/migrations/fix_batched_migrations_old_format_job_arguments_spec.rb b/spec/migrations/fix_batched_migrations_old_format_job_arguments_spec.rb
new file mode 100644
index 00000000000..e15011d0dab
--- /dev/null
+++ b/spec/migrations/fix_batched_migrations_old_format_job_arguments_spec.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+# rubocop:disable Style/WordArray
+RSpec.describe FixBatchedMigrationsOldFormatJobArguments do
+ let(:batched_background_migrations) { table(:batched_background_migrations) }
+
+ context 'when migrations with legacy job arguments exists' do
+ it 'updates job arguments to current format' do
+ legacy_events_migration = create_batched_migration('events', 'id', ['id', 'id_convert_to_bigint'])
+ legacy_push_event_payloads_migration = create_batched_migration('push_event_payloads', 'event_id', ['event_id', 'event_id_convert_to_bigint'])
+
+ migrate!
+
+ expect(legacy_events_migration.reload.job_arguments).to eq([['id'], ['id_convert_to_bigint']])
+ expect(legacy_push_event_payloads_migration.reload.job_arguments).to eq([['event_id'], ['event_id_convert_to_bigint']])
+ end
+ end
+
+ context 'when only migrations with current job arguments exists' do
+ it 'updates nothing' do
+ events_migration = create_batched_migration('events', 'id', [['id'], ['id_convert_to_bigint']])
+ push_event_payloads_migration = create_batched_migration('push_event_payloads', 'event_id', [['event_id'], ['event_id_convert_to_bigint']])
+
+ migrate!
+
+ expect(events_migration.reload.job_arguments).to eq([['id'], ['id_convert_to_bigint']])
+ expect(push_event_payloads_migration.reload.job_arguments).to eq([['event_id'], ['event_id_convert_to_bigint']])
+ end
+ end
+
+ context 'when migrations with both legacy and current job arguments exist' do
+ it 'updates nothing' do
+ legacy_events_migration = create_batched_migration('events', 'id', ['id', 'id_convert_to_bigint'])
+ events_migration = create_batched_migration('events', 'id', [['id'], ['id_convert_to_bigint']])
+ legacy_push_event_payloads_migration = create_batched_migration('push_event_payloads', 'event_id', ['event_id', 'event_id_convert_to_bigint'])
+ push_event_payloads_migration = create_batched_migration('push_event_payloads', 'event_id', [['event_id'], ['event_id_convert_to_bigint']])
+
+ migrate!
+
+ expect(legacy_events_migration.reload.job_arguments).to eq(['id', 'id_convert_to_bigint'])
+ expect(events_migration.reload.job_arguments).to eq([['id'], ['id_convert_to_bigint']])
+ expect(legacy_push_event_payloads_migration.reload.job_arguments).to eq(['event_id', 'event_id_convert_to_bigint'])
+ expect(push_event_payloads_migration.reload.job_arguments).to eq([['event_id'], ['event_id_convert_to_bigint']])
+ end
+ end
+
+ def create_batched_migration(table_name, column_name, job_arguments)
+ batched_background_migrations.create!(
+ max_value: 10,
+ batch_size: 10,
+ sub_batch_size: 10,
+ interval: 1,
+ job_class_name: 'CopyColumnUsingBackgroundMigrationJob',
+ table_name: table_name,
+ column_name: column_name,
+ job_arguments: job_arguments
+ )
+ end
+end
+# rubocop:enable Style/WordArray
diff --git a/spec/migrations/re_schedule_latest_pipeline_id_population_spec.rb b/spec/migrations/re_schedule_latest_pipeline_id_population_spec.rb
new file mode 100644
index 00000000000..354a0896ac9
--- /dev/null
+++ b/spec/migrations/re_schedule_latest_pipeline_id_population_spec.rb
@@ -0,0 +1,61 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe ReScheduleLatestPipelineIdPopulation do
+ let(:namespaces) { table(:namespaces) }
+ let(:pipelines) { table(:ci_pipelines) }
+ let(:projects) { table(:projects) }
+ let(:project_settings) { table(:project_settings) }
+ let(:vulnerability_statistics) { table(:vulnerability_statistics) }
+
+ let(:letter_grade_a) { 0 }
+
+ let(:namespace) { namespaces.create!(name: 'gitlab', path: 'gitlab-org') }
+ let(:project_1) { projects.create!(namespace_id: namespace.id, name: 'Foo 1') }
+ let(:project_2) { projects.create!(namespace_id: namespace.id, name: 'Foo 2') }
+ let(:project_3) { projects.create!(namespace_id: namespace.id, name: 'Foo 3') }
+ let(:project_4) { projects.create!(namespace_id: namespace.id, name: 'Foo 4') }
+
+ before do
+ project_settings.create!(project_id: project_1.id, has_vulnerabilities: true)
+ project_settings.create!(project_id: project_2.id, has_vulnerabilities: true)
+ project_settings.create!(project_id: project_3.id)
+ project_settings.create!(project_id: project_4.id, has_vulnerabilities: true)
+
+ pipeline = pipelines.create!(project_id: project_2.id, ref: 'master', sha: 'adf43c3a')
+
+ vulnerability_statistics.create!(project_id: project_2.id, letter_grade: letter_grade_a, latest_pipeline_id: pipeline.id)
+ vulnerability_statistics.create!(project_id: project_4.id, letter_grade: letter_grade_a)
+
+ allow(Gitlab).to receive(:ee?).and_return(is_ee?)
+ stub_const("#{described_class.name}::BATCH_SIZE", 1)
+ end
+
+ around do |example|
+ freeze_time { example.run }
+ end
+
+ context 'when the installation is FOSS' do
+ let(:is_ee?) { false }
+
+ it 'does not schedule any background job' do
+ migrate!
+
+ expect(BackgroundMigrationWorker.jobs.size).to be(0)
+ end
+ end
+
+ context 'when the installation is EE' do
+ let(:is_ee?) { true }
+
+ it 'schedules the background jobs' do
+ migrate!
+
+ expect(BackgroundMigrationWorker.jobs.size).to be(2)
+ expect(described_class::MIGRATION).to be_scheduled_delayed_migration(described_class::DELAY_INTERVAL, project_1.id, project_1.id)
+ expect(described_class::MIGRATION).to be_scheduled_delayed_migration(2 * described_class::DELAY_INTERVAL, project_4.id, project_4.id)
+ end
+ end
+end
diff --git a/spec/migrations/rename_services_to_integrations_spec.rb b/spec/migrations/rename_services_to_integrations_spec.rb
new file mode 100644
index 00000000000..812dd5efecb
--- /dev/null
+++ b/spec/migrations/rename_services_to_integrations_spec.rb
@@ -0,0 +1,255 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require_migration!
+
+RSpec.describe RenameServicesToIntegrations do
+ let(:migration) { described_class.new }
+ let(:namespaces) { table(:namespaces) }
+ let(:projects) { table(:projects) }
+ let(:integrations) { table(:integrations) }
+ let(:services) { table(:services) }
+
+ before do
+ @namespace = namespaces.create!(name: 'foo', path: 'foo')
+ @project = projects.create!(namespace_id: @namespace.id)
+ end
+
+ RSpec.shared_examples 'a table (or view) with triggers' do
+ describe 'INSERT tracker trigger' do
+ it 'sets `has_external_issue_tracker` to true when active `issue_tracker` is inserted' do
+ expect do
+ subject.create!(category: 'issue_tracker', active: true, project_id: @project.id)
+ end.to change { @project.reload.has_external_issue_tracker }.to(true)
+ end
+
+ it 'does not set `has_external_issue_tracker` to true when integration is for a different project' do
+ different_project = projects.create!(namespace_id: @namespace.id)
+
+ expect do
+ subject.create!(category: 'issue_tracker', active: true, project_id: different_project.id)
+ end.not_to change { @project.reload.has_external_issue_tracker }
+ end
+
+ it 'does not set `has_external_issue_tracker` to true when inactive `issue_tracker` is inserted' do
+ expect do
+ subject.create!(category: 'issue_tracker', active: false, project_id: @project.id)
+ end.not_to change { @project.reload.has_external_issue_tracker }
+ end
+
+ it 'does not set `has_external_issue_tracker` to true when a non-`issue tracker` active integration is inserted' do
+ expect do
+ subject.create!(category: 'my_type', active: true, project_id: @project.id)
+ end.not_to change { @project.reload.has_external_issue_tracker }
+ end
+ end
+
+ describe 'UPDATE tracker trigger' do
+ it 'sets `has_external_issue_tracker` to true when `issue_tracker` is made active' do
+ integration = subject.create!(category: 'issue_tracker', active: false, project_id: @project.id)
+
+ expect do
+ integration.update!(active: true)
+ end.to change { @project.reload.has_external_issue_tracker }.to(true)
+ end
+
+ it 'sets `has_external_issue_tracker` to false when `issue_tracker` is made inactive' do
+ integration = subject.create!(category: 'issue_tracker', active: true, project_id: @project.id)
+
+ expect do
+ integration.update!(active: false)
+ end.to change { @project.reload.has_external_issue_tracker }.to(false)
+ end
+
+ it 'sets `has_external_issue_tracker` to false when `issue_tracker` is made inactive, and an inactive `issue_tracker` exists' do
+ subject.create!(category: 'issue_tracker', active: false, project_id: @project.id)
+ integration = subject.create!(category: 'issue_tracker', active: true, project_id: @project.id)
+
+ expect do
+ integration.update!(active: false)
+ end.to change { @project.reload.has_external_issue_tracker }.to(false)
+ end
+
+ it 'does not change `has_external_issue_tracker` when `issue_tracker` is made inactive, if an active `issue_tracker` exists' do
+ subject.create!(category: 'issue_tracker', active: true, project_id: @project.id)
+ integration = subject.create!(category: 'issue_tracker', active: true, project_id: @project.id)
+
+ expect do
+ integration.update!(active: false)
+ end.not_to change { @project.reload.has_external_issue_tracker }
+ end
+
+ it 'does not change `has_external_issue_tracker` when integration is for a different project' do
+ different_project = projects.create!(namespace_id: @namespace.id)
+ integration = subject.create!(category: 'issue_tracker', active: false, project_id: different_project.id)
+
+ expect do
+ integration.update!(active: true)
+ end.not_to change { @project.reload.has_external_issue_tracker }
+ end
+ end
+
+ describe 'DELETE tracker trigger' do
+ it 'sets `has_external_issue_tracker` to false when `issue_tracker` is deleted' do
+ integration = subject.create!(category: 'issue_tracker', active: true, project_id: @project.id)
+
+ expect do
+ integration.delete
+ end.to change { @project.reload.has_external_issue_tracker }.to(false)
+ end
+
+ it 'sets `has_external_issue_tracker` to false when `issue_tracker` is deleted, if an inactive `issue_tracker` still exists' do
+ subject.create!(category: 'issue_tracker', active: false, project_id: @project.id)
+ integration = subject.create!(category: 'issue_tracker', active: true, project_id: @project.id)
+
+ expect do
+ integration.delete
+ end.to change { @project.reload.has_external_issue_tracker }.to(false)
+ end
+
+ it 'does not change `has_external_issue_tracker` when `issue_tracker` is deleted, if an active `issue_tracker` still exists' do
+ subject.create!(category: 'issue_tracker', active: true, project_id: @project.id)
+ integration = subject.create!(category: 'issue_tracker', active: true, project_id: @project.id)
+
+ expect do
+ integration.delete
+ end.not_to change { @project.reload.has_external_issue_tracker }
+ end
+
+ it 'does not change `has_external_issue_tracker` when integration is for a different project' do
+ different_project = projects.create!(namespace_id: @namespace.id)
+ integration = subject.create!(category: 'issue_tracker', active: true, project_id: different_project.id)
+
+ expect do
+ integration.delete
+ end.not_to change { @project.reload.has_external_issue_tracker }
+ end
+ end
+
+ describe 'INSERT wiki trigger' do
+ it 'sets `has_external_wiki` to true when active `ExternalWikiService` is inserted' do
+ expect do
+ subject.create!(type: 'ExternalWikiService', active: true, project_id: @project.id)
+ end.to change { @project.reload.has_external_wiki }.to(true)
+ end
+
+ it 'does not set `has_external_wiki` to true when integration is for a different project' do
+ different_project = projects.create!(namespace_id: @namespace.id)
+
+ expect do
+ subject.create!(type: 'ExternalWikiService', active: true, project_id: different_project.id)
+ end.not_to change { @project.reload.has_external_wiki }
+ end
+
+ it 'does not set `has_external_wiki` to true when inactive `ExternalWikiService` is inserted' do
+ expect do
+ subject.create!(type: 'ExternalWikiService', active: false, project_id: @project.id)
+ end.not_to change { @project.reload.has_external_wiki }
+ end
+
+ it 'does not set `has_external_wiki` to true when active other integration is inserted' do
+ expect do
+ subject.create!(type: 'MyService', active: true, project_id: @project.id)
+ end.not_to change { @project.reload.has_external_wiki }
+ end
+ end
+
+ describe 'UPDATE wiki trigger' do
+ it 'sets `has_external_wiki` to true when `ExternalWikiService` is made active' do
+ integration = subject.create!(type: 'ExternalWikiService', active: false, project_id: @project.id)
+
+ expect do
+ integration.update!(active: true)
+ end.to change { @project.reload.has_external_wiki }.to(true)
+ end
+
+ it 'sets `has_external_wiki` to false when `ExternalWikiService` is made inactive' do
+ integration = subject.create!(type: 'ExternalWikiService', active: true, project_id: @project.id)
+
+ expect do
+ integration.update!(active: false)
+ end.to change { @project.reload.has_external_wiki }.to(false)
+ end
+
+ it 'does not change `has_external_wiki` when integration is for a different project' do
+ different_project = projects.create!(namespace_id: @namespace.id)
+ integration = subject.create!(type: 'ExternalWikiService', active: false, project_id: different_project.id)
+
+ expect do
+ integration.update!(active: true)
+ end.not_to change { @project.reload.has_external_wiki }
+ end
+ end
+
+ describe 'DELETE wiki trigger' do
+ it 'sets `has_external_wiki` to false when `ExternalWikiService` is deleted' do
+ integration = subject.create!(type: 'ExternalWikiService', active: true, project_id: @project.id)
+
+ expect do
+ integration.delete
+ end.to change { @project.reload.has_external_wiki }.to(false)
+ end
+
+ it 'does not change `has_external_wiki` when integration is for a different project' do
+ different_project = projects.create!(namespace_id: @namespace.id)
+ integration = subject.create!(type: 'ExternalWikiService', active: true, project_id: different_project.id)
+
+ expect do
+ integration.delete
+ end.not_to change { @project.reload.has_external_wiki }
+ end
+ end
+ end
+
+ RSpec.shared_examples 'a table (or view) without triggers' do
+ specify do
+ number_of_triggers = ActiveRecord::Base.connection
+ .execute("SELECT count(*) FROM information_schema.triggers WHERE event_object_table = '#{subject.table_name}'")
+ .first['count']
+
+ expect(number_of_triggers).to eq(0)
+ end
+ end
+
+ describe '#up' do
+ before do
+ # LOCK TABLE statements must be in a transaction
+ ActiveRecord::Base.transaction { migrate! }
+ end
+
+ context 'the integrations table' do
+ subject { integrations }
+
+ it_behaves_like 'a table (or view) with triggers'
+ end
+
+ context 'the services table' do
+ subject { services }
+
+ it_behaves_like 'a table (or view) without triggers'
+ end
+ end
+
+ describe '#down' do
+ before do
+ # LOCK TABLE statements must be in a transaction
+ ActiveRecord::Base.transaction do
+ migration.up
+ migration.down
+ end
+ end
+
+ context 'the services table' do
+ subject { services }
+
+ it_behaves_like 'a table (or view) with triggers'
+ end
+
+ context 'the integrations table' do
+ subject { integrations }
+
+ it_behaves_like 'a table (or view) without triggers'
+ end
+ end
+end
diff --git a/spec/migrations/reset_job_token_scope_enabled_spec.rb b/spec/migrations/reset_job_token_scope_enabled_spec.rb
new file mode 100644
index 00000000000..40dfe4de34b
--- /dev/null
+++ b/spec/migrations/reset_job_token_scope_enabled_spec.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require_migration!
+
+RSpec.describe ResetJobTokenScopeEnabled do
+ let(:settings) { table(:project_ci_cd_settings) }
+ let(:projects) { table(:projects) }
+ let(:namespaces) { table(:namespaces) }
+ let(:namespace) { namespaces.create!(name: 'gitlab', path: 'gitlab-org') }
+ let(:project_1) { projects.create!(name: 'proj-1', path: 'gitlab-org', namespace_id: namespace.id)}
+ let(:project_2) { projects.create!(name: 'proj-2', path: 'gitlab-org', namespace_id: namespace.id)}
+
+ before do
+ settings.create!(id: 1, project_id: project_1.id, job_token_scope_enabled: true)
+ settings.create!(id: 2, project_id: project_2.id, job_token_scope_enabled: false)
+ end
+
+ it 'migrates job_token_scope_enabled to be always false' do
+ expect { migrate! }
+ .to change { settings.where(job_token_scope_enabled: false).count }
+ .from(1).to(2)
+ end
+end
diff --git a/spec/migrations/schedule_backfill_draft_status_on_merge_requests_spec.rb b/spec/migrations/schedule_backfill_draft_status_on_merge_requests_spec.rb
new file mode 100644
index 00000000000..5a1c07d810f
--- /dev/null
+++ b/spec/migrations/schedule_backfill_draft_status_on_merge_requests_spec.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require_migration!
+
+RSpec.describe ScheduleBackfillDraftStatusOnMergeRequests, :sidekiq do
+ let(:namespaces) { table(:namespaces) }
+ let(:projects) { table(:projects) }
+ let(:merge_requests) { table(:merge_requests) }
+
+ let(:group) { namespaces.create!(name: 'gitlab', path: 'gitlab') }
+ let(:project) { projects.create!(namespace_id: group.id) }
+
+ let(:draft_prefixes) { ["[Draft]", "(Draft)", "Draft:", "Draft", "[WIP]", "WIP:", "WIP"] }
+
+ def create_merge_request(params)
+ common_params = {
+ target_project_id: project.id,
+ target_branch: 'feature1',
+ source_branch: 'master'
+ }
+
+ merge_requests.create!(common_params.merge(params))
+ end
+
+ before do
+ draft_prefixes.each do |prefix|
+ (1..4).each do |n|
+ create_merge_request(
+ title: "#{prefix} This is a title",
+ draft: false,
+ state_id: n
+ )
+ end
+ end
+
+ stub_const("#{described_class}::BATCH_SIZE", 1)
+ end
+
+ it 'schedules BackfillDraftStatusOnMergeRequests background jobs' do
+ Sidekiq::Testing.fake! do
+ draft_mrs = Gitlab::BackgroundMigration::BackfillDraftStatusOnMergeRequests::MergeRequest.eligible
+
+ first_mr_id = draft_mrs.first.id
+ second_mr_id = draft_mrs.second.id
+
+ freeze_time do
+ migrate!
+
+ expect(BackgroundMigrationWorker.jobs.size).to eq(7)
+ expect(described_class::MIGRATION)
+ .to be_scheduled_delayed_migration(2.minutes, first_mr_id, first_mr_id)
+ expect(described_class::MIGRATION)
+ .to be_scheduled_delayed_migration(4.minutes, second_mr_id, second_mr_id)
+ end
+ end
+ end
+end
diff --git a/spec/migrations/schedule_delete_orphaned_deployments_spec.rb b/spec/migrations/schedule_delete_orphaned_deployments_spec.rb
new file mode 100644
index 00000000000..618958a3d90
--- /dev/null
+++ b/spec/migrations/schedule_delete_orphaned_deployments_spec.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require_migration!
+
+RSpec.describe ScheduleDeleteOrphanedDeployments, :sidekiq, schema: 20210617161348 do
+ let!(:namespace) { table(:namespaces).create!(name: 'user', path: 'user') }
+ let!(:project) { table(:projects).create!(namespace_id: namespace.id) }
+ let!(:environment) { table(:environments).create!(name: 'production', slug: 'production', project_id: project.id) }
+ let(:background_migration_jobs) { table(:background_migration_jobs) }
+
+ before do
+ create_deployment!(environment.id, project.id)
+ create_deployment!(environment.id, project.id)
+ create_deployment!(environment.id, project.id)
+ create_deployment!(non_existing_record_id, project.id)
+ create_deployment!(non_existing_record_id, project.id)
+ create_deployment!(non_existing_record_id, project.id)
+ create_deployment!(non_existing_record_id, project.id)
+
+ stub_const("#{described_class}::BATCH_SIZE", 1)
+ end
+
+ it 'schedules DeleteOrphanedDeployments background jobs' do
+ Sidekiq::Testing.fake! do
+ freeze_time do
+ migrate!
+
+ expect(BackgroundMigrationWorker.jobs.size).to eq(7)
+ table(:deployments).find_each do |deployment|
+ expect(described_class::MIGRATION).to be_scheduled_migration(deployment.id, deployment.id)
+ end
+ end
+ end
+ end
+
+ def create_deployment!(environment_id, project_id)
+ table(:deployments).create!(
+ environment_id: environment_id,
+ project_id: project_id,
+ ref: 'master',
+ tag: false,
+ sha: 'x',
+ status: 1,
+ iid: table(:deployments).count + 1)
+ end
+end