diff options
| author | teddywing | 2017-08-01 17:39:10 +0200 |
|---|---|---|
| committer | GitHub | 2017-08-01 17:39:10 +0200 |
| commit | 1f09ead58c9c603e9d767781ceb82859b2393f49 (patch) | |
| tree | aec7d66e003ef9768156976750e27c38fd22cc0a /spec | |
| parent | 60ae8866d6d4c55bc064a2a83c1a1ffa87894202 (diff) | |
| parent | ee75bd1e579ab366eb6cac938f50e7786536472b (diff) | |
| download | chouette-core-1f09ead58c9c603e9d767781ceb82859b2393f49.tar.bz2 | |
Merge pull request #46 from af83/3507_1726_impl_workbench_import
3507 1726 impl workbench import
Diffstat (limited to 'spec')
28 files changed, 573 insertions, 26 deletions
diff --git a/spec/concerns/configurable_spec.rb b/spec/concerns/configurable_spec.rb new file mode 100644 index 000000000..330241b72 --- /dev/null +++ b/spec/concerns/configurable_spec.rb @@ -0,0 +1,35 @@ +RSpec.describe Configurable do + + subject do + Class.new do + include Configurable + end + end + + let( :something ){ double('something') } + + it 'can be configured' do + expect{ subject.config.anything }.to raise_error(NoMethodError) + + subject.config.something = something + + expect( subject.config.something ).to eq(something) + # Instances delegate to the class + expect( subject.new.send(:config).something ).to eq(something) + # **All** instances delegate to the class + expect( subject.new.send(:config).something ).to eq(something) + end + + it 'can be configured with a block' do + + subject.config do | c | + c.something = something + end + + expect( subject.config.something ).to eq(something) + # Instances delegate to the class + expect( subject.new.send(:config).something ).to eq(something) + # **All** instances delegate to the class + expect( subject.new.send(:config).something ).to eq(something) + end +end diff --git a/spec/controllers/imports_controller_spec.rb b/spec/controllers/imports_controller_spec.rb index 7b575ab61..f07190496 100644 --- a/spec/controllers/imports_controller_spec.rb +++ b/spec/controllers/imports_controller_spec.rb @@ -15,6 +15,7 @@ RSpec.describe ImportsController, :type => :controller do it 'should be successful' do get :download, workbench_id: workbench.id, id: import.id, token: import.token_download expect(response).to be_success + expect( response.body ).to eq(import.file.read) end end end diff --git a/spec/factories/api_keys.rb b/spec/factories/api_keys.rb new file mode 100644 index 000000000..bd31edecc --- /dev/null +++ b/spec/factories/api_keys.rb @@ -0,0 +1,6 @@ +FactoryGirl.define do + factory :api_key, class: Api::V1::ApiKey do + token { "#{referential.id}-#{SecureRandom.hex}" } + referential + end +end diff --git a/spec/factories/import_tasks.rb b/spec/factories/import_tasks.rb deleted file mode 100644 index 9ca6db899..000000000 --- a/spec/factories/import_tasks.rb +++ /dev/null @@ -1,10 +0,0 @@ -FactoryGirl.define do - factory :import_task do |f| - user_name "dummy" - user_id 123 - no_save false - format "Neptune" - resources { Rack::Test::UploadedFile.new 'spec/fixtures/neptune.zip', 'application/zip', false } - referential { Referential.find_by_slug("first") } - end -end diff --git a/spec/factories/imports.rb b/spec/factories/imports.rb index e19fe92bb..aa9288fe9 100644 --- a/spec/factories/imports.rb +++ b/spec/factories/imports.rb @@ -13,5 +13,8 @@ FactoryGirl.define do factory :netex_import, class: NetexImport do file {File.open(Rails.root.join('spec', 'fixtures', 'terminated_job.json'))} end + factory :workbench_import, class: WorkbenchImport do + file {File.open(Rails.root.join('spec', 'fixtures', 'terminated_job.json'))} + end end end diff --git a/spec/fixtures/multiple_references_import.zip b/spec/fixtures/multiple_references_import.zip Binary files differnew file mode 100644 index 000000000..28ddff198 --- /dev/null +++ b/spec/fixtures/multiple_references_import.zip diff --git a/spec/fixtures/neptune.zip b/spec/fixtures/neptune.zip Binary files differdeleted file mode 100644 index 86b688b51..000000000 --- a/spec/fixtures/neptune.zip +++ /dev/null diff --git a/spec/fixtures/nozip.zip b/spec/fixtures/nozip.zip new file mode 100644 index 000000000..505bd213a --- /dev/null +++ b/spec/fixtures/nozip.zip @@ -0,0 +1 @@ +no zip file diff --git a/spec/fixtures/ref1.zip b/spec/fixtures/ref1.zip Binary files differnew file mode 100644 index 000000000..1cbd0268e --- /dev/null +++ b/spec/fixtures/ref1.zip diff --git a/spec/fixtures/ref2.zip b/spec/fixtures/ref2.zip Binary files differnew file mode 100644 index 000000000..342353b07 --- /dev/null +++ b/spec/fixtures/ref2.zip diff --git a/spec/fixtures/single_reference_import.zip b/spec/fixtures/single_reference_import.zip Binary files differnew file mode 100644 index 000000000..4aee23614 --- /dev/null +++ b/spec/fixtures/single_reference_import.zip diff --git a/spec/lib/result_spec.rb b/spec/lib/result_spec.rb new file mode 100644 index 000000000..949de163c --- /dev/null +++ b/spec/lib/result_spec.rb @@ -0,0 +1,20 @@ +RSpec.describe Result do + + context 'is a wrapper of a value' do + it { expect( described_class.ok('hello').value ).to eq('hello') } + it { expect( described_class.error('hello').value ).to eq('hello') } + end + + context 'it has status information' do + it { expect( described_class.ok('hello') ).to be_ok } + it { expect( described_class.ok('hello').status ).to eq(:ok) } + + it { expect( described_class.error('hello') ).not_to be_ok } + it { expect( described_class.error('hello').status ).to eq(:error) } + end + + context 'nil is just another value' do + it { expect( described_class.ok(nil) ).to be_ok } + it { expect( described_class.ok(nil).value ).to be_nil } + end +end diff --git a/spec/models/api/v1/api_key_spec.rb b/spec/models/api/v1/api_key_spec.rb index 8a34c9221..5f39a65e4 100644 --- a/spec/models/api/v1/api_key_spec.rb +++ b/spec/models/api/v1/api_key_spec.rb @@ -1,11 +1,34 @@ describe Api::V1::ApiKey, :type => :model do - let!(:referential){create(:referential)} - subject { Api::V1::ApiKey.create( :name => "test", :referential => referential)} - it "test" do - expect(subject).to be_valid + let(:referential){ create :referential } + + subject { described_class.create( :name => "test", :referential => referential)} + + it "validity test" do + expect_it.to be_valid expect(subject.referential).to eq(referential) + end + + context 'Creation' do + let( :name ){ SecureRandom.urlsafe_base64 } + + it 'can be created from a referential with a name, iff needed' do + # 1st time create a new record + expect{ described_class.from(referential, name: name) }.to change{ described_class.count }.by(1) + expect( described_class.last.attributes.values_at(*%w{referential_id name}) ).to eq([ + referential.id, name + ]) + + # 2nd time get the same record + expect{ described_class.from(referential, name: name) }.not_to change{ described_class.count } + expect( described_class.last.attributes.values_at(*%w{referential_id name}) ).to eq([ + referential.id, name + ]) + end + it 'cannot be created without a referential' do + expect{ described_class.from(nil, name:name) rescue nil }.not_to change{ described_class.count } + end end end diff --git a/spec/models/import_spec.rb b/spec/models/import_spec.rb index 34bfb0b23..c56858b44 100644 --- a/spec/models/import_spec.rb +++ b/spec/models/import_spec.rb @@ -1,11 +1,12 @@ -require 'rails_helper' - RSpec.describe Import, :type => :model do + it { should belong_to(:referential) } it { should belong_to(:workbench) } it { should belong_to(:parent).class_name(described_class.to_s) } - it { should enumerize(:status).in(:new, :pending, :successful, :failed, :canceled, :running, :aborted ) } + it { should enumerize(:status).in("aborted", "canceled", "failed", "new", "pending", "running", "successful") } it { should validate_presence_of(:file) } + it { should validate_presence_of(:referential) } + it { should validate_presence_of(:workbench) } end diff --git a/spec/models/organisation_spec.rb b/spec/models/organisation_spec.rb index 527f71015..b16324a56 100644 --- a/spec/models/organisation_spec.rb +++ b/spec/models/organisation_spec.rb @@ -1,5 +1,3 @@ -require 'spec_helper' - describe Organisation, :type => :model do it { should validate_presence_of(:name) } it { should validate_uniqueness_of(:code) } @@ -17,7 +15,7 @@ describe Organisation, :type => :model do let(:conf) { Rails.application.config.stif_portail_api } before :each do stub_request(:get, "#{conf[:url]}/api/v1/organizations"). - with(headers: { 'Authorization' => "Token token=\"#{conf[:key]}\"" }). + with(stub_headers(authorization_token: conf[:key])). to_return(body: File.open(File.join(Rails.root, 'spec', 'fixtures', 'organizations.json')), status: 200) end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 3a9ae37e9..51ccfccd3 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -67,7 +67,7 @@ RSpec.describe User, :type => :model do let(:conf) { Rails.application.config.stif_portail_api } before :each do stub_request(:get, "#{conf[:url]}/api/v1/users"). - with(headers: { 'Authorization' => "Token token=\"#{conf[:key]}\"" }). + with(stub_headers(authorization_token: conf[:key])). to_return(body: File.open(File.join(Rails.root, 'spec', 'fixtures', 'users.json')), status: 200) end diff --git a/spec/requests/api/v1/netex_import_spec.rb b/spec/requests/api/v1/netex_import_spec.rb index 9fbf8f801..ab1e7f6ae 100644 --- a/spec/requests/api/v1/netex_import_spec.rb +++ b/spec/requests/api/v1/netex_import_spec.rb @@ -4,7 +4,7 @@ RSpec.describe "NetexImport", type: :request do let( :referential ){ create :referential } - let( :file_path ){'spec/fixtures/neptune.zip'} + let( :file_path ){ fixtures_path 'single_reference_import.zip' } let( :file ){ fixture_file_upload( file_path ) } let( :post_request ) do @@ -19,7 +19,8 @@ RSpec.describe "NetexImport", type: :request do { name: 'hello world', file: file, - referential_id: referential.id + referential_id: referential.id, + workbench_id: referential.workbench_id } end 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 diff --git a/spec/support/fixtures_helper.rb b/spec/support/fixtures_helper.rb new file mode 100644 index 000000000..20963261b --- /dev/null +++ b/spec/support/fixtures_helper.rb @@ -0,0 +1,18 @@ +module Support + module FixturesHelper + def fixtures_path *segments + Rails.root.join( fixture_path, *segments ) + end + + def open_fixture *segments + File.open(fixtures_path(*segments)) + end + def read_fixture *segments + File.read(fixtures_path(*segments)) + end + end +end + +RSpec.configure do |c| + c.include Support::FixturesHelper +end diff --git a/spec/support/webmock/helpers.rb b/spec/support/webmock/helpers.rb new file mode 100644 index 000000000..fc6c77850 --- /dev/null +++ b/spec/support/webmock/helpers.rb @@ -0,0 +1,18 @@ +module Support + module Webmock + module Helpers + def stub_headers(*args) + {headers: make_headers(*args)} + end + + def make_headers(headers={}, authorization_token:) + headers.merge('Authorization' => "Token token=#{authorization_token.inspect}") + end + end + end +end + +RSpec.configure do | conf | + conf.include Support::Webmock::Helpers, type: :model + conf.include Support::Webmock::Helpers, type: :worker +end diff --git a/spec/tasks/reflex_rake_spec.rb b/spec/tasks/reflex_rake_spec.rb index 04c5886aa..6ece223d2 100644 --- a/spec/tasks/reflex_rake_spec.rb +++ b/spec/tasks/reflex_rake_spec.rb @@ -5,7 +5,7 @@ describe 'reflex:sync' do before(:each) do ['getOP', 'getOR'].each do |method| stub_request(:get, "#{Rails.application.config.reflex_api_url}/?format=xml&idRefa=0&method=#{method}"). - to_return(body: File.open("#{fixture_path}/reflex.zip"), status: 200) + to_return(body: open_fixture('reflex.zip'), status: 200) end stop_area_ref = create(:stop_area_referential, name: 'Reflex') @@ -43,7 +43,7 @@ describe 'reflex:sync' do before(:each) do ['getOP', 'getOR'].each do |method| stub_request(:get, "#{Rails.application.config.reflex_api_url}/?format=xml&idRefa=0&method=#{method}"). - to_return(body: File.open("#{fixture_path}/reflex_updated.zip"), status: 200) + to_return(body: open_fixture('reflex_updated.zip'), status: 200) end Stif::ReflexSynchronization.synchronize end diff --git a/spec/workers/stop_area_referential_sync_worker_spec.rb b/spec/workers/stop_area_referential_sync_worker_spec.rb index 48b64e55e..50c7cf45f 100644 --- a/spec/workers/stop_area_referential_sync_worker_spec.rb +++ b/spec/workers/stop_area_referential_sync_worker_spec.rb @@ -1,4 +1,3 @@ -require 'rails_helper' RSpec.describe StopAreaReferentialSyncWorker, type: :worker do let!(:stop_area_referential_sync) { create :stop_area_referential_sync } diff --git a/spec/workers/workbench_import_worker_spec.rb b/spec/workers/workbench_import_worker_spec.rb new file mode 100644 index 000000000..b719cbb98 --- /dev/null +++ b/spec/workers/workbench_import_worker_spec.rb @@ -0,0 +1,119 @@ +RSpec.describe WorkbenchImportWorker, type: [:worker, :request] do + + let( :worker ) { described_class.new } + let( :import ){ build_stubbed :import, token_download: download_token, file: zip_file } + + let( :workbench ){ import.workbench } + let( :referential ){ import.referential } + let( :api_key ){ build_stubbed :api_key, referential: referential, token: "#{referential.id}-#{SecureRandom.hex}" } + let( :params ) do + { netex_import: + { referential_id: referential.id, workbench_id: workbench.id } + } + end + + # http://www.example.com/workbenches/:workbench_id/imports/:id/download + let( :host ){ Rails.configuration.rails_host } + let( :path ){ download_workbench_import_path(workbench, import) } + + let( :downloaded_zip ){ double("downloaded zip") } + let( :download_zip_response ){ OpenStruct.new( body: downloaded_zip ) } + let( :download_token ){ SecureRandom.urlsafe_base64 } + + + let( :upload_path ) { api_v1_netex_imports_path(format: :json) } + + let( :entry_group_streams ) do + entry_count.times.map{ |i| double( "entry group stream #{i}" ) } + end + let( :entry_groups ) do + entry_count.times.map do | i | + {"entry_group_name#{i}" => entry_group_streams[i] } + end + end + + let( :zip_service ){ double("zip service") } + let( :zip_file ){ open_fixture('multiple_references_import.zip') } + + let( :post_response_ok ){ double(status: 201, body: "{}") } + + before do + # Silence Logger + allow_any_instance_of(Logger).to receive(:info) + allow_any_instance_of(Logger).to receive(:warn) + + # That should be `build_stubbed's` job, no? + allow(Import).to receive(:find).with(import.id).and_return(import) + + allow(Api::V1::ApiKey).to receive(:from).and_return(api_key) + allow(ZipService).to receive(:new).with(downloaded_zip).and_return zip_service + expect(zip_service).to receive(:entry_group_streams).and_return(entry_groups) + expect( import ).to receive(:update_attributes).with(status: 'running') + end + + + context 'multireferential zipfile, no errors' do + let( :entry_count ){ 2 } + + it 'downloads a zip file, cuts it, and uploads all pieces' do + + expect(HTTPService).to receive(:get_resource) + .with(host: host, path: path, params: {token: download_token}) + .and_return( download_zip_response ) + + entry_groups.each do | entry_group_name, entry_group_stream | + mock_post entry_group_name, entry_group_stream, post_response_ok + end + + expect( import ).to receive(:update_attributes).with(total_steps: 2) + expect( import ).to receive(:update_attributes).with(current_step: 1) + expect( import ).to receive(:update_attributes).with(current_step: 2) + + worker.perform import.id + + end + end + + context 'multireferential zipfile with error' do + let( :entry_count ){ 3 } + let( :post_response_failure ){ double(status: 406, body: {error: 'What was you thinking'}) } + + it 'downloads a zip file, cuts it, and uploads some pieces' do + expect(HTTPService).to receive(:get_resource) + .with(host: host, path: path, params: {token: download_token}) + .and_return( download_zip_response ) + + # First entry_group succeeds + entry_groups[0..0].each do | entry_group_name, entry_group_stream | + mock_post entry_group_name, entry_group_stream, post_response_ok + end + + # Second entry_group fails (M I S E R A B L Y) + entry_groups[1..1].each do | entry_group_name, entry_group_stream | + mock_post entry_group_name, entry_group_stream, post_response_failure + WorkbenchImportWorker::RETRY_DELAYS.each do | delay | + mock_post entry_group_name, entry_group_stream, post_response_failure + expect_any_instance_of(RetryService).to receive(:sleep).with(delay) + end + end + + expect( import ).to receive(:update_attributes).with(total_steps: 3) + expect( import ).to receive(:update_attributes).with(current_step: 1) + expect( import ).to receive(:update_attributes).with(current_step: 2) + expect( import ).to receive(:update_attributes).with(current_step: 3, status: 'failed') + + worker.perform import.id + + end + end + + def mock_post entry_group_name, entry_group_stream, response + expect( HTTPService ).to receive(:post_resource) + .with(host: host, + path: upload_path, + token: api_key.token, + params: params, + upload: {file: [entry_group_stream, 'application/zip', entry_group_name]}) + .and_return(response) + end +end |
