diff options
Diffstat (limited to 'spec/services')
| -rw-r--r-- | spec/services/file_service_spec.rb | 17 | ||||
| -rw-r--r-- | spec/services/http_service_spec.rb | 74 | ||||
| -rw-r--r-- | spec/services/retry_service_spec.rb | 137 | ||||
| -rw-r--r-- | spec/services/zip_service/zip_entry_data_spec.rb | 32 | ||||
| -rw-r--r-- | spec/services/zip_service/zip_entry_dirs_spec.rb | 33 | ||||
| -rw-r--r-- | spec/services/zip_service/zip_output_streams_spec.rb | 21 |
6 files changed, 314 insertions, 0 deletions
diff --git a/spec/services/file_service_spec.rb b/spec/services/file_service_spec.rb new file mode 100644 index 000000000..4426ee145 --- /dev/null +++ b/spec/services/file_service_spec.rb @@ -0,0 +1,17 @@ +# TODO: Delete me after stable implementation of #1726 +# RSpec.describe FileService do + +# it 'computes a unique filename' do +# expect( File ).to receive(:exists?).with('xxx/yyy_0').and_return( false ) + +# expect(described_class.unique_filename('xxx/yyy')).to eq('xxx/yyy_0') +# end + +# it 'handles duplicate names by means of a counter' do +# expect( File ).to receive(:exists?).with('xxx/yyy_0').and_return( true ) +# expect( File ).to receive(:exists?).with('xxx/yyy_1').and_return( true ) +# expect( File ).to receive(:exists?).with('xxx/yyy_2').and_return( false ) + +# expect(described_class.unique_filename('xxx/yyy')).to eq('xxx/yyy_2') +# end +# end diff --git a/spec/services/http_service_spec.rb b/spec/services/http_service_spec.rb new file mode 100644 index 000000000..8c8af480c --- /dev/null +++ b/spec/services/http_service_spec.rb @@ -0,0 +1,74 @@ +RSpec.describe HTTPService do + + subject{ described_class } + + %i{host params path result}.each do |param| + let(param){ double(param) } + end + let( :token ){ SecureRandom.hex } + + let( :faraday_connection ){ double('faraday_connection') } + let( :headers ){ {} } + + + context 'get_resource' do + let( :params ){ double('params') } + + it 'sets authorization and returns result' do + expect(Faraday).to receive(:new).with(url: host).and_yield(faraday_connection) + expect(faraday_connection).to receive(:adapter).with(Faraday.default_adapter) + expect(faraday_connection).to receive(:headers).and_return headers + expect(faraday_connection).to receive(:get).with(path, params).and_return(result) + + expect(subject.get_resource(host: host, path: path, token: token, params: params)).to eq(result) + expect(headers['Authorization']).to eq( "Token token=#{token.inspect}" ) + end + end + + context 'post_resource' do + %i{as_name mime_type name upload_io value}.each do | param | + let( param ){ double(param) } + end + + let( :upload_list ){ [value, mime_type, as_name] } + + it 'sets authorization and posts data' do + expect(Faraday::UploadIO).to receive(:new).with(*upload_list).and_return upload_io + expect(params).to receive(:update).with(name => upload_io) + + expect(Faraday).to receive(:new).with(url: host).and_yield(faraday_connection) + expect(faraday_connection).to receive(:adapter).with(Faraday.default_adapter) + expect(faraday_connection).to receive(:headers).and_return headers + expect(faraday_connection).to receive(:request).with(:multipart) + expect(faraday_connection).to receive(:request).with(:url_encoded) + + expect(faraday_connection).to receive(:post).with(path, params).and_return(result) + + expect(subject.post_resource( + host: host, + path: path, + token: token, + params: params, + upload: {name => upload_list} )).to eq(result) + expect(headers['Authorization']).to eq( "Token token=#{token.inspect}" ) + end + + end + + context 'get_json_resource' do + + let( :content ){ SecureRandom.hex } + + it 'delegates an parses the response' do + expect_it.to receive(:get_resource) + .with(host: host, path: path, token: token, params: params) + .and_return(double(body: {content: content}.to_json, status: 200)) + + expect( subject.get_json_resource( + host: host, + path: path, + token: token, + params: params) ).to eq('content' => content) + end + end +end diff --git a/spec/services/retry_service_spec.rb b/spec/services/retry_service_spec.rb new file mode 100644 index 000000000..bb3416373 --- /dev/null +++ b/spec/services/retry_service_spec.rb @@ -0,0 +1,137 @@ +RSpec.describe RetryService do + subject { described_class.new delays: [2, 3], rescue_from: [NameError, ArgumentError] } + + context 'no retry necessary' do + before do + expect( subject ).not_to receive(:sleep) + end + + it 'returns an ok result' do + expect( subject.execute { 42 } ).to eq(Result.ok(42)) + end + it 'does not fail on nil' do + expect( subject.execute { nil } ).to eq(Result.ok(nil)) + end + + it 'fails wihout retries if raising un unregistered exception' do + expect{ subject.execute{ raise KeyError } }.to raise_error(KeyError) + end + + end + + context 'all retries fail' do + before do + expect( subject ).to receive(:sleep).with(2) + expect( subject ).to receive(:sleep).with(3) + end + it 'fails after raising a registered exception n times' do + result = subject.execute{ raise ArgumentError } + expect( result.status ).to eq(:error) + expect( result.value ).to be_kind_of(ArgumentError) + end + it 'fails with an explicit try again (automatically registered exception)' do + result = subject.execute{ raise RetryService::Retry } + expect( result.status ).to eq(:error) + expect( result.value ).to be_kind_of(RetryService::Retry) + end + end + + context "if at first you don't succeed" do + before do + @count = 0 + expect( subject ).to receive(:sleep).with(2) + end + + it 'succeeds the second time' do + expect( subject.execute{ succeed_later(ArgumentError){ 42 } } ).to eq(Result.ok(42)) + end + + it 'succeeds the second time with try again (automatically registered exception)' do + expect( subject.execute{ succeed_later(RetryService::Retry){ 42 } } ).to eq(Result.ok(42)) + end + end + + context 'last chance' do + before do + @count = 0 + expect( subject ).to receive(:sleep).with(2) + expect( subject ).to receive(:sleep).with(3) + end + it 'succeeds the third time with try again (automatically registered exception)' do + result = subject.execute{ succeed_later(RetryService::Retry, count: 2){ 42 } } + expect( result ).to eq( Result.ok(42) ) + end + end + + context 'failure callback once' do + subject do + described_class.new delays: [2, 3], rescue_from: [NameError, ArgumentError] do |reason, count| + @reason=reason + @callback_count=count + @failures += 1 + end + end + + before do + @failures = 0 + @count = 0 + expect( subject ).to receive(:sleep).with(2) + end + + it 'succeeds the second time and calls the failure_callback once' do + subject.execute{ succeed_later(RetryService::Retry){ 42 } } + expect( @failures ).to eq(1) + end + it '... and the failure is passed into the callback' do + subject.execute{ succeed_later(RetryService::Retry){ 42 } } + expect( @reason ).to be_a(RetryService::Retry) + expect( @callback_count ).to eq(1) + end + end + + context 'failure callback twice' do + subject do + described_class.new delays: [2, 3], rescue_from: [NameError, ArgumentError] do |_reason, _count| + @failures += 1 + end + end + + before do + @failures = 0 + @count = 0 + expect( subject ).to receive(:sleep).with(2) + expect( subject ).to receive(:sleep).with(3) + end + + it 'succeeds the third time and calls the failure_callback twice' do + subject.execute{ succeed_later(NameError, count: 2){ 42 } } + expect( @failures ).to eq(2) + end + end + + context 'failure callback in constructor' do + subject do + described_class.new(delays: [1, 2], &method(:add2failures)) + end + before do + @failures = [] + @count = 0 + expect( subject ).to receive(:sleep).with(1) + expect( subject ).to receive(:sleep).with(2) + end + it 'succeeds the second time and calls the failure_callback once' do + subject.execute{ succeed_later(RetryService::Retry, count: 2){ 42 } } + expect( @failures ).to eq([1,2]) + end + end + + def add2failures( e, c) + @failures << c + end + + def succeed_later error, count: 1, &blk + return blk.() unless @count < count + @count += 1 + raise error, 'error' + end +end diff --git a/spec/services/zip_service/zip_entry_data_spec.rb b/spec/services/zip_service/zip_entry_data_spec.rb new file mode 100644 index 000000000..2a7226eb4 --- /dev/null +++ b/spec/services/zip_service/zip_entry_data_spec.rb @@ -0,0 +1,32 @@ +RSpec.describe ZipService do + + subject{ described_class.new(read_fixture('multiple_references_import.zip')) } + + it 'can group all entries' do + expect( subject.entry_groups.keys ).to eq(%w{ref1 ref2}) + end + + context 'creates correct zip data for each subdir' do + it 'e.g. reference1' do + reference1_stream = subject.entry_group_streams['ref1'] + control_stream = Zip::InputStream.open( reference1_stream ) + control_entries = described_class.entries(control_stream) + expect( control_entries.map{ |e| [e.name, e.get_input_stream.read]}.force ).to eq([ + ["multiref/ref1/", ""], + ["multiref/ref1/datum-1", "multi-ref1-datum1\n"], + ["multiref/ref1/datum-2", "multi-ref1-datum2\n"] + ]) + end + it 'e.g. reference2' do + reference2_stream = subject.entry_group_streams['ref2'] + control_stream = Zip::InputStream.open( reference2_stream ) + control_entries = described_class.entries(control_stream) + expect( control_entries.map{ |e| [e.name, e.get_input_stream.read]}.force ).to eq([ + ["multiref/ref2/", ""], + ["multiref/ref2/datum-1", "multi-ref2-datum1\n"], + ["multiref/ref2/datum-2", "multi-ref2-datum2\n"] + ]) + end + end + +end diff --git a/spec/services/zip_service/zip_entry_dirs_spec.rb b/spec/services/zip_service/zip_entry_dirs_spec.rb new file mode 100644 index 000000000..8ca1b0f1a --- /dev/null +++ b/spec/services/zip_service/zip_entry_dirs_spec.rb @@ -0,0 +1,33 @@ +RSpec.describe ZipService do + + let( :zip_service ){ described_class } + + let( :zip_data ){ File.read zip_file } + + shared_examples_for 'a correct zip entry reader' do + it 'gets all entries of the zip file' do + expect( zip_service.new(zip_data).entry_groups.keys ).to eq(expected) + end + end + + context 'single entry' do + let( :zip_file ){ fixtures_path 'multiple_references_import.zip' } + let( :expected ){ %w{ref1 ref2} } + + it_behaves_like 'a correct zip entry reader' + end + + context 'more entries' do + let( :zip_file ){ fixtures_path 'single_reference_import.zip' } + let( :expected ){ %w{ref} } + + it_behaves_like 'a correct zip entry reader' + end + + context 'illegal file' do + let( :zip_file ){ fixtures_path 'nozip.zip' } + let( :expected ){ [] } + + it_behaves_like 'a correct zip entry reader' + end +end diff --git a/spec/services/zip_service/zip_output_streams_spec.rb b/spec/services/zip_service/zip_output_streams_spec.rb new file mode 100644 index 000000000..fbc60ae92 --- /dev/null +++ b/spec/services/zip_service/zip_output_streams_spec.rb @@ -0,0 +1,21 @@ +RSpec.describe ZipService do + + subject{ described_class.new(read_fixture('multiple_references_import.zip')) } + + + it 'can write itself to a file' do + streams = subject.entry_group_streams + streams.each do | name, stream | + File.write("tmp/#{name}.zip", stream.string) + end + ref1_lines = %x(unzip -l tmp/ref1.zip).split("\n").grep(%r{multiref/ref}).map(&:strip).map(&:split).map(&:last) + ref2_lines = %x(unzip -l tmp/ref2.zip).split("\n").grep(%r{multiref/ref}).map(&:strip).map(&:split).map(&:last) + + expect( ref1_lines ).to eq %w(multiref/ref1/ multiref/ref1/datum-1 multiref/ref1/datum-2) + expect( ref2_lines ).to eq %w(multiref/ref2/ multiref/ref2/datum-1 multiref/ref2/datum-2) + end + + it "exposes its size" do + expect( subject.entry_group_streams.size ).to eq(2) + end +end |
