inferno_core 0.0.8 → 0.1.0.pre
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/lib/inferno/apps/web/controllers/test_runs/create.rb +2 -1
- data/lib/inferno/db/migrations/001_create_initial_structure.rb +54 -53
- data/lib/inferno/db/migrations/002_add_wait_support.rb +2 -2
- data/lib/inferno/db/migrations/003_update_session_data.rb +7 -7
- data/lib/inferno/db/migrations/004_add_request_results_table.rb +2 -2
- data/lib/inferno/db/migrations/005_add_updated_at_index_to_results.rb +1 -1
- data/lib/inferno/db/migrations/006_remove_unused_tables.rb +38 -0
- data/lib/inferno/db/schema.rb +17 -43
- data/lib/inferno/dsl/configurable.rb +12 -5
- data/lib/inferno/dsl/fhir_client.rb +44 -6
- data/lib/inferno/dsl/fhir_client_builder.rb +16 -0
- data/lib/inferno/dsl/oauth_credentials.rb +119 -0
- data/lib/inferno/dsl/runnable.rb +20 -8
- data/lib/inferno/entities/request.rb +7 -1
- data/lib/inferno/exceptions.rb +19 -0
- data/lib/inferno/ext/fhir_client.rb +13 -0
- data/lib/inferno/public/bundle.js +14 -14
- data/lib/inferno/repositories/session_data.rb +40 -6
- data/lib/inferno/spec_support.rb +1 -1
- data/lib/inferno/test_runner.rb +8 -3
- data/lib/inferno/version.rb +1 -1
- data/spec/factories/request.rb +1 -1
- data/spec/factories/result.rb +2 -2
- data/spec/fixtures/basic_test_group.rb +1 -0
- metadata +7 -4
@@ -0,0 +1,119 @@
|
|
1
|
+
require_relative '../entities/attributes'
|
2
|
+
|
3
|
+
module Inferno
|
4
|
+
module DSL
|
5
|
+
class OAuthCredentials
|
6
|
+
ATTRIBUTES = [
|
7
|
+
:access_token,
|
8
|
+
:refresh_token,
|
9
|
+
:token_url,
|
10
|
+
:client_id,
|
11
|
+
:client_secret,
|
12
|
+
:token_retrieval_time,
|
13
|
+
:expires_in,
|
14
|
+
:name
|
15
|
+
].freeze
|
16
|
+
|
17
|
+
include Entities::Attributes
|
18
|
+
|
19
|
+
attr_accessor :client
|
20
|
+
|
21
|
+
def initialize(raw_attributes_hash)
|
22
|
+
attributes_hash = raw_attributes_hash.symbolize_keys
|
23
|
+
|
24
|
+
invalid_keys = attributes_hash.keys - ATTRIBUTES
|
25
|
+
|
26
|
+
raise Exceptions::UnknownAttributeException.new(invalid_keys, self.class) if invalid_keys.present?
|
27
|
+
|
28
|
+
attributes_hash.each do |name, value|
|
29
|
+
value = DateTime.parse(value) if name == :token_retrieval_time && value.is_a?(String)
|
30
|
+
|
31
|
+
instance_variable_set(:"@#{name}", value)
|
32
|
+
end
|
33
|
+
|
34
|
+
self.token_retrieval_time = DateTime.now if token_retrieval_time.blank?
|
35
|
+
end
|
36
|
+
|
37
|
+
# @api private
|
38
|
+
def to_hash
|
39
|
+
self.class::ATTRIBUTES.each_with_object({}) do |attribute, hash|
|
40
|
+
value = send(attribute)
|
41
|
+
next if value.nil?
|
42
|
+
|
43
|
+
value = token_retrieval_time.iso8601 if attribute == :token_retrieval_time
|
44
|
+
|
45
|
+
hash[attribute] = value
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# @api private
|
50
|
+
def to_s
|
51
|
+
JSON.generate(to_hash)
|
52
|
+
end
|
53
|
+
|
54
|
+
# @api private
|
55
|
+
def add_to_client(client)
|
56
|
+
client.oauth_credentials = self
|
57
|
+
self.client = client
|
58
|
+
|
59
|
+
return unless access_token.present?
|
60
|
+
|
61
|
+
client.set_bearer_token(access_token)
|
62
|
+
end
|
63
|
+
|
64
|
+
# @api private
|
65
|
+
def need_to_refresh?
|
66
|
+
return false if access_token.blank? || refresh_token.blank?
|
67
|
+
|
68
|
+
return true if expires_in.blank?
|
69
|
+
|
70
|
+
token_retrieval_time.to_i + expires_in - DateTime.now.to_i < 60
|
71
|
+
end
|
72
|
+
|
73
|
+
# @api private
|
74
|
+
def able_to_refresh?
|
75
|
+
refresh_token.present? && token_url.present?
|
76
|
+
end
|
77
|
+
|
78
|
+
# @api private
|
79
|
+
def confidential_client?
|
80
|
+
client_id.present? && client_secret.present?
|
81
|
+
end
|
82
|
+
|
83
|
+
# @api private
|
84
|
+
def oauth2_refresh_params
|
85
|
+
{
|
86
|
+
'grant_type' => 'refresh_token',
|
87
|
+
'refresh_token' => refresh_token
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
91
|
+
# @api private
|
92
|
+
def oauth2_refresh_headers
|
93
|
+
base_headers = { 'Content-Type' => 'application/x-www-form-urlencoded' }
|
94
|
+
|
95
|
+
return base_headers unless confidential_client?
|
96
|
+
|
97
|
+
credentials = "#{client_id}:#{client_secret}"
|
98
|
+
|
99
|
+
base_headers.merge(
|
100
|
+
'Authorization' => "Basic #{Base64.strict_encode64(credentials)}"
|
101
|
+
)
|
102
|
+
end
|
103
|
+
|
104
|
+
def update_from_response_body(request)
|
105
|
+
token_response_body = JSON.parse(request.response_body)
|
106
|
+
|
107
|
+
expires_in = token_response_body['expires_in'].is_a?(Numeric) ? token_response_body['expires_in'] : nil
|
108
|
+
|
109
|
+
self.access_token = token_response_body['access_token']
|
110
|
+
self.refresh_token = token_response_body['refresh_token']
|
111
|
+
self.expires_in = expires_in
|
112
|
+
self.token_retrieval_time = DateTime.now
|
113
|
+
|
114
|
+
add_to_client(client)
|
115
|
+
self
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
data/lib/inferno/dsl/runnable.rb
CHANGED
@@ -229,12 +229,14 @@ module Inferno
|
|
229
229
|
# @param input_definition [Hash] options for input such as type, description, or title
|
230
230
|
# @option input_definition [String] :title Human readable title for input
|
231
231
|
# @option input_definition [String] :description Description for the input
|
232
|
-
# @option input_definition [String] :type text | textarea
|
232
|
+
# @option input_definition [String] :type text | textarea | radio
|
233
233
|
# @option input_definition [String] :default The default value for the input
|
234
234
|
# @option input_definition [Boolean] :optional Set to true to not require input for test execution
|
235
|
+
# @option input_definition [Hash] :options Possible input option formats based on input type
|
236
|
+
# @option options [Array] :list_options Array of options for input formats that require a list of possible values
|
235
237
|
# @return [void]
|
236
238
|
# @example
|
237
|
-
# input :
|
239
|
+
# input :patient_id, title: 'Patient ID', description: 'The ID of the patient being searched for',
|
238
240
|
# default: 'default_patient_id'
|
239
241
|
# @example
|
240
242
|
# input :textarea, title: 'Textarea Input Example', type: 'textarea', optional: true
|
@@ -252,14 +254,24 @@ module Inferno
|
|
252
254
|
|
253
255
|
# Define outputs
|
254
256
|
#
|
255
|
-
# @param
|
257
|
+
# @param identifier [Symbol] identifier for the output
|
258
|
+
# @param other_identifiers [Symbol] array of symbols if specifying multiple outputs
|
259
|
+
# @param output_definition [Hash] options for output
|
260
|
+
# @option output_definition [String] :type text | textarea | oauth_credentials
|
256
261
|
# @return [void]
|
257
262
|
# @example
|
258
|
-
# output :patient_id, :
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
+
# output :patient_id, :condition_id, :observation_id
|
264
|
+
# @example
|
265
|
+
# output :oauth_credentials, type: 'oauth_credentials'
|
266
|
+
def output(identifier, *other_identifiers, **output_definition)
|
267
|
+
if other_identifiers.present?
|
268
|
+
[identifier, *other_identifiers].compact.each do |output_identifier|
|
269
|
+
outputs << output_identifier
|
270
|
+
config.add_output(output_identifier)
|
271
|
+
end
|
272
|
+
else
|
273
|
+
outputs << identifier
|
274
|
+
config.add_output(identifier, output_definition)
|
263
275
|
end
|
264
276
|
end
|
265
277
|
|
@@ -186,6 +186,12 @@ module Inferno
|
|
186
186
|
.map { |header_name, value| Header.new(name: header_name.downcase, value: value, type: 'request') }
|
187
187
|
response_headers = response[:headers]
|
188
188
|
.map { |header_name, value| Header.new(name: header_name.downcase, value: value, type: 'response') }
|
189
|
+
request_body =
|
190
|
+
if request.dig(:headers, 'Content-Type')&.include?('application/x-www-form-urlencoded')
|
191
|
+
URI.encode_www_form(request[:payload])
|
192
|
+
else
|
193
|
+
request[:payload]
|
194
|
+
end
|
189
195
|
|
190
196
|
new(
|
191
197
|
verb: request[:method],
|
@@ -193,7 +199,7 @@ module Inferno
|
|
193
199
|
direction: direction,
|
194
200
|
name: name,
|
195
201
|
status: response[:code].to_i,
|
196
|
-
request_body:
|
202
|
+
request_body: request_body,
|
197
203
|
response_body: response[:body],
|
198
204
|
test_session_id: test_session_id,
|
199
205
|
headers: request_headers + response_headers
|
data/lib/inferno/exceptions.rb
CHANGED
@@ -62,5 +62,24 @@ module Inferno
|
|
62
62
|
super('The chosen runnable must be run as part of a group')
|
63
63
|
end
|
64
64
|
end
|
65
|
+
|
66
|
+
class UnknownAttributeException < RuntimeError
|
67
|
+
def initialize(attributes, klass)
|
68
|
+
attributes_string = attributes.map { |attribute| "'#{attribute}'" }.join(', ')
|
69
|
+
super("Unknown attributes for #{klass.name}: #{attributes_string}")
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
class UnknownSessionDataType < RuntimeError
|
74
|
+
def initialize(output)
|
75
|
+
super("Unknown type '#{output[:type]}' for '#{output[:name]}'.")
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class BadSessionDataType < RuntimeError
|
80
|
+
def initialize(name, expected_class, actual_class)
|
81
|
+
super("Expected '#{name}' to be a #{expected_class.name}, but found a #{actual_class.name}.")
|
82
|
+
end
|
83
|
+
end
|
65
84
|
end
|
66
85
|
end
|