inferno_core 0.0.3 → 0.0.7
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 +30 -10
- data/lib/inferno/apps/web/controllers/test_runs/show.rb +10 -0
- data/lib/inferno/apps/web/controllers/test_sessions/create.rb +1 -0
- data/lib/inferno/apps/web/controllers/test_sessions/last_test_run.rb +22 -0
- data/lib/inferno/apps/web/controllers/test_sessions/results/index.rb +6 -1
- data/lib/inferno/apps/web/controllers/test_sessions/session_data/index.rb +21 -0
- data/lib/inferno/apps/web/router.rb +15 -0
- data/lib/inferno/apps/web/serializers/hash_value_extractor.rb +11 -0
- data/lib/inferno/apps/web/serializers/request.rb +1 -0
- data/lib/inferno/apps/web/serializers/result.rb +8 -0
- data/lib/inferno/apps/web/serializers/session_data.rb +10 -0
- data/lib/inferno/apps/web/serializers/test.rb +3 -6
- data/lib/inferno/apps/web/serializers/test_group.rb +5 -8
- data/lib/inferno/apps/web/serializers/test_run.rb +1 -0
- data/lib/inferno/apps/web/serializers/test_session.rb +1 -1
- data/lib/inferno/apps/web/serializers/test_suite.rb +1 -0
- data/lib/inferno/config/application.rb +8 -2
- data/lib/inferno/config/boot/db.rb +3 -2
- data/lib/inferno/config/boot/logging.rb +2 -0
- data/lib/inferno/config/boot/sidekiq.rb +11 -0
- data/lib/inferno/config/boot/suites.rb +4 -6
- data/lib/inferno/config/boot.rb +2 -0
- data/lib/inferno/db/migrations/001_create_initial_structure.rb +0 -21
- data/lib/inferno/db/migrations/002_add_wait_support.rb +7 -0
- data/lib/inferno/db/migrations/003_update_session_data.rb +18 -0
- data/lib/inferno/db/migrations/004_add_request_results_table.rb +9 -0
- data/lib/inferno/db/migrations/005_add_updated_at_index_to_results.rb +5 -0
- data/lib/inferno/db/schema.rb +154 -0
- data/lib/inferno/dsl/assertions.rb +85 -0
- data/lib/inferno/dsl/configurable.rb +126 -0
- data/lib/inferno/dsl/fhir_client.rb +8 -6
- data/lib/inferno/dsl/fhir_client_builder.rb +19 -3
- data/lib/inferno/dsl/fhir_validation.rb +1 -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 +34 -13
- data/lib/inferno/dsl/results.rb +49 -0
- data/lib/inferno/dsl/resume_test_route.rb +89 -0
- data/lib/inferno/dsl/runnable.rb +183 -28
- data/lib/inferno/dsl.rb +1 -3
- data/lib/inferno/entities/header.rb +14 -7
- data/lib/inferno/entities/message.rb +16 -6
- data/lib/inferno/entities/request.rb +59 -20
- data/lib/inferno/entities/result.rb +45 -22
- data/lib/inferno/entities/session_data.rb +39 -0
- data/lib/inferno/entities/test.rb +48 -8
- data/lib/inferno/entities/test_group.rb +8 -0
- data/lib/inferno/entities/test_run.rb +36 -6
- data/lib/inferno/entities/test_session.rb +17 -11
- data/lib/inferno/entities.rb +1 -1
- data/lib/inferno/exceptions.rb +24 -0
- data/lib/inferno/jobs/execute_test_run.rb +14 -0
- data/lib/inferno/jobs/resume_test_run.rb +14 -0
- data/lib/inferno/jobs.rb +16 -0
- data/lib/inferno/public/bundle.js +1 -1
- data/lib/inferno/repositories/in_memory_repository.rb +1 -1
- data/lib/inferno/repositories/repository.rb +13 -0
- data/lib/inferno/repositories/requests.rb +5 -4
- data/lib/inferno/repositories/results.rb +151 -3
- data/lib/inferno/repositories/session_data.rb +47 -0
- data/lib/inferno/repositories/test_runs.rb +81 -0
- data/lib/inferno/spec_support.rb +1 -1
- data/lib/inferno/test_runner.rb +126 -32
- data/lib/inferno/utils/markdown_formatter.rb +15 -0
- data/lib/inferno/utils/middleware/request_logger.rb +17 -4
- data/lib/inferno/utils/migration.rb +17 -0
- data/lib/inferno/version.rb +1 -1
- data/lib/inferno.rb +4 -4
- data/spec/factories/request.rb +14 -7
- data/spec/factories/result.rb +8 -0
- data/spec/factories/test_run.rb +2 -0
- metadata +84 -7
- data/bin/inferno-console +0 -8
- data/lib/inferno/dsl/fhir_manipulation.rb +0 -25
- data/lib/inferno/entities/test_input.rb +0 -20
@@ -0,0 +1,154 @@
|
|
1
|
+
Sequel.migration do
|
2
|
+
change do
|
3
|
+
create_table(:schema_info) do
|
4
|
+
Integer :version, :default=>0, :null=>false
|
5
|
+
end
|
6
|
+
|
7
|
+
create_table(:test_sessions) do
|
8
|
+
String :id, :size=>255, :null=>false
|
9
|
+
String :test_suite_id, :size=>255
|
10
|
+
DateTime :created_at, :null=>false
|
11
|
+
DateTime :updated_at, :null=>false
|
12
|
+
|
13
|
+
primary_key [:id]
|
14
|
+
end
|
15
|
+
|
16
|
+
create_table(:session_data, :ignore_index_errors=>true) do
|
17
|
+
String :id, :size=>255, :null=>false
|
18
|
+
foreign_key :test_session_id, :test_sessions, :type=>String, :size=>255
|
19
|
+
String :name, :size=>255
|
20
|
+
String :value, :text=>true
|
21
|
+
|
22
|
+
index [:id], :unique=>true
|
23
|
+
index [:test_session_id]
|
24
|
+
index [:test_session_id, :name], :unique=>true
|
25
|
+
end
|
26
|
+
|
27
|
+
create_table(:test_runs, :ignore_index_errors=>true) do
|
28
|
+
String :id, :size=>255, :null=>false
|
29
|
+
String :status, :size=>255
|
30
|
+
foreign_key :test_session_id, :test_sessions, :type=>String, :size=>255
|
31
|
+
String :test_suite_id, :size=>255
|
32
|
+
String :test_group_id, :size=>255
|
33
|
+
String :test_id, :size=>255
|
34
|
+
DateTime :created_at, :null=>false
|
35
|
+
DateTime :updated_at, :null=>false
|
36
|
+
String :identifier, :text=>true
|
37
|
+
DateTime :wait_timeout
|
38
|
+
|
39
|
+
primary_key [:id]
|
40
|
+
|
41
|
+
index [:status, :identifier, :wait_timeout, :updated_at]
|
42
|
+
index [:test_group_id]
|
43
|
+
index [:test_id]
|
44
|
+
index [:test_session_id]
|
45
|
+
index [:test_session_id, :status]
|
46
|
+
index [:test_suite_id]
|
47
|
+
end
|
48
|
+
|
49
|
+
create_table(:results, :ignore_index_errors=>true) do
|
50
|
+
String :id, :size=>255, :null=>false
|
51
|
+
foreign_key :test_run_id, :test_runs, :type=>String, :size=>255
|
52
|
+
foreign_key :test_session_id, :test_sessions, :type=>String, :size=>255
|
53
|
+
String :result, :size=>255
|
54
|
+
String :result_message, :size=>255
|
55
|
+
String :test_suite_id, :size=>255
|
56
|
+
String :test_group_id, :size=>255
|
57
|
+
String :test_id, :size=>255
|
58
|
+
DateTime :created_at, :null=>false
|
59
|
+
DateTime :updated_at, :null=>false
|
60
|
+
String :input_json, :text=>true
|
61
|
+
String :output_json, :text=>true
|
62
|
+
|
63
|
+
primary_key [:id]
|
64
|
+
|
65
|
+
index [:test_run_id]
|
66
|
+
index [:test_run_id, :updated_at]
|
67
|
+
index [:test_session_id]
|
68
|
+
index [:test_session_id, :test_group_id]
|
69
|
+
index [:test_session_id, :test_id]
|
70
|
+
index [:test_session_id, :test_suite_id]
|
71
|
+
end
|
72
|
+
|
73
|
+
create_table(:messages, :ignore_index_errors=>true) do
|
74
|
+
primary_key :index
|
75
|
+
String :id, :size=>255, :null=>false
|
76
|
+
foreign_key :result_id, :results, :type=>String, :size=>255
|
77
|
+
String :type, :size=>255
|
78
|
+
String :message, :size=>255
|
79
|
+
DateTime :created_at, :null=>false
|
80
|
+
DateTime :updated_at, :null=>false
|
81
|
+
|
82
|
+
index [:id]
|
83
|
+
index [:result_id]
|
84
|
+
end
|
85
|
+
|
86
|
+
create_table(:requests, :ignore_index_errors=>true) do
|
87
|
+
primary_key :index
|
88
|
+
String :id, :size=>255, :null=>false
|
89
|
+
String :verb, :size=>255
|
90
|
+
String :url, :size=>255
|
91
|
+
String :direction, :size=>255
|
92
|
+
Integer :status
|
93
|
+
String :name, :size=>255
|
94
|
+
String :request_body, :text=>true
|
95
|
+
String :response_body, :text=>true
|
96
|
+
foreign_key :result_id, :results, :type=>String, :size=>255
|
97
|
+
foreign_key :test_session_id, :test_sessions, :type=>String, :size=>255
|
98
|
+
String :"[:test_session_id, :name]"
|
99
|
+
DateTime :created_at, :null=>false
|
100
|
+
DateTime :updated_at, :null=>false
|
101
|
+
|
102
|
+
index [:id]
|
103
|
+
index [:result_id]
|
104
|
+
index [:test_session_id]
|
105
|
+
end
|
106
|
+
|
107
|
+
create_table(:result_outputs, :ignore_index_errors=>true) do
|
108
|
+
String :id, :size=>255, :null=>false
|
109
|
+
foreign_key :result_id, :results, :type=>String, :size=>255
|
110
|
+
String :test_output_id, :size=>255
|
111
|
+
String :value, :size=>255
|
112
|
+
DateTime :created_at, :null=>false
|
113
|
+
DateTime :updated_at, :null=>false
|
114
|
+
|
115
|
+
primary_key [:id]
|
116
|
+
|
117
|
+
index [:result_id]
|
118
|
+
end
|
119
|
+
|
120
|
+
create_table(:result_prompt_values, :ignore_index_errors=>true) do
|
121
|
+
String :id, :size=>255, :null=>false
|
122
|
+
foreign_key :result_id, :results, :type=>String, :size=>255
|
123
|
+
String :test_prompt_id, :size=>255, :null=>false
|
124
|
+
String :value, :size=>255, :null=>false
|
125
|
+
DateTime :created_at, :null=>false
|
126
|
+
DateTime :updated_at, :null=>false
|
127
|
+
|
128
|
+
primary_key [:id]
|
129
|
+
|
130
|
+
index [:result_id]
|
131
|
+
end
|
132
|
+
|
133
|
+
create_table(:headers, :ignore_index_errors=>true) do
|
134
|
+
String :id, :size=>255, :null=>false
|
135
|
+
foreign_key :request_id, :requests, :type=>String, :size=>255
|
136
|
+
String :type, :size=>255
|
137
|
+
String :name, :size=>255
|
138
|
+
String :value, :size=>255
|
139
|
+
DateTime :created_at, :null=>false
|
140
|
+
DateTime :updated_at, :null=>false
|
141
|
+
|
142
|
+
index [:id]
|
143
|
+
index [:request_id]
|
144
|
+
end
|
145
|
+
|
146
|
+
create_table(:requests_results, :ignore_index_errors=>true) do
|
147
|
+
foreign_key :results_id, :results, :type=>String, :size=>255, :null=>false
|
148
|
+
foreign_key :requests_id, :requests, :type=>String, :size=>255, :null=>false
|
149
|
+
|
150
|
+
index [:requests_id]
|
151
|
+
index [:results_id]
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
@@ -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,12 +69,14 @@ 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
|
-
# @
|
72
|
+
# @option options [Hash] Input headers here - headers are optional and
|
73
|
+
# must be entered as the last piece of input to this method
|
73
74
|
# @return [Inferno::Entities::Request]
|
74
|
-
def fhir_operation(path, body: nil, client: :default, name: nil, **
|
75
|
+
def fhir_operation(path, body: nil, client: :default, name: nil, **options)
|
75
76
|
store_request('outgoing', name) do
|
76
77
|
headers = fhir_client(client).fhir_headers
|
77
78
|
headers.merge!('Content-Type' => 'application/fhir+json') if body.present?
|
79
|
+
headers.merge!(options[:headers]) if options[:headers].present?
|
78
80
|
fhir_client(client).send(:post, path, body, headers)
|
79
81
|
end
|
80
82
|
end
|
@@ -126,13 +128,13 @@ module Inferno
|
|
126
128
|
|
127
129
|
# @todo Make this a FHIR class method? Something like
|
128
130
|
# FHIR.class_for(resource_type)
|
129
|
-
# @
|
131
|
+
# @private
|
130
132
|
def fhir_class_from_resource_type(resource_type)
|
131
133
|
FHIR.const_get(resource_type.to_s.camelize)
|
132
134
|
end
|
133
135
|
|
134
136
|
module ClassMethods
|
135
|
-
# @
|
137
|
+
# @private
|
136
138
|
def fhir_client_definitions
|
137
139
|
@fhir_client_definitions ||= {}
|
138
140
|
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)
|
@@ -14,6 +14,7 @@ module Inferno
|
|
14
14
|
FHIR::Client.new(url).tap do |client|
|
15
15
|
client.additional_headers = headers if headers
|
16
16
|
client.default_json
|
17
|
+
client.set_bearer_token bearer_token if bearer_token
|
17
18
|
end
|
18
19
|
end
|
19
20
|
|
@@ -32,6 +33,21 @@ module Inferno
|
|
32
33
|
end
|
33
34
|
end
|
34
35
|
|
36
|
+
# Define the bearer token for a client. A string or symbol can be provided.
|
37
|
+
# A string is interpreted as a token. A symbol is interpreted as the name of
|
38
|
+
# an input to the Runnable.
|
39
|
+
#
|
40
|
+
# @param bearer_token [String, Symbol]
|
41
|
+
# @return [void]
|
42
|
+
def bearer_token(bearer_token = nil)
|
43
|
+
@bearer_token ||=
|
44
|
+
if bearer_token.is_a? Symbol
|
45
|
+
runnable.send(bearer_token)
|
46
|
+
else
|
47
|
+
bearer_token
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
35
51
|
# Define custom headers for a client
|
36
52
|
#
|
37
53
|
# @param headers [Hash]
|
@@ -40,14 +56,14 @@ module Inferno
|
|
40
56
|
@headers ||= headers
|
41
57
|
end
|
42
58
|
|
43
|
-
# @
|
59
|
+
# @private
|
44
60
|
def method_missing(name, *args, &block)
|
45
61
|
return runnable.call(name, *args, &block) if runnable.respond_to? name
|
46
62
|
|
47
63
|
super
|
48
64
|
end
|
49
65
|
|
50
|
-
# @
|
66
|
+
# @private
|
51
67
|
def respond_to_missing?(name)
|
52
68
|
runnable.respond_to?(name) || super
|
53
69
|
end
|
@@ -16,7 +16,7 @@ module Inferno
|
|
16
16
|
# # performs a GET to https://example.com
|
17
17
|
# get
|
18
18
|
# # performs a GET to https://example.com/abc
|
19
|
-
#
|
19
|
+
# get('abc')
|
20
20
|
#
|
21
21
|
# request # the most recent request
|
22
22
|
# response # the most recent response
|
@@ -27,7 +27,7 @@ module Inferno
|
|
27
27
|
# @see Inferno::FHIRClientBuilder Documentation for the client
|
28
28
|
# configuration DSL
|
29
29
|
module HTTPClient
|
30
|
-
# @
|
30
|
+
# @private
|
31
31
|
def self.included(klass)
|
32
32
|
klass.extend ClassMethods
|
33
33
|
klass.include RequestStorage
|
@@ -47,7 +47,7 @@ module Inferno
|
|
47
47
|
http_clients[client] = HTTPClientBuilder.new.build(self, definition)
|
48
48
|
end
|
49
49
|
|
50
|
-
# @
|
50
|
+
# @private
|
51
51
|
def http_clients
|
52
52
|
@http_clients ||= {}
|
53
53
|
end
|
@@ -60,16 +60,17 @@ module Inferno
|
|
60
60
|
# @param client [Symbol]
|
61
61
|
# @param name [Symbol] Name for this request to allow it to be used by
|
62
62
|
# other tests
|
63
|
-
# @
|
63
|
+
# @option options [Hash] Input headers here - headers are optional and
|
64
|
+
# must be entered as the last piece of input to this method
|
64
65
|
# @return [Inferno::Entities::Request]
|
65
|
-
def get(url = '', client: :default, name: nil, **
|
66
|
+
def get(url = '', client: :default, name: nil, **options)
|
66
67
|
store_request('outgoing', name) do
|
67
68
|
client = http_client(client)
|
68
69
|
|
69
70
|
if client
|
70
|
-
client.get(url)
|
71
|
+
client.get(url, nil, options[:headers])
|
71
72
|
elsif url.match?(%r{\Ahttps?://})
|
72
|
-
Faraday.get(url)
|
73
|
+
Faraday.get(url, nil, options[:headers])
|
73
74
|
else
|
74
75
|
raise StandardError, 'Must use an absolute url or define an HTTP client with a base url'
|
75
76
|
end
|
@@ -85,16 +86,17 @@ module Inferno
|
|
85
86
|
# @param client [Symbol]
|
86
87
|
# @param name [Symbol] Name for this request to allow it to be used by
|
87
88
|
# other tests
|
88
|
-
# @
|
89
|
+
# @option options [Hash] Input headers here - headers are optional and
|
90
|
+
# must be entered as the last piece of input to this method
|
89
91
|
# @return [Inferno::Entities::Request]
|
90
|
-
def post(url = '', body: nil, client: :default, name: nil, **
|
92
|
+
def post(url = '', body: nil, client: :default, name: nil, **options)
|
91
93
|
store_request('outgoing', name) do
|
92
94
|
client = http_client(client)
|
93
95
|
|
94
96
|
if client
|
95
|
-
client.post(url, body)
|
97
|
+
client.post(url, body, options[:headers])
|
96
98
|
elsif url.match?(%r{\Ahttps?://})
|
97
|
-
Faraday.post(url, body)
|
99
|
+
Faraday.post(url, body, options[:headers])
|
98
100
|
else
|
99
101
|
raise StandardError, 'Must use an absolute url or define an HTTP client with a base url'
|
100
102
|
end
|
@@ -102,7 +104,7 @@ module Inferno
|
|
102
104
|
end
|
103
105
|
|
104
106
|
module ClassMethods
|
105
|
-
# @
|
107
|
+
# @private
|
106
108
|
def http_client_definitions
|
107
109
|
@http_client_definitions ||= {}
|
108
110
|
end
|
@@ -4,7 +4,7 @@ module Inferno
|
|
4
4
|
class HTTPClientBuilder
|
5
5
|
attr_accessor :runnable
|
6
6
|
|
7
|
-
# @
|
7
|
+
# @private
|
8
8
|
def build(runnable, block)
|
9
9
|
self.runnable = runnable
|
10
10
|
instance_exec(self, &block)
|
@@ -38,14 +38,14 @@ module Inferno
|
|
38
38
|
@headers ||= headers
|
39
39
|
end
|
40
40
|
|
41
|
-
# @
|
41
|
+
# @private
|
42
42
|
def method_missing(name, *args, &block)
|
43
43
|
return runnable.call(name, *args, &block) if runnable.respond_to? name
|
44
44
|
|
45
45
|
super
|
46
46
|
end
|
47
47
|
|
48
|
-
# @
|
48
|
+
# @private
|
49
49
|
def respond_to_missing?(name)
|
50
50
|
runnable.respond_to?(name) || super
|
51
51
|
end
|