From 802c366ea73485d145cb97346a639a905dfdfc3b Mon Sep 17 00:00:00 2001 From: rpassas Date: Mon, 12 Feb 2024 21:03:00 -0500 Subject: [PATCH] update #save, remove create, schema update --- lib/inferno/config/boot/validator.rb | 4 +- .../migrations/010_add_validator_sessions.rb | 12 +-- lib/inferno/db/schema.rb | 9 +- lib/inferno/dsl/fhir_resource_validation.rb | 12 ++- lib/inferno/entities/validator_session.rb | 41 ++++---- lib/inferno/jobs/invoke_validator_session.rb | 11 +-- lib/inferno/repositories.rb | 1 - .../repositories/validator_sessions.rb | 56 ++++++----- .../fhir_resource_validation_spec.rb | 96 +++++++++++++++++++ 9 files changed, 172 insertions(+), 70 deletions(-) create mode 100644 spec/inferno/repositories/fhir_resource_validation_spec.rb diff --git a/lib/inferno/config/boot/validator.rb b/lib/inferno/config/boot/validator.rb index 0e4b252b9a..fc8ed1b2dd 100644 --- a/lib/inferno/config/boot/validator.rb +++ b/lib/inferno/config/boot/validator.rb @@ -7,10 +7,10 @@ next if Sidekiq.server? Inferno::Repositories::TestSuites.new.all.each do |suite| - suite.fhir_validators.each do |name, validators| + suite.fhir_validators.each do |name, validators, required_suite_options| validators.each_with_index do |validator, index| if validator.is_a? Inferno::DSL::FHIRResourceValidation::Validator - Inferno::Jobs.perform(Inferno::Jobs::InvokeValidatorSession, suite.id, name.to_s, index) + Inferno::Jobs.perform(Inferno::Jobs::InvokeValidatorSession, suite.id, name.to_s, index, required_suite_options) end end end diff --git a/lib/inferno/db/migrations/010_add_validator_sessions.rb b/lib/inferno/db/migrations/010_add_validator_sessions.rb index 2ae4a5e6ad..4e1ef02c7d 100644 --- a/lib/inferno/db/migrations/010_add_validator_sessions.rb +++ b/lib/inferno/db/migrations/010_add_validator_sessions.rb @@ -2,14 +2,12 @@ change do create_table :validator_sessions do column :id, String, primary_key: true, null: false, size: 36 - column :validator_session_id, String, null: false, size: 255 + column :validator_session_id, String, null: false, size: 255, unique: true column :test_suite_id, String, null: false, size: 255 - column :validator_name, String, null: false, size:255 - column :validator_index, String, null: false, size:255 - column :created_at, DateTime, null: false - column :updated_at, DateTime, null: false - index [:validator_index] - index [:test_suite_id] + column :validator_name, String, null: false, size: 255 + column :suite_options, String, text: true, size: 255 + column :last_accessed, DateTime, null: false + index [:validator_name, :test_suite_id, :suite_options] end end end diff --git a/lib/inferno/db/schema.rb b/lib/inferno/db/schema.rb index 040e07b4fa..2cd969dc88 100644 --- a/lib/inferno/db/schema.rb +++ b/lib/inferno/db/schema.rb @@ -28,14 +28,13 @@ String :validator_session_id, :size=>255, :null=>false String :test_suite_id, :size=>255, :null=>false String :validator_name, :size=>255, :null=>false - String :validator_index, :size=>255, :null=>false - DateTime :created_at, :null=>false - DateTime :updated_at, :null=>false + String :suite_options, :text=>true + DateTime :last_accessed, :null=>false primary_key [:id] - index [:test_suite_id] - index [:validator_index] + index [:validator_session_id], :name=>:sqlite_autoindex_validator_sessions_2, :unique=>true + index [:validator_name, :test_suite_id, :suite_options] end create_table(:session_data, :ignore_index_errors=>true) do diff --git a/lib/inferno/dsl/fhir_resource_validation.rb b/lib/inferno/dsl/fhir_resource_validation.rb index e7bd2598f1..7dc68d1929 100644 --- a/lib/inferno/dsl/fhir_resource_validation.rb +++ b/lib/inferno/dsl/fhir_resource_validation.rb @@ -27,10 +27,12 @@ def self.included(klass) class Validator attr_reader :requirements - attr_accessor :session_id + attr_accessor :session_id, :name, :test_suite_id # @private - def initialize(requirements = nil, &) + def initialize(name = nil, test_suite_id = nil, requirements = nil, &) + @name = name + @test_suite_id = test_suite_id instance_eval(&) @requirements = requirements end @@ -231,6 +233,10 @@ def issue_message(issue, resource) # @private def wrap_resource_for_hl7_wrapper(resource, profile_url) + validator_session_id = + Inferno::Repositories::ValidatorSessions.new.find_validator_session_id(test_suite_id, + name.to_s, requirements) + @session_id = validator_session_id if validator_session_id wrapped_resource = { cliContext: { **cli_context.definition, @@ -353,7 +359,7 @@ def fhir_validators def fhir_resource_validator(name = :default, required_suite_options: nil, &block) current_validators = fhir_validators[name] || [] - new_validator = Inferno::DSL::FHIRResourceValidation::Validator.new(required_suite_options, &block) + new_validator = Inferno::DSL::FHIRResourceValidation::Validator.new(name, id, required_suite_options, &block) current_validators.reject! { |validator| validator.requirements == required_suite_options } current_validators << new_validator diff --git a/lib/inferno/entities/validator_session.rb b/lib/inferno/entities/validator_session.rb index d602cddcb0..61eb5f36db 100644 --- a/lib/inferno/entities/validator_session.rb +++ b/lib/inferno/entities/validator_session.rb @@ -1,25 +1,22 @@ module Inferno - module Entities - class ValidatorSession < Entity - ATTRIBUTES = [ - :id, - :created_at, - :updated_at, - :validator_session_id, - :test_suite_id, - :validator_name, - :validator_index - ].freeze - - include Inferno::Entities::Attributes - - def initialize(params) - super(params, ATTRIBUTES) - end - - def test_suite - @test_suite ||= Repositories::TestSuites.new.find(test_suite_id) - end + module Entities + class ValidatorSession < Entity + ATTRIBUTES = [ + :id, + :created_at, + :updated_at, + :validator_session_id, + :test_suite_id, + :validator_name, + :suite_options, + :validator_index + ].freeze + + include Inferno::Entities::Attributes + + def initialize(params) + super(params, ATTRIBUTES) end end - end \ No newline at end of file + end +end diff --git a/lib/inferno/jobs/invoke_validator_session.rb b/lib/inferno/jobs/invoke_validator_session.rb index bb94e20b7d..063fcde33f 100644 --- a/lib/inferno/jobs/invoke_validator_session.rb +++ b/lib/inferno/jobs/invoke_validator_session.rb @@ -1,10 +1,9 @@ - module Inferno module Jobs class InvokeValidatorSession include Sidekiq::Worker - def perform(suite_id, validator_name, validator_index) + def perform(suite_id, validator_name, validator_index, required_suite_options) suite = Inferno::Repositories::TestSuites.new.find suite_id validator = suite.fhir_validators[validator_name.to_sym][validator_index] response_body = validator.validate(FHIR::Patient.new, 'http://hl7.org/fhir/StructureDefinition/Patient') @@ -12,12 +11,8 @@ def perform(suite_id, validator_name, validator_index) res = JSON.parse(response_body) session_id = res['sessionId'] session_repo = Inferno::Repositories::ValidatorSessions.new - begin - result = session_repo.create(test_suite_id: suite_id, validator_session_id: session_id, \ - validator_name: validator_name, validator_index: validator_index) - rescue Sequel::ValidationFailed => e - puts e.message - end + session_repo.save(test_suite_id: suite_id, validator_session_id: session_id, + validator_name:, suite_options: required_suite_options) validator.session_id = session_id else Inferno::Application['logger'].error("InvokeValidatorSession - error from validator: #{response_body}") diff --git a/lib/inferno/repositories.rb b/lib/inferno/repositories.rb index c08a5ed13f..aecea7367c 100644 --- a/lib/inferno/repositories.rb +++ b/lib/inferno/repositories.rb @@ -3,7 +3,6 @@ require_relative 'repositories/test_groups' require_relative 'repositories/test_suites' require_relative 'repositories/tests' -require_relative 'repositories/validator_sessions' # Skip loading things which require the db when not necessary, such as CLI # commands which don't need the db diff --git a/lib/inferno/repositories/validator_sessions.rb b/lib/inferno/repositories/validator_sessions.rb index 0bf76a4f2e..55f5ae57f1 100644 --- a/lib/inferno/repositories/validator_sessions.rb +++ b/lib/inferno/repositories/validator_sessions.rb @@ -9,37 +9,49 @@ def save(params) validator_session_id = params[:validator_session_id] validator_name = params[:validator_name] test_suite_id = params[:test_suite_id] - validator_index = params[:validator_index] + raw_suite_options = params[:suite_options] + time = Time.now + + suite_options = + if raw_suite_options.blank? + '[]' + else + JSON.generate(raw_suite_options.map(&:to_hash)) + end db.insert_conflict( - target: :validator_session_id, - update: { validator_session_id:, - test_suite_id:, - validator_name:, - validator_index:} - ).insert( - validator_session_id:, - test_suite_id:, - validator_name:, - validator_index: - ) + target: :validator_session_id, + update: { validator_session_id:, + test_suite_id:, + suite_options:, + validator_name: + } + ).insert( + id: "#{validator_session_id}_#{validator_name}", + validator_session_id:, + test_suite_id:, + validator_name:, + suite_options:, + last_accessed: time + ) end - def validation_session(test_suite_id, validator_name, validator_index) - validation_session_id = - self.class::Model - .find(test_suite_id: test_suite_id, \ - validator_name: validator_name, validator_index: validator_index)[:validator_session_id] + def find_validator_session_id(test_suite_id, validator_name, suite_options) + suite_options = "[]" if suite_options.nil? + session = self.class::Model + .find(test_suite_id:, validator_name:, suite_options:) + return nil if session.nil? + time = Time.now + session_id = session[:validator_session_id] + rec = self.class::Model.where(:validator_session_id=>session_id).update(:last_accessed=>time) + session_id end class Model < Sequel::Model(db) - def before_create - self.id = Base62.encode(SecureRandom.random_number(2**64)) + def before_save time = Time.now - self.created_at ||= time - self.updated_at ||= time - super + self.last_accessed ||= time end end end diff --git a/spec/inferno/repositories/fhir_resource_validation_spec.rb b/spec/inferno/repositories/fhir_resource_validation_spec.rb new file mode 100644 index 0000000000..440f222fdc --- /dev/null +++ b/spec/inferno/repositories/fhir_resource_validation_spec.rb @@ -0,0 +1,96 @@ +RSpec.describe Inferno::Repositories::ValidatorSessions do + let(:repo) { described_class.new } + let(:validator_name) { 'basic_name' } + let(:test_suite_id) { 'basic_suite' } + let(:validator_session_id1) { 'basic_validator1' } + let(:validator_session_id2) { 'basic_validator2' } + let(:suite_options1) {[Inferno::DSL::SuiteOption.new(id: :ig_version, value: '1')]} + let(:suite_options2) {[Inferno::DSL::SuiteOption.new(id: :ig_version, value: '2')]} + let(:session1_params) do + { + validator_session_id: validator_session_id1, + validator_name: validator_name, + test_suite_id: test_suite_id, + suite_options: suite_options1 + } + end + let(:session2_params) do + { + validator_session_id: validator_session_id2, + validator_name: validator_name, + test_suite_id: test_suite_id, + suite_options: suite_options2 + } + end + let(:session3_params) do + { + validator_session_id: validator_session_id1, + validator_name: 'new_name', + test_suite_id: test_suite_id, + suite_options: suite_options1 + } + end + + describe '#create' do + + before do + repo.save(session1_params) + end + + context 'with valid params' do + it 'persists data' do + record = repo.db.first + expect(repo.db.count).to eq(1) + expect(record[:validator_session_id]).to eq(validator_session_id1) + expect(record[:validator_name]).to eq(validator_name) + expect(record[:test_suite_id]).to eq(test_suite_id) + end + + it 'creates a separate record given a different validator session id' do + repo.save(session2_params) + record = repo.db.all[1] + expect(repo.db.count).to eq(2) + expect(record[:validator_session_id]).to eq(validator_session_id2) + expect(record[:validator_name]).to eq(validator_name) + expect(record[:test_suite_id]).to eq(test_suite_id) + end + + it 'overwrites an existing record given the same validator session id' do + repo.save(session3_params) + record = repo.db.first + expect(repo.db.count).to eq(1) + expect(record[:validator_session_id]).to eq(validator_session_id1) + expect(record[:validator_name]).to eq('new_name') + expect(record[:test_suite_id]).to eq(test_suite_id) + end + end + end + + describe '#find' do + before do + repo.save(session1_params) + end + + it 'single record' do + record = repo.db.first + suite_options = JSON.generate(session1_params[:suite_options].map(&:to_hash)) + validator_id = repo.find_validator_session_id(session1_params[:test_suite_id], + session1_params[:validator_name], suite_options) + expect(record[:validator_session_id]).to eq(validator_id) + end + + it 'two record, discriminated by suite options' do + repo.save(session2_params) + record = repo.db.first + record2 = repo.db.all[1] + suite_options = JSON.generate(session1_params[:suite_options].map(&:to_hash)) + suite_options2 = JSON.generate(session2_params[:suite_options].map(&:to_hash)) + validator_id = repo.find_validator_session_id(session1_params[:test_suite_id], + session1_params[:validator_name], suite_options) + validator_id2 = repo.find_validator_session_id(session2_params[:test_suite_id], + session2_params[:validator_name], suite_options2) + expect(record[:validator_session_id]).to eq(validator_id) + expect(record2[:validator_session_id]).to eq(validator_id2) + end + end +end \ No newline at end of file