gitlab-ce/spec/models/bulk_imports/export_status_spec.rb

401 lines
11 KiB
Ruby

# frozen_string_literal: true
require 'spec_helper'
RSpec.describe BulkImports::ExportStatus, :clean_gitlab_redis_cache, feature_category: :importers do
let_it_be(:relation) { 'labels' }
let_it_be(:import) { create(:bulk_import) }
let_it_be(:config) { create(:bulk_import_configuration, bulk_import: import) }
let_it_be(:entity) { create(:bulk_import_entity, bulk_import: import, source_full_path: 'foo') }
let_it_be(:tracker) { create(:bulk_import_tracker, entity: entity) }
let(:batched) { false }
let(:batches) { [] }
let(:response_double) do
instance_double(HTTParty::Response,
parsed_response: [
{
'relation' => 'labels',
'status' => status,
'error' => 'error!',
'batched' => batched,
'batches' => batches,
'batches_count' => 1,
'total_objects_count' => 1
}
]
)
end
subject { described_class.new(tracker, relation) }
before do
allow_next_instance_of(BulkImports::Clients::HTTP) do |client|
allow(client).to receive(:get).and_return(response_double)
end
end
describe '#started?' do
context 'when export status is started' do
let(:status) { BulkImports::Export::STARTED }
it 'returns true' do
expect(subject.started?).to eq(true)
end
end
context 'when export status is not started' do
let(:status) { BulkImports::Export::FAILED }
it 'returns false' do
expect(subject.started?).to eq(false)
end
end
context 'when export status is not present' do
let(:response_double) do
instance_double(HTTParty::Response, parsed_response: [])
end
it 'returns false' do
expect(subject.started?).to eq(false)
end
end
context 'when something goes wrong during export status fetch' do
before do
allow_next_instance_of(BulkImports::Clients::HTTP) do |client|
allow(client).to receive(:get).and_raise(
BulkImports::NetworkError.new("Unsuccessful response", response: nil)
)
end
end
it 'returns false' do
expect(subject.started?).to eq(false)
end
end
end
describe '#failed?' do
context 'when export status is failed' do
let(:status) { BulkImports::Export::FAILED }
it 'returns true' do
expect(subject.failed?).to eq(true)
end
end
context 'when export status is not failed' do
let(:status) { BulkImports::Export::STARTED }
it 'returns false' do
expect(subject.failed?).to eq(false)
end
end
context 'when export status is not present' do
let(:response_double) do
instance_double(HTTParty::Response, parsed_response: [])
end
it 'returns false' do
expect(subject.failed?).to eq(false)
end
end
context 'when something goes wrong during export status fetch' do
before do
allow_next_instance_of(BulkImports::Clients::HTTP) do |client|
allow(client).to receive(:get).and_raise(
BulkImports::NetworkError.new("Unsuccessful response", response: nil)
)
end
end
it 'returns true' do
expect(subject.failed?).to eq(true)
end
end
end
describe '#empty?' do
context 'when export status is present' do
let(:status) { 'any status' }
it { expect(subject.empty?).to eq(false) }
end
context 'when export status is not present' do
let(:response_double) do
instance_double(HTTParty::Response, parsed_response: [])
end
it 'returns true' do
expect(subject.empty?).to eq(true)
end
end
context 'when export status is empty' do
let(:response_double) do
instance_double(HTTParty::Response, parsed_response: nil)
end
it 'returns true' do
expect(subject.empty?).to eq(true)
end
end
context 'when something goes wrong during export status fetch' do
before do
allow_next_instance_of(BulkImports::Clients::HTTP) do |client|
allow(client).to receive(:get).and_raise(
BulkImports::NetworkError.new("Unsuccessful response", response: nil)
)
end
end
it 'returns false' do
expect(subject.empty?).to eq(false)
end
end
end
describe '#error' do
let(:status) { BulkImports::Export::FAILED }
it 'returns error message' do
expect(subject.error).to eq('error!')
end
context 'when something goes wrong during export status fetch' do
let(:exception) { BulkImports::NetworkError.new('Error!') }
before do
allow_next_instance_of(BulkImports::Clients::HTTP) do |client|
allow(client).to receive(:get).once.and_raise(exception)
end
end
it 'raises RetryPipelineError' do
allow(exception).to receive(:retriable?).with(tracker).and_return(true)
expect { subject.failed? }.to raise_error(BulkImports::RetryPipelineError)
end
context 'when error is not retriable' do
it 'returns exception class as error' do
expect(subject.error).to eq('Error!')
expect(subject.failed?).to eq(true)
end
end
context 'when error raised is not a network error' do
it 'returns exception class as error' do
allow_next_instance_of(BulkImports::Clients::HTTP) do |client|
allow(client).to receive(:get).once.and_raise(StandardError, 'Standard Error!')
end
expect(subject.error).to eq('Standard Error!')
expect(subject.failed?).to eq(true)
end
end
end
end
describe 'batching information' do
let(:status) { BulkImports::Export::FINISHED }
describe '#batched?' do
context 'when export is batched' do
let(:batched) { true }
it 'returns true' do
expect(subject.batched?).to eq(true)
end
end
context 'when export is not batched' do
it 'returns false' do
expect(subject.batched?).to eq(false)
end
end
context 'when export batch information is missing' do
let(:response_double) do
instance_double(HTTParty::Response, parsed_response: [{ 'relation' => 'labels', 'status' => status }])
end
it 'returns false' do
expect(subject.batched?).to eq(false)
end
end
end
describe '#batches_count' do
context 'when batches count is present' do
it 'returns batches count' do
expect(subject.batches_count).to eq(1)
end
end
context 'when batches count is missing' do
let(:response_double) do
instance_double(HTTParty::Response, parsed_response: [{ 'relation' => 'labels', 'status' => status }])
end
it 'returns 0' do
expect(subject.batches_count).to eq(0)
end
end
end
describe '#batch' do
context 'when export is batched' do
let(:batched) { true }
let(:batches) do
[
{ 'relation' => 'labels', 'status' => status, 'batch_number' => 1 },
{ 'relation' => 'milestones', 'status' => status, 'batch_number' => 2 }
]
end
context 'when batch number is in range' do
it 'returns batch information' do
expect(subject.batch(1)['relation']).to eq('labels')
expect(subject.batch(2)['relation']).to eq('milestones')
expect(subject.batch(3)).to eq(nil)
end
end
end
context 'when batch number is less than 1' do
it 'raises error' do
expect { subject.batch(0) }.to raise_error(ArgumentError)
end
end
context 'when export is not batched' do
it 'returns nil' do
expect(subject.batch(1)).to eq(nil)
end
end
end
end
describe 'caching' do
let(:cached_status) do
subject.send(:status)
subject.send(:status_from_cache)
end
shared_examples 'does not result in a cached status' do
specify do
expect(cached_status).to be_nil
end
end
shared_examples 'results in a cached status' do
specify do
expect(cached_status).to include('status' => status)
end
context 'when something goes wrong during export status fetch' do
before do
allow_next_instance_of(BulkImports::Clients::HTTP) do |client|
allow(client).to receive(:get).and_raise(
BulkImports::NetworkError.new("Unsuccessful response", response: nil)
)
end
end
include_examples 'does not result in a cached status'
end
end
context 'when export status is started' do
let(:status) { BulkImports::Export::STARTED }
it_behaves_like 'does not result in a cached status'
end
context 'when export status is failed' do
let(:status) { BulkImports::Export::FAILED }
it_behaves_like 'results in a cached status'
end
context 'when export status is finished' do
let(:status) { BulkImports::Export::FINISHED }
it_behaves_like 'results in a cached status'
end
context 'when export status is not present' do
let(:status) { nil }
it_behaves_like 'does not result in a cached status'
end
context 'when the cache is empty' do
let(:status) { BulkImports::Export::FAILED }
it 'fetches the status from the remote' do
expect(subject).to receive(:status_from_remote).and_call_original
expect(subject.send(:status)).to include('status' => status)
end
end
context 'when the cache is not empty' do
let(:status) { BulkImports::Export::FAILED }
before do
Gitlab::Cache::Import::Caching.write(
described_class.new(tracker, 'labels').send(:cache_key),
{ 'status' => 'mock status' }.to_json
)
end
it 'does not fetch the status from the remote' do
expect(subject).not_to receive(:status_from_remote)
expect(subject.send(:status)).to eq({ 'status' => 'mock status' })
end
context 'with a different entity' do
before do
tracker.entity = create(:bulk_import_entity, bulk_import: import, source_full_path: 'foo')
end
it 'fetches the status from the remote' do
expect(subject).to receive(:status_from_remote).and_call_original
expect(subject.send(:status)).to include('status' => status)
end
end
context 'with a different relation' do
let_it_be(:relation) { 'merge_requests' }
let(:response_double) do
instance_double(HTTParty::Response, parsed_response: [
{ 'relation' => 'labels', 'status' => status },
{ 'relation' => 'merge_requests', 'status' => status }
])
end
it 'fetches the status from the remote' do
expect(subject).to receive(:status_from_remote).and_call_original
expect(subject.send(:status)).to include('status' => status)
end
end
end
end
describe '#total_objects_count' do
let(:status) { BulkImports::Export::FINISHED }
it 'returns total objects count' do
expect(subject.total_objects_count).to eq(1)
end
end
end