diff options
18 files changed, 356 insertions, 224 deletions
| diff --git a/app/controllers/exports_controller.rb b/app/controllers/exports_controller.rb index 1b947299f..d56b14fb2 100644 --- a/app/controllers/exports_controller.rb +++ b/app/controllers/exports_controller.rb @@ -2,17 +2,9 @@ class ExportsController < ChouetteController    include PolicyChecker    include RansackDateFilter    include IevInterfaces -  skip_before_action :authenticate_user!, only: [:upload] +  # skip_before_action :authenticate_user!, only: [:upload]    defaults resource_class: Export::Base, collection_name: 'exports', instance_name: 'export' -  def upload -    if params[:token] == resource.token_download -      send_file resource.file.path -    else -      user_not_authorized -    end -  end -    private    def build_resource diff --git a/app/models/export/netex.rb b/app/models/export/netex.rb new file mode 100644 index 000000000..858f09549 --- /dev/null +++ b/app/models/export/netex.rb @@ -0,0 +1,2 @@ +class Export::Netex < Export::Base +end diff --git a/spec/controllers/exports_controller_spec.rb b/spec/controllers/exports_controller_spec.rb index 6cd6e4c54..a1a40d571 100644 --- a/spec/controllers/exports_controller_spec.rb +++ b/spec/controllers/exports_controller_spec.rb @@ -1,22 +1,32 @@ -require 'spec_helper' - -describe ExportsController, :type => :controller do +RSpec.describe ExportsController, :type => :controller do    login_user -  describe "GET 'new'" do -    it "returns http success" do -      pending -      get 'new' +  let(:workbench) { create :workbench } +  let(:export)    { create :export, workbench: workbench } + +  describe 'GET #new' do +    it 'should be successful if authorized' do +      get :new, workbench_id: workbench.id        expect(response).to be_success      end -  end -  describe "GET 'index'" do -    it "returns http success" do -      pending -      get 'index' -      expect(response).to be_success +    it 'should be unsuccessful unless authorized' do +      remove_permissions('exports.create', from_user: @user, save: true) +      get :new, workbench_id: workbench.id +      expect(response).not_to be_success      end    end +  describe "POST #create" do +    it "displays a flash message" do +      post :create, workbench_id: workbench.id, +        export: { +          name: 'Offre' +        } + +      expect(controller).to set_flash[:notice].to( +        I18n.t('flash.exports.create.notice') +      ) +    end +  end  end diff --git a/spec/factories/exports.rb b/spec/factories/exports.rb deleted file mode 100644 index 34427edb8..000000000 --- a/spec/factories/exports.rb +++ /dev/null @@ -1,5 +0,0 @@ -FactoryGirl.define do -  factory :export do -    referential { Referential.find_by_slug("first") } -  end -end diff --git a/spec/factories/exports/export_messages.rb b/spec/factories/exports/export_messages.rb new file mode 100644 index 000000000..55394ec45 --- /dev/null +++ b/spec/factories/exports/export_messages.rb @@ -0,0 +1,7 @@ +FactoryGirl.define do +  factory :export_message, class: Export::Message do +    association :export +    association :resource, factory: :export_resource +    criticity :info  +  end +end diff --git a/spec/factories/exports/export_resources.rb b/spec/factories/exports/export_resources.rb new file mode 100644 index 000000000..e09787b52 --- /dev/null +++ b/spec/factories/exports/export_resources.rb @@ -0,0 +1,9 @@ +FactoryGirl.define do +  factory :export_resource, class: Export::Resource do +    association :export +    status :WARNING +    sequence(:name) { |n| "Export resource #{n}" } +    resource_type 'type' +    reference 'reference' +  end +end diff --git a/spec/factories/exports/exports.rb b/spec/factories/exports/exports.rb new file mode 100644 index 000000000..66afe7652 --- /dev/null +++ b/spec/factories/exports/exports.rb @@ -0,0 +1,35 @@ +FactoryGirl.define do +  factory :export, class: Export::Base do +    sequence(:name) { |n| "Export #{n}" } +    current_step_id "MyString" +    current_step_progress 1.5 +    association :workbench +    association :referential +    file {File.open(File.join(Rails.root, 'spec', 'fixtures', 'OFFRE_TRANSDEV_2017030112251.zip'))} +    status :new +    started_at nil +    ended_at nil +    creator 'rspec' + +    after(:build) do |export| +      export.class.skip_callback(:create, :before, :initialize_fields) +    end +  end + +  factory :bad_export, class: Export::Base do +    sequence(:name) { |n| "Export #{n}" } +    current_step_id "MyString" +    current_step_progress 1.5 +    association :workbench +    association :referential +    file {File.open(File.join(Rails.root, 'spec', 'fixtures', 'terminated_job.json'))} +    status :new +    started_at nil +    ended_at nil +    creator 'rspec' + +    after(:build) do |export| +      export.class.skip_callback(:create, :before, :initialize_fields) +    end +  end +end diff --git a/spec/factories/exports/netex_exports.rb b/spec/factories/exports/netex_exports.rb new file mode 100644 index 000000000..288bba314 --- /dev/null +++ b/spec/factories/exports/netex_exports.rb @@ -0,0 +1,7 @@ +FactoryGirl.define do +  factory :netex_export, class: Export::Netex, parent: :export do +    file { File.open(Rails.root.join('spec', 'fixtures', 'OFFRE_TRANSDEV_2017030112251.zip')) } +    association :parent, factory: :workbench_export + +  end +end diff --git a/spec/factories/exports/workbench_exports.rb b/spec/factories/exports/workbench_exports.rb new file mode 100644 index 000000000..e00efb58a --- /dev/null +++ b/spec/factories/exports/workbench_exports.rb @@ -0,0 +1,5 @@ +FactoryGirl.define do +  factory :workbench_export, class: Export::Workbench, parent: :export do +    file { File.open(Rails.root.join('spec', 'fixtures', 'OFFRE_TRANSDEV_2017030112251.zip')) } +  end +end diff --git a/spec/models/export/export_message_spec.rb b/spec/models/export/export_message_spec.rb new file mode 100644 index 000000000..61a3b6319 --- /dev/null +++ b/spec/models/export/export_message_spec.rb @@ -0,0 +1,7 @@ +require 'rails_helper' + +RSpec.describe Export::Message, :type => :model do +  it { should validate_presence_of(:criticity) } +  it { should belong_to(:export) } +  it { should belong_to(:resource) } +end diff --git a/spec/models/export/export_resource_spec.rb b/spec/models/export/export_resource_spec.rb new file mode 100644 index 000000000..7537cd2a8 --- /dev/null +++ b/spec/models/export/export_resource_spec.rb @@ -0,0 +1,19 @@ +require 'rails_helper' + +RSpec.describe Export::Resource, :type => :model do +  it { should belong_to(:export) } + +  it { should enumerize(:status).in("OK", "ERROR", "WARNING", "IGNORED") } + +  it { should validate_presence_of(:name) } +  it { should validate_presence_of(:resource_type) } +  it { should validate_presence_of(:reference) } + +  describe 'states' do +    let(:export_resource) { create(:export_resource) } + +    it 'should initialize with new state' do +      expect(export_resource.status).to eq("WARNING") +    end +  end +end diff --git a/spec/models/export/export_spec.rb b/spec/models/export/export_spec.rb new file mode 100644 index 000000000..089f4a2b7 --- /dev/null +++ b/spec/models/export/export_spec.rb @@ -0,0 +1,239 @@ +RSpec.describe Export::Base, type: :model do + +  it { should belong_to(:referential) } +  it { should belong_to(:workbench) } +  it { should belong_to(:parent) } + +  it { should enumerize(:status).in("aborted", "canceled", "failed", "new", "pending", "running", "successful", "warning") } + +  it { should validate_presence_of(:workbench) } +  it { should validate_presence_of(:creator) } + +  include ActionDispatch::TestProcess +  it { should allow_value(fixture_file_upload('OFFRE_TRANSDEV_2017030112251.zip')).for(:file) } +  it { should_not allow_value(fixture_file_upload('users.json')).for(:file).with_message(I18n.t('errors.messages.extension_whitelist_error', extension: '"json"', allowed_types: "zip")) } + +  let(:workbench_export) {netex_export.parent} +  let(:workbench_export_with_completed_steps) do +    build_stubbed( +      :workbench_export, +      total_steps: 2, +      current_step: 2 +    ) +  end + +  let(:netex_export) do +    build_stubbed( +      :netex_export +    ) +  end + +  describe ".abort_old" do +    it "changes exports older than 4 hours to aborted" do +      Timecop.freeze(Time.now) do +        old_export = create( +          :workbench_export, +          status: 'pending', +          created_at: 4.hours.ago - 1.minute +        ) +        current_export = create(:workbench_export, status: 'pending') + +        Export::Base.abort_old + +        expect(current_export.reload.status).to eq('pending') +        expect(old_export.reload.status).to eq('aborted') +      end +    end + +    it "doesn't work on exports with a `finished_status`" do +      Timecop.freeze(Time.now) do +        export = create( +          :workbench_export, +          status: 'successful', +          created_at: 4.hours.ago - 1.minute +        ) + +        Export::Base.abort_old + +        expect(export.reload.status).to eq('successful') +      end +    end + +    it "only works on the caller type" do +      Timecop.freeze(Time.now) do +        workbench_export = create( +          :workbench_export, +          status: 'pending', +          created_at: 4.hours.ago - 1.minute +        ) +        netex_export = create( +          :netex_export, +          status: 'pending', +          created_at: 4.hours.ago - 1.minute +        ) + +        Export::Netex.abort_old + +        expect(workbench_export.reload.status).to eq('pending') +        expect(netex_export.reload.status).to eq('aborted') +      end +    end +  end + +  describe "#destroy" do +    it "must destroy all child exports" do +      netex_export = create(:netex_export) + +      netex_export.parent.destroy + +      expect(netex_export.parent).to be_destroyed +      expect(Export::Netex.count).to eq(0) +    end + +    it "must destroy all associated Export::Messages" do +      export = create(:export) +      create(:export_resource, export: export) + +      export.destroy + +      expect(Export::Resource.count).to eq(0) +    end + +    it "must destroy all associated Export::Resources" do +      export = create(:export) +      create(:export_message, export: export) + +      export.destroy + +      expect(Export::Message.count).to eq(0) +    end +  end + +  describe "#notify_parent" do +    it "must call #child_change on its parent" do +      allow(netex_export).to receive(:update) + +      expect(workbench_export).to receive(:child_change) + +      netex_export.notify_parent +    end + +    it "must update the :notified_parent_at field of the child export" do +      allow(workbench_export).to receive(:child_change) + +      Timecop.freeze(DateTime.now) do +        expect(netex_export).to receive(:update).with( +          notified_parent_at: DateTime.now +        ) + +        netex_export.notify_parent +      end +    end +  end + +  describe "#child_change" do +    it "calls #update_status" do +      allow(workbench_export).to receive(:update) + +      expect(workbench_export).to receive(:update_status) +      workbench_export.child_change +    end +  end + +  describe "#update_status" do +    shared_examples( +      "updates :status to failed when >=1 child has failing status" +    ) do |failure_status| +      it "updates :status to failed when >=1 child has failing status" do +        workbench_export = create(:workbench_export) +        create( +          :netex_export, +          parent: workbench_export, +          status: failure_status +        ) + +        workbench_export.update_status + +        expect(workbench_export.status).to eq('failed') +      end +    end + +    include_examples( +      "updates :status to failed when >=1 child has failing status", +      "failed" +    ) +    include_examples( +      "updates :status to failed when >=1 child has failing status", +      "aborted" +    ) +    include_examples( +      "updates :status to failed when >=1 child has failing status", +      "canceled" +    ) + +    it "updates :status to successful when all children are successful" do +      workbench_export = create(:workbench_export) +      exports = create_list( +        :netex_export, +        2, +        parent: workbench_export, +        status: 'successful' +      ) + +      workbench_export.update_status + +      expect(workbench_export.status).to eq('successful') +    end + +    it "updates :status to failed when any child has failed" do +      workbench_export = create(:workbench_export) +      [ +        'failed', +        'successful' +      ].each do |status| +        create( +          :netex_export, +          parent: workbench_export, +          status: status +        ) +      end + +      workbench_export.update_status + +      expect(workbench_export.status).to eq('failed') +    end + +    it "updates :status to warning when any child has warning or successful" do +      workbench_export = create(:workbench_export) +      [ +        'warning', +        'successful' +      ].each do |status| +        create( +          :netex_export, +          parent: workbench_export, +          status: status +        ) +      end + +      workbench_export.update_status + +      expect(workbench_export.status).to eq('warning') +    end + +    it "updates :ended_at to now when status is finished" do +      workbench_export = create(:workbench_export) +      create( +        :netex_export, +        parent: workbench_export, +        status: 'failed' +      ) + +      Timecop.freeze(Time.now) do +        workbench_export.update_status + +        expect(workbench_export.ended_at).to eq(Time.now) +      end +    end +  end +end diff --git a/spec/models/import_message_spec.rb b/spec/models/import/import_message_spec.rb index 48e03a2cc..48e03a2cc 100644 --- a/spec/models/import_message_spec.rb +++ b/spec/models/import/import_message_spec.rb diff --git a/spec/models/import_resource_spec.rb b/spec/models/import/import_resource_spec.rb index 7d2eab8f1..7d2eab8f1 100644 --- a/spec/models/import_resource_spec.rb +++ b/spec/models/import/import_resource_spec.rb diff --git a/spec/models/import_spec.rb b/spec/models/import/import_spec.rb index cbc5907fa..cbc5907fa 100644 --- a/spec/models/import_spec.rb +++ b/spec/models/import/import_spec.rb diff --git a/spec/models/import_task_spec.rb b/spec/models/import_task_spec.rb deleted file mode 100644 index 3aa006a69..000000000 --- a/spec/models/import_task_spec.rb +++ /dev/null @@ -1,196 +0,0 @@ -# require 'spec_helper' - -# describe ImportTask, :type => :model do - -#   subject { build :import_task } - -#   describe ".new" do - -#     it "should use type attribute to create a subclass" do -#       expect(ImportTask.new(:format => "Neptune")).to be_an_instance_of(NeptuneImport) -#       expect(ImportTask.new(:format => "Gtfs")).to be_an_instance_of(GtfsImport) -#       expect(ImportTask.new(:format => "Netex")).to be_an_instance_of(NetexImport) -#       expect(ImportTask.new(:format => "Csv")).to be_an_instance_of(CsvImport) - -#       expect(NeptuneImport.new).to be_an_instance_of(NeptuneImport) -#       expect(GtfsImport.new).to be_an_instance_of(GtfsImport) -#       expect(NetexImport.new).to be_an_instance_of(NetexImport) -#       expect(CsvImport.new).to be_an_instance_of(CsvImport) -#     end - -#   end - -#   describe "#delayed_import" do -#     before(:each) do -#       allow(subject).to receive_messages( :delay => double( :import => true)) -#     end -#     it "should call delay#import" do -#       expect(subject.delay).to receive( :import) -#       subject.send :delayed_import -#     end -#   end - -#   describe ".create" do -#     before(:each) do -#       allow(subject).to receive_messages( :save_resources => true ) -#     end -#     it "should call save_resource" do -#       expect(subject).to receive( :save_resources) -#       subject.send :save -#     end -#     it "should update file_path with #saved_resources" do -#       subject.send :save -#       expect(ImportTask.find( subject.id).file_path).to eq(subject.send( :saved_resources)) -#     end -#     it "should have a compliance_check_task" do -#       subject.send :save -#       expect(ImportTask.find( subject.id).compliance_check_task).not_to be_nil -#     end -#   end - -#   describe "#compliance_check_task" do -#     let(:rule_parameter_set){ Factory( :rule_parameter_set) } -#     let(:import_task){ Factory(:import_task, :rule_parameter_set_id => rule_parameter_set.id) } -#     let(:compliance_check_task){ import_task.compliance_check_task } - -#     it "should have same #referential as import_task" do -#       expect(compliance_check_task.referential).to eq(import_task.referential) -#     end - -#     it "should have same #rule_parameter_set_id as import_task" do -#       expect(compliance_check_task.rule_parameter_set_id).to eq(import_task.rule_parameter_set_id) -#     end - -#     it "should have same #user_id as import_task" do -#       expect(compliance_check_task.user_id).to eq(import_task.user_id) -#     end - -#     it "should have same #user_name as import_task" do -#       expect(compliance_check_task.user_name).to eq(import_task.user_name) -#     end -#   end - -#   describe "#file_path_extension" do -#     let(:import_task){ Factory(:import_task) } -#     context "zip file to import" do -#       before(:each) do -#         import_task.file_path = "aaa/bbb.zip" -#       end -#       it "should return zip" do -#         expect(import_task.file_path_extension).to eq("zip") -#       end -#     end -#     context "xml file to import" do -#       before(:each) do -#         import_task.file_path = "aaa/bbb.xml" -#       end -#       it "should return xml" do -#         expect(import_task.file_path_extension).to eq("xml") -#       end -#     end -#     context "csv file to import" do -#       before(:each) do -#         import_task.file_path = "aaa/bbb.csv" -#       end -#       it "should return csv" do -#         expect(import_task.file_path_extension).to eq("basic") -#       end -#     end - -#   end - -#   context "options attributes" do -#     let(:import_task){ Factory(:import_task) } -#     describe "#no_save" do -#       it "should read parameter_set['no_save']" do -#         import_task.parameter_set[ "no_save"] = "dummy" -#         expect(import_task.no_save).to eq("dummy") -#       end -#     end -#     describe "#format" do -#       it "should read parameter_set['format']" do -#         import_task.parameter_set[ "format"] = "dummy" -#         expect(import_task.format).to eq("dummy") -#       end -#     end -#     describe "#file_path" do -#       it "should read parameter_set['file_path']" do -#         import_task.parameter_set[ "file_path"] = "dummy" -#         expect(import_task.file_path).to eq("dummy") -#       end -#     end -#     describe "#no_save=" do -#       it "should read parameter_set['no_save']" do -#         import_task.no_save = "dummy" -#         expect(import_task.parameter_set[ "no_save"]).to eq(false) -#       end -#     end -#     describe "#format=" do -#       it "should read parameter_set['format']" do -#         import_task.format = "dummy" -#         expect(import_task.parameter_set[ "format"]).to eq("dummy") -#       end -#     end -#     describe "#file_path=" do -#       it "should read parameter_set['file_path']" do -#         import_task.file_path = "dummy" -#         expect(import_task.parameter_set[ "file_path"]).to eq("dummy") -#       end -#     end -#   end - -#   describe "#chouette_command" do -#     it "should be a Chouette::Command instance" do -#       expect(subject.send( :chouette_command).class).to eq(Chouette::Command) -#     end -#     it "should have schema same as referential.slug" do -#       expect(subject.send( :chouette_command).schema).to eq(subject.referential.slug) -#     end -#   end - -#   describe "#import" do -#     let(:import_task){ Factory(:import_task) } -#     let(:chouette_command) { "dummy" } -#     context "for failing import" do -#       before(:each) do -#         allow(chouette_command).to receive( :run!).and_raise( "dummy") -#         allow(import_task).to receive_messages( :chouette_command => chouette_command) -#       end -#       it "should have status 'failed'" do -#         import_task.import -#         expect(import_task.status).to eq("failed") -#       end -#       it "should have status 'failed' for compliance_check_task" do -#         import_task.import -#         expect(import_task.compliance_check_task.status).to eq("failed") -#       end -#     end -#     context "for successful import" do -#       before(:each) do -#         allow(import_task).to receive_messages( :chouette_command => double( :run! => true )) -#       end -#       it "should have status 'completed'" do -#         import_task.import -#         expect(import_task.status).to eq("completed") -#       end -#       it "should have status 'completed' for compliance_check_task" do -#         import_task.import -#         expect(import_task.status).to eq("completed") -#       end -#     end -#   end - -#   describe "#import" do -#     let(:import_task){ Factory(:import_task) } -#     let(:command_args){ "dummy" } -#     before(:each) do -#       allow(import_task).to receive_messages( :chouette_command => double( :run! => true )) -#       allow(import_task).to receive_messages( :chouette_command_args => command_args) -#     end -#     it "should call chouette_command.run! with :c => 'import', :id => id" do -#       expect(import_task.send( :chouette_command)).to receive( :run! ).with(  command_args) -#       import_task.import -#     end -#   end - -# end diff --git a/spec/policies/import_policy_spec.rb b/spec/policies/import_policy_spec.rb index f9effd21a..9c7fca8a5 100644 --- a/spec/policies/import_policy_spec.rb +++ b/spec/policies/import_policy_spec.rb @@ -1,4 +1,4 @@ -RSpec.describe Import::BasePolicy, type: :policy do +RSpec.describe ImportPolicy, type: :policy do    let( :record ){ build_stubbed :import }    before { stub_policy_scope(record) } diff --git a/spec/support/permissions.rb b/spec/support/permissions.rb index 95afd6c1c..825e44725 100644 --- a/spec/support/permissions.rb +++ b/spec/support/permissions.rb @@ -17,6 +17,7 @@ module Support          connection_links          calendars          footnotes +        exports          imports          merges          journey_patterns | 
