Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 74 additions & 56 deletions lib/us_core_test_kit/search_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,9 @@ def perform_post_search(get_search_resources, params)

check_search_response

post_search_resources = fetch_and_assert_all_bundled_resources.select { |resource| resource.resourceType == resource_type }
post_search_resources = fetch_and_assert_all_bundled_resources.select do |resource|
resource.resourceType == resource_type
end

filter_conditions(post_search_resources) if resource_type == 'Condition' && metadata.version == 'v5.0.1'
filter_devices(post_search_resources) if resource_type == 'Device'
Expand All @@ -150,7 +152,7 @@ def perform_post_search(get_search_resources, params)
search_variant_test_records[:post_variant] = true

assert get_resource_count == post_resource_count,
"Expected search by POST to return the same results as search by GET, " \
'Expected search by POST to return the same results as search by GET, ' \
"but GET search returned #{get_resource_count} resources, and POST search " \
"returned #{post_resource_count} resources."
end
Expand Down Expand Up @@ -293,18 +295,18 @@ def perform_search_with_system(params, patient_id)
fetch_and_assert_all_bundled_resources(params: search_params)
.select { |resource| resource.resourceType == resource_type }

assert resources_returned.present?, "No resources were returned when searching by `system|code`"
assert resources_returned.present?, 'No resources were returned when searching by `system|code`'

search_variant_test_records[:token_variants] = true
end

def perform_search_with_status(
original_params,
patient_id,
status_search_values: self.status_search_values,
resource_type: self.resource_type
)
assert resource.is_a?(FHIR::OperationOutcome), "Server returned a status of 400 without an OperationOutcome"
original_params,
patient_id,
status_search_values: self.status_search_values,
resource_type: self.resource_type
)
assert resource.is_a?(FHIR::OperationOutcome), 'Server returned a status of 400 without an OperationOutcome'
# TODO: warn about documenting status requirements
status_search_values.flat_map do |status_value|
search_params = original_params.merge("#{status_search_param_name}": status_value)
Expand Down Expand Up @@ -336,6 +338,11 @@ def default_search_values(param_name)
definition[:multiple_or] == 'SHALL' ? [definition[:values].join(',')] : Array.wrap(definition[:values])
end

def contains_all_search_params(resource, search_params)
search_params.keys.all? do |param_name|
resource.instance_variable_get("@#{param_name}").present? || param_name == 'patient'
end
end

def perform_multiple_or_search_test
resolved_one = false
Expand All @@ -350,7 +357,12 @@ def perform_multiple_or_search_test
multiple_or_search_params.each do |param_name|
search_value = default_search_values(param_name.to_sym)
search_params = search_params.merge("#{param_name}" => search_value)
existing_values[param_name.to_sym] = scratch_resources_for_patient(patient_id).map(&param_name.to_sym).compact.uniq

existing_values[param_name.to_sym] =
scratch_resources_for_patient(patient_id)
.filter { |resource| contains_all_search_params(resource, search_params) }
.map(&param_name.to_sym)
.compact.uniq
end

# skip patient without multiple-or values
Expand All @@ -365,15 +377,17 @@ def perform_multiple_or_search_test
.select { |resource| resource.resourceType == resource_type }

multiple_or_search_params.each do |param_name|
missing_values[param_name.to_sym] = existing_values[param_name.to_sym] - resources_returned.map(&param_name.to_sym)
missing_values[param_name.to_sym] =
existing_values[param_name.to_sym] - resources_returned.map(&param_name.to_sym)
end

missing_value_message = missing_values
.reject { |_param_name, missing_value| missing_value.empty? }
.map { |param_name, missing_value| "#{missing_value.join(',')} values from #{param_name}" }
.join(' and ')

assert missing_value_message.blank?, "Could not find #{missing_value_message} in any of the resources returned for Patient/#{patient_id}"
assert missing_value_message.blank?,
"Could not find #{missing_value_message} in any of the resources returned for Patient/#{patient_id}"

break if resolved_one
end
Expand Down Expand Up @@ -428,7 +442,8 @@ def test_medication_inclusion(base_resources, params, patient_id)
end

not_matched_included_medications_string = not_matched_included_medications.join(',')
assert not_matched_included_medications.empty?, "No #{resource_type} references #{not_matched_included_medications_string} in the search result."
assert not_matched_included_medications.empty?,
"No #{resource_type} references #{not_matched_included_medications_string} in the search result."

medications.uniq!(&:id)

Expand All @@ -438,8 +453,8 @@ def test_medication_inclusion(base_resources, params, patient_id)
search_variant_test_records[:medication_inclusion] = true
end

