182 lines
6.5 KiB
Ruby
182 lines
6.5 KiB
Ruby
# 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
|