inferno_core 0.0.7 → 0.0.8.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/inferno/apps/web/index.html.erb +1 -0
- data/lib/inferno/dsl/fhir_client.rb +18 -14
- data/lib/inferno/dsl/fhir_validation.rb +104 -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/utils/middleware/request_logger.rb +8 -2
- data/lib/inferno/version.rb +1 -1
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 225c877bb710ee45ff9e6da9875ff1d08a46945bd0836d26c45f9864f08d8d57
|
4
|
+
data.tar.gz: 6bf0f02557ca8a6403b1da40afe0efadce186b4bb70076e9927c7d6283310889
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 357187f80bb794cb9ec0052526544aa5b8de34081c800fa9f291f695738cf84b498167fba0c777203b1c3f2a1126753cbe4e6081d187e050c1342d7d2bca5e4b
|
7
|
+
data.tar.gz: f8ae794f5ac94fb712a5d2397a47fe4cf727232601feedcef4d17af24f404a01f34e9dcdd701c4b366062e8bba3f539ddb03842c6c2958cb583a40c2ffa9e319
|
@@ -69,15 +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
|
-
# @
|
73
|
-
# must be entered as the last piece of input to this method
|
72
|
+
# @param headers [Hash] custom headers for this operation
|
74
73
|
# @return [Inferno::Entities::Request]
|
75
|
-
def fhir_operation(path, body: nil, client: :default, name: nil,
|
74
|
+
def fhir_operation(path, body: nil, client: :default, name: nil, headers: {})
|
76
75
|
store_request('outgoing', name) do
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
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)
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
@@ -86,9 +86,8 @@ module Inferno
|
|
86
86
|
# @param client [Symbol]
|
87
87
|
# @param name [Symbol] Name for this request to allow it to be used by
|
88
88
|
# other tests
|
89
|
-
# @param _options [Hash] TODO
|
90
89
|
# @return [Inferno::Entities::Request]
|
91
|
-
def fhir_get_capability_statement(client: :default, name: nil
|
90
|
+
def fhir_get_capability_statement(client: :default, name: nil)
|
92
91
|
store_request('outgoing', name) do
|
93
92
|
fhir_client(client).conformance_statement
|
94
93
|
fhir_client(client).reply
|
@@ -102,9 +101,8 @@ module Inferno
|
|
102
101
|
# @param client [Symbol]
|
103
102
|
# @param name [Symbol] Name for this request to allow it to be used by
|
104
103
|
# other tests
|
105
|
-
# @param _options [Hash] TODO
|
106
104
|
# @return [Inferno::Entities::Request]
|
107
|
-
def fhir_read(resource_type, id, client: :default, name: nil
|
105
|
+
def fhir_read(resource_type, id, client: :default, name: nil)
|
108
106
|
store_request('outgoing', name) do
|
109
107
|
fhir_client(client).read(fhir_class_from_resource_type(resource_type), id)
|
110
108
|
end
|
@@ -117,12 +115,18 @@ module Inferno
|
|
117
115
|
# @param params [Hash] the search params
|
118
116
|
# @param name [Symbol] Name for this request to allow it to be used by
|
119
117
|
# other tests
|
120
|
-
# @param
|
118
|
+
# @param search_method [Symbol] Use `:post` to search via POST
|
121
119
|
# @return [Inferno::Entities::Request]
|
122
|
-
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
|
123
127
|
store_request('outgoing', name) do
|
124
128
|
fhir_client(client)
|
125
|
-
.search(fhir_class_from_resource_type(resource_type),
|
129
|
+
.search(fhir_class_from_resource_type(resource_type), { search: search })
|
126
130
|
end
|
127
131
|
end
|
128
132
|
|
@@ -1,38 +1,113 @@
|
|
1
1
|
module Inferno
|
2
2
|
module DSL
|
3
|
+
# This module contains the methods needed to configure a validator to
|
4
|
+
# perform validation of FHIR resources. The actual validation is performed
|
5
|
+
# by an external FHIR validation service. Tests will typically rely on
|
6
|
+
# `assert_valid_resource` for validation rather than directly calling
|
7
|
+
# methods on a validator.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
#
|
11
|
+
# validator do
|
12
|
+
# url 'http://example.com/validator'
|
13
|
+
# exclude_message { |message| message.type == 'info' }
|
14
|
+
# perform_additional_validation do |resource, profile_url|
|
15
|
+
# if something_is_wrong
|
16
|
+
# { type: 'error', message: 'something is wrong' }
|
17
|
+
# else
|
18
|
+
# { type: 'info', message: 'everything is ok' }
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
# end
|
3
22
|
module FHIRValidation
|
4
23
|
def self.included(klass)
|
5
24
|
klass.extend ClassMethods
|
6
25
|
end
|
7
26
|
|
27
|
+
# Perform validation, and add validation messages to the runnable
|
28
|
+
#
|
29
|
+
# @param resource [FHIR::Model]
|
30
|
+
# @param profile_url [String]
|
31
|
+
# @param validator [Symbol] the name of the validator to use
|
32
|
+
# @return [Boolean] whether the resource is valid
|
8
33
|
def resource_is_valid?(resource: self.resource, profile_url: nil, validator: :default)
|
9
34
|
find_validator(validator).resource_is_valid?(resource, profile_url, self)
|
10
35
|
end
|
11
36
|
|
37
|
+
# Find a particular validator. Looks through a runnable's parents up to
|
38
|
+
# the suite to find a validator with a particular name
|
12
39
|
def find_validator(validator_name)
|
13
40
|
self.class.find_validator(validator_name)
|
14
41
|
end
|
15
42
|
|
16
43
|
class Validator
|
44
|
+
# @private
|
17
45
|
def initialize(&block)
|
18
46
|
instance_eval(&block)
|
19
47
|
end
|
20
48
|
|
49
|
+
# @private
|
21
50
|
def default_validator_url
|
22
51
|
ENV.fetch('VALIDATOR_URL')
|
23
52
|
end
|
24
53
|
|
54
|
+
# Set the url of the validator service
|
55
|
+
#
|
56
|
+
# @param url [String]
|
25
57
|
def url(validator_url = nil)
|
26
58
|
@url = validator_url if validator_url
|
27
59
|
|
28
60
|
@url
|
29
61
|
end
|
30
62
|
|
63
|
+
# @private
|
64
|
+
def additional_validations
|
65
|
+
@additional_validations ||= []
|
66
|
+
end
|
67
|
+
|
68
|
+
# Perform validation steps in addition to FHIR validation.
|
69
|
+
#
|
70
|
+
# @example
|
71
|
+
# perform_additional_validation do |resource, profile_url|
|
72
|
+
# if something_is_wrong
|
73
|
+
# { type: 'error', message: 'something is wrong' }
|
74
|
+
# else
|
75
|
+
# { type: 'info', message: 'everything is ok' }
|
76
|
+
# end
|
77
|
+
# end
|
78
|
+
# @yieldparam resource [FHIR::Model] the resource being validated
|
79
|
+
# @yieldparam profile_url [String] the profile the resource is being
|
80
|
+
# validated against
|
81
|
+
# @yieldreturn [Array<Hash<Symbol, String>>,Hash<Symbol, String>] The
|
82
|
+
# block should return a Hash or an Array of Hashes if any validation
|
83
|
+
# messages should be added. The Hash must contain two keys: `:type`
|
84
|
+
# and `:message`. `:type` can have a value of `'info'`, `'warning'`,
|
85
|
+
# or `'error'`. A type of `'error'` means the resource is invalid.
|
86
|
+
# `:message` contains the message string itself.
|
87
|
+
def perform_additional_validation(&block)
|
88
|
+
additional_validations << block
|
89
|
+
end
|
90
|
+
|
91
|
+
# @private
|
92
|
+
def additional_validation_messages(resource, profile_url)
|
93
|
+
additional_validations
|
94
|
+
.flat_map { |step| step.call(resource, profile_url) }
|
95
|
+
.select { |message| message.is_a? Hash }
|
96
|
+
end
|
97
|
+
|
98
|
+
# Filter out unwanted validation messages
|
99
|
+
#
|
100
|
+
# @example
|
101
|
+
# validator do
|
102
|
+
# exclude_message { |message| message.type == 'info' }
|
103
|
+
# end
|
104
|
+
# @yieldparam message [Inferno::Entities::Message]
|
31
105
|
def exclude_message(&block)
|
32
106
|
@exclude_message = block if block_given?
|
33
107
|
@exclude_message
|
34
108
|
end
|
35
109
|
|
110
|
+
# @see Inferno::DSL::FHIRValidation#resource_is_valid?
|
36
111
|
def resource_is_valid?(resource, profile_url, runnable)
|
37
112
|
profile_url ||= FHIR::Definitions.resource_definition(resource.resourceType).url
|
38
113
|
|
@@ -40,6 +115,8 @@ module Inferno
|
|
40
115
|
|
41
116
|
message_hashes = outcome.issue&.map { |issue| message_hash_from_issue(issue) } || []
|
42
117
|
|
118
|
+
message_hashes.concat(additional_validation_messages(resource, profile_url))
|
119
|
+
|
43
120
|
filter_messages(message_hashes)
|
44
121
|
|
45
122
|
message_hashes
|
@@ -47,10 +124,12 @@ module Inferno
|
|
47
124
|
.none? { |message_hash| message_hash[:type] == 'error' }
|
48
125
|
end
|
49
126
|
|
127
|
+
# @private
|
50
128
|
def filter_messages(message_hashes)
|
51
129
|
message_hashes.reject! { |message| exclude_message.call(Entities::Message.new(message)) } if exclude_message
|
52
130
|
end
|
53
131
|
|
132
|
+
# @private
|
54
133
|
def message_hash_from_issue(issue)
|
55
134
|
{
|
56
135
|
type: issue_severity(issue),
|
@@ -58,6 +137,7 @@ module Inferno
|
|
58
137
|
}
|
59
138
|
end
|
60
139
|
|
140
|
+
# @private
|
61
141
|
def issue_severity(issue)
|
62
142
|
case issue.severity
|
63
143
|
when 'warning'
|
@@ -69,6 +149,7 @@ module Inferno
|
|
69
149
|
end
|
70
150
|
end
|
71
151
|
|
152
|
+
# @private
|
72
153
|
def issue_message(issue)
|
73
154
|
location = if issue.respond_to?(:expression)
|
74
155
|
issue.expression&.join(', ')
|
@@ -79,6 +160,11 @@ module Inferno
|
|
79
160
|
"#{location}: #{issue&.details&.text}"
|
80
161
|
end
|
81
162
|
|
163
|
+
# Post a resource to the validation service for validating.
|
164
|
+
#
|
165
|
+
# @param resource [FHIR::Model]
|
166
|
+
# @param profile_url [String]
|
167
|
+
# @return [String] the body of the validation response
|
82
168
|
def validate(resource, profile_url)
|
83
169
|
RestClient.post(
|
84
170
|
"#{url}/validate",
|
@@ -94,10 +180,28 @@ module Inferno
|
|
94
180
|
@fhir_validators ||= {}
|
95
181
|
end
|
96
182
|
|
183
|
+
# Define a validator
|
184
|
+
# @example
|
185
|
+
# validator do
|
186
|
+
# url 'http://example.com/validator'
|
187
|
+
# exclude_message { |message| message.type == 'info' }
|
188
|
+
# perform_additional_validation do |resource, profile_url|
|
189
|
+
# if something_is_wrong
|
190
|
+
# { type: 'error', message: 'something is wrong' }
|
191
|
+
# else
|
192
|
+
# { type: 'info', message: 'everything is ok' }
|
193
|
+
# end
|
194
|
+
# end
|
195
|
+
# end
|
196
|
+
#
|
197
|
+
# @param name [Symbol] the name of the validator, only needed if you are
|
198
|
+
# using multiple validators
|
97
199
|
def validator(name = :default, &block)
|
98
200
|
fhir_validators[name] = Inferno::DSL::FHIRValidation::Validator.new(&block)
|
99
201
|
end
|
100
202
|
|
203
|
+
# Find a particular validator. Looks through a runnable's parents up to
|
204
|
+
# the suite to find a validator with a particular name
|
101
205
|
def find_validator(validator_name)
|
102
206
|
validator = fhir_validators[validator_name] || parent&.find_validator(validator_name)
|
103
207
|
|
@@ -1 +1 @@
|
|
1
|
-
(self.webpackChunkinferno_web_app=self.webpackChunkinferno_web_app||[]).push([[217],{3217:(t,e,n)=>{
|
1
|
+
"use strict";(self.webpackChunkinferno_web_app=self.webpackChunkinferno_web_app||[]).push([[217],{3217:(t,e,n)=>{n.r(e),n.d(e,{getCLS:()=>v,getFCP:()=>g,getFID:()=>h,getLCP:()=>y,getTTFB:()=>F});var i,a,r=function(){return"".concat(Date.now(),"-").concat(Math.floor(8999999999999*Math.random())+1e12)},o=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:-1;return{name:t,value:e,delta:0,entries:[],id:r(),isFinal:!1}},s=function(t,e){try{if(PerformanceObserver.supportedEntryTypes.includes(t)){var n=new PerformanceObserver((function(t){return t.getEntries().map(e)}));return n.observe({type:t,buffered:!0}),n}}catch(t){}},u=!1,c=!1,p=function(t){u=!t.persisted},f=function(){addEventListener("pagehide",p),addEventListener("beforeunload",(function(){}))},l=function(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1];c||(f(),c=!0),addEventListener("visibilitychange",(function(e){var n=e.timeStamp;"hidden"===document.visibilityState&&t({timeStamp:n,isUnloading:u})}),{capture:!0,once:e})},d=function(t,e,n,i){var a;return function(){n&&e.isFinal&&n.disconnect(),e.value>=0&&(i||e.isFinal||"hidden"===document.visibilityState)&&(e.delta=e.value-(a||0),(e.delta||e.isFinal||void 0===a)&&(t(e),a=e.value))}},v=function(t){var e,n=arguments.length>1&&void 0!==arguments[1]&&arguments[1],i=o("CLS",0),a=function(t){t.hadRecentInput||(i.value+=t.value,i.entries.push(t),e())},r=s("layout-shift",a);r&&(e=d(t,i,r,n),l((function(t){var n=t.isUnloading;r.takeRecords().map(a),n&&(i.isFinal=!0),e()})))},m=function(){return void 0===i&&(i="hidden"===document.visibilityState?0:1/0,l((function(t){var e=t.timeStamp;return i=e}),!0)),{get timeStamp(){return i}}},g=function(t){var e,n=o("FCP"),i=m(),a=s("paint",(function(t){"first-contentful-paint"===t.name&&t.startTime<i.timeStamp&&(n.value=t.startTime,n.isFinal=!0,n.entries.push(t),e())}));a&&(e=d(t,n,a))},h=function(t){var e=o("FID"),n=m(),i=function(t){t.startTime<n.timeStamp&&(e.value=t.processingStart-t.startTime,e.entries.push(t),e.isFinal=!0,r())},a=s("first-input",i),r=d(t,e,a);a?l((function(){a.takeRecords().map(i),a.disconnect()}),!0):window.perfMetrics&&window.perfMetrics.onFirstInputDelay&&window.perfMetrics.onFirstInputDelay((function(t,i){i.timeStamp<n.timeStamp&&(e.value=t,e.isFinal=!0,e.entries=[{entryType:"first-input",name:i.type,target:i.target,cancelable:i.cancelable,startTime:i.timeStamp,processingStart:i.timeStamp+t}],r())}))},S=function(){return a||(a=new Promise((function(t){return["scroll","keydown","pointerdown"].map((function(e){addEventListener(e,t,{once:!0,passive:!0,capture:!0})}))}))),a},y=function(t){var e,n=arguments.length>1&&void 0!==arguments[1]&&arguments[1],i=o("LCP"),a=m(),r=function(t){var n=t.startTime;n<a.timeStamp?(i.value=n,i.entries.push(t)):i.isFinal=!0,e()},u=s("largest-contentful-paint",r);if(u){e=d(t,i,u,n);var c=function(){i.isFinal||(u.takeRecords().map(r),i.isFinal=!0,e())};S().then(c),l(c,!0)}},F=function(t){var e,n=o("TTFB");e=function(){try{var e=performance.getEntriesByType("navigation")[0]||function(){var t=performance.timing,e={entryType:"navigation",startTime:0};for(var n in t)"navigationStart"!==n&&"toJSON"!==n&&(e[n]=Math.max(t[n]-t.navigationStart,0));return e}();n.value=n.delta=e.responseStart,n.entries=[e],n.isFinal=!0,t(n)}catch(t){}},"complete"===document.readyState?setTimeout(e,0):addEventListener("pageshow",e)}}}]);
|