From cb8c37b2902c07a1869ce991ce3f382eea25c812 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 16 Oct 2017 10:28:18 +0200 Subject: Hotfix correction --- .../genric_attribute_validation/min_max_validation_spec.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/models/compliance_control_validations/genric_attribute_validation/min_max_validation_spec.rb b/spec/models/compliance_control_validations/genric_attribute_validation/min_max_validation_spec.rb index 276d09a92..4d30d61e3 100644 --- a/spec/models/compliance_control_validations/genric_attribute_validation/min_max_validation_spec.rb +++ b/spec/models/compliance_control_validations/genric_attribute_validation/min_max_validation_spec.rb @@ -1,8 +1,8 @@ -# RSpec.describe GenericAttributeControl::MinMax do +RSpec.describe GenericAttributeControl::MinMax do -# let( :factory ){ :generic_attribute_control_min_max } -# subject{ build factory } + let( :factory ){ :generic_attribute_control_min_max } + subject{ build factory } -# it_behaves_like 'has min_max_values' + it_behaves_like 'has min_max_values' -# end +end -- cgit v1.2.3 From 3d69e36539cee8796f9da2a981ba3c6b5e535e9f Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 16 Oct 2017 12:39:14 +0200 Subject: migrated --- db/schema.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/schema.rb b/db/schema.rb index 181c83402..a64a426de 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -408,9 +408,9 @@ ActiveRecord::Schema.define(version: 20171016074044) do t.string "type" t.integer "parent_id", limit: 8 t.string "parent_type" + t.datetime "notified_parent_at" t.integer "current_step", default: 0 t.integer "total_steps", default: 0 - t.datetime "notified_parent_at" t.string "creator" end -- cgit v1.2.3 From aaa5d31971ebf2b429efea3c869a8e132f9d0836 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 16 Oct 2017 21:50:56 +0200 Subject: Refs: #4727@3h; Specing and implementing lib function to clone ComplianceControlSet --- config/locales/compliance_control_blocks.en.yml | 4 +- config/locales/compliance_control_blocks.fr.yml | 4 +- config/locales/compliance_control_sets.en.yml | 2 + config/locales/compliance_control_sets.fr.yml | 2 + config/locales/compliance_controls.en.yml | 2 + config/locales/compliance_controls.fr.yml | 2 + lib/compliance_control_set_cloner.rb | 89 +++++++++++++++ spec/lib/compliance_control_set_cloner_spec.rb | 142 ++++++++++++++++++++++++ 8 files changed, 245 insertions(+), 2 deletions(-) create mode 100644 lib/compliance_control_set_cloner.rb create mode 100644 spec/lib/compliance_control_set_cloner_spec.rb diff --git a/config/locales/compliance_control_blocks.en.yml b/config/locales/compliance_control_blocks.en.yml index a37b41db5..fbface6b2 100644 --- a/config/locales/compliance_control_blocks.en.yml +++ b/config/locales/compliance_control_blocks.en.yml @@ -10,9 +10,11 @@ fr: transport_mode: Transport mode sub_transport_mode: Transport submode compliance_control_blocks: + clone: + prefix: 'Copy of' actions: destroy_confirm: Are you sure you want to destroy this block ? new: title: Create a control block edit: - title: "Edit the control block : %{compliance_control_block}" \ No newline at end of file + title: "Edit the control block : %{compliance_control_block}" diff --git a/config/locales/compliance_control_blocks.fr.yml b/config/locales/compliance_control_blocks.fr.yml index f93cafa54..66df008be 100644 --- a/config/locales/compliance_control_blocks.fr.yml +++ b/config/locales/compliance_control_blocks.fr.yml @@ -10,9 +10,11 @@ fr: transport_mode: Mode de transport transport_submode: Sous-mode de transport compliance_control_blocks: + clone: + prefix: 'Copie de' actions: destroy_confirm: Etes vous sûr de supprimer ce bloc ? new: title: Créer un groupe de contrôle(s) edit: - title: "Editer le groupe de contrôle : %{compliance_control_block}" \ No newline at end of file + title: "Editer le groupe de contrôle : %{compliance_control_block}" diff --git a/config/locales/compliance_control_sets.en.yml b/config/locales/compliance_control_sets.en.yml index 83b14642c..f72342894 100644 --- a/config/locales/compliance_control_sets.en.yml +++ b/config/locales/compliance_control_sets.en.yml @@ -1,5 +1,7 @@ en: compliance_control_sets: + clone: + prefix: 'Copie de' index: title: Compliance control set new: New compliance control set diff --git a/config/locales/compliance_control_sets.fr.yml b/config/locales/compliance_control_sets.fr.yml index 37851d7c4..c31eb9423 100644 --- a/config/locales/compliance_control_sets.fr.yml +++ b/config/locales/compliance_control_sets.fr.yml @@ -1,5 +1,7 @@ fr: compliance_control_sets: + clone: + prefix: 'Copy of' index: title: "Liste des jeux de contrôles" edit: diff --git a/config/locales/compliance_controls.en.yml b/config/locales/compliance_controls.en.yml index 3063c35a4..887bc2009 100644 --- a/config/locales/compliance_controls.en.yml +++ b/config/locales/compliance_controls.en.yml @@ -1,5 +1,7 @@ en: compliance_controls: + clone: + prefix: 'Copy of' min_max_values: "the minimum (%{min}) is not supposed to be greater than the maximum (%{max})" errors: incoherent_control_sets: "Impossible to assign a control to a set (id: %{direct_set_name}) differing from the one of its group (id: %{indirect_set_name})" diff --git a/config/locales/compliance_controls.fr.yml b/config/locales/compliance_controls.fr.yml index 2038b9eb7..2feb201bf 100644 --- a/config/locales/compliance_controls.fr.yml +++ b/config/locales/compliance_controls.fr.yml @@ -1,5 +1,7 @@ fr: compliance_controls: + clone: + prefix: 'Copie de' min_max_values: "la valeur de minimum (%{min}) ne doit pas être superieur à la valuer du maximum (%{max})" errors: incoherent_control_sets: "Le contrôle ne peut pas être associé à un jeu de contrôle (id: %{direct_set_name}) différent de celui de son groupe (id: %{indirect_set_name})" diff --git a/lib/compliance_control_set_cloner.rb b/lib/compliance_control_set_cloner.rb new file mode 100644 index 000000000..50c757a9f --- /dev/null +++ b/lib/compliance_control_set_cloner.rb @@ -0,0 +1,89 @@ +class ComplianceControlSetCloner + + # Naming Convention: As we are in a domain with quite long names we + # abbreviate compliance_control to cc and + # compliance_check to cck iff used as prefixes. + + attr_reader :source_set_id + + def copy source_set_id + @source_set_id = source_set_id + copy_set + end + + + private + + # Workers + # ------- + + # Copy Set: + def copy_set + # Force lazy creation of target_set, just in case source_set is _empty_. + target_set + copy_controls + copy_blocks + end + + # Copy Blocks: + def copy_block source_block + target_set.compliance_control_blocks.create( + name: name_of_copy(:compliance_control_blocks, source_block.name), + condition_attributes: source_block.condition_attributes).tap do | target_block | + relink_checks_to_block source_block, target_block + end + end + def copy_blocks + source_set.compliance_control_blocks.order(:id).each(&method(:copy_block)) + end + def relink_checks_to_block source_block, target_block + source_block + .compliance_controls + .order(:id) + .each do | source_control | + control_id_map[source_control.id] + .update(compliance_control_block_id: target_block.id) + end + end + + # Copy Controls: + def copy_controls + source_set.compliance_controls.order(:id).each(&method(:copy_control)) + end + def copy_control(compliance_control) + target_set.compliance_controls.create( + code: compliance_control.code, + comment: compliance_control.comment, + control_attributes: compliance_control.control_attributes, + criticity: compliance_control.criticity, + name: name_of_copy(:compliance_controls, compliance_control.name), + origin_code: compliance_control.origin_code, + type: compliance_control.type + ).tap do | control | + control_id_map.update compliance_control.id => control + end + end + + def name_of_copy resource, name + [I18n.t("#{resource}.clone.prefix"), name].join(' ') + end + + # Lazy Values + # ----------- + def source_set + @__source_set__ ||= ComplianceControlSet.find(source_set_id) + end + def target_set + @__target_set__ ||= ComplianceControlSet.create!( + organisation: source_set.organisation, + name: name_of_copy(:compliance_control_sets, source_set.name) + ) + end + def control_id_map + # Map: compliance_control_id -> compliance_control (origin_id -> copied object) + @__control_id_to_check__ ||= Hash.new + end + def referential + @__referential__ ||= Referential.find(referential_id) + end +end diff --git a/spec/lib/compliance_control_set_cloner_spec.rb b/spec/lib/compliance_control_set_cloner_spec.rb new file mode 100644 index 000000000..5313c15de --- /dev/null +++ b/spec/lib/compliance_control_set_cloner_spec.rb @@ -0,0 +1,142 @@ +RSpec.describe ComplianceControlSetCloner do + + subject{ described_class.new } + + let( :source_set ){ create :compliance_control_set } + let( :set_prefix ){ I18n.t('compliance_control_sets.clone.prefix') } + let( :block_prefix ){ I18n.t('compliance_control_blocks.clone.prefix') } + let( :control_prefix ){ I18n.t('compliance_controls.clone.prefix') } + + + context 'Copying empty set' do + + context 'correct organisation' do + + # + # + # + # + # + # + # + # +-------------------+ + # +---------------------+----------------| Control (direct0) | + # | | +-------------------+ + # | | + # | | +-------------------+ + # +---------------------)------------+---| Control (direct1) | + # | | | +-------------------+ + # | | | + # | | | +-------------------+ + # +---------------------)------------)---| Control (direct2) | + # | | | +-------------------+ + # | | | + # | | | + # | | | + # v v | + # +------------+ +--------------+ | +---------------------+ + # | ControlSet |<----+----| ControlBlock |<-)--| Control (indirect0) | + # +------------+ | +--------------+ | +---------------------+ + # | | + # | +--------------+<-+ +---------------------+ + # |<---| ControlBlock |<----| Control (indirect1) | + # | +--------------+ +---------------------+ + # | + # | +--------------+ +---------------------+ + # +----| ControlBlock |<----| Control (indirect2) | + # +--------------+ +---------------------+ + + context 'Directed Acyclic Graph is copied correctly' do + let(:source_blox){ + 3.times.map{ |_| create :compliance_control_block, compliance_control_set: source_set } + } + let(:direct_ccs){ + 3.times.map{ |n| create :compliance_control, compliance_control_set: source_set, name: "direct #{n.succ}", code: "direct-#{n.succ}" } + } + # Needed to check we do not dulicate a node (compliance_control) twice + let(:indirect_ccs){ + # Create 1 child for each block and also associate first of the direct ccs to the first block + # seconf of the direct css to the second block + source_blox.take(2).zip(direct_ccs.take(2)).each do | source_block, cc | + cc.update compliance_control_block_id: source_block.id + end + source_blox.each_with_index.map{ | source_block, n | + create(:compliance_control, compliance_control_set: source_set, compliance_control_block: source_block, name: "indirect #{n.succ}", code: "indirect-#{n.succ}") + } + } + let( :sources ){ source_set.compliance_controls.order(:id) } + + let( :target_set ){ ComplianceControlSet.last } + let( :target_blox ){ ComplianceControlBlock.last 3 } + let( :targets ){ target_set.compliance_controls.order(:id) } + + before do + direct_ccs + indirect_ccs + end + it 'correctly creates a set for a complete DAG' do + # Slowness of tests constrains us to create a minimum of objects in the DB, + # hence only one example :( + # + # Execute copy and keep count + counts = object_counts + subject.copy(source_set.id) + delta = count_diff counts, object_counts + + # Check correctly copied set + expect(target_set.organisation).to eq(source_set.organisation) + expect(target_set.name).to eq( [set_prefix, source_set.name].join(' ') ) + + # Check correctly copied controls + targets.zip(sources).each do | target, source | + expect( target.code ).to eq(source.code ) + expect( target.comment ).to eq(source.comment ) + expect( target.compliance_control_set ).to eq( target_set ) + expect( target.control_attributes ).to eq(source.control_attributes) + expect( target.criticity ).to eq(source.criticity ) + expect( target.name ).to eq([control_prefix, source.name].join(' ')) + expect( target.origin_code ).to eq(source.origin_code ) + expect( target.type ).to eq(source.type) + end + # Check correctly copied blocks + target_blox.zip(source_blox).each do | target_block, source_block | + expect( target_block.compliance_control_set ).to eq(target_set) + expect( target_block.name ).to eq( [block_prefix, source_block.name].join(' ') ) + expect( target_block.condition_attributes ).to eq( source_block.condition_attributes ) + end + + # Check correct block associations + # See diagram above to understand the meaning of this: + # - The first two controls have been assigned to the first two blocks accordingly + # - The third has no block + # - The last three controls have been created from the three blocks in order + expected_block_ids = target_blox.take(2).map(&:id) + [ nil ] + target_blox.map(&:id) + expect( targets.pluck(:compliance_control_block_id) ).to eq( expected_block_ids ) + + # Check overall counts (no additional creations) + expect( delta ).to eq(counts) + end + end + + end + + def object_counts + { + source_set_count: ComplianceControlSet.count, + cc_block_count: ComplianceControlBlock.count, + cc_count: ComplianceControl.count, + cck_set_count: ComplianceCheckSet.count, + cck_block_count: ComplianceCheckBlock.count, + cck_count: ComplianceCheck.count + } + end + + def count_diff count1, count2 + count1.inject({}){ |h, (k,v)| + h.merge( k => count2[k] - v ) + } + end + + end + +end -- cgit v1.2.3 From 8fffc6dd27175b20cc18c246a10151bc98bba4ee Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 17 Oct 2017 10:32:33 +0200 Subject: Refs: #4727@2h; Debugged test setup to comply to new validation --- lib/compliance_control_set_cloner.rb | 1 + spec/lib/compliance_control_set_cloner_spec.rb | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/compliance_control_set_cloner.rb b/lib/compliance_control_set_cloner.rb index 50c757a9f..3856ce25e 100644 --- a/lib/compliance_control_set_cloner.rb +++ b/lib/compliance_control_set_cloner.rb @@ -58,6 +58,7 @@ class ComplianceControlSetCloner criticity: compliance_control.criticity, name: name_of_copy(:compliance_controls, compliance_control.name), origin_code: compliance_control.origin_code, + target: compliance_control.target, type: compliance_control.type ).tap do | control | control_id_map.update compliance_control.id => control diff --git a/spec/lib/compliance_control_set_cloner_spec.rb b/spec/lib/compliance_control_set_cloner_spec.rb index 5313c15de..ca359536a 100644 --- a/spec/lib/compliance_control_set_cloner_spec.rb +++ b/spec/lib/compliance_control_set_cloner_spec.rb @@ -51,7 +51,7 @@ RSpec.describe ComplianceControlSetCloner do 3.times.map{ |_| create :compliance_control_block, compliance_control_set: source_set } } let(:direct_ccs){ - 3.times.map{ |n| create :compliance_control, compliance_control_set: source_set, name: "direct #{n.succ}", code: "direct-#{n.succ}" } + 3.times.map{ |n| create :generic_attribute_control_min_max, compliance_control_set: source_set, name: "direct #{n.succ}", code: "direct-#{n.succ}" } } # Needed to check we do not dulicate a node (compliance_control) twice let(:indirect_ccs){ @@ -61,7 +61,7 @@ RSpec.describe ComplianceControlSetCloner do cc.update compliance_control_block_id: source_block.id end source_blox.each_with_index.map{ | source_block, n | - create(:compliance_control, compliance_control_set: source_set, compliance_control_block: source_block, name: "indirect #{n.succ}", code: "indirect-#{n.succ}") + create(:generic_attribute_control_min_max, compliance_control_set: source_set, compliance_control_block: source_block, name: "indirect #{n.succ}", code: "indirect-#{n.succ}") } } let( :sources ){ source_set.compliance_controls.order(:id) } -- cgit v1.2.3 From bacb624a9d0415337dfab6418de240cd2afa7305 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 17 Oct 2017 10:50:41 +0200 Subject: Fixes: #4727@0.5h; Worker speced and implemented --- app/workers/compliance_control_set_cloning_worker.rb | 8 ++++++++ spec/workers/clean_up_worker_spec.rb | 1 - spec/workers/compliance_control_set_cloning_worker_spec.rb | 14 ++++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 app/workers/compliance_control_set_cloning_worker.rb create mode 100644 spec/workers/compliance_control_set_cloning_worker_spec.rb diff --git a/app/workers/compliance_control_set_cloning_worker.rb b/app/workers/compliance_control_set_cloning_worker.rb new file mode 100644 index 000000000..6194a06ad --- /dev/null +++ b/app/workers/compliance_control_set_cloning_worker.rb @@ -0,0 +1,8 @@ +class ComplianceControlSetCloningWorker + include Sidekiq::Worker + + def perform id + ComplianceControlSetCloner.new.copy id + end + +end diff --git a/spec/workers/clean_up_worker_spec.rb b/spec/workers/clean_up_worker_spec.rb index e85768fa3..fd767db00 100644 --- a/spec/workers/clean_up_worker_spec.rb +++ b/spec/workers/clean_up_worker_spec.rb @@ -1,4 +1,3 @@ -require 'rails_helper' RSpec.describe CleanUpWorker, type: :worker do pending "add some examples to (or delete) #{__FILE__}" end diff --git a/spec/workers/compliance_control_set_cloning_worker_spec.rb b/spec/workers/compliance_control_set_cloning_worker_spec.rb new file mode 100644 index 000000000..dee3e6dd5 --- /dev/null +++ b/spec/workers/compliance_control_set_cloning_worker_spec.rb @@ -0,0 +1,14 @@ +RSpec.describe ComplianceControlSetCloningWorker do + + + it 'is a worker' do + expect( described_class.new ).to be_a(Sidekiq::Worker) + end + + it 'delegates perform to the correct lib call' do + id = random_int + expect_any_instance_of(ComplianceControlSetCloner).to receive(:copy).with(id) + described_class.new.perform(id) + end + +end -- cgit v1.2.3 From 0b744d48fdc84445f593114fe61baaafca4e17f4 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 17 Oct 2017 12:28:35 +0200 Subject: Fixes: #4727@0.1h; Added organisation to clone for and rebased master --- app/workers/compliance_control_set_cloning_worker.rb | 4 ++-- lib/compliance_control_set_cloner.rb | 12 ++++++++---- spec/lib/compliance_control_set_cloner_spec.rb | 6 ++++-- spec/workers/compliance_control_set_cloning_worker_spec.rb | 7 ++++--- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/app/workers/compliance_control_set_cloning_worker.rb b/app/workers/compliance_control_set_cloning_worker.rb index 6194a06ad..9cbe5c81a 100644 --- a/app/workers/compliance_control_set_cloning_worker.rb +++ b/app/workers/compliance_control_set_cloning_worker.rb @@ -1,8 +1,8 @@ class ComplianceControlSetCloningWorker include Sidekiq::Worker - def perform id - ComplianceControlSetCloner.new.copy id + def perform id, organisation_id + ComplianceControlSetCloner.new.copy id, organisation_id end end diff --git a/lib/compliance_control_set_cloner.rb b/lib/compliance_control_set_cloner.rb index 3856ce25e..1cf58a38d 100644 --- a/lib/compliance_control_set_cloner.rb +++ b/lib/compliance_control_set_cloner.rb @@ -4,10 +4,11 @@ class ComplianceControlSetCloner # abbreviate compliance_control to cc and # compliance_check to cck iff used as prefixes. - attr_reader :source_set_id - - def copy source_set_id + attr_reader :organisation_id, :source_set_id + + def copy source_set_id, organisation_id @source_set_id = source_set_id + @organisation_id = organisation_id copy_set end @@ -71,12 +72,15 @@ class ComplianceControlSetCloner # Lazy Values # ----------- + def organisation + @__organisation__ ||= Organisation.find(organisation_id) + end def source_set @__source_set__ ||= ComplianceControlSet.find(source_set_id) end def target_set @__target_set__ ||= ComplianceControlSet.create!( - organisation: source_set.organisation, + organisation: organisation, name: name_of_copy(:compliance_control_sets, source_set.name) ) end diff --git a/spec/lib/compliance_control_set_cloner_spec.rb b/spec/lib/compliance_control_set_cloner_spec.rb index ca359536a..4305ec70b 100644 --- a/spec/lib/compliance_control_set_cloner_spec.rb +++ b/spec/lib/compliance_control_set_cloner_spec.rb @@ -2,6 +2,8 @@ RSpec.describe ComplianceControlSetCloner do subject{ described_class.new } + let( :new_organisation ){ create :organisation } + let( :source_set ){ create :compliance_control_set } let( :set_prefix ){ I18n.t('compliance_control_sets.clone.prefix') } let( :block_prefix ){ I18n.t('compliance_control_blocks.clone.prefix') } @@ -80,11 +82,11 @@ RSpec.describe ComplianceControlSetCloner do # # Execute copy and keep count counts = object_counts - subject.copy(source_set.id) + subject.copy(source_set.id, new_organisation.id) delta = count_diff counts, object_counts # Check correctly copied set - expect(target_set.organisation).to eq(source_set.organisation) + expect(target_set.organisation).to eq(new_organisation) expect(target_set.name).to eq( [set_prefix, source_set.name].join(' ') ) # Check correctly copied controls diff --git a/spec/workers/compliance_control_set_cloning_worker_spec.rb b/spec/workers/compliance_control_set_cloning_worker_spec.rb index dee3e6dd5..3a2332f62 100644 --- a/spec/workers/compliance_control_set_cloning_worker_spec.rb +++ b/spec/workers/compliance_control_set_cloning_worker_spec.rb @@ -6,9 +6,10 @@ RSpec.describe ComplianceControlSetCloningWorker do end it 'delegates perform to the correct lib call' do - id = random_int - expect_any_instance_of(ComplianceControlSetCloner).to receive(:copy).with(id) - described_class.new.perform(id) + id = double('id') + organisation_id = double('organisation_id') + expect_any_instance_of(ComplianceControlSetCloner).to receive(:copy).with(id, organisation_id) + described_class.new.perform(id, organisation_id) end end -- cgit v1.2.3