summaryrefslogtreecommitdiff
path: root/spec/lib/gitlab/database/background_migration/scheduler_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/lib/gitlab/database/background_migration/scheduler_spec.rb')
-rw-r--r--spec/lib/gitlab/database/background_migration/scheduler_spec.rb182
1 files changed, 182 insertions, 0 deletions
diff --git a/spec/lib/gitlab/database/background_migration/scheduler_spec.rb b/spec/lib/gitlab/database/background_migration/scheduler_spec.rb
new file mode 100644
index 00000000000..ba745acdf8a
--- /dev/null
+++ b/spec/lib/gitlab/database/background_migration/scheduler_spec.rb
@@ -0,0 +1,182 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::BackgroundMigration::Scheduler, '#perform' do
+ let(:scheduler) { described_class.new }
+
+ shared_examples_for 'it has no jobs to run' do
+ it 'does not create and run a migration job' do
+ test_wrapper = double('test wrapper')
+
+ expect(test_wrapper).not_to receive(:perform)
+
+ expect do
+ scheduler.perform(migration_wrapper: test_wrapper)
+ end.not_to change { Gitlab::Database::BackgroundMigration::BatchedJob.count }
+ end
+ end
+
+ context 'when there are no active migrations' do
+ let!(:migration) { create(:batched_background_migration, :finished) }
+
+ it_behaves_like 'it has no jobs to run'
+ end
+
+ shared_examples_for 'it has completed the migration' do
+ it 'marks the migration as finished' do
+ relation = Gitlab::Database::BackgroundMigration::BatchedMigration.finished.where(id: first_migration.id)
+
+ expect { scheduler.perform }.to change { relation.count }.by(1)
+ end
+ end
+
+ context 'when there are active migrations' do
+ let!(:first_migration) { create(:batched_background_migration, :active, batch_size: 2) }
+ let!(:last_migration) { create(:batched_background_migration, :active) }
+
+ let(:job_relation) do
+ Gitlab::Database::BackgroundMigration::BatchedJob.where(batched_background_migration_id: first_migration.id)
+ end
+
+ context 'when the migration interval has not elapsed' do
+ before do
+ expect_next_found_instance_of(Gitlab::Database::BackgroundMigration::BatchedMigration) do |migration|
+ expect(migration).to receive(:interval_elapsed?).and_return(false)
+ end
+ end
+
+ it_behaves_like 'it has no jobs to run'
+ end
+
+ context 'when the interval has elapsed' do
+ before do
+ expect_next_found_instance_of(Gitlab::Database::BackgroundMigration::BatchedMigration) do |migration|
+ expect(migration).to receive(:interval_elapsed?).and_return(true)
+ end
+ end
+
+ context 'when the first migration has no previous jobs' do
+ context 'when the migration has batches to process' do
+ let!(:event1) { create(:event) }
+ let!(:event2) { create(:event) }
+ let!(:event3) { create(:event) }
+
+ it 'runs the job for the first batch' do
+ first_migration.update!(min_value: event1.id, max_value: event3.id)
+
+ expect_next_instance_of(Gitlab::Database::BackgroundMigration::BatchedMigrationWrapper) do |wrapper|
+ expect(wrapper).to receive(:perform).and_wrap_original do |_, job_record|
+ expect(job_record).to eq(job_relation.first)
+ end
+ end
+
+ expect { scheduler.perform }.to change { job_relation.count }.by(1)
+
+ expect(job_relation.first).to have_attributes(
+ min_value: event1.id,
+ max_value: event2.id,
+ batch_size: first_migration.batch_size,
+ sub_batch_size: first_migration.sub_batch_size)
+ end
+ end
+
+ context 'when the migration has no batches to process' do
+ it_behaves_like 'it has no jobs to run'
+ it_behaves_like 'it has completed the migration'
+ end
+ end
+
+ context 'when the first migration has previous jobs' do
+ let!(:event1) { create(:event) }
+ let!(:event2) { create(:event) }
+ let!(:event3) { create(:event) }
+
+ let!(:previous_job) do
+ create(:batched_background_migration_job,
+ batched_migration: first_migration,
+ min_value: event1.id,
+ max_value: event2.id,
+ batch_size: 2,
+ sub_batch_size: 1)
+ end
+
+ context 'when the migration is ready to process another job' do
+ it 'runs the migration job for the next batch' do
+ first_migration.update!(min_value: event1.id, max_value: event3.id)
+
+ expect_next_instance_of(Gitlab::Database::BackgroundMigration::BatchedMigrationWrapper) do |wrapper|
+ expect(wrapper).to receive(:perform).and_wrap_original do |_, job_record|
+ expect(job_record).to eq(job_relation.last)
+ end
+ end
+
+ expect { scheduler.perform }.to change { job_relation.count }.by(1)
+
+ expect(job_relation.last).to have_attributes(
+ min_value: event3.id,
+ max_value: event3.id,
+ batch_size: first_migration.batch_size,
+ sub_batch_size: first_migration.sub_batch_size)
+ end
+ end
+
+ context 'when the migration has no batches remaining' do
+ let!(:final_job) do
+ create(:batched_background_migration_job,
+ batched_migration: first_migration,
+ min_value: event3.id,
+ max_value: event3.id,
+ batch_size: 2,
+ sub_batch_size: 1)
+ end
+
+ it_behaves_like 'it has no jobs to run'
+ it_behaves_like 'it has completed the migration'
+ end
+ end
+
+ context 'when the bounds of the next batch exceed the migration maximum value' do
+ let!(:events) { create_list(:event, 3) }
+ let(:event1) { events[0] }
+ let(:event2) { events[1] }
+
+ context 'when the batch maximum exceeds the migration maximum' do
+ it 'clamps the batch maximum to the migration maximum' do
+ first_migration.update!(batch_size: 5, min_value: event1.id, max_value: event2.id)
+
+ expect_next_instance_of(Gitlab::Database::BackgroundMigration::BatchedMigrationWrapper) do |wrapper|
+ expect(wrapper).to receive(:perform)
+ end
+
+ expect { scheduler.perform }.to change { job_relation.count }.by(1)
+
+ expect(job_relation.first).to have_attributes(
+ min_value: event1.id,
+ max_value: event2.id,
+ batch_size: first_migration.batch_size,
+ sub_batch_size: first_migration.sub_batch_size)
+ end
+ end
+
+ context 'when the batch minimum exceeds the migration maximum' do
+ let!(:previous_job) do
+ create(:batched_background_migration_job,
+ batched_migration: first_migration,
+ min_value: event1.id,
+ max_value: event2.id,
+ batch_size: 5,
+ sub_batch_size: 1)
+ end
+
+ before do
+ first_migration.update!(batch_size: 5, min_value: 1, max_value: event2.id)
+ end
+
+ it_behaves_like 'it has no jobs to run'
+ it_behaves_like 'it has completed the migration'
+ end
+ end
+ end
+ end
+end