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 12 commits
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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ TestScript Engine is in the early stages of development; it is neither functiona

- `[FHIR Server URL]`
- Full URL of the FHIR server being tested. Defaults to the public instance of HAPI FHIR.
- If a TestScript contains multi destinations, corresponding server URLs need to be entered.
- If a TestScript contains multiple destinations, corresponding base endpoints need to be entered at run time.
- `[TestScript Folder]`
- Relative or full path to a folder of TestScript resources. Defaults to `./TestScripts`
- `[TestScript file]`
- `[TestScript File]`
- Specify one or more TestScript file names to be executed.

**Folders and Files:**
Expand Down
34 changes: 12 additions & 22 deletions lib/TestScriptEngine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
require_relative './MessageHandler'

class TestScriptEngine
prepend MessageHandler
prepend MessageHandler

attr_accessor :endpoint, :directory_path, :file_name
attr_accessor :endpoints, :directory_path, :file_name

def scripts
@scripts ||= {}
Expand All @@ -24,18 +24,15 @@ def root
directory_path || "../TestScripts"
end

<<<<<<< HEAD
def client
@client ||= begin
info(:begin_initialize_client)
client = FHIR::Client.new(endpoint || 'localhost:3000')
info(:finish_initialize_client)
client
end
end
# def client
# @client ||= begin
# info(:begin_initialize_client)
# client = FHIR::Client.new(endpoint || 'localhost:3000')
# info(:finish_initialize_client)
# client
# end
# end

=======
>>>>>>> c6f4de8 (Added multi-destination features, example testscript)
def initialize(endpoints = nil, directory_path = nil, file_name = nil)
self.endpoints = endpoints
self.directory_path = directory_path
Expand Down Expand Up @@ -113,27 +110,20 @@ def make_runnables script = nil
def execute_runnables runnable_id = nil
if runnable_id
if runnables[runnable_id]
<<<<<<< HEAD
reports[runnable_id] = runnable.run client
=======
puts "\nBeggining execution of #{runnable_id}.\n\n"
reports[runnable_id] = runnable.execute
puts "\nFinished execution of #{runnable_id}. Score: #{reports[runnable_id].score} \n"
>>>>>>> c6f4de8 (Added multi-destination features, example testscript)

else
error(:no_runnable_stored, runnable_id)
end
else
runnables.each do |id, runnable|
<<<<<<< HEAD
reports[id] = runnable.run client
end
=======
puts "\nBeggining execution of #{id}.\n\n"
runnable.endpoints(endpoints)
reports[id] = runnable.run
puts "\nFinished execution of #{id}. Score: #{reports[id].score} \n"
end
>>>>>>> c6f4de8 (Added multi-destination features, example testscript)
end
end

Expand Down
69 changes: 28 additions & 41 deletions lib/TestScriptRunnable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ def autocreate_ids
@autocreate_ids ||= []
end

def eps
@eps ||= []
end

def autodelete_ids
@autodelete_ids ||= []
end
Expand All @@ -53,12 +57,19 @@ def script(script = nil)
@script
end

def client(endpoints, script)
def endpoints(endpoints = nil)
@endpoints = endpoints if endpoints
@endpoints
end

def client(script)
if script.destination.length > endpoints.length
FHIR.logger.error "[.initialize] Not enough server endpoints (#{endpoints.length}) for destination (#{script.destination.length}) in TestScript"
exit
end

info(:begin_initialize_client)

@clients = Hash[]
if script.destination.length == 0
@clients.store (0), (FHIR::Client.new(endpoints[0] || 'localhost:3000'))
Expand All @@ -68,9 +79,11 @@ def client(endpoints, script)
script.destination.each do |destination|
@clients.store (destination.index), (FHIR::Client.new(endpoints[destination.index-1] || 'localhost:3000'))
end

info(:finish_initialize_client)
end

def get_client(destination)
def get_client(destination = nil)
return @clients[0] if destination == nil
return @clients[destination]
end
Expand All @@ -96,9 +109,8 @@ def initialize endpoints, script
# preprocessing
end

<<<<<<< HEAD
def run(client = nil)
client(client)
def run
client(script)
fresh_testreport

preprocessing # TODO: remove this
Expand All @@ -122,7 +134,7 @@ def preprocessing
load_fixtures

autocreate_ids.each do |fixture_id|
client.send(*create_request((operation_create(fixture_id))))
get_client.send(*create_request((operation_create(fixture_id))))
end
end

Expand All @@ -139,10 +151,9 @@ def teardown
end

def postprocessing

autodelete_ids.each do |fixture_id|
FHIR.logger.info "Auto-deleting dynamic fixture #{fixture_id}"
client.send(*create_request((operation_delete(fixture_id))))
get_client.send(*create_request((operation_delete(fixture_id))))
end
end

Expand Down Expand Up @@ -181,6 +192,7 @@ def load_fixtures
return FHIR.logger.info '[.load_fixtures] No fixture found' if script.fixture.length == 0

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 @@ -233,13 +245,8 @@ def execute_operation(op)
end

begin
<<<<<<< HEAD
#binding.pry
client.send(*request)
=======
#binding.pry
get_client(op.destination).send(*request)
jhlee-mitre marked this conversation as resolved.
Show resolved Hide resolved
>>>>>>> c6f4de8 (Added multi-destination features, example testscript)

