inferno_core 0.0.5 → 0.0.8.pre2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/inferno +7 -0
- data/lib/inferno/apps/cli/console.rb +12 -0
- data/lib/inferno/apps/cli/main.rb +18 -0
- data/lib/inferno/apps/cli/migration.rb +14 -0
- data/lib/inferno/apps/cli.rb +8 -0
- data/lib/inferno/apps/web/controllers/test_runs/create.rb +15 -2
- data/lib/inferno/apps/web/index.html.erb +1 -0
- data/lib/inferno/apps/web/serializers/hash_value_extractor.rb +11 -0
- data/lib/inferno/apps/web/serializers/test.rb +3 -4
- data/lib/inferno/apps/web/serializers/test_group.rb +4 -6
- data/lib/inferno/config/application.rb +4 -0
- data/lib/inferno/config/boot/db.rb +1 -9
- data/lib/inferno/config/boot/logging.rb +2 -0
- data/lib/inferno/config/boot/suites.rb +4 -6
- data/lib/inferno/db/migrations/001_create_initial_structure.rb +1 -1
- data/lib/inferno/db/schema.rb +1 -1
- data/lib/inferno/dsl/assertions.rb +85 -0
- data/lib/inferno/dsl/configurable.rb +126 -0
- data/lib/inferno/dsl/fhir_client.rb +22 -16
- data/lib/inferno/dsl/fhir_client_builder.rb +3 -3
- data/lib/inferno/dsl/fhir_validation.rb +105 -1
- data/lib/inferno/dsl/http_client.rb +14 -12
- data/lib/inferno/dsl/http_client_builder.rb +3 -3
- data/lib/inferno/dsl/request_storage.rb +26 -17
- data/lib/inferno/dsl/results.rb +1 -1
- data/lib/inferno/dsl/resume_test_route.rb +10 -10
- data/lib/inferno/dsl/runnable.rb +104 -38
- data/lib/inferno/entities/header.rb +14 -7
- data/lib/inferno/entities/message.rb +16 -8
- data/lib/inferno/entities/request.rb +34 -21
- data/lib/inferno/entities/result.rb +36 -29
- data/lib/inferno/entities/session_data.rb +12 -6
- data/lib/inferno/entities/test.rb +29 -2
- data/lib/inferno/entities/test_group.rb +8 -0
- data/lib/inferno/entities/test_run.rb +29 -6
- data/lib/inferno/entities/test_session.rb +16 -10
- data/lib/inferno/exceptions.rb +12 -0
- data/lib/inferno/public/217.bundle.js +1 -1
- data/lib/inferno/public/bundle.js +154 -1
- data/lib/inferno/public/bundle.js.LICENSE.txt +15 -0
- data/lib/inferno/repositories/in_memory_repository.rb +1 -1
- data/lib/inferno/repositories/results.rb +1 -1
- data/lib/inferno/repositories/test_runs.rb +15 -0
- data/lib/inferno/spec_support.rb +1 -1
- data/lib/inferno/test_runner.rb +21 -19
- data/lib/inferno/utils/markdown_formatter.rb +15 -0
- data/lib/inferno/utils/middleware/request_logger.rb +9 -3
- data/lib/inferno/utils/migration.rb +17 -0
- data/lib/inferno/version.rb +1 -1
- data/lib/inferno.rb +0 -4
- data/spec/factories/request.rb +14 -7
- metadata +46 -10
- data/bin/inferno-console +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 323de6e32c25feac594840493d69222a2388bdabef39c36a5d378a1cfeb2b7cc
|
4
|
+
data.tar.gz: d08c713be3303b146a40a6316765e017d76a4213e3981c6121fd502e7eb4e577
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1dfa395166fd30624510ff16f12a216b5580f60265bf8512391fd50d731c9bf7022aec60fa0527aa55e7de48d7fc38c16bb2b4777666c7947c632f6ce4dc2c6a
|
7
|
+
data.tar.gz: 207262300f159a2eb75bca71f95c8550169dc19488e826d4a2e97556d3c9722ce9bdf97436c9f862cddde5ab62b9d2be4895703c02da5c8eac6cf24cdb4e4475
|
data/bin/inferno
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative 'console'
|
2
|
+
require_relative 'migration'
|
3
|
+
|
4
|
+
module Inferno
|
5
|
+
module CLI
|
6
|
+
class Main < Thor
|
7
|
+
desc 'console', 'Start an interactive console session with Inferno'
|
8
|
+
def console
|
9
|
+
Console.new.run
|
10
|
+
end
|
11
|
+
|
12
|
+
desc 'migrate', 'Run database migrations'
|
13
|
+
def migrate
|
14
|
+
Migration.new.run
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -5,7 +5,8 @@ module Inferno
|
|
5
5
|
class Create < Controller
|
6
6
|
include Import[
|
7
7
|
test_sessions_repo: 'repositories.test_sessions',
|
8
|
-
session_data_repo: 'repositories.session_data'
|
8
|
+
session_data_repo: 'repositories.session_data',
|
9
|
+
test_runs_repo: 'repositories.test_runs'
|
9
10
|
]
|
10
11
|
|
11
12
|
PARAMS = [:test_session_id, :test_suite_id, :test_group_id, :test_id].freeze
|
@@ -14,8 +15,18 @@ module Inferno
|
|
14
15
|
test_session = test_sessions_repo.find(params[:test_session_id])
|
15
16
|
|
16
17
|
# if testsession.nil?
|
18
|
+
if test_runs_repo.active_test_run_for_session?(test_session.id)
|
19
|
+
self.status = 409
|
20
|
+
self.body = { error: 'Cannot run new test while another test run is in progress' }.to_json
|
21
|
+
return
|
22
|
+
end
|
17
23
|
|
18
24
|
test_run = repo.create(create_params(params).merge(status: 'queued'))
|
25
|
+
missing_inputs = test_run.runnable.missing_inputs(params[:inputs])
|
26
|
+
|
27
|
+
raise Inferno::Exceptions::RequiredInputsNotFound, missing_inputs if missing_inputs.any?
|
28
|
+
raise Inferno::Exceptions::NotUserRunnableException unless test_run.runnable.user_runnable?
|
29
|
+
|
19
30
|
self.body = serialize(test_run)
|
20
31
|
|
21
32
|
params[:inputs]&.each do |input|
|
@@ -27,7 +38,9 @@ module Inferno
|
|
27
38
|
end
|
28
39
|
|
29
40
|
Jobs.perform(Jobs::ExecuteTestRun, test_run.id)
|
30
|
-
rescue Sequel::ValidationFailed, Sequel::ForeignKeyConstraintViolation
|
41
|
+
rescue Sequel::ValidationFailed, Sequel::ForeignKeyConstraintViolation,
|
42
|
+
Inferno::Exceptions::RequiredInputsNotFound,
|
43
|
+
Inferno::Exceptions::NotUserRunnableException => e
|
31
44
|
self.body = { errors: e.message }.to_json
|
32
45
|
self.status = 422
|
33
46
|
rescue StandardError => e
|
@@ -4,11 +4,10 @@ module Inferno
|
|
4
4
|
class Test < Serializer
|
5
5
|
identifier :id
|
6
6
|
field :title
|
7
|
-
field :inputs
|
8
|
-
field :
|
9
|
-
test.outputs.map { |output| { name: output } }
|
10
|
-
end
|
7
|
+
field :input_definitions, name: :inputs, extractor: HashValueExtractor, blueprint: Input
|
8
|
+
field :output_definitions, name: :outputs, extractor: HashValueExtractor
|
11
9
|
field :description
|
10
|
+
field :user_runnable?, name: :user_runnable
|
12
11
|
end
|
13
12
|
end
|
14
13
|
end
|
@@ -4,18 +4,16 @@ module Inferno
|
|
4
4
|
class TestGroup < Serializer
|
5
5
|
identifier :id
|
6
6
|
|
7
|
-
# TODO: fill out test group
|
8
7
|
field :title
|
9
8
|
field :description
|
10
9
|
field :test_count
|
11
|
-
|
10
|
+
field :run_as_group?, name: :run_as_group
|
11
|
+
field :user_runnable?, name: :user_runnable
|
12
12
|
|
13
13
|
association :groups, name: :test_groups, blueprint: TestGroup
|
14
14
|
association :tests, blueprint: Test
|
15
|
-
field :inputs
|
16
|
-
field :
|
17
|
-
group.outputs.map { |input| { name: input } }
|
18
|
-
end
|
15
|
+
field :input_definitions, name: :inputs, extractor: HashValueExtractor, blueprint: Input
|
16
|
+
field :output_definitions, name: :outputs, extractor: HashValueExtractor
|
19
17
|
end
|
20
18
|
end
|
21
19
|
end
|
@@ -1,4 +1,7 @@
|
|
1
|
+
require 'active_support/all'
|
2
|
+
require 'dotenv'
|
1
3
|
require 'dry/system/container'
|
4
|
+
require 'sequel'
|
2
5
|
require_relative 'boot'
|
3
6
|
|
4
7
|
module Inferno
|
@@ -9,6 +12,7 @@ module Inferno
|
|
9
12
|
|
10
13
|
Application.register('js_host', ENV.fetch('JS_HOST', ''))
|
11
14
|
Application.register('async_jobs', ENV['ASYNC_JOBS'] != 'false')
|
15
|
+
Application.register('inferno_host', ENV.fetch('INFERNO_HOST', 'http://localhost:4567'))
|
12
16
|
|
13
17
|
configure do |config|
|
14
18
|
config.root = File.expand_path('../../..', __dir__)
|
@@ -12,6 +12,7 @@ Inferno::Application.boot(:db) do
|
|
12
12
|
config = YAML.load_file(config_path)[ENV['APP_ENV']]
|
13
13
|
.merge(logger: Inferno::Application['logger'])
|
14
14
|
connection = Sequel.connect(config)
|
15
|
+
connection.sql_log_level = :debug
|
15
16
|
|
16
17
|
register('db.config', config)
|
17
18
|
register('db.connection', connection)
|
@@ -19,14 +20,5 @@ Inferno::Application.boot(:db) do
|
|
19
20
|
|
20
21
|
start do
|
21
22
|
Sequel.extension :migration
|
22
|
-
db = Inferno::Application['db.connection']
|
23
|
-
migration_path = File.join(Inferno::Application.root, 'lib', 'inferno', 'db', 'migrations')
|
24
|
-
Sequel::Migrator.run(db, migration_path)
|
25
|
-
|
26
|
-
if ENV['APP_ENV'] == 'development'
|
27
|
-
schema_path = File.join(Inferno::Application.root, 'lib', 'inferno', 'db', 'schema.rb')
|
28
|
-
db.extension :schema_dumper
|
29
|
-
File.open(schema_path, 'w') { |f| f.print(db.dump_schema_migration) }
|
30
|
-
end
|
31
23
|
end
|
32
24
|
end
|
@@ -4,12 +4,10 @@ Inferno::Application.boot(:suites) do
|
|
4
4
|
|
5
5
|
files_to_load = Dir.glob(File.join(Dir.pwd, 'lib', '*.rb'))
|
6
6
|
|
7
|
-
if ENV['LOAD_DEV_SUITES']
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
if ENV['LOAD_UI_SUITES'] == 'true'
|
12
|
-
files_to_load.concat Dir.glob(File.join(Inferno::Application.root, 'ui_suites', '**', '*.rb'))
|
7
|
+
if ENV['LOAD_DEV_SUITES'].present?
|
8
|
+
ENV['LOAD_DEV_SUITES'].split(',').map(&:strip).reject(&:empty?).each do |suite|
|
9
|
+
files_to_load.concat Dir.glob(File.join(Inferno::Application.root, 'dev_suites', suite, '**', '*.rb'))
|
10
|
+
end
|
13
11
|
end
|
14
12
|
|
15
13
|
if ENV['APP_ENV'] == 'test'
|
@@ -116,7 +116,7 @@ Sequel.migration do
|
|
116
116
|
# Requires requests to be a part of tests now.
|
117
117
|
foreign_key :result_id, :results, index: true, type: String
|
118
118
|
foreign_key :test_session_id, :test_sessions, index: true, type: String
|
119
|
-
|
119
|
+
index [:test_session_id, :name], concurrently: true
|
120
120
|
|
121
121
|
column :created_at, DateTime, null: false
|
122
122
|
column :updated_at, DateTime, null: false
|
data/lib/inferno/db/schema.rb
CHANGED
@@ -95,13 +95,13 @@ Sequel.migration do
|
|
95
95
|
String :response_body, :text=>true
|
96
96
|
foreign_key :result_id, :results, :type=>String, :size=>255
|
97
97
|
foreign_key :test_session_id, :test_sessions, :type=>String, :size=>255
|
98
|
-
String :"[:test_session_id, :name]"
|
99
98
|
DateTime :created_at, :null=>false
|
100
99
|
DateTime :updated_at, :null=>false
|
101
100
|
|
102
101
|
index [:id]
|
103
102
|
index [:result_id]
|
104
103
|
index [:test_session_id]
|
104
|
+
index [:test_session_id, :name]
|
105
105
|
end
|
106
106
|
|
107
107
|
create_table(:result_outputs, :ignore_index_errors=>true) do
|
@@ -3,22 +3,43 @@ require_relative '../exceptions'
|
|
3
3
|
module Inferno
|
4
4
|
module DSL
|
5
5
|
module Assertions
|
6
|
+
# Make an assertion
|
7
|
+
#
|
8
|
+
# @param test a value whose truthiness will determine whether the
|
9
|
+
# assertion passes or fails
|
10
|
+
# @param message [String] failure message
|
6
11
|
def assert(test, message = '')
|
7
12
|
raise Exceptions::AssertionException, message unless test
|
8
13
|
end
|
9
14
|
|
15
|
+
# @private
|
10
16
|
def bad_response_status_message(expected, received)
|
11
17
|
"Bad response status: expected #{Array.wrap(expected).join(', ')}, but received #{received}"
|
12
18
|
end
|
13
19
|
|
20
|
+
# Check an response's status
|
21
|
+
#
|
22
|
+
# @param status [Integer, Array<Integer>] a single integer or an array of
|
23
|
+
# integer status codes
|
24
|
+
# @param response [Hash]
|
14
25
|
def assert_response_status(status, response: self.response)
|
15
26
|
assert Array.wrap(status).include?(response[:status]), bad_response_status_message(status, response[:status])
|
16
27
|
end
|
17
28
|
|
29
|
+
# @private
|
18
30
|
def bad_resource_type_message(expected, received)
|
19
31
|
"Bad resource type received: expected #{expected}, but received #{received}"
|
20
32
|
end
|
21
33
|
|
34
|
+
# Check a FHIR resource's type
|
35
|
+
#
|
36
|
+
# @param resource_type [String, Symbol, Class]
|
37
|
+
# @param resource [FHIR::Model]
|
38
|
+
# @example
|
39
|
+
# # The resource type can be a symbol, String, or FHIR::Model class
|
40
|
+
# assert_resource_type(:capability_statement)
|
41
|
+
# assert_resource_type('CapabilityStatement')
|
42
|
+
# assert_resource_type(FHIR::CapabilityStatement)
|
22
43
|
def assert_resource_type(resource_type, resource: self.resource)
|
23
44
|
resource_type_name = normalize_resource_type(resource_type)
|
24
45
|
|
@@ -26,15 +47,48 @@ module Inferno
|
|
26
47
|
bad_resource_type_message(resource_type_name, resource&.resourceType)
|
27
48
|
end
|
28
49
|
|
50
|
+
# @private
|
29
51
|
def invalid_resource_message(profile_url)
|
30
52
|
"Resource does not conform to the profile: #{profile_url}"
|
31
53
|
end
|
32
54
|
|
55
|
+
# Validate a FHIR resource
|
56
|
+
#
|
57
|
+
# @param resource [FHIR::Model]
|
58
|
+
# @param profile_url [String] url of the profile to validate against,
|
59
|
+
# defaults to validating against the base FHIR resource
|
33
60
|
def assert_valid_resource(resource: self.resource, profile_url: nil)
|
34
61
|
assert resource_is_valid?(resource: resource, profile_url: profile_url),
|
35
62
|
invalid_resource_message(profile_url)
|
36
63
|
end
|
37
64
|
|
65
|
+
# Validate each entry of a Bundle
|
66
|
+
#
|
67
|
+
# @param bundle [FHIR::Bundle]
|
68
|
+
# @param resource_types
|
69
|
+
# [String,Symbol,FHIR::Model,Array<String,Symbol,FHIR::Model>,Hash] If a
|
70
|
+
# string, symbol, or FHIR::Model is provided, only that resource type
|
71
|
+
# will be validated. If an array of strings is provided, only those
|
72
|
+
# resource types will be validated. If a hash is provided with resource
|
73
|
+
# types as keys and profile urls (or nil) as values, only those resource
|
74
|
+
# types will be validated against the provided profile url or the base
|
75
|
+
# resource if nil.
|
76
|
+
# @example
|
77
|
+
# # Only validate Patient bundle entries
|
78
|
+
# assert_valid_bundle_entries(resource_types: 'Patient')
|
79
|
+
#
|
80
|
+
# # Only valiadte Patient and Condition bundle entries
|
81
|
+
# assert_valid_bundle_entries(resource_types: ['Patient', 'Condition'])
|
82
|
+
#
|
83
|
+
# # Only validate Patient and Condition bundle entries. Validate Patient
|
84
|
+
# # resources against the given profile, and Codition resources against the
|
85
|
+
# # base FHIR Condition resource.
|
86
|
+
# assert_valid_bundle_entries(
|
87
|
+
# resource_types: {
|
88
|
+
# 'Patient': 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient',
|
89
|
+
# 'Condition': nil
|
90
|
+
# }
|
91
|
+
# )
|
38
92
|
def assert_valid_bundle_entries(bundle: resource, resource_types: {})
|
39
93
|
assert_resource_type('Bundle', resource: bundle)
|
40
94
|
|
@@ -56,6 +110,7 @@ module Inferno
|
|
56
110
|
assert invalid_resources.empty?, invalid_bundle_entries_message(invalid_resources)
|
57
111
|
end
|
58
112
|
|
113
|
+
# @private
|
59
114
|
def invalid_bundle_entries_message(invalid_resources)
|
60
115
|
identifier_strings =
|
61
116
|
invalid_resources
|
@@ -64,6 +119,7 @@ module Inferno
|
|
64
119
|
"The following bundle entries are invalid: #{identifier_strings}"
|
65
120
|
end
|
66
121
|
|
122
|
+
# @private
|
67
123
|
def normalize_resource_type(resource_type)
|
68
124
|
if resource_type.is_a? Class
|
69
125
|
resource_type.name.demodulize
|
@@ -72,6 +128,7 @@ module Inferno
|
|
72
128
|
end
|
73
129
|
end
|
74
130
|
|
131
|
+
# @private
|
75
132
|
def normalize_types_to_check(resource_types)
|
76
133
|
case resource_types
|
77
134
|
when Hash
|
@@ -83,11 +140,39 @@ module Inferno
|
|
83
140
|
end
|
84
141
|
end
|
85
142
|
|
143
|
+
# Check for valid JSON
|
144
|
+
#
|
145
|
+
# @param maybe_json_string [String]
|
146
|
+
# @param message [String] extra failure message
|
86
147
|
def assert_valid_json(maybe_json_string, message = '')
|
87
148
|
assert JSON.parse(maybe_json_string)
|
88
149
|
rescue JSON::ParserError
|
89
150
|
assert false, "Invalid JSON. #{message}"
|
90
151
|
end
|
152
|
+
|
153
|
+
# Check for a valid http/https uri
|
154
|
+
#
|
155
|
+
# @param uri [String]
|
156
|
+
# @param message [String] custom failure message
|
157
|
+
def assert_valid_http_uri(uri, message = '')
|
158
|
+
error_message = message.presence || "\"#{uri}\" is not a valid URI"
|
159
|
+
assert uri =~ /\A#{URI::DEFAULT_PARSER.make_regexp(['http', 'https'])}\z/, error_message
|
160
|
+
end
|
161
|
+
|
162
|
+
def assert_response_content_type(type, request: self.request)
|
163
|
+
header = request.response_header('Content-Type')
|
164
|
+
assert header.present?, no_content_type_message
|
165
|
+
|
166
|
+
assert header.value.start_with?(type), bad_content_type_message(type, header.value)
|
167
|
+
end
|
168
|
+
|
169
|
+
def no_content_type_message
|
170
|
+
'Response did not contain a `Content-Type` header.'
|
171
|
+
end
|
172
|
+
|
173
|
+
def bad_content_type_message(expected, received)
|
174
|
+
"Expected `Content-Type` to be `#{expected}`, but found `#{received}`"
|
175
|
+
end
|
91
176
|
end
|
92
177
|
end
|
93
178
|
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
module Inferno
|
2
|
+
module DSL
|
3
|
+
# This module contains the DSL for managing runnable configuration.
|
4
|
+
module Configurable
|
5
|
+
def self.extended(klass)
|
6
|
+
klass.extend Forwardable
|
7
|
+
klass.def_delegator 'self.class', :config
|
8
|
+
end
|
9
|
+
|
10
|
+
def config(new_configuration = {})
|
11
|
+
@config ||= Configuration.new
|
12
|
+
|
13
|
+
return @config if new_configuration.blank?
|
14
|
+
|
15
|
+
@config.apply(new_configuration)
|
16
|
+
end
|
17
|
+
|
18
|
+
# @private
|
19
|
+
class Configuration
|
20
|
+
attr_accessor :configuration
|
21
|
+
|
22
|
+
def initialize(configuration = {})
|
23
|
+
self.configuration = configuration
|
24
|
+
end
|
25
|
+
|
26
|
+
def apply(new_configuration)
|
27
|
+
config_to_apply =
|
28
|
+
if new_configuration.is_a? Configuration
|
29
|
+
new_configuration.configuration
|
30
|
+
else
|
31
|
+
new_configuration
|
32
|
+
end
|
33
|
+
|
34
|
+
self.configuration = configuration.deep_merge(config_to_apply)
|
35
|
+
end
|
36
|
+
|
37
|
+
def options
|
38
|
+
configuration[:options] ||= {}
|
39
|
+
end
|
40
|
+
|
41
|
+
### Input Configuration ###
|
42
|
+
|
43
|
+
def inputs
|
44
|
+
configuration[:inputs] ||= {}
|
45
|
+
end
|
46
|
+
|
47
|
+
def add_input(identifier, new_config = {})
|
48
|
+
existing_config = input_config(identifier) || {}
|
49
|
+
inputs[identifier] = default_input_config(identifier).merge(existing_config, new_config)
|
50
|
+
end
|
51
|
+
|
52
|
+
def default_input_config(identifier)
|
53
|
+
{ name: identifier, type: 'text' }
|
54
|
+
end
|
55
|
+
|
56
|
+
def input_config_exists?(identifier)
|
57
|
+
inputs.key? identifier
|
58
|
+
end
|
59
|
+
|
60
|
+
def input_config(identifier)
|
61
|
+
inputs[identifier]
|
62
|
+
end
|
63
|
+
|
64
|
+
def input_name(identifier)
|
65
|
+
inputs.dig(identifier, :name) || identifier
|
66
|
+
end
|
67
|
+
|
68
|
+
### Output Configuration ###
|
69
|
+
|
70
|
+
def outputs
|
71
|
+
configuration[:outputs] ||= {}
|
72
|
+
end
|
73
|
+
|
74
|
+
def add_output(identifier)
|
75
|
+
return if output_config_exists?(identifier)
|
76
|
+
|
77
|
+
outputs[identifier] = default_output_config(identifier)
|
78
|
+
end
|
79
|
+
|
80
|
+
def default_output_config(identifier)
|
81
|
+
{ name: identifier }
|
82
|
+
end
|
83
|
+
|
84
|
+
def output_config_exists?(identifier)
|
85
|
+
outputs.key? identifier
|
86
|
+
end
|
87
|
+
|
88
|
+
def output_config(identifier)
|
89
|
+
outputs[identifier]
|
90
|
+
end
|
91
|
+
|
92
|
+
def output_name(identifier)
|
93
|
+
outputs.dig(identifier, :name) || identifier
|
94
|
+
end
|
95
|
+
|
96
|
+
### Request Configuration ###
|
97
|
+
|
98
|
+
def requests
|
99
|
+
configuration[:requests] ||= {}
|
100
|
+
end
|
101
|
+
|
102
|
+
def add_request(identifier)
|
103
|
+
return if request_config_exists?(identifier)
|
104
|
+
|
105
|
+
requests[identifier] = default_request_config(identifier)
|
106
|
+
end
|
107
|
+
|
108
|
+
def default_request_config(identifier)
|
109
|
+
{ name: identifier }
|
110
|
+
end
|
111
|
+
|
112
|
+
def request_config_exists?(identifier)
|
113
|
+
requests.key? identifier
|
114
|
+
end
|
115
|
+
|
116
|
+
def request_config(identifier)
|
117
|
+
requests[identifier]
|
118
|
+
end
|
119
|
+
|
120
|
+
def request_name(identifier)
|
121
|
+
requests.dig(identifier, :name) || identifier
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -35,7 +35,7 @@ module Inferno
|
|
35
35
|
# @see Inferno::FHIRClientBuilder Documentation for the client
|
36
36
|
# configuration DSL
|
37
37
|
module FHIRClient
|
38
|
-
# @
|
38
|
+
# @private
|
39
39
|
def self.included(klass)
|
40
40
|
klass.extend ClassMethods
|
41
41
|
klass.extend Forwardable
|
@@ -54,7 +54,7 @@ module Inferno
|
|
54
54
|
FHIRClientBuilder.new.build(self, self.class.fhir_client_definitions[client])
|
55
55
|
end
|
56
56
|
|
57
|
-
# @
|
57
|
+
# @private
|
58
58
|
def fhir_clients
|
59
59
|
@fhir_clients ||= {}
|
60
60
|
end
|
@@ -69,13 +69,15 @@ module Inferno
|
|
69
69
|
# @param client [Symbol]
|
70
70
|
# @param name [Symbol] Name for this request to allow it to be used by
|
71
71
|
# other tests
|
72
|
-
# @param
|
72
|
+
# @param headers [Hash] custom headers for this operation
|
73
73
|
# @return [Inferno::Entities::Request]
|
74
|
-
def fhir_operation(path, body: nil, client: :default, name: nil,
|
74
|
+
def fhir_operation(path, body: nil, client: :default, name: nil, headers: {})
|
75
75
|
store_request('outgoing', name) do
|
76
|
-
|
77
|
-
|
78
|
-
|
76
|
+
operation_headers = fhir_client(client).fhir_headers
|
77
|
+
operation_headers.merge!('Content-Type' => 'application/fhir+json') if body.present?
|
78
|
+
operation_headers.merge!(headers) if headers.present?
|
79
|
+
|
80
|
+
fhir_client(client).send(:post, path, body, operation_headers)
|
79
81
|
end
|
80
82
|
end
|
81
83
|
|
@@ -84,9 +86,8 @@ module Inferno
|
|
84
86
|
# @param client [Symbol]
|
85
87
|
# @param name [Symbol] Name for this request to allow it to be used by
|
86
88
|
# other tests
|
87
|
-
# @param _options [Hash] TODO
|
88
89
|
# @return [Inferno::Entities::Request]
|
89
|
-
def fhir_get_capability_statement(client: :default, name: nil
|
90
|
+
def fhir_get_capability_statement(client: :default, name: nil)
|
90
91
|
store_request('outgoing', name) do
|
91
92
|
fhir_client(client).conformance_statement
|
92
93
|
fhir_client(client).reply
|
@@ -100,9 +101,8 @@ module Inferno
|
|
100
101
|
# @param client [Symbol]
|
101
102
|
# @param name [Symbol] Name for this request to allow it to be used by
|
102
103
|
# other tests
|
103
|
-
# @param _options [Hash] TODO
|
104
104
|
# @return [Inferno::Entities::Request]
|
105
|
-
def fhir_read(resource_type, id, client: :default, name: nil
|
105
|
+
def fhir_read(resource_type, id, client: :default, name: nil)
|
106
106
|
store_request('outgoing', name) do
|
107
107
|
fhir_client(client).read(fhir_class_from_resource_type(resource_type), id)
|
108
108
|
end
|
@@ -115,24 +115,30 @@ module Inferno
|
|
115
115
|
# @param params [Hash] the search params
|
116
116
|
# @param name [Symbol] Name for this request to allow it to be used by
|
117
117
|
# other tests
|
118
|
-
# @param
|
118
|
+
# @param search_method [Symbol] Use `:post` to search via POST
|
119
119
|
# @return [Inferno::Entities::Request]
|
120
|
-
def fhir_search(resource_type, client: :default, params: {}, name: nil,
|
120
|
+
def fhir_search(resource_type, client: :default, params: {}, name: nil, search_method: :get)
|
121
|
+
search =
|
122
|
+
if search_method == :post
|
123
|
+
{ body: params }
|
124
|
+
else
|
125
|
+
{ parameters: params }
|
126
|
+
end
|
121
127
|
store_request('outgoing', name) do
|
122
128
|
fhir_client(client)
|
123
|
-
.search(fhir_class_from_resource_type(resource_type),
|
129
|
+
.search(fhir_class_from_resource_type(resource_type), { search: search })
|
124
130
|
end
|
125
131
|
end
|
126
132
|
|
127
133
|
# @todo Make this a FHIR class method? Something like
|
128
134
|
# FHIR.class_for(resource_type)
|
129
|
-
# @
|
135
|
+
# @private
|
130
136
|
def fhir_class_from_resource_type(resource_type)
|
131
137
|
FHIR.const_get(resource_type.to_s.camelize)
|
132
138
|
end
|
133
139
|
|
134
140
|
module ClassMethods
|
135
|
-
# @
|
141
|
+
# @private
|
136
142
|
def fhir_client_definitions
|
137
143
|
@fhir_client_definitions ||= {}
|
138
144
|
end
|
@@ -6,7 +6,7 @@ module Inferno
|
|
6
6
|
class FHIRClientBuilder
|
7
7
|
attr_accessor :runnable
|
8
8
|
|
9
|
-
# @
|
9
|
+
# @private
|
10
10
|
def build(runnable, block)
|
11
11
|
self.runnable = runnable
|
12
12
|
instance_exec(self, &block)
|
@@ -56,14 +56,14 @@ module Inferno
|
|
56
56
|
@headers ||= headers
|
57
57
|
end
|
58
58
|
|
59
|
-
# @
|
59
|
+
# @private
|
60
60
|
def method_missing(name, *args, &block)
|
61
61
|
return runnable.call(name, *args, &block) if runnable.respond_to? name
|
62
62
|
|
63
63
|
super
|
64
64
|
end
|
65
65
|
|
66
|
-
# @
|
66
|
+
# @private
|
67
67
|
def respond_to_missing?(name)
|
68
68
|
runnable.respond_to?(name) || super
|
69
69
|
end
|