Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multi destination #26

Closed
wants to merge 16 commits into from
Closed
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
Prev Previous commit
Next Next commit
WIP
  • Loading branch information
jhlee-mitre committed Sep 7, 2022
commit c3054829bde914f8b66ad7eb90bad4b0354ad444
4 changes: 2 additions & 2 deletions lib/TestScriptEngine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ def client
end
end

def initialize(endpoint = nil, directory_path = nil, file_name = nil)
self.endpoint = endpoint
def initialize(endpoints = nil, directory_path = nil, file_name = nil)
self.endpoints = endpoints
self.directory_path = directory_path
self.file_name = file_name
self.debug_mode = true
Expand Down
71 changes: 57 additions & 14 deletions lib/TestScriptRunnable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,12 @@ def operation_delete(sourceId)
end

def load_fixtures
if script.fixture.length == 0
then FHIR.logger.info '[.load_fixtures] No fixture found'
return
end

FHIR.logger.info 'Beginning loading fixtures.'
script.fixture.each do |fixture|
info(:no_static_fixture_id) unless fixture.id
info(:no_static_fixture_resource) unless fixture.resource
Expand Down Expand Up @@ -194,16 +200,22 @@ def execute_operation(op)
return false
end

FHIR.logger.info "[.execute_operation] " + op.description
FHIR.logger.info "[.execute_operation] Destination: " + op.destination.to_s if op.destination != nil

request = create_request(op)
if request.nil?
fail(:invalid_request, (op.label || "unlabeled"))
reply = nil
return false
end

# FHIR.logger.info "[.execute_operation] Request: " + request.to_s

begin
#binding.pry
client.send(*request)

rescue StandardError => e
fail(:execute_operation_error, (op.label || 'unlabeled'), e.message ) # TODO: Switch to ERROR
reply = nil
Expand All @@ -228,22 +240,54 @@ def create_request(op)
request.compact
end

# The assertion to perform
# + Rule: Only a single assertion SHALL be present within setup action assert element.
# + Rule: Setup action assert SHALL contain either compareToSourceId and compareToSourceExpression, compareToSourceId and compareToSourcePath or neither.
# + Rule: Setup action assert response and responseCode SHALL be empty when direction equals request
def evaluate assertion
return unless assertion

return report.fail 'invalidAssert' unless assertion.is_a? FHIR::TestScript::Setup::Action::Assert

assertTypes = ['compareToSourceExpression', 'compareToSourcePath', 'contentType', 'expression', 'headerField', 'minimumId', 'navigationLinks', 'path', 'requestMethod', 'requestURL', 'response', 'responseCode', 'resource', 'validateProfileId']

begin
rawType = assertion.to_hash.find { |k, v| assertTypes.include? k }
assertType = rawType[0].split(/(?<=\p{Ll})(?=\p{Lu})|(?<=\p{Lu})(?=\p{Lu}\p{Ll})/).map(&:downcase).join('_')
self.send(("assert_#{assertType}").to_sym, assertion)

rescue AssertionException => e
return assertion.warningOnly ? report.warning(e.message) : report.fail(e.message)
rescue StandardError => e
FHIR.logger.error "Unable to process assertion. Error: #{e.message}"
report.error e.message
return
end
report.pass
end

def extract_path(operation, request_type)
# If "url" element is defined, then "targetId", "resource", and "params" elements will be ignored.
# Test engines would use whatever is specified in "url" without tampering with the string (beyond encoding the URL for HTTP).
# Test engines do have to look for placeholders (${}) and replace the variable placeholders with the variable values at runtime before sending the request.
return replace_variables(operation.url) if operation.url

# If "params" element is specified, then "targetId" element is ignored.
# For FHIR operations that require a resource (e.g. "read" and "vread" operations), the "resource" element must be specified when "params" element is specified.
if operation.params
mime = "_format=#{get_format(operation.contentType)}" if operation.contentType
params = "#{replace_variables(operation.params)}"
params = "?_#{params}" if params and !params.start_with?('/')
if mime
if params
mime = "&#{mime}"
else
mime = "?#{mime}"
end
end
search = '/_search' if request_type == :post and params.start_with?("?")
"#{operation.resource}#{search}#{params}#{mime}"
mime = "&_format=#{get_format(operation.contentType)}" if operation.contentType
params = "#{replace_variables(operation.params)}#{mime}"
search = '/_search' if request_type == :post
"#{operation.resource}#{search}#{params}"
# If "url" and "params" elements are absent, then the request url will be constructed from "targetId" fixture if present.
# For "read" operation, the resource and id values will be extracted from "targetId" fixture and used to construct the url.
# For "vread" and "history" operations, the versionId value will also be used.
# Test engines would append whatever is specified for "params" to the URL after the resource type without tampering with the string (beyond encoding the URL for HTTP).
# The "params" element does not correspond exactly to "search parameters". Nor is it the "path".
# It corresponds to the part of the URL that comes after the [type] (when "resource" element is specified);
# e.g. It corresponds to "/[id]/_history/[vid] {?_format=[mime-type]}" in the following operation:
# GET [base]/[type]/[id]/_history/[vid] {?_format=[mime-type]}
# Test engines do have to look for placeholders (${}) and replace the variable placeholders with the variable values at runtime before sending the request.
elsif operation.targetId
resource = response_map[operation.targetId]&.[](:body)
return if (resource.nil? and SENDERS.include?(request_type))
Expand All @@ -252,6 +296,7 @@ def extract_path(operation, request_type)
return unless type
id = id_map[operation.targetId]
return "#{type}/#{id}" unless type.nil? || id.nil?
# sourceId: the id of the fixture used as the body of a PUT or POST request
elsif operation.sourceId
(fixtures[operation.sourceId] || begin
resource = response_map[operation.sourceId]&.[](:body)
Expand Down Expand Up @@ -297,8 +342,6 @@ def storage(op)
response_map[op.responseId] = reply.response if op.responseId

(reply.resource = FHIR.from_contents(reply.response&.[](:body).to_s)) rescue {}
(reply.response[:body] = reply.resource)
response_map[op.responseId][:body] = reply.resource if reply.resource and response_map[op.responseId]

if op.targetId and (reply.request[:method] == :delete) and successful?(reply.response[:code])
id_map.delete(op.targetId) and return
Expand Down
6 changes: 3 additions & 3 deletions lib/driver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@
end
end

puts "SERVER: #{test_server_url}"
puts "SERVER: #{test_server_urls}"
puts "TESTSCRIPT PATH: #{testscript_path}"
puts "TESTSCRIPT FILE: #{testscript_file}"

default_engine = TestScriptEngine.new(test_server_url, testscript_path, testscript_file)
default_engine = TestScriptEngine.new(test_server_urls, testscript_path, testscript_file)
default_engine.load_scripts
default_engine.make_runnables
default_engine.execute_runnables
default_engine.write_reports
# default_engine.write_reports

#default_engine.generate_runnables
# default_engine.execute(FHIR::Client.new('http:https://hapi.fhir.org/baseR4'))