gitlab-org--gitlab-foss/spec/lib/gitlab/database/background_migration/batched_migration_wrapper_s...

161 lines
5.1 KiB
Ruby

# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Database::BackgroundMigration::BatchedMigrationWrapper, '#perform' do
subject(:perform) { described_class.new(connection: connection, metrics: metrics_tracker).perform(job_record) }
let(:connection) { Gitlab::Database.database_base_models[:main].connection }
let(:metrics_tracker) { instance_double('::Gitlab::Database::BackgroundMigration::PrometheusMetrics', track: nil) }
let(:job_class) { Class.new(Gitlab::BackgroundMigration::BatchedMigrationJob) }
let_it_be(:pause_ms) { 250 }
let_it_be(:active_migration) { create(:batched_background_migration, :active, job_arguments: [:id, :other_id]) }
let!(:job_record) do
create(:batched_background_migration_job, batched_migration: active_migration, pause_ms: pause_ms)
end
let(:job_instance) { instance_double('Gitlab::BackgroundMigration::BatchedMigrationJob') }
around do |example|
Gitlab::Database::SharedModel.using_connection(connection) do
example.run
end
end
before do
allow(active_migration).to receive(:job_class).and_return(job_class)
allow(job_class).to receive(:new).and_return(job_instance)
end
it 'runs the migration job' do
expect(job_class).to receive(:new)
.with(start_id: 1,
end_id: 10,
batch_table: 'events',
batch_column: 'id',
sub_batch_size: 1,
pause_ms: pause_ms,
job_arguments: active_migration.job_arguments,
connection: connection)
.and_return(job_instance)
expect(job_instance).to receive(:perform).with(no_args)
perform
end
it 'updates the tracking record in the database' do
test_metrics = { 'my_metrics' => 'some value' }
expect(job_instance).to receive(:perform).with(no_args)
expect(job_instance).to receive(:batch_metrics).and_return(test_metrics)
freeze_time do
perform
reloaded_job_record = job_record.reload
expect(reloaded_job_record).not_to be_pending
expect(reloaded_job_record.attempts).to eq(1)
expect(reloaded_job_record.started_at).to eq(Time.current)
expect(reloaded_job_record.metrics).to eq(test_metrics)
end
end
context 'when running a job that failed previously' do
let!(:job_record) do
create(:batched_background_migration_job, :failed,
batched_migration: active_migration,
pause_ms: pause_ms,
attempts: 1,
finished_at: 1.hour.ago,
metrics: { 'my_metrics' => 'some_value' }
)
end
it 'increments attempts and updates other fields' do
updated_metrics = { 'updated_metrics' => 'some_value' }
expect(job_instance).to receive(:perform).with(no_args)
expect(job_instance).to receive(:batch_metrics).and_return(updated_metrics)
freeze_time do
perform
job_record.reload
expect(job_record).not_to be_failed
expect(job_record.attempts).to eq(2)
expect(job_record.started_at).to eq(Time.current)
expect(job_record.finished_at).to eq(Time.current)
expect(job_record.metrics).to eq(updated_metrics)
end
end
end
context 'when the migration job does not raise an error' do
it 'marks the tracking record as succeeded' do
expect(job_instance).to receive(:perform).with(no_args)
freeze_time do
perform
reloaded_job_record = job_record.reload
expect(reloaded_job_record).to be_succeeded
expect(reloaded_job_record.finished_at).to eq(Time.current)
end
end
it 'tracks metrics of the execution' do
expect(job_instance).to receive(:perform).with(no_args)
expect(metrics_tracker).to receive(:track).with(job_record)
perform
end
end
context 'when the migration job raises an error' do
shared_examples 'an error is raised' do |error_class|
it 'marks the tracking record as failed' do
expect(job_instance).to receive(:perform).with(no_args).and_raise(error_class)
freeze_time do
expect { perform }.to raise_error(error_class)
reloaded_job_record = job_record.reload
expect(reloaded_job_record).to be_failed
expect(reloaded_job_record.finished_at).to eq(Time.current)
end
end
it 'tracks metrics of the execution' do
expect(job_instance).to receive(:perform).with(no_args).and_raise(error_class)
expect(metrics_tracker).to receive(:track).with(job_record)
expect { perform }.to raise_error(error_class)
end
end
it_behaves_like 'an error is raised', RuntimeError.new('Something broke!')
it_behaves_like 'an error is raised', SignalException.new('SIGTERM')
it_behaves_like 'an error is raised', ActiveRecord::StatementTimeout.new('Timeout!')
end
context 'when the batched background migration does not inherit from BatchedMigrationJob' do
let(:job_class) { Class.new }
let(:job_instance) { job_class.new }
it 'runs the job with the correct arguments' do
expect(job_class).to receive(:new).with(no_args).and_return(job_instance)
expect(job_instance).to receive(:perform).with(1, 10, 'events', 'id', 1, pause_ms, 'id', 'other_id')
perform
end
end
end