121 lines
		
	
	
	
		
			4.2 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			121 lines
		
	
	
	
		
			4.2 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| # frozen_string_literal: true
 | |
| 
 | |
| require 'rails_helper'
 | |
| 
 | |
| RSpec.describe Import::RowWorker do
 | |
|   subject { described_class.new }
 | |
| 
 | |
|   let(:row) { Fabricate(:bulk_import_row, bulk_import: import) }
 | |
| 
 | |
|   describe '#perform' do
 | |
|     before { allow(BulkImportRowService).to receive(:new).and_return(service_double) }
 | |
| 
 | |
|     shared_context 'when service succeeds' do
 | |
|       let(:service_double) { instance_double(BulkImportRowService, call: true) }
 | |
|     end
 | |
| 
 | |
|     shared_context 'when service fails' do
 | |
|       let(:service_double) { instance_double(BulkImportRowService, call: false) }
 | |
|     end
 | |
| 
 | |
|     shared_context 'when service errors' do
 | |
|       let(:service_double) { instance_double(BulkImportRowService) }
 | |
|       before { allow(service_double).to receive(:call).and_raise('dummy error') }
 | |
|     end
 | |
| 
 | |
|     shared_examples 'clean failure' do
 | |
|       it 'calls service, increases processed items, preserves imported items, and keeps row' do
 | |
|         expect { subject.perform(row.id) }
 | |
|           .to change { import.reload.processed_items }.by(+1)
 | |
|           .and not_change { import.reload.imported_items }
 | |
|           .and(not_change { BulkImportRow.exists?(row.id) }.from(true))
 | |
|         expect(service_double)
 | |
|           .to have_received(:call).with(row)
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     shared_examples 'unclean failure' do
 | |
|       it 'raises an error, preserves processed items, and keeps row' do
 | |
|         expect { subject.perform(row.id) }
 | |
|           .to raise_error(StandardError, 'dummy error')
 | |
|           .and(not_change { import.reload.processed_items })
 | |
|           .and(not_change { BulkImportRow.exists?(row.id) }.from(true))
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     shared_examples 'clean success' do
 | |
|       it 'calls service, increases processed items, increases imported items, and deletes row' do
 | |
|         expect { subject.perform(row.id) }
 | |
|           .to change { import.reload.processed_items }.by(+1)
 | |
|           .and change { import.reload.imported_items }.by(+1)
 | |
|           .and(change { BulkImportRow.exists?(row.id) }.from(true).to(false))
 | |
|         expect(service_double).to have_received(:call).with(row)
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     context 'when there are multiple rows to process' do
 | |
|       let(:import) { Fabricate(:bulk_import, total_items: 2, processed_items: 0, imported_items: 0, state: :in_progress) }
 | |
| 
 | |
|       context 'with a clean failure' do
 | |
|         include_context 'when service fails'
 | |
|         it_behaves_like 'clean failure'
 | |
| 
 | |
|         it 'does not mark the import as finished' do
 | |
|           expect { subject.perform(row.id) }
 | |
|             .to_not(change { import.reload.state.to_sym })
 | |
|         end
 | |
|       end
 | |
| 
 | |
|       context 'with an unclean failure' do
 | |
|         include_context 'when service errors'
 | |
|         it_behaves_like 'unclean failure'
 | |
| 
 | |
|         it 'does not mark the import as finished' do
 | |
|           expect { subject.perform(row.id) }
 | |
|             .to raise_error(StandardError)
 | |
|             .and(not_change { import.reload.state.to_sym })
 | |
|         end
 | |
|       end
 | |
| 
 | |
|       context 'with a clean success' do
 | |
|         include_context 'when service succeeds'
 | |
|         it_behaves_like 'clean success'
 | |
| 
 | |
|         it 'does not mark the import as finished' do
 | |
|           expect { subject.perform(row.id) }
 | |
|             .to_not(change { import.reload.state.to_sym })
 | |
|         end
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     context 'when this is the last row to process' do
 | |
|       let(:import) { Fabricate(:bulk_import, total_items: 2, processed_items: 1, imported_items: 0, state: :in_progress) }
 | |
| 
 | |
|       context 'with a clean failure' do
 | |
|         include_context 'when service fails'
 | |
|         it_behaves_like 'clean failure'
 | |
| 
 | |
|         it 'marks the import as finished' do
 | |
|           expect { subject.perform(row.id) }
 | |
|             .to change { import.reload.state.to_sym }.from(:in_progress).to(:finished)
 | |
|         end
 | |
|       end
 | |
| 
 | |
|       context 'with an unclean failure' do
 | |
|         # NOTE: sidekiq retry logic may be a bit too difficult to test, so leaving this blind spot for now
 | |
|         include_context 'when service errors'
 | |
|         it_behaves_like 'unclean failure'
 | |
|       end
 | |
| 
 | |
|       context 'with a clean success' do
 | |
|         include_context 'when service succeeds'
 | |
|         it_behaves_like 'clean success'
 | |
| 
 | |
|         it 'marks the import as finished' do
 | |
|           expect { subject.perform(row.id) }
 | |
|             .to change { import.reload.state.to_sym }.from(:in_progress).to(:finished)
 | |
|         end
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| end
 |