diff options
| author | Xinhui | 2017-06-16 17:58:08 +0200 |
|---|---|---|
| committer | Xinhui | 2017-06-16 17:58:08 +0200 |
| commit | 641b1458236d2718a76ffaf0c04a5998623276bf (patch) | |
| tree | db738af25bcdd7b3b400a0f8db5e6350ef373c51 /spec | |
| parent | 6886441ce86bcd720b27cdd089567def5b9d771a (diff) | |
| parent | 9ef3d205aa091d509455b3607d5ecc74431c6196 (diff) | |
| download | chouette-core-641b1458236d2718a76ffaf0c04a5998623276bf.tar.bz2 | |
Merge branch 'master' into staging
Diffstat (limited to 'spec')
37 files changed, 780 insertions, 359 deletions
diff --git a/spec/controllers/devise/cas_sessions_controller_spec.rb b/spec/controllers/devise/cas_sessions_controller_spec.rb new file mode 100644 index 000000000..950d141fd --- /dev/null +++ b/spec/controllers/devise/cas_sessions_controller_spec.rb @@ -0,0 +1,27 @@ +RSpec.describe Devise::CasSessionsController, type: :controller do + + login_user + + context 'login is correctly redirected' do + it 'to #service' do + get :new + expect(response).to redirect_to(unauthenticated_root_path) + end + end + + context 'user does not have any boiv:.+ permission' do + xit 'cannot login and will be redirected to the login page, with a corresponding message' do + get :service + expect(controller).to set_flash[:alert].to(%r{IBOO}) + expect(response).to redirect_to("http://stif-portail-dev.af83.priv/sessions/login?service=http%3A%2F%2Ftest.host%2Fusers%2Fservice") + end + end + + context 'user does have a boiv:.+ permission' do + it 'can login and will be redirected to the referentials page' do + @user.update_attribute :permissions, (@user.permissions << 'boiv:UnameIt') + get :service + expect(response).to redirect_to(authenticated_root_path) + end + end +end diff --git a/spec/controllers/imports_controller_spec.rb b/spec/controllers/imports_controller_spec.rb index bffb89338..7b575ab61 100644 --- a/spec/controllers/imports_controller_spec.rb +++ b/spec/controllers/imports_controller_spec.rb @@ -1,5 +1,3 @@ -require 'rails_helper' - RSpec.describe ImportsController, :type => :controller do login_user diff --git a/spec/controllers/route_stop_points_controller_spec.rb b/spec/controllers/route_stop_points_controller_spec.rb index 2f5fa41c7..ac9e2f11b 100644 --- a/spec/controllers/route_stop_points_controller_spec.rb +++ b/spec/controllers/route_stop_points_controller_spec.rb @@ -15,9 +15,7 @@ RSpec.describe RouteStopPointsController, type: :controller do end it 'returns a JSON of stop areas' do - expect(response.body).to eq(route.stop_points.map { |sp| { id: sp.id, name: sp.name } }.to_json) + expect(response.body).to eq(route.stop_points.map { |sp| { id: sp.id, stop_area_id: sp.stop_area.id, name: sp.name, zip_code: sp.stop_area.zip_code, city_name: sp.stop_area.city_name } }.to_json) end end end - - diff --git a/spec/factories/chouette_time_table.rb b/spec/factories/chouette_time_table.rb index f462349cf..6480df79d 100644 --- a/spec/factories/chouette_time_table.rb +++ b/spec/factories/chouette_time_table.rb @@ -1,6 +1,7 @@ FactoryGirl.define do factory :time_table_date, :class => Chouette::TimeTableDate do + association :time_table, :factory => :time_table end factory :time_table_period, :class => Chouette::TimeTablePeriod do diff --git a/spec/factories/chouette_vehicle_journey.rb b/spec/factories/chouette_vehicle_journey.rb index 452909f23..e7ecb79ac 100644 --- a/spec/factories/chouette_vehicle_journey.rb +++ b/spec/factories/chouette_vehicle_journey.rb @@ -18,11 +18,16 @@ FactoryGirl.define do after(:create) do |vehicle_journey, evaluator| vehicle_journey.journey_pattern.stop_points.each_with_index do |stop_point, index| + prev_stop = vehicle_journey.vehicle_journey_at_stops[index - 1] + + arrival_time = prev_stop ? prev_stop[:departure_time] + 1.minute : evaluator.stop_arrival_time + departure_time = prev_stop ? arrival_time + 1.minute : evaluator.stop_departure_time + vehicle_journey.vehicle_journey_at_stops << create(:vehicle_journey_at_stop, :vehicle_journey => vehicle_journey, :stop_point => stop_point, - :arrival_time => "2000-01-01 #{evaluator.stop_arrival_time} UTC", - :departure_time => "2000-01-01 #{evaluator.stop_departure_time} UTC") + :arrival_time => "2000-01-01 #{arrival_time} UTC", + :departure_time => "2000-01-01 #{departure_time} UTC") end end diff --git a/spec/factories/clean_ups.rb b/spec/factories/clean_ups.rb index 41165ac16..d3746c3b2 100644 --- a/spec/factories/clean_ups.rb +++ b/spec/factories/clean_ups.rb @@ -1,15 +1,6 @@ FactoryGirl.define do factory :clean_up do - status "MyString" -started_at "2016-11-14 14:45:18" -ended_at "2016-11-14 14:45:18" -referential nil -keep_lines false -keep_stops false -keep_companies false -keep_networks false -keep_group_of_lines false -expected_date "2016-11-14 14:45:18" + begin_date { Date.today} + end_date { Date.today + 1.month } end - end diff --git a/spec/features/calendars_spec.rb b/spec/features/calendars_spec.rb index 2089939bb..e15624295 100644 --- a/spec/features/calendars_spec.rb +++ b/spec/features/calendars_spec.rb @@ -19,12 +19,20 @@ describe 'Calendars', type: :feature do context 'filtering' do it 'supports filtering by short name' do - fill_in 'q[short_name_cont]', with: calendars.first.short_name + fill_in 'q[name_or_short_name_cont]', with: calendars.first.short_name click_button 'search_btn' expect(page).to have_content(calendars.first.short_name) expect(page).not_to have_content(calendars.last.short_name) end + it 'supports filtering by name' do + fill_in 'q[name_or_short_name_cont]', with: calendars.first.name + click_button 'search_btn' + expect(page).to have_content(calendars.first.name) + expect(page).not_to have_content(calendars.last.name) + end + + it 'supports filtering by shared' do shared_calendar = create :calendar, organisation_id: 1, shared: true visit calendars_path diff --git a/spec/features/lines_spec.rb b/spec/features/lines_spec.rb index e7e1e601c..a55f30ebc 100644 --- a/spec/features/lines_spec.rb +++ b/spec/features/lines_spec.rb @@ -1,7 +1,4 @@ -# -*- coding: utf-8 -*- -require 'spec_helper' - -describe "Lines", :type => :feature do +describe "Lines", type: :feature do login_user let(:line_referential) { create :line_referential } diff --git a/spec/features/referentials_permissions_spec.rb b/spec/features/referentials_permissions_spec.rb new file mode 100644 index 000000000..0216eeeb0 --- /dev/null +++ b/spec/features/referentials_permissions_spec.rb @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- + +describe "Referentials", :type => :feature do + + login_user + let(:referential) { Referential.first } + + let( :edit_link_text ){ I18n.t('actions.edit') } + let( :destroy_link_text ){ I18n.t('actions.destroy') } + + + context 'permissions' do + before do + allow_any_instance_of(ReferentialPolicy).to receive(:organisation_match?).and_return organisation_match + visit path + end + + context 'on show view with common lines' do + let( :path ){ referential_path(referential) } + before do + allow_any_instance_of(ReferentialPolicy).to receive(:common_lines?).and_return common_lines + end + + context 'if organisations match →' do + let( :organisation_match ){ true } + let( :common_lines ){ false } + + it 'shows the edit button' do + expected_href = edit_referential_path(referential) + expect( page ).to have_link(edit_link_text, href: expected_href) + end + it 'shows the delete button' do + expected_href = referential_path(referential) + expect( page ).to have_css(%{a[href=#{expected_href.inspect}] span}, text: destroy_link_text) + end + end + + context 'if organisations do not match →' do + let( :organisation_match ){ false } + let( :common_lines ){ true } + + it 'does not show the delete button' do + expected_href = edit_referential_path(referential) + expect( page ).not_to have_link(edit_link_text, href: expected_href) + end + it 'does not show the delete button' do + expected_href = referential_path(referential) + expect( page ).not_to have_css(%{a[href=#{expected_href.inspect}] span}, text: destroy_link_text) + end + end + end + + end +end diff --git a/spec/features/referentials_spec.rb b/spec/features/referentials_spec.rb index 3c2258a3a..337271fea 100644 --- a/spec/features/referentials_spec.rb +++ b/spec/features/referentials_spec.rb @@ -1,6 +1,4 @@ # -*- coding: utf-8 -*- -require 'spec_helper' - describe "Referentials", :type => :feature do login_user @@ -111,13 +109,9 @@ describe "Referentials", :type => :feature do end describe "create" do - it "should" do visit new_referential_path fill_in "Nom", :with => "Test" - fill_in "Code", :with => "test" - fill_in "Point haut/droite de l'emprise par défaut", :with => "0.0, 0.0" - fill_in "Point bas/gauche de l'emprise par défaut", :with => "1.0, 1.0" click_button "Valider" expect(Referential.where(:name => "Test")).not_to be_nil diff --git a/spec/features/routes_spec.rb b/spec/features/routes_spec.rb index 6d9ba990d..28015f011 100644 --- a/spec/features/routes_spec.rb +++ b/spec/features/routes_spec.rb @@ -36,10 +36,13 @@ describe "Routes", :type => :feature do visit referential_line_path(referential, line) click_link "Ajouter un itinéraire" fill_in "route_name", :with => "A to B" + fill_in "route_published_name", :with => "Published A to B" # select 'Aller', :from => "route_direction" check('route[wayback]') click_button("Valider") expect(page).to have_content("A to B") + expect(page).to have_content("Published A to B") + end end diff --git a/spec/features/routing_constraint_zones_spec.rb b/spec/features/routing_constraint_zones_spec.rb index 9e8c7dad4..b116b38bd 100644 --- a/spec/features/routing_constraint_zones_spec.rb +++ b/spec/features/routing_constraint_zones_spec.rb @@ -20,7 +20,7 @@ describe 'RoutingConstraintZones', type: :feature do context 'user has permission to create routing_constraint_zones' do it 'shows a create link for routing_constraint_zones' do - expect(page).to have_content(I18n.t('routing_constraint_zones.actions.new')) + expect(page).to have_content(I18n.t('actions.new')) end end @@ -28,7 +28,7 @@ describe 'RoutingConstraintZones', type: :feature do it 'does not show a create link for routing_constraint_zones' do @user.update_attribute(:permissions, []) visit referential_line_routing_constraint_zones_path(referential, line) - expect(page).not_to have_content(I18n.t('routing_constraint_zones.actions.new')) + expect(page).not_to have_content(I18n.t('actions.new')) end end diff --git a/spec/features/users/connection_spec.rb b/spec/features/users/connection_spec.rb new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/spec/features/users/connection_spec.rb diff --git a/spec/features/workbenches_spec.rb b/spec/features/workbenches_spec.rb index c11fbd03d..953eb2bf5 100644 --- a/spec/features/workbenches_spec.rb +++ b/spec/features/workbenches_spec.rb @@ -46,8 +46,6 @@ describe 'Workbenches', type: :feature do click_link I18n.t('actions.add') fill_in "referential[name]", with: "Referential to test creation" # Nom du JDD - fill_in "referential[slug]", with: "test" # Code - fill_in "referential[prefix]", with: "test" # Prefix Neptune select workbench.lines.first.id, from: 'referential[metadatas_attributes][0][lines][]' # Lignes click_button "Valider" diff --git a/spec/javascripts/time_table/reducers/pagination_spec.js b/spec/javascripts/time_table/reducers/pagination_spec.js index 740ded3ac..5da58427e 100644 --- a/spec/javascripts/time_table/reducers/pagination_spec.js +++ b/spec/javascripts/time_table/reducers/pagination_spec.js @@ -118,11 +118,4 @@ describe('pagination reducer', () => { }) ).toEqual(Object.assign({}, state, {stateChanged: true})) }) - it('should handle UPDATE_DAY_TYPES', () => { - expect( - paginationReducer(state, { - type: 'UPDATE_DAY_TYPES' - }) - ).toEqual(Object.assign({}, state, {stateChanged: true})) - }) }) diff --git a/spec/javascripts/vehicle_journeys/reducers/vehicle_journeys_spec.js b/spec/javascripts/vehicle_journeys/reducers/vehicle_journeys_spec.js index 662c3d82f..23ebc3d9f 100644 --- a/spec/javascripts/vehicle_journeys/reducers/vehicle_journeys_spec.js +++ b/spec/javascripts/vehicle_journeys/reducers/vehicle_journeys_spec.js @@ -111,7 +111,9 @@ describe('vehicleJourneys reducer', () => { time_tables: [], vehicle_journey_at_stops: pristineVjasList, selected: false, - deletable: false + deletable: false, + transport_mode: 'undefined', + transport_submode: 'undefined' }, ...state]) }) diff --git a/spec/lib/af83/cloning/clone_schema_spec.rb b/spec/lib/af83/cloning/clone_schema_spec.rb new file mode 100644 index 000000000..3d541f3e9 --- /dev/null +++ b/spec/lib/af83/cloning/clone_schema_spec.rb @@ -0,0 +1,113 @@ +RSpec.describe AF83::SchemaCloner, type: :pg_catalog do + let( :source_schema ){ "source_schema" } + let( :target_schema ){ "target_schema" } + let( :child_table ){ "children" } + let( :parent_table ){ "parents" } + + subject { described_class.new source_schema, target_schema } + + context "after cloning" do + before do + create_schema_with_tables + subject.clone_schema + end + + it "table information is correctly duplicated" do + expect(get_table_information(source_schema, child_table)) + .to eq([{"table_schema"=>"source_schema", + "table_name"=>"children", + "table_type"=>"BASE TABLE", + "self_referencing_column_name"=>nil, + "reference_generation"=>nil, + "user_defined_type_catalog"=>nil, + "user_defined_type_schema"=>nil, + "user_defined_type_name"=>nil, + "is_insertable_into"=>"YES", + "is_typed"=>"NO", + "commit_action"=>nil}]) + + expect( get_table_information(target_schema, child_table)) + .to eq([{"table_schema"=>"target_schema", + "table_name"=>"children", + "table_type"=>"BASE TABLE", + "self_referencing_column_name"=>nil, + "reference_generation"=>nil, + "user_defined_type_catalog"=>nil, + "user_defined_type_schema"=>nil, + "user_defined_type_name"=>nil, + "is_insertable_into"=>"YES", + "is_typed"=>"NO", + "commit_action"=>nil}]) + end + + it "table content is the same and sequences are synchronized" do + expect_same_content(parent_table) + expect_same_content(child_table) + + expect_same_sequence_params("#{parent_table}_id_seq") + expect_same_sequence_params("#{child_table}_id_seq") + end + + it "has correctly updated default values" do + child_table_pk_default = get_columns(target_schema, child_table) + .find{ |col| col["column_name"] == "id" }["column_default"] + expect( child_table_pk_default ).to eq("nextval('#{target_schema}.children_id_seq'::regclass)") + end + + it "has the correct foreign keys" do + expect( get_foreign_keys(target_schema, child_table) ) + .to eq([{ + "constraint_name" => "children_parents", + "constraint_def" => "FOREIGN KEY (parents_id) REFERENCES target_schema.parents(id)"}]) + end + + xit "it has the correct unique keys UNTESTABLE SO FAR" do + insert source_schema, child_table, "#{parent_table}_id" => 1, some_key: 400 + insert target_schema, child_table, "#{parent_table}_id" => 1, some_key: 400 + reinsert_sql = "INSERT INTO #{source_schema}.#{child_table} (#{parent_table}_id, some_key) VALUES (1, 400)" + expect{ execute(reinsert_sql) rescue nil}.not_to change{ execute("SELECT COUNT(*) FROM #{source_schema}.#{child_table}") } + + # expect{ insert(target_schema, child_table, "#{parent_table}_id" => 1, some_key: 400) }.to raise_error(ActiveRecord::RecordNotUnique) + end + + it "inserts are independent" do + insert source_schema, child_table, "#{parent_table}_id" => 1, some_key: 400 + insert target_schema, child_table, "#{parent_table}_id" => 1, some_key: 400 + last_source = get_content(source_schema, child_table).last + last_target = get_content(target_schema, child_table).last + + expect( last_source ).to eq("id"=>"3", "parents_id"=>"1", "some_key"=>"400", "is_orphan"=>"f") + expect( last_target ).to eq("id"=>"3", "parents_id"=>"1", "some_key"=>"400", "is_orphan"=>"f") + end + + end + + def create_schema_with_tables + execute <<-EOSQL + DROP SCHEMA IF EXISTS #{source_schema} CASCADE; + CREATE SCHEMA #{source_schema}; + + CREATE TABLE #{source_schema}.#{parent_table} ( + id bigserial PRIMARY KEY + ); + CREATE TABLE #{source_schema}.#{child_table} ( + id bigserial PRIMARY KEY, + #{parent_table}_id bigint, + some_key bigint NOT NULL, + is_orphan boolean DEFAULT false + ); + + CREATE UNIQUE INDEX #{child_table}_some_key_idx ON #{source_schema}.#{child_table} (some_key); + + ALTER TABLE #{source_schema}.#{child_table} + ADD CONSTRAINT #{child_table}_#{parent_table} + FOREIGN KEY( #{parent_table}_id ) REFERENCES #{source_schema}.#{parent_table}(id); + + INSERT INTO #{source_schema}.#{parent_table} VALUES (DEFAULT); + INSERT INTO #{source_schema}.#{parent_table} VALUES (DEFAULT); + EOSQL + insert source_schema, child_table, "#{parent_table}_id" => 1, some_key: 200 + insert source_schema, child_table, "#{parent_table}_id" => 2, some_key: 300, is_orphan: true + end + +end diff --git a/spec/lib/af83/stored_procedure_spec.rb b/spec/lib/af83/stored_procedure_spec.rb deleted file mode 100644 index 2530d7fc1..000000000 --- a/spec/lib/af83/stored_procedure_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -require 'rails_helper' - -RSpec.describe StoredProcedures do - - - before do - described_class.create_stored_procedure(:clone_schema) - end - - let( :source_schema_name ){ "parissudest201604" } - let( :dest_schema_name ){ "#{source_schema_name}_v1"} - - context "Error cases" do - it "raises an error if stored procedure does not exist" do - expect{ described_class.invoke_stored_procedure(:idonotexist) } - .to raise_error(ArgumentError, %r{no such stored procedure "idonotexist"}) - end - end - -end diff --git a/spec/lib/af83/stored_procedures/clone_schema_spec.rb b/spec/lib/af83/stored_procedures/clone_schema_spec.rb deleted file mode 100644 index c387ddc7d..000000000 --- a/spec/lib/af83/stored_procedures/clone_schema_spec.rb +++ /dev/null @@ -1,167 +0,0 @@ -require 'spec_helper' - -include Support::PGCatalog - -RSpec.describe StoredProcedures do - let( :source_schema ){ "source_schema" } - let( :target_schema ){ "target_schema" } - let( :child_table ){ "children" } - let( :parent_table ){ "parents" } - - before do - create_schema_with_tables - StoredProcedures.create_stored_procedure :clone_schema - end - - # :meta specs are not run, as the describe the testing methd and not the application - context "meta specs describe source schema's introspection", :meta do - it "table information is correctly read" do - expect(get_table_information(source_schema, child_table)) - .to eq([{"table_schema"=>"source_schema", - "table_name"=>"children", - "table_type"=>"BASE TABLE", - "self_referencing_column_name"=>nil, - "reference_generation"=>nil, - "user_defined_type_catalog"=>nil, - "user_defined_type_schema"=>nil, - "user_defined_type_name"=>nil, - "is_insertable_into"=>"YES", - "is_typed"=>"NO", - "commit_action"=>nil}]) - - expect( get_table_information(target_schema, child_table) ).to be_empty - end - - it "sequences are correctly read" do - expect(get_sequences(source_schema, child_table)) - .to eq([{"sequence_name"=>"#{child_table}_id_seq", - "last_value"=>"1", - "start_value"=>"1", - "increment_by"=>"1", - "max_value"=>"9223372036854775807", - "min_value"=>"1", - "cache_value"=>"1", - "log_cnt"=>"0", - "is_cycled"=>"f", - "is_called"=>"f"}]) - - expect(get_sequences(source_schema, parent_table)) - .to eq([{"sequence_name"=>"#{parent_table}_id_seq", - "last_value"=>"1", - "start_value"=>"1", - "increment_by"=>"1", - "max_value"=>"9223372036854775807", - "min_value"=>"1", - "cache_value"=>"1", - "log_cnt"=>"0", - "is_cycled"=>"f", - "is_called"=>"f"}]) - end - - it "shows foreign key constraints are correctly read" do - expect( get_foreign_keys(source_schema, child_table) ) - .to eq([{ - "constraint_name" => "children_parents", - "constraint_def" => "FOREIGN KEY (parents_id) REFERENCES source_schema.parents(id)"}]) - end - end - - context "before cloning" do - it "target schema does not exist" do - expect( get_schema_oid(target_schema) ).to be_nil - end - end - - context "after cloning" do - before do - described_class.invoke_stored_procedure(:clone_schema, source_schema, target_schema, false) - end - - it "target schema does exist" do - expect( get_schema_oid(target_schema) ).not_to be_nil - end - - it "table information is correctly read" do - expect(get_table_information(source_schema, child_table)) - .to eq([{"table_schema"=>"source_schema", - "table_name"=>"children", - "table_type"=>"BASE TABLE", - "self_referencing_column_name"=>nil, - "reference_generation"=>nil, - "user_defined_type_catalog"=>nil, - "user_defined_type_schema"=>nil, - "user_defined_type_name"=>nil, - "is_insertable_into"=>"YES", - "is_typed"=>"NO", - "commit_action"=>nil}]) - - expect( get_table_information(target_schema, child_table)) - .to eq([{"table_schema"=>"target_schema", - "table_name"=>"children", - "table_type"=>"BASE TABLE", - "self_referencing_column_name"=>nil, - "reference_generation"=>nil, - "user_defined_type_catalog"=>nil, - "user_defined_type_schema"=>nil, - "user_defined_type_name"=>nil, - "is_insertable_into"=>"YES", - "is_typed"=>"NO", - "commit_action"=>nil}]) - end - - it "has the correct sequences" do - expect(get_sequences(target_schema, child_table)) - .to eq([{"sequence_name"=>"#{child_table}_id_seq", - "last_value"=>"1", - "start_value"=>"1", - "increment_by"=>"1", - "max_value"=>"9223372036854775807", - "min_value"=>"1", - "cache_value"=>"1", - "log_cnt"=>"0", - "is_cycled"=>"f", - "is_called"=>"f"}]) - - expect(get_sequences(target_schema, parent_table)) - .to eq([{"sequence_name"=>"#{parent_table}_id_seq", - "last_value"=>"1", - "start_value"=>"1", - "increment_by"=>"1", - "max_value"=>"9223372036854775807", - "min_value"=>"1", - "cache_value"=>"1", - "log_cnt"=>"0", - "is_cycled"=>"f", - "is_called"=>"f"}]) - end - - it "has the correct foreign keys" do - expect( get_foreign_keys(target_schema, child_table) ) - .to eq([{ - "constraint_name" => "children_parents", - "constraint_def" => "FOREIGN KEY (parents_id) REFERENCES target_schema.parents(id)"}]) - end - - end - -end - -def create_schema_with_tables - execute("CREATE SCHEMA IF NOT EXISTS #{source_schema}") - execute <<-EOSQL - DROP SCHEMA IF EXISTS #{source_schema} CASCADE; - CREATE SCHEMA #{source_schema}; - - CREATE TABLE #{source_schema}.#{parent_table} ( - id bigserial PRIMARY KEY - ); - CREATE TABLE #{source_schema}.#{child_table} ( - id bigserial PRIMARY KEY, - #{parent_table}_id bigint - ); - ALTER TABLE #{source_schema}.#{child_table} - ADD CONSTRAINT #{child_table}_#{parent_table} - FOREIGN KEY( #{parent_table}_id ) REFERENCES #{source_schema}.#{parent_table}(id); - EOSQL -end - diff --git a/spec/lib/time_duration_spec.rb b/spec/lib/time_duration_spec.rb index 1cba1f6d5..bf23f7ba6 100644 --- a/spec/lib/time_duration_spec.rb +++ b/spec/lib/time_duration_spec.rb @@ -4,15 +4,17 @@ describe TimeDuration do describe ".exceeds_gap?" do context "when duration is 4.hours" do it "should return false if gap < 1.hour" do - t1 = Time.now - t2 = Time.now + 3.minutes - expect(TimeDuration.exceeds_gap?(4.hours, t1, t2)).to be_falsey + earlier = Time.now + later = Time.now + 3.minutes + + expect(TimeDuration.exceeds_gap?(4.hours, earlier, later)).to be false end it "should return true if gap > 4.hour" do - t1 = Time.now - t2 = Time.now + (4.hours + 1.minutes) - expect(TimeDuration.exceeds_gap?(4.hours, t1, t2)).to be_truthy + earlier = Time.now + later = Time.now + (4.hours + 1.minutes) + + expect(TimeDuration.exceeds_gap?(4.hours, earlier, later)).to be true end it "returns true when `earlier` is later than `later`" do diff --git a/spec/models/chouette/time_table_spec.rb b/spec/models/chouette/time_table_spec.rb index 3d45bd346..7a8863cb3 100644 --- a/spec/models/chouette/time_table_spec.rb +++ b/spec/models/chouette/time_table_spec.rb @@ -1,12 +1,47 @@ require 'spec_helper' describe Chouette::TimeTable, :type => :model do - subject { create(:time_table) } it { is_expected.to validate_presence_of :comment } it { is_expected.to validate_uniqueness_of :objectid } + context "merge with calendar" do + let(:calendar) { create(:calendar) } + + it 'should add calendar dates to time_table' do + subject.dates.clear + subject.merge!(calendar.convert_to_time_table) + expect(subject.dates.map(&:date)).to include(*calendar.dates) + end + end + + describe "actualize" do + let(:calendar) { create(:calendar) } + let(:int_day_types) { 508 } + + before do + subject.int_day_types = int_day_types + subject.calendar = calendar + subject.save + subject.actualize + end + + it 'should override dates' do + expect(subject.dates.map(&:date)).to match_array calendar.dates + end + + it 'should override periods' do + [:period_start, :period_end].each do |key| + expect(subject.periods.map(&key)).to match_array calendar.convert_to_time_table.periods.map(&key) + end + end + + it 'should not change int_day_types' do + expect(subject.int_day_types).to eq(int_day_types) + end + end + describe "Update state" do def time_table_to_state time_table time_table.slice('id', 'comment').tap do |item| @@ -119,7 +154,7 @@ describe Chouette::TimeTable, :type => :model do end it 'should create new include date' do - day = state['current_month'].first + day = state['current_month'].find{|d| !d['excluded_date'] && !d['include_date'] } date = Date.parse(day['date']) day['include_date'] = true expect(subject.included_days).not_to include(date) @@ -131,7 +166,7 @@ describe Chouette::TimeTable, :type => :model do end it 'should create new exclude date' do - day = state['current_month'].first + day = state['current_month'].find{|d| !d['excluded_date'] && !d['include_date']} date = Date.parse(day['date']) day['excluded_date'] = true expect(subject.excluded_days).not_to include(date) @@ -973,7 +1008,7 @@ end expect(subject.periods[2].period_start).to eq(Date.new(2014, 8, 1)) expect(subject.periods[2].period_end).to eq(Date.new(2014, 8, 12)) end - it "should have common day_types" do + it "should not modify day_types" do expect(subject.int_day_types).to eq(4|16|128) end it "should have dates for thursdays and fridays" do @@ -1007,9 +1042,6 @@ end it "should have no period" do expect(subject.periods.size).to eq(0) end - it "should have no day_types" do - expect(subject.int_day_types).to eq(0) - end it "should have date all common days" do expect(subject.dates.size).to eq(3) expect(subject.dates[0].date).to eq(Date.new(2014,7,16)) @@ -1038,7 +1070,7 @@ end it "should have 0 period" do expect(subject.periods.size).to eq(0) end - it "should have no day_types" do + it "should not modify day_types" do expect(subject.int_day_types).to eq(0) end it "should have date reduced for period" do @@ -1063,8 +1095,8 @@ end it "should have 0 result periods" do expect(subject.periods.size).to eq(0) end - it "should have no day_types" do - expect(subject.int_day_types).to eq(0) + it "should not modify day_types" do + expect(subject.int_day_types).to eq(4|8|16) end it "should have 1 date " do expect(subject.dates.size).to eq(1) @@ -1093,9 +1125,6 @@ end it "should have 0 periods" do expect(subject.periods.size).to eq(0) end - it "should have 0 day_types" do - expect(subject.int_day_types).to eq(0) - end it "should have only dates " do expect(subject.dates.size).to eq(11) expect(subject.dates[0].date).to eq(Date.new(2014,6,30)) @@ -1134,7 +1163,7 @@ end it "should have 0 period" do expect(subject.periods.size).to eq(0) end - it "should have no remained day_types" do + it "should not modify day_types" do expect(subject.int_day_types).to eq(0) end it "should have date reduced for period" do @@ -1163,9 +1192,6 @@ end it "should have 0 result periods" do expect(subject.periods.size).to eq(0) end - it "should have no remained day_types" do - expect(subject.int_day_types).to eq(0) - end it "should have dates for period reduced" do expect(subject.dates.size).to eq(4) expect(subject.dates[0].date).to eq(Date.new(2014,7,3)) @@ -1197,9 +1223,6 @@ end it "should have 0 result periods" do expect(subject.periods.size).to eq(0) end - it "should have no remained day_types" do - subject.int_day_types == 0 - end it "should have 3 dates left" do expect(subject.dates.size).to eq(3) expect(subject.dates[0].date).to eq(Date.new(2014,7,16)) @@ -1233,10 +1256,6 @@ end expect(subject.periods.size).to eq(0) end - it "should have no remained day_types" do - subject.int_day_types == 0 - end - it "should have 0 dates left" do expect(subject.dates.size).to eq(0) end @@ -1261,10 +1280,6 @@ end expect(subject.periods.size).to eq(0) end - it "should have 0 day_types" do - expect(subject.int_day_types).to eq(0) - end - it "should have 6 dates " do expect(subject.dates.size).to eq(6) expect(subject.dates[0].date).to eq(Date.new(2014,8,11)) @@ -1303,8 +1318,8 @@ end end end - it "should have 0 day_types" do - expect(subject.int_day_types).to eq(0) + it "should not modify day_types" do + expect(subject.int_day_types).to eq(4|8|16) end it "should have 1 dates " do @@ -1342,8 +1357,8 @@ end end end - it "should have 0 day_types" do - expect(subject.int_day_types).to eq(0) + it "should not modify day_types" do + expect(subject.int_day_types).to eq(4|8|16) end it "should have only 1 dates " do @@ -1373,9 +1388,6 @@ end it "should have same 0 result periods" do expect(subject.periods.size).to eq(0) end - it "should have 0 day_types" do - expect(subject.int_day_types).to eq(0) - end it "should have 0 dates " do expect(subject.dates.size).to eq(0) end diff --git a/spec/models/chouette/vehicle_journey_at_stops_day_offset_spec.rb b/spec/models/chouette/vehicle_journey_at_stops_day_offset_spec.rb new file mode 100644 index 000000000..69a2d5cb9 --- /dev/null +++ b/spec/models/chouette/vehicle_journey_at_stops_day_offset_spec.rb @@ -0,0 +1,90 @@ +require 'spec_helper' + +describe Chouette::VehicleJourneyAtStop do + describe "#calculate" do + it "increments day offset when departure & arrival are on different sides + of midnight" do + at_stops = [] + [ + ['22:30', '22:35'], + ['23:50', '00:05'], + ['00:30', '00:35'], + ].each do |arrival_time, departure_time| + at_stops << build_stubbed( + :vehicle_journey_at_stop, + arrival_time: arrival_time, + departure_time: departure_time + ) + end + + offsetter = Chouette::VehicleJourneyAtStopsDayOffset.new(at_stops) + + offsetter.calculate! + + expect(at_stops[0].arrival_day_offset).to eq(0) + expect(at_stops[0].departure_day_offset).to eq(0) + + expect(at_stops[1].arrival_day_offset).to eq(0) + expect(at_stops[1].departure_day_offset).to eq(1) + + expect(at_stops[2].arrival_day_offset).to eq(1) + expect(at_stops[2].departure_day_offset).to eq(1) + end + + it "increments day offset when an at_stop passes midnight the next day" do + at_stops = [] + [ + ['22:30', '22:35'], + ['01:02', '01:14'], + ].each do |arrival_time, departure_time| + at_stops << build_stubbed( + :vehicle_journey_at_stop, + arrival_time: arrival_time, + departure_time: departure_time + ) + end + + offsetter = Chouette::VehicleJourneyAtStopsDayOffset.new(at_stops) + + offsetter.calculate! + + expect(at_stops[0].arrival_day_offset).to eq(0) + expect(at_stops[0].departure_day_offset).to eq(0) + + expect(at_stops[1].arrival_day_offset).to eq(1) + expect(at_stops[1].departure_day_offset).to eq(1) + end + + it "increments day offset for multi-day offsets" do + at_stops = [] + [ + ['22:30', '22:35'], + ['01:02', '01:14'], + ['04:30', '04:35'], + ['00:00', '00:04'], + ].each do |arrival_time, departure_time| + at_stops << build_stubbed( + :vehicle_journey_at_stop, + arrival_time: arrival_time, + departure_time: departure_time + ) + end + + offsetter = Chouette::VehicleJourneyAtStopsDayOffset.new(at_stops) + + offsetter.calculate! + + expect(at_stops[0].arrival_day_offset).to eq(0) + expect(at_stops[0].departure_day_offset).to eq(0) + + expect(at_stops[1].arrival_day_offset).to eq(1) + expect(at_stops[1].departure_day_offset).to eq(1) + + expect(at_stops[2].arrival_day_offset).to eq(1) + expect(at_stops[2].departure_day_offset).to eq(1) + + expect(at_stops[3].arrival_day_offset).to eq(2) + expect(at_stops[3].departure_day_offset).to eq(2) + end + end +end diff --git a/spec/models/chouette/vehicle_journey_spec.rb b/spec/models/chouette/vehicle_journey_spec.rb index 4a108d7c0..8f9080b99 100644 --- a/spec/models/chouette/vehicle_journey_spec.rb +++ b/spec/models/chouette/vehicle_journey_spec.rb @@ -1,7 +1,38 @@ require 'spec_helper' + describe Chouette::VehicleJourney, :type => :model do - describe "state_update" do + describe "vjas_departure_time_must_be_before_next_stop_arrival_time" do + let(:vehicle_journey) { create :vehicle_journey } + let(:vjas) { vehicle_journey.vehicle_journey_at_stops } + + it 'should add errors a stop departure_time is greater then next stop arrival time' do + vjas[0][:departure_time] = vjas[1][:arrival_time] + 1.minute + vehicle_journey.validate + + expect(vjas[0].errors[:departure_time]).not_to be_blank + expect(vehicle_journey.errors[:vehicle_journey_at_stops].count).to eq(1) + expect(vehicle_journey).not_to be_valid + end + + it 'should consider valid to have departure_time equal to next stop arrival time' do + vjas[0][:departure_time] = vjas[1][:arrival_time] + vehicle_journey.validate + + expect(vjas[0].errors[:departure_time]).to be_blank + expect(vehicle_journey.errors[:vehicle_journey_at_stops]).to be_empty + expect(vehicle_journey).to be_valid + end + + it 'should not add errors when departure_time is less then next stop arrival time' do + vehicle_journey.validate + vjas.each do |stop| + expect(stop.errors).to be_empty + end + expect(vehicle_journey).to be_valid + end + end + describe "state_update" do def vehicle_journey_at_stop_to_state vjas at_stop = {'stop_area_object_id' => vjas.stop_point.stop_area.objectid } [:id, :connecting_service_id, :boarding_alighting_possibility].map do |att| @@ -136,16 +167,12 @@ describe Chouette::VehicleJourney, :type => :model do it 'should return errors when validation failed' do state['published_journey_name'] = 'edited_name' - # Exceeds_gap departure time validation failed - prev = state['vehicle_journey_at_stops'].last(2).first - last = state['vehicle_journey_at_stops'].last - prev['departure_time']['hour'] = '01' - last['departure_time']['hour'] = '23' + state['vehicle_journey_at_stops'].last['departure_time']['hour'] = '23' expect { Chouette::VehicleJourney.state_update(route, collection) }.not_to change(vehicle_journey, :published_journey_name) - expect(state['errors'][:vehicle_journey_at_stops].size).to eq 1 + expect(state['vehicle_journey_at_stops'].last['errors']).not_to be_empty end it 'should delete vj with deletable set to true from state' do @@ -190,8 +217,8 @@ describe Chouette::VehicleJourney, :type => :model do end end - describe '.vehicle_journey_at_stops_matrix' do - it 'should fill missing VehicleJourneyAtStop with dummy' do + describe '#vehicle_journey_at_stops_matrix' do + it 'should fill missing vjas with dummy vjas' do vehicle_journey.journey_pattern.stop_points.delete_all vehicle_journey.vehicle_journey_at_stops.delete_all @@ -201,14 +228,28 @@ describe Chouette::VehicleJourney, :type => :model do expect(at_stops.count).to eq route.stop_points.count end - it 'should fill VehicleJourneyAtStop with new vjas when vj has been save without departure time' do + it 'should set dummy to false for active stop_points vjas' do + # Destroy vjas but stop_points is still active + # it should fill a new vjas without dummy flag + vehicle_journey.vehicle_journey_at_stops[3].destroy + at_stops = vehicle_journey.reload.vehicle_journey_at_stops_matrix + expect(at_stops[3].dummy).to be false + end + + it 'should set dummy to true for deactivated stop_points vjas' do + vehicle_journey.journey_pattern.stop_points.delete(vehicle_journey.journey_pattern.stop_points.first) + at_stops = vehicle_journey.reload.vehicle_journey_at_stops_matrix + expect(at_stops.first.dummy).to be true + end + + it 'should fill vjas for active stop_points without vjas yet' do vehicle_journey.vehicle_journey_at_stops.destroy_all at_stops = vehicle_journey.reload.vehicle_journey_at_stops_matrix expect(at_stops.map(&:stop_point_id)).to eq vehicle_journey.journey_pattern.stop_points.map(&:id) end - it 'should keep index order of VehicleJourneyAtStop' do + it 'should keep index order of vjas' do vehicle_journey.vehicle_journey_at_stops[3].destroy at_stops = vehicle_journey.reload.vehicle_journey_at_stops_matrix diff --git a/spec/models/clean_up_spec.rb b/spec/models/clean_up_spec.rb index c495abdfe..4b1bf4da9 100644 --- a/spec/models/clean_up_spec.rb +++ b/spec/models/clean_up_spec.rb @@ -1,20 +1,227 @@ require 'rails_helper' RSpec.describe CleanUp, :type => :model do - let(:cleaner) { CleanUp.new } it { should validate_presence_of(:begin_date) } + it { should validate_presence_of(:date_type) } it { should belong_to(:referential) } - it 'should delete vehiclejourneys without timetables' do - create_list(:vehicle_journey, 2) - create_list(:vehicle_journey, 2, time_tables:[create(:time_table)]) - expect(cleaner.clean_vehicle_journeys).to eq 2 + context '#exclude_dates_in_overlapping_period with :before date_type' do + let(:time_table) { create(:time_table) } + let(:period) { time_table.periods[0] } + let(:cleaner) { create(:clean_up, date_type: :before) } + + it 'should add exclude date into period for overlapping period' do + days_in_period = (period.period_start..period.period_end).count + cleaner.begin_date = period.period_end + + expect { cleaner.exclude_dates_in_overlapping_period(period) }.to change { + time_table.dates.where(in_out: false).count + }.by(days_in_period - 1) + end + + it 'should not add exclude date if no overlapping found' do + cleaner.begin_date = period.period_start + expect { cleaner.exclude_dates_in_overlapping_period(period) }.to_not change { + time_table.dates.where(in_out: false).count + } + end + end + + context '#exclude_dates_in_overlapping_period with :after date_type' do + let(:time_table) { create(:time_table) } + let(:period) { time_table.periods[0] } + let(:cleaner) { create(:clean_up, date_type: :after) } + + it 'should add exclude date into period for overlapping period' do + days_in_period = (period.period_start..period.period_end).count + cleaner.begin_date = period.period_start + 1.day + expect { cleaner.exclude_dates_in_overlapping_period(period) }.to change { + time_table.dates.where(in_out: false).count + }.by(days_in_period - 2) + end + + it 'should not add exclude date if no overlapping found' do + cleaner.begin_date = period.period_end + expect { cleaner.exclude_dates_in_overlapping_period(period) }.to_not change { + time_table.dates.where(in_out: false).count + } + end + end + + context '#exclude_dates_in_overlapping_period with :between date_type' do + let(:time_table) { create(:time_table) } + let(:period) { time_table.periods[0] } + let(:cleaner) { create(:clean_up, date_type: :between, begin_date: period.period_start + 3.day, end_date: period.period_end) } + + it 'should add exclude date into period for overlapping period' do + expected_day_out = (cleaner.begin_date..cleaner.end_date).count + expect { cleaner.exclude_dates_in_overlapping_period(period) }.to change { + time_table.dates.where(in_out: false).count + }.by(expected_day_out) + end + + it 'should not add exclude date if no overlapping found' do + cleaner.begin_date = period.period_end + 1.day + cleaner.end_date = cleaner.begin_date + 1.day + + expect { cleaner.exclude_dates_in_overlapping_period(period) }.to_not change { + time_table.dates.where(in_out: false).count + } + end + end + + context '#overlapping_periods' do + let(:cleaner) { create(:clean_up, date_type: :before, end_date: nil) } + let(:time_table) { create(:time_table) } + + it 'should detect overlapping periods' do + cleaner.begin_date = time_table.periods[0].period_start + expect(cleaner.overlapping_periods).to include(time_table.periods[0]) + end + + it 'should not return none overlapping periods' do + cleaner.begin_date = time_table.periods[0].period_start - 1.day + expect(cleaner.overlapping_periods).to_not include(time_table.periods[0]) + end + end + + context '#clean' do + let(:cleaner) { create(:clean_up, date_type: :before) } + + it 'should call destroy_time_tables_before' do + cleaner.date_type = :before + expect(cleaner).to receive(:destroy_time_tables_before) + expect(cleaner).to receive(:destroy_time_tables_dates_before) + expect(cleaner).to receive(:destroy_time_tables_periods_before) + cleaner.clean + end + + it 'should call destroy_time_tables_after' do + cleaner.date_type = :after + expect(cleaner).to receive(:destroy_time_tables_after) + expect(cleaner).to receive(:destroy_time_tables_dates_after) + expect(cleaner).to receive(:destroy_time_tables_periods_after) + cleaner.clean + end + + it 'should call destroy_time_tables_between' do + cleaner.date_type = :between + expect(cleaner).to receive(:destroy_time_tables_between) + expect(cleaner).to receive(:destroy_time_tables_dates_between) + expect(cleaner).to receive(:destroy_time_tables_periods_between) + cleaner.clean + end + end + + context '#destroy_time_tables_dates_between' do + let!(:time_table) { create(:time_table) } + let(:cleaner) { create(:clean_up, date_type: :between) } + + before do + time_table.periods.clear + time_table.save + cleaner.begin_date = time_table.start_date + cleaner.end_date = time_table.end_date + end + + it 'should destroy record' do + expect{ cleaner.destroy_time_tables_dates_between }.to change { + Chouette::TimeTableDate.count + }.by(-time_table.dates.count) + end + + it 'should not destroy record not in range' do + cleaner.begin_date = time_table.end_date + 1.day + cleaner.end_date = cleaner.begin_date + 1.day + + expect{ cleaner.destroy_time_tables_dates_between }.to_not change { + Chouette::TimeTableDate.count + } + end + end + + context '#destroy_time_tables_dates_after' do + let!(:time_table_date) { create(:time_table_date, date: Date.yesterday, in_out: true) } + let(:cleaner) { create(:clean_up, date_type: :after, begin_date: time_table_date.date) } + + it 'should destroy record' do + count = Chouette::TimeTableDate.where('date > ?', cleaner.begin_date).count + expect{ cleaner.destroy_time_tables_dates_after }.to change { + Chouette::TimeTableDate.count + }.by(-count) + end + end + + context '#destroy_time_tables_between' do + let!(:time_table) { create(:time_table ) } + let(:cleaner) { create(:clean_up, date_type: :after, begin_date: time_table.start_date, end_date: time_table.end_date) } + + it 'should destroy time_tables with validity period in purge range' do + expect{ cleaner.destroy_time_tables_between }.to change { + Chouette::TimeTable.count + }.by(-1) + end + + it 'should not destroy time_tables if not totaly inside purge range' do + cleaner.begin_date = time_table.start_date + 1.day + expect{ cleaner.destroy_time_tables_between }.to_not change { + Chouette::TimeTable.count + } + end + end + + context '#destroy_time_tables_after' do + let!(:time_table) { create(:time_table ) } + let(:cleaner) { create(:clean_up, date_type: :after, begin_date: time_table.start_date - 1.day) } + + it 'should destroy time_tables with start_date > purge begin_date' do + expect{ cleaner.destroy_time_tables_after }.to change { + Chouette::TimeTable.count + }.by(-1) + end + + it 'should not destroy time_tables with start_date < purge begin date' do + cleaner.begin_date = time_table.end_date + expect{ cleaner.destroy_time_tables_after }.to_not change { + Chouette::TimeTable.count + } + end end - it 'should delete journeypatterns without vehicle journeys' do - create_list(:journey_pattern, 2) - create_list(:vehicle_journey, 2, journey_pattern: create(:journey_pattern)) - expect(cleaner.clean_journey_patterns).to eq 2 + context '#destroy_time_tables' do + let!(:time_table) { create(:time_table) } + let(:cleaner) { create(:clean_up, date_type: :before) } + + it 'should destroy all time_tables' do + expect{cleaner.destroy_time_tables(Chouette::TimeTable.all)}.to change { + Chouette::TimeTable.count + }.by(-1) + end + + it 'should destroy associated vehicle_journeys' do + create(:vehicle_journey, time_tables: [time_table]) + expect{cleaner.destroy_time_tables(Chouette::TimeTable.all)}.to change { + Chouette::VehicleJourney.count + }.by(-1) + end + end + + context '#destroy_time_tables_before' do + let!(:time_table) { create(:time_table ) } + let(:cleaner) { create(:clean_up, date_type: :before, begin_date: time_table.end_date + 1.day) } + + it 'should destroy time_tables with end_date < purge begin_date' do + expect{ cleaner.destroy_time_tables_before }.to change { + Chouette::TimeTable.count + }.by(-1) + end + + it 'should not destroy time_tables with end_date > purge begin date' do + cleaner.begin_date = Date.today + expect{ cleaner.destroy_time_tables_before }.to_not change { + Chouette::TimeTable.count + } + end end end diff --git a/spec/models/referential_cloning_spec.rb b/spec/models/referential_cloning_spec.rb index 30391b53e..5acd433ec 100644 --- a/spec/models/referential_cloning_spec.rb +++ b/spec/models/referential_cloning_spec.rb @@ -1,4 +1,4 @@ -require 'rails_helper' +require 'spec_helper' RSpec.describe ReferentialCloning, :type => :model do it 'should have a valid factory' do @@ -7,4 +7,12 @@ RSpec.describe ReferentialCloning, :type => :model do it { should belong_to :source_referential } it { should belong_to :target_referential } + + describe "ReferentialCloningWorker" do + let(:referential_cloning) { FactoryGirl.create(:referential_cloning) } + + it "should schedule a job in worker" do + expect{referential_cloning.run_callbacks(:commit)}.to change {ReferentialCloningWorker.jobs.count}.by(1) + end + end end diff --git a/spec/models/time_table_combination_spec.rb b/spec/models/time_table_combination_spec.rb index 0a8b3296a..3e60fa444 100644 --- a/spec/models/time_table_combination_spec.rb +++ b/spec/models/time_table_combination_spec.rb @@ -87,7 +87,7 @@ describe TimeTableCombination, :type => :model do end it "should intersect combined to source" do - expect(source.int_day_types).to eq(0) + expect(source.int_day_types).to eq(508) expect(source.periods.size).to eq(1) expect(source.dates.size).to eq(0) @@ -119,7 +119,7 @@ describe TimeTableCombination, :type => :model do end it "should disjoin combined to source" do - expect(source.int_day_types).to eq(0) + expect(source.int_day_types).to eq(508) expect(source.periods.size).to eq(1) expect(source.dates.size).to eq(0) diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 5c7aa0b98..6f98e5ce7 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -118,7 +118,7 @@ describe User, :type => :model do context 'permissions' do it 'should give edit permissions to user if user has "edit offer" permission in portail' do User.portail_sync - expect(User.find_by(username: 'vlatka.pavisic').permissions).not_to be_empty + expect(User.find_by(username: 'vlatka.pavisic').permissions).to include_all(User.edit_offer_permissions) expect(User.find_by(username: 'pierre.vabre').permissions).to be_empty end end diff --git a/spec/policies/boiv_policy_spec.rb b/spec/policies/boiv_policy_spec.rb index bf09cdcd9..514534adc 100644 --- a/spec/policies/boiv_policy_spec.rb +++ b/spec/policies/boiv_policy_spec.rb @@ -11,5 +11,4 @@ RSpec.describe BoivPolicy, type: :policy do permissions :show? do it_behaves_like 'permitted policy and same organisation', 'boiv:read-offer' end - end diff --git a/spec/policies/login_policy_spec.rb b/spec/policies/login_policy_spec.rb new file mode 100644 index 000000000..132e57433 --- /dev/null +++ b/spec/policies/login_policy_spec.rb @@ -0,0 +1,15 @@ +RSpec.describe LoginPolicy, type: :policy do + permissions :boiv? do + it 'no permission starting with boiv:. → denies' do + expect( LoginPolicy.new(user_context.user) ).not_to be_boiv + end + + with_user_permission 'boiv:anything' do + it { expect( LoginPolicy.new(user_context.user) ).to be_boiv } + end + with_user_permission 'boiv:' do + it { expect( LoginPolicy.new(user_context.user) ).not_to be_boiv } + end + end + +end diff --git a/spec/support/bare_sql.rb b/spec/support/bare_sql.rb new file mode 100644 index 000000000..03a50ef77 --- /dev/null +++ b/spec/support/bare_sql.rb @@ -0,0 +1,58 @@ +module Support + module BareSQL + + def insert(schema, table, values) + execute "INSERT INTO #{schema}.#{table} (#{_keys(values)}) VALUES (#{_values values})" + end + + def execute(sql) + base_connection.execute(sql) + end + + def expect_same_content(table_name) + expected_content = get_content(source_schema, table_name) + actual_content = get_content(target_schema, table_name) + expect( actual_content ).to eq(expected_content) + end + + def expect_same_sequence_params(sequence_name) + expected_seq = Hash.without(get_sequences(source_schema, sequence_name).first, 'log_cnt') + actual_seq = Hash.without(get_sequences(target_schema, sequence_name).first, 'log_cnt') + expect( actual_seq ).to eq(expected_seq) + end + + def get_content(schema_name, table_name) + execute("SELECT * FROM #{schema_name}.#{table_name}").to_a + end + + private + + def base_connection + ActiveRecord::Base.connection + end + + def _keys(values) + values.keys.map(&:to_s).join(", ") + end + + def _values(values) + values + .values + .map(&method(:_format)) + .join(', ') + end + + def _format(val) + case val + when String + "'#{val}'" + when TrueClass + "'t'" + when FalseClass + "'f'" + else + val.to_s + end + end + end +end diff --git a/spec/support/custom_matchers.rb b/spec/support/custom_matchers.rb new file mode 100644 index 000000000..bdc3efaa0 --- /dev/null +++ b/spec/support/custom_matchers.rb @@ -0,0 +1,7 @@ +require 'rspec/expectations' + +RSpec::Matchers.define :include_all do |expected| + match do |actual| + ( expected - actual ).empty? + end +end diff --git a/spec/support/devise.rb b/spec/support/devise.rb index 14e316bea..d4a279a41 100644 --- a/spec/support/devise.rb +++ b/spec/support/devise.rb @@ -36,8 +36,8 @@ module DeviseRequestHelper end module DeviseControllerHelper - def login_user - before(:each) do + def setup_user + before do @request.env["devise.mapping"] = Devise.mappings[:user] organisation = Organisation.where(:code => "first").first_or_create(attributes_for(:organisation)) @user = create(:user, :organisation => organisation, @@ -47,6 +47,11 @@ module DeviseControllerHelper 'access_points.create', 'access_points.edit', 'access_points.destroy', 'access_links.create', 'access_links.edit', 'access_links.destroy', 'connection_links.create', 'connection_links.edit', 'connection_links.destroy', 'route_sections.create', 'route_sections.edit', 'route_sections.destroy', 'referentials.create', 'referentials.edit', 'referentials.destroy']) + end + end + def login_user() + setup_user + before do sign_in @user end end diff --git a/spec/support/hash.rb b/spec/support/hash.rb new file mode 100644 index 000000000..ec9a2f895 --- /dev/null +++ b/spec/support/hash.rb @@ -0,0 +1,6 @@ +class << Hash + def without(hash, *keys) + nk = hash.keys - keys + Hash[*nk.zip(hash.values_at(*nk)).flatten] + end +end diff --git a/spec/support/pg_catalog.rb b/spec/support/pg_catalog.rb index bb61adba5..ca02f2550 100644 --- a/spec/support/pg_catalog.rb +++ b/spec/support/pg_catalog.rb @@ -1,11 +1,12 @@ +require_relative 'bare_sql' module Support module PGCatalog - # TODO: Check what of the follwowing can be done with ActiveRecord. E.g. - # @connection.foreign_keys(table)... + include Support::BareSQL def get_columns(schema_name, table_name) - execute("SELECT * from information_schema.columns WHERE table_name = '#{table_name}' AND table_schema = '#{schema_name}'") + execute("SELECT column_name, column_default FROM information_schema.columns WHERE table_name = '#{table_name}' AND table_schema = '#{schema_name}'").to_a end + def get_foreign_keys(schema_oid, table_name) schema_oid = get_schema_oid(schema_oid) unless Integer === schema_oid return [] unless schema_oid @@ -20,11 +21,8 @@ module Support .first end - def get_sequences(schema_name, table_name) - sequences = execute <<-EOSQL - SELECT sequence_name FROM information_schema.sequences - WHERE sequence_schema = '#{schema_name}' AND sequence_name LIKE '#{table_name}%' - EOSQL + def get_sequences(schema_name, sequence_name) + sequences = execute(sequence_query(schema_name, sequence_name)) sequences.values.flatten.map do | sequence | execute "SELECT * from #{schema_name}.#{sequence}" end.flat_map(&:to_a) @@ -38,39 +36,20 @@ module Support private - def base_connection - ActiveRecord::Base.connection - end - - def execute(sql) - base_connection.execute(sql) - end def foreign_key_query(schema_oid, table_name) - key = [:foreign_key_query, schema_oid, table_name] - get_or_create_query(key){ <<-EOQ - SELECT ct.conname AS constraint_name, pg_get_constraintdef(ct.oid) AS constraint_def - FROM pg_constraint ct JOIN pg_class rn ON rn.oid = ct.conrelid - WHERE connamespace = #{schema_oid} AND rn.relname = '#{table_name}' AND rn.relkind = 'r' AND ct.contype = 'f' - EOQ - } - end - - def sequence_properties_query(schema_name, sequence_name) - key = [:sequence_properies_query, schema_name, sequence_name] - get_or_create_query(key){ <<-EOQ - Coming Soon - EOQ - } - - end - - def get_or_create_query(query_key, &query_value) - queries.fetch(query_key){ queries[query_key] = query_value.() } + <<-EOQ + SELECT ct.conname AS constraint_name, pg_get_constraintdef(ct.oid) AS constraint_def + FROM pg_constraint ct JOIN pg_class rn ON rn.oid = ct.conrelid + WHERE connamespace = #{schema_oid} AND rn.relname = '#{table_name}' AND rn.relkind = 'r' AND ct.contype = 'f' + EOQ end - def queries - @__queries__ ||= {} + def sequence_query(schema_name, sequence_name) + <<-EOQ + SELECT sequence_name FROM information_schema.sequences + WHERE sequence_schema = '#{schema_name}' AND sequence_name = '#{sequence_name}' + EOQ end def without_keys(*keys) @@ -82,3 +61,7 @@ module Support end end end + +RSpec.configure do | conf | + conf.include Support::PGCatalog, type: :pg_catalog +end diff --git a/spec/support/pundit/policies.rb b/spec/support/pundit/policies.rb index 637a2a528..e18309226 100644 --- a/spec/support/pundit/policies.rb +++ b/spec/support/pundit/policies.rb @@ -16,6 +16,7 @@ module Support for_user.permissions ||= [] for_user.permissions += permissions.flatten end + end module PoliciesMacros @@ -27,6 +28,12 @@ module Support let( :user ) { create :user } end end + def with_user_permission(permission, &blk) + it "with user permission #{permission.inspect}" do + add_permissions(permission, for_user: user) + blk.() + end + end end end end diff --git a/spec/views/referentials/new.html.erb_spec.rb b/spec/views/referentials/new.html.erb_spec.rb index 0673b4578..554e71d29 100644 --- a/spec/views/referentials/new.html.erb_spec.rb +++ b/spec/views/referentials/new.html.erb_spec.rb @@ -5,15 +5,9 @@ describe "referentials/new", :type => :view do before(:each) do assign(:referential, Referential.new) end - + it "should have a textfield for name" do render expect(rendered).to have_field("referential[name]") end - - it "should have a textfield for slug" do - render - expect(rendered).to have_field("referential[slug]") - end - end diff --git a/spec/workers/referential_cloning_worker_spec.rb b/spec/workers/referential_cloning_worker_spec.rb index 85d771742..52ed8913b 100644 --- a/spec/workers/referential_cloning_worker_spec.rb +++ b/spec/workers/referential_cloning_worker_spec.rb @@ -9,37 +9,29 @@ RSpec.describe ReferentialCloningWorker do let( :worker ){ described_class.new } + def make_referential(schema_name) + return OpenStruct.new( slug: schema_name ) + end let( :source_schema ){ "source_schema" } - let( :target_schema ){ "#{source_schema}_tmp" } - let( :referential_cloning ){ OpenStruct.new(source_referential: OpenStruct.new(slug: source_schema)) } + let( :target_schema ){ "target_schema" } + let( :referential_cloning ){ OpenStruct.new(source_referential: make_referential(source_schema), + target_referential: make_referential(target_schema)) } + let( :cloner ){ 'cloner' } + before do expect( ReferentialCloning ).to receive(:find).with(id).and_return(referential_cloning) - expect( StoredProcedures ) - .to receive(:invoke_stored_procedure) - .with(:clone_schema, source_schema, target_schema, true) - - expect( worker ).to receive(:execute_sql).with( "DROP SCHEMA #{source_schema} CASCADE;" ) + expect( AF83::SchemaCloner ).to receive(:new).with( source_schema, target_schema ).and_return(cloner) + expect( cloner ).to receive(:clone_schema) expect( referential_cloning ).to receive(:run!) end it "invokes the correct stored procedure, updates the database and the AASM" do - expect( worker ).to receive(:execute_sql).with( "ALTER SCHEMA #{target_schema} RENAME TO #{source_schema};" ) expect( referential_cloning ).to receive(:successful!) worker.perform(id) end - - it "handles failure correctly" do - expect( worker ) - .to receive(:execute_sql) - .with( "ALTER SCHEMA #{target_schema} RENAME TO #{source_schema};" ) - .and_raise(RuntimeError) - - expect( referential_cloning ).to receive(:failed!) - worker.perform(id) - end end - + end |