def is_reference_match? (reference, local_reference)
regex_pattern = /^(#{Regexp.escape(local_reference)}|\S+\/#{Regexp.escape(local_reference)}(?:[\/|]\S+)*)$/
def is_reference_match?(reference, local_reference)
regex_pattern = %r{^(#{Regexp.escape(local_reference)}|\S+/#{Regexp.escape(local_reference)}(?:[/|]\S+)*)$}
reference.match?(regex_pattern)
end

Expand Down Expand Up @@ -468,7 +483,7 @@ def fixed_value_search_param_values

def fixed_value_search_params(value, patient_id)
search_param_names.each_with_object({}) do |name, params|
patient_id_param?(name) ? params[name] = patient_id : params[name] = value
params[name] = patient_id_param?(name) ? patient_id : value
end
end

Expand All @@ -482,9 +497,14 @@ def search_params_with_values(search_param_names, patient_id, include_system: fa
end
end

params_with_partial_value = resources.each_with_object({}) do |resource, outer_params|
resources.each_with_object({}) do |resource, outer_params|
results_from_one_resource = search_param_names.each_with_object({}) do |name, params|
value = patient_id_param?(name) ? patient_id : search_param_value(name, resource, include_system: include_system)
value = if patient_id_param?(name)
patient_id
else
search_param_value(name, resource,
include_system: include_system)
end
params[name] = value
end

Expand All @@ -493,8 +513,6 @@ def search_params_with_values(search_param_names, patient_id, include_system: fa
# stop if all parameter values are found
return outer_params if outer_params.all? { |_key, value| value.present? }
end

params_with_partial_value
end

def patient_id_list
Expand All @@ -513,9 +531,7 @@ def patient_id_param?(name)

def search_param_paths(name)
paths = metadata.search_definitions[name.to_sym][:paths]
if paths.first =='class'
paths[0] = 'local_class'
end
paths[0] = 'local_class' if paths.first == 'class'

paths
end
Expand All @@ -539,39 +555,40 @@ def empty_search_params_message(empty_search_params)
def no_resources_skip_message(resource_type = self.resource_type)
msg = "No #{resource_type} resources appear to be available"

if (resource_type == 'Device' && implantable_device_codes.present?)
if resource_type == 'Device' && implantable_device_codes.present?
msg.concat(" with the following Device Type Code filter: #{implantable_device_codes}")
end

msg + ". Please use patients with more information"
msg + '. Please use patients with more information'
end

def fetch_and_assert_all_bundled_resources(
resource_type: self.resource_type,
reply_handler: nil,
max_pages: 20,
additional_resource_types: [],
params: nil
)
tags = tags(params)
bundle = resource
additional_resource_types << 'Medication' if ['MedicationRequest', 'MedicationDispense'].include?(resource_type)

assert_handler = Proc.new do |response|
assert_response_status(200, response: response)
assert_valid_json(response[:body], "Could not resolve bundle as JSON: #{response[:body]}")
end
resource_type: self.resource_type,
reply_handler: nil,
max_pages: 20,
additional_resource_types: [],
params: nil
)
tags = tags(params)
bundle = resource
additional_resource_types << 'Medication' if ['MedicationRequest', 'MedicationDispense'].include?(resource_type)

assert_handler = proc do |response|
assert_response_status(200, response: response)
assert_valid_json(response[:body], "Could not resolve bundle as JSON: #{response[:body]}")
end

if reply_handler
reply_and_assert_handler = Proc.new do |response|
assert_handler.call(response)
reply_handler.call(response)
end
else
reply_and_assert_handler = assert_handler
end
reply_and_assert_handler = if reply_handler
proc do |response|
assert_handler.call(response)
reply_handler.call(response)
end
else
assert_handler
end

fetch_all_bundled_resources(resource_type:, bundle:, reply_handler: reply_and_assert_handler, max_pages:, additional_resource_types:, tags:)
fetch_all_bundled_resources(resource_type:, bundle:, reply_handler: reply_and_assert_handler, max_pages:,
additional_resource_types:, tags:)
end

def search_param_value(name, resource, include_system: false)
Expand Down Expand Up @@ -619,8 +636,8 @@ def search_param_value(name, resource, include_system: false)
# Goal.target-date has day precision
# All others have second + time offset precision
if /^\d{4}(-\d{2})?$/.match?(element) || # YYYY or YYYY-MM
(/^\d{4}-\d{2}-\d{2}$/.match?(element) && resource_type != "Goal") # YYY-MM-DD AND Resource is NOT Goal
"gt#{(DateTime.xmlschema(element)-1).xmlschema}"
(/^\d{4}-\d{2}-\d{2}$/.match?(element) && resource_type != 'Goal') # YYY-MM-DD AND Resource is NOT Goal
"gt#{(DateTime.xmlschema(element) - 1).xmlschema}"
else
element
end
Expand All @@ -632,8 +649,7 @@ def search_param_value(name, resource, include_system: false)
break if search_value.present?
end

escaped_value = search_value&.gsub(',', '\\,')
escaped_value
search_value&.gsub(',', '\\,')
end

def element_has_valid_value?(element, include_system)
Expand Down Expand Up @@ -669,12 +685,14 @@ def save_resource_reference(resource_type, reference)
scratch[:references][resource_type] << reference
end

def save_delayed_references(resources, containing_resource_type = self.resource_type)
def save_delayed_references(resources, containing_resource_type = resource_type)
resources.each do |resource|
references_to_save(containing_resource_type).each do |reference_to_save|
resolve_path(resource, reference_to_save[:path])
.select { |reference| reference.is_a?(FHIR::Reference) &&
!reference.contained? && reference.reference.present? }
.select do |reference|
reference.is_a?(FHIR::Reference) &&
!reference.contained? && reference.reference.present?
end
.each do |reference|
resource_type = reference.resource_class.name.demodulize
need_to_save = reference_to_save[:resources].include?(resource_type)
Expand Down Expand Up @@ -779,7 +797,7 @@ def resource_matches_param?(resource, search_param_name, escaped_search_value, v
values_found.any? { |identifier| identifier.value == search_value }
end
when 'string'
searched_values = search_value.downcase.split(/(?<!\\\\),/).map{ |string| string.gsub('\\,', ',') }
searched_values = search_value.downcase.split(/(?<!\\\\),/).map { |string| string.gsub('\\,', ',') }
values_found.any? do |value_found|
searched_values.any? { |searched_value| value_found.downcase.starts_with? searched_value }
end
Expand Down
Loading