123 lines
4 KiB
Ruby
123 lines
4 KiB
Ruby
|
# frozen_string_literal: true
|
||
|
|
||
|
require 'spec_helper'
|
||
|
|
||
|
describe Gitlab::ImportExport::ImportFailureService do
|
||
|
let(:importable) { create(:project, :builds_enabled, :issues_disabled, name: 'project', path: 'project') }
|
||
|
let(:label) { create(:label) }
|
||
|
let(:subject) { described_class.new(importable) }
|
||
|
let(:action) { "save_relation" }
|
||
|
let(:relation_key) { "labels" }
|
||
|
let(:relation_index) { 0 }
|
||
|
|
||
|
describe '#log_import_failure' do
|
||
|
let(:standard_error_message) { "StandardError message" }
|
||
|
let(:exception) { StandardError.new(standard_error_message) }
|
||
|
let(:correlation_id) { 'my-correlation-id' }
|
||
|
let(:retry_count) { 2 }
|
||
|
let(:log_import_failure) do
|
||
|
subject.log_import_failure(
|
||
|
source: action,
|
||
|
relation_key: relation_key,
|
||
|
relation_index: relation_index,
|
||
|
exception: exception,
|
||
|
retry_count: retry_count)
|
||
|
end
|
||
|
|
||
|
before do
|
||
|
# Import is running from the rake task, `correlation_id` is not assigned
|
||
|
allow(Labkit::Correlation::CorrelationId).to receive(:current_or_new_id).and_return(correlation_id)
|
||
|
end
|
||
|
|
||
|
context 'when importable is a group' do
|
||
|
let(:importable) { create(:group) }
|
||
|
|
||
|
it_behaves_like 'log import failure', :group_id
|
||
|
end
|
||
|
|
||
|
context 'when importable is a project' do
|
||
|
it_behaves_like 'log import failure', :project_id
|
||
|
end
|
||
|
|
||
|
context 'when ImportFailure does not support importable class' do
|
||
|
let(:importable) { create(:merge_request) }
|
||
|
|
||
|
it 'raise exception' do
|
||
|
expect { subject }.to raise_exception(ActiveRecord::AssociationNotFoundError, "Association named 'import_failures' was not found on MergeRequest; perhaps you misspelled it?")
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
describe '#with_retry' do
|
||
|
let(:perform_retry) do
|
||
|
subject.with_retry(action: action, relation_key: relation_key, relation_index: relation_index) do
|
||
|
label.save!
|
||
|
end
|
||
|
end
|
||
|
|
||
|
context 'when exceptions are retriable' do
|
||
|
where(:exception) { Gitlab::ImportExport::ImportFailureService::RETRIABLE_EXCEPTIONS }
|
||
|
|
||
|
with_them do
|
||
|
context 'when retry succeeds' do
|
||
|
before do
|
||
|
expect(label).to receive(:save!).and_raise(exception.new)
|
||
|
expect(label).to receive(:save!).and_return(true)
|
||
|
end
|
||
|
|
||
|
it 'retries and logs import failure once with correct params' do
|
||
|
expect(subject).to receive(:log_import_failure).with(
|
||
|
source: action,
|
||
|
relation_key: relation_key,
|
||
|
relation_index: relation_index,
|
||
|
exception: instance_of(exception),
|
||
|
retry_count: 1).once
|
||
|
|
||
|
perform_retry
|
||
|
end
|
||
|
end
|
||
|
|
||
|
context 'when retry continues to fail with intermittent errors' do
|
||
|
let(:maximum_retry_count) do
|
||
|
Retriable.config.tries
|
||
|
end
|
||
|
|
||
|
before do
|
||
|
expect(label).to receive(:save!)
|
||
|
.exactly(maximum_retry_count).times
|
||
|
.and_raise(exception.new)
|
||
|
end
|
||
|
|
||
|
it 'retries the number of times allowed and raise exception', :aggregate_failures do
|
||
|
expect { perform_retry }.to raise_exception(exception)
|
||
|
end
|
||
|
|
||
|
it 'logs import failure each time and raise exception', :aggregate_failures do
|
||
|
maximum_retry_count.times do |index|
|
||
|
retry_count = index + 1
|
||
|
|
||
|
expect(subject).to receive(:log_import_failure).with(
|
||
|
source: action, relation_key: relation_key,
|
||
|
relation_index: relation_index,
|
||
|
exception: instance_of(exception),
|
||
|
retry_count: retry_count)
|
||
|
end
|
||
|
|
||
|
expect { perform_retry }.to raise_exception(exception)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
context 'when exception is not retriable' do
|
||
|
let(:exception) { StandardError.new }
|
||
|
|
||
|
it 'raise the exception', :aggregate_failures do
|
||
|
expect(label).to receive(:save!).once.and_raise(exception)
|
||
|
expect(subject).not_to receive(:log_import_failure)
|
||
|
expect { perform_retry }.to raise_exception(exception)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|