2020-03-13 15:44:24 +05:30
# frozen_string_literal: true
require 'spec_helper'
2020-07-28 23:09:34 +05:30
RSpec . describe Gitlab :: ImportExport :: ImportFailureService do
2020-03-13 15:44:24 +05:30
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