rescue StandardError => e
fail(:execute_operation_error, (op.label || 'unlabeled'), e.message ) # TODO: Switch to ERROR
reply = nil
Expand All @@ -264,31 +271,6 @@ 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.
Expand Down Expand Up @@ -359,14 +341,19 @@ def successful? code
end

def storage(op)
self.reply = get_client(op.destination).reply
reply.nil? ? return : get_client(op.destination).reply = nil
client = get_client(op.destination)
self.reply = client.reply
reply.nil? ? return : client.reply = nil

request_map[op.requestId] = reply.request if op.requestId
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]

FHIR.logger.info "[.execute_operation] Result code: " + reply.response[:code].to_s

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

test_server_url = "http:https://hapi.fhir.org/baseR4" #'http:https://server.fire.ly' # #
testscript_path = '../TestScripts'
testscript_file = nil

parameters = ARGV
parameters.each do |parameter|
if parameter.start_with?('http')
test_server_url = parameter
elsif parameter.include?('.json') || parameter.include?('.xml')
testscript_file = parameter
=======
endpoints = []
directory_path = '../TestScripts'
file_name = nil
Expand All @@ -23,7 +12,6 @@
parameters.each do |parameter|
if parameter.include?('.json') || parameter.include?('.xml')
jhlee-mitre marked this conversation as resolved.
Show resolved Hide resolved
file_name = parameter
>>>>>>> c6f4de8 (Added multi-destination features, example testscript)
elsif parameter.include?('http')
endpoints << parameter
else
Expand Down
51 changes: 29 additions & 22 deletions spec/store_response_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@
let(:id_map) { { targetId => serverId } }
let(:operation) { FHIR::TestScript::Setup::Action::Operation.new }
let(:client_reply) { FHIR::ClientReply.new(request, response, client) }
let(:endpoints) {[]}
let(:script) {
FHIR::TestScript.new(
{
"resourceType": 'TestScript',
"url": 'http:https://hl7.org/fhir/TestScript/testscript-example-history',
"name": 'TestScript-Example-History',
"status": 'draft',
"destination": []
}
)
}
let(:request) do
{
method: :get,
Expand All @@ -29,24 +41,19 @@
}
end
let(:runnable) do
TestScriptRunnable.new FHIR::TestScript.new(
{
"resourceType": 'TestScript',
"url": 'http:https://hl7.org/fhir/TestScript/testscript-example-history',
"name": 'TestScript-Example-History',
"status": 'draft'
}
)
TestScriptRunnable.new script
end

before do
runnable.id_map[targetId] = serverId
runnable.client.reply = client_reply
runnable.endpoints(endpoints)
runnable.client(script)
runnable.get_client.reply = client_reply
end

context '#storage' do
context 'with client.reply == nil' do
before { runnable.client.reply = nil }
before { runnable.get_client.reply = nil }

it 'sets @reply to nil' do
runnable.storage(operation)
Expand All @@ -57,7 +64,7 @@
it 'sets client.reply to nil' do
runnable.storage(operation)

expect(runnable.client.reply).to be_nil
expect(runnable.get_client.reply).to be_nil
end

it 'returns nil' do
Expand All @@ -75,7 +82,7 @@
it 'sets client.reply to nil' do
runnable.storage(operation)

expect(runnable.client.reply).to be_nil
expect(runnable.get_client.reply).to be_nil
end

context 'with op.requestId' do
Expand Down Expand Up @@ -107,7 +114,7 @@
end

context 'with non-FHIR resource response' do
before { runnable.client.reply.response[:body] = nil }
before { runnable.get_client.reply.response[:body] = nil }

it 'ignores reply.resource' do
runnable.storage(operation)
Expand All @@ -129,8 +136,8 @@

context 'with unsuccessful :delete' do
before do
runnable.client.reply.request[:method] = :delete
runnable.client.reply.response[:code] = 400
runnable.get_client.reply.request[:method] = :delete
runnable.get_client.reply.response[:code] = 400
end

it "doesn't delete @id_map[targetId]" do
Expand All @@ -142,8 +149,8 @@

context 'with successful :delete' do
before do
runnable.client.reply.request[:method] = :delete
runnable.client.reply.response[:code] = 204
runnable.get_client.reply.request[:method] = :delete
runnable.get_client.reply.response[:code] = 204
end

it 'deletes @id_map[targetId]' do
Expand All @@ -159,8 +166,8 @@
operation.requestId = requestId
operation.responseId = responseId
operation.targetId = targetId
runnable.client.reply.request[:method] = :delete
runnable.client.reply.response[:code] = 204
runnable.get_client.reply.request[:method] = :delete
runnable.get_client.reply.response[:code] = 204
end

it 'stores both request and response and deletes @id_map[targetId]' do
Expand Down Expand Up @@ -195,7 +202,7 @@
end

context 'without reply.resource and with location header' do
before { runnable.client.reply.response[:body] = nil }
before { runnable.get_client.reply.response[:body] = nil }

context 'with op.responseId' do
before { operation.responseId = responseId }
Expand All @@ -220,8 +227,8 @@

context 'without reply.resource nor location header' do
before do
runnable.client.reply.response[:body] = nil
runnable.client.reply.response[:headers] = nil
runnable.get_client.reply.response[:body] = nil
runnable.get_client.reply.response[:headers] = nil
end

it 'ignores id_map and returns nil' do
Expand Down