aboutsummaryrefslogtreecommitdiffstats
path: root/spec/services
diff options
context:
space:
mode:
Diffstat (limited to 'spec/services')
-rw-r--r--spec/services/file_service_spec.rb17
-rw-r--r--spec/services/http_service_spec.rb74
-rw-r--r--spec/services/retry_service_spec.rb137
-rw-r--r--spec/services/zip_service/zip_entry_data_spec.rb32
-rw-r--r--spec/services/zip_service/zip_entry_dirs_spec.rb33
-rw-r--r--spec/services/zip_service/zip_output_streams_spec.rb21
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