auscvdrisk_inferno 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: bcbe60d262e2e5db84dbd5d0c5dd5d89ecbe1a80ce5a30db952f7c1c96c60a29
4
+ data.tar.gz: 9938beb41fa23bf852e852f31d7015506b17b9a559853a01396b00357863c0f7
5
+ SHA512:
6
+ metadata.gz: bef956f3427cef93e9b595018a7d74e028d27705dd7e6aec017769fc75d0ed49c9806cb2ef3dd2fe7f6aa67179451546cdf0af32b1edadd51deb76e44c112539
7
+ data.tar.gz: 06adbbce609d183edb91bd6e2d450f34f86b80b6178f5746324f21bff229ffea58a830c0246188fcf40fc55507433b9acd65eac48a18dfeb85f460e0977622f6
@@ -0,0 +1,195 @@
1
+ require_relative 'helpers'
2
+
3
+ module AusCVDRisk
4
+ class Context < Inferno::TestGroup
5
+ include AusCVDRisk::Helpers
6
+
7
+ title 'Context'
8
+ id :context
9
+
10
+ test do
11
+ title 'Server declares support for reading Patient resources'
12
+
13
+ run do
14
+ fhir_get_capability_statement
15
+
16
+ assert_response_status(200)
17
+ assert_resource_type(:capability_statement)
18
+ capability_statement = resource
19
+
20
+ resource_type = 'Patient'
21
+ interaction = 'read'
22
+
23
+ rest_component = capability_statement.rest&.find { |r| r.mode == 'server' }
24
+ assert rest_component.present?, 'CapabilityStatement does not have a REST component with mode "server"'
25
+
26
+ resource_component = rest_component.resource&.find { |r| r.type == resource_type }
27
+ assert resource_component.present?, "CapabilityStatement does not declare support for #{resource_type} resource"
28
+
29
+ has_interaction = resource_component.interaction&.any? { |i| i.code == interaction }
30
+ assert has_interaction, "CapabilityStatement does not declare support for #{interaction} interaction on #{resource_type} resource"
31
+ end
32
+ end
33
+
34
+ test do
35
+ title 'Server declares support for reading Practitioner resources'
36
+
37
+ run do
38
+ fhir_get_capability_statement
39
+
40
+ assert_response_status(200)
41
+ assert_resource_type(:capability_statement)
42
+ capability_statement = resource
43
+
44
+ resource_type = 'Practitioner'
45
+ interaction = 'read'
46
+
47
+ rest_component = capability_statement.rest&.find { |r| r.mode == 'server' }
48
+ assert rest_component.present?, 'CapabilityStatement does not have a REST component with mode "server"'
49
+
50
+ resource_component = rest_component.resource&.find { |r| r.type == resource_type }
51
+ assert resource_component.present?, "CapabilityStatement does not declare support for #{resource_type} resource"
52
+
53
+ has_interaction = resource_component.interaction&.any? { |i| i.code == interaction }
54
+ assert has_interaction, "CapabilityStatement does not declare support for #{interaction} interaction on #{resource_type} resource"
55
+ end
56
+ end
57
+
58
+ test do
59
+ title 'Server declares support for AU Core Patient profile'
60
+
61
+ run do
62
+ fhir_get_capability_statement
63
+
64
+ assert_response_status(200)
65
+ assert_resource_type(:capability_statement)
66
+ capability_statement = resource
67
+
68
+ resource_type = 'Patient'
69
+ profile_url = 'http://hl7.org.au/fhir/core/StructureDefinition/au-core-patient'
70
+
71
+ has_profile = check_capability_statement_for_profile(capability_statement, resource_type, profile_url)
72
+
73
+ assert has_profile, "CapabilityStatement does not declare support for AU Core Patient profile"
74
+ end
75
+ end
76
+
77
+ test do
78
+ title 'Server declares support for AU Core Practitioner profile'
79
+
80
+ run do
81
+ fhir_get_capability_statement
82
+
83
+ assert_response_status(200)
84
+ assert_resource_type(:capability_statement)
85
+ capability_statement = resource
86
+
87
+ resource_type = 'Practitioner'
88
+ profile_url = 'http://hl7.org.au/fhir/core/StructureDefinition/au-core-practitioner'
89
+
90
+ has_profile = check_capability_statement_for_profile(capability_statement, resource_type, profile_url)
91
+
92
+ assert has_profile, "CapabilityStatement does not declare support for AU Core Practitioner profile"
93
+ end
94
+ end
95
+
96
+ test do
97
+ title 'Test Patient conforms to AU Core profile'
98
+
99
+ input :patient_id,
100
+ title: 'Patient ID',
101
+ description: 'ID of a patient resource on the server'
102
+
103
+ run do
104
+ skip_if patient_id.blank?, 'No patient ID provided'
105
+
106
+ fhir_read(:patient, patient_id)
107
+
108
+ assert_response_status(200)
109
+ assert_resource_type(:patient)
110
+
111
+ assert_valid_resource(profile_url: 'https://www.cvdcheck.org.au/fhir/StructureDefinition/CVDRiskPatient')
112
+ assert_valid_resource(profile_url: 'http://hl7.org.au/fhir/core/StructureDefinition/au-core-patient')
113
+
114
+ pass 'Test Patient has no validation errors'
115
+ end
116
+ end
117
+
118
+ test do
119
+ title 'Test Practitioner conforms to AU Core profile'
120
+
121
+ input :practitioner_id,
122
+ title: 'Practitioner ID',
123
+ description: 'ID of a practitioner resource on the server'
124
+
125
+ run do
126
+ skip_if practitioner_id.blank?, 'No practitioner ID provided'
127
+
128
+ fhir_read(:practitioner, practitioner_id)
129
+
130
+ assert_response_status(200)
131
+ assert_resource_type(:practitioner)
132
+
133
+ assert_valid_resource(profile_url: 'http://hl7.org.au/fhir/core/StructureDefinition/au-core-practitioner')
134
+
135
+ pass 'Test Practitioner has no validation errors'
136
+ end
137
+ end
138
+
139
+ test do
140
+ optional
141
+ title 'Server declares support for reading Encounter resources'
142
+
143
+ run do
144
+ fhir_get_capability_statement
145
+
146
+ assert_response_status(200)
147
+ assert_resource_type(:capability_statement)
148
+ capability_statement = resource
149
+
150
+ resource_type = 'Encounter'
151
+ interaction = 'read'
152
+
153
+ rest_component = capability_statement.rest&.find { |r| r.mode == 'server' }
154
+ assert rest_component.present?, 'CapabilityStatement does not have a REST component with mode "server"'
155
+
156
+ resource_component = rest_component.resource&.find { |r| r.type == resource_type }
157
+
158
+ if resource_component.present?
159
+ has_interaction = resource_component.interaction&.any? { |i| i.code == interaction }
160
+
161
+ if has_interaction
162
+ pass "Server declares support for reading Encounter resources in its CapabilityStatement"
163
+ else
164
+ warning "CapabilityStatement declares support for Encounter resource but not the read interaction"
165
+ end
166
+ else
167
+ warning "CapabilityStatement does not declare support for Encounter resource, but this is a SHOULD requirement"
168
+ end
169
+ end
170
+ end
171
+
172
+ test do
173
+ optional
174
+ title 'Test Encounter conforms to AU Core profile'
175
+
176
+ input :encounter_id,
177
+ title: 'Encounter ID',
178
+ description: 'ID of an encounter resource on the server',
179
+ optional: true
180
+
181
+ run do
182
+ assert encounter_id.present?, 'No encounter ID provided'
183
+
184
+ fhir_read(:encounter, encounter_id)
185
+
186
+ assert_response_status(200)
187
+ assert_resource_type(:encounter)
188
+
189
+ assert_valid_resource(profile_url: 'http://hl7.org.au/fhir/core/StructureDefinition/au-core-encounter')
190
+
191
+ pass 'Test Encounter has no validation errors'
192
+ end
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,125 @@
1
+ module AusCVDRisk
2
+ module Helpers
3
+ def fhir_get_capability_statement
4
+ fhir_client.capabilities.resource
5
+ @resource = fhir_client.reply.resource
6
+ @response = fhir_client.reply.response
7
+ end
8
+
9
+ def check_capability_statement_for_profile(capability_statement, resource_type, profile_url)
10
+ rest_component = capability_statement.rest&.find { |r| r.mode == 'server' }
11
+ return false unless rest_component.present?
12
+
13
+ resource_component = rest_component.resource&.find { |r| r.type == resource_type }
14
+ return false unless resource_component.present?
15
+
16
+ # Check if the profile is supported
17
+ has_profile = resource_component.supportedProfile&.any? { |p| p.include?(profile_url) } ||
18
+ resource_component.profile&.include?(profile_url)
19
+
20
+ has_profile
21
+ end
22
+
23
+ def check_search_parameter_support(capability_statement, resource_type, parameter_name)
24
+ rest_component = capability_statement.rest&.find { |r| r.mode == 'server' }
25
+ return false unless rest_component.present?
26
+
27
+ resource_component = rest_component.resource&.find { |r| r.type == resource_type }
28
+ return false unless resource_component.present?
29
+
30
+ # Check if the search parameter is supported
31
+ has_parameter = resource_component.searchParam&.any? { |p| p.name == parameter_name }
32
+
33
+ has_parameter
34
+ end
35
+
36
+ def check_global_search_parameter_support(capability_statement, parameter_name)
37
+ rest_component = capability_statement.rest&.find { |r| r.mode == 'server' }
38
+ return false unless rest_component.present?
39
+
40
+ # Check if the search parameter is supported
41
+ has_parameter = rest_component.searchParam&.any? { |p| p.name == parameter_name }
42
+
43
+ has_parameter
44
+ end
45
+
46
+ def check_search_combination_support(capability_statement, resource_type, parameter_names)
47
+ rest_component = capability_statement.rest&.find { |r| r.mode == 'server' }
48
+ return false unless rest_component.present?
49
+
50
+ resource_component = rest_component.resource&.find { |r| r.type == resource_type }
51
+ return false unless resource_component.present?
52
+
53
+ # Check if all individual parameters are supported
54
+ all_params_supported = parameter_names.all? do |param|
55
+ resource_component.searchParam&.any? { |p| p.name == param }
56
+ end
57
+
58
+ # Check if the combination is explicitly supported
59
+ combination_supported = resource_component.searchInclude&.any? do |combo|
60
+ combo == parameter_names.join('+')
61
+ end
62
+
63
+ all_params_supported && combination_supported
64
+ end
65
+
66
+ def check_include_support(capability_statement, resource_type, include_param)
67
+ rest_component = capability_statement.rest&.find { |r| r.mode == 'server' }
68
+ return false unless rest_component.present?
69
+
70
+ resource_component = rest_component.resource&.find { |r| r.type == resource_type }
71
+ return false unless resource_component.present?
72
+
73
+ # Check if the _include parameter is supported
74
+ has_include = resource_component.searchInclude&.any? { |p| p == include_param }
75
+
76
+ has_include
77
+ end
78
+
79
+ # Verify that all search parameters in the original query are present in the self link
80
+ def verify_search_parameters_in_self_link(bundle, original_params)
81
+ assert bundle.key?('link'), 'No link found in the search results bundle'
82
+ self_link = bundle['link'].find { |link| link['relation'] == 'self' }
83
+ assert self_link.present?, 'Self link not found in the search results bundle'
84
+
85
+ # Extract the query part from the self link URL
86
+ query_string = self_link['url'].split('?').last
87
+
88
+ # Parse the original parameters and the self link parameters
89
+ original_params_hash = parse_query_string(original_params)
90
+ self_link_params_hash = parse_query_string(query_string)
91
+
92
+ # Check that all original parameters are in the self link
93
+ original_params_hash.each do |key, value|
94
+ return false unless self_link_params_hash.key?(key)
95
+
96
+ # For parameters that can have multiple values (comma-separated)
97
+ if value.include?(',')
98
+ original_values = value.split(',').map(&:strip)
99
+ self_values = if self_link_params_hash[key].include?(',')
100
+ self_link_params_hash[key].split(',').map(&:strip)
101
+ else
102
+ [self_link_params_hash[key]]
103
+ end
104
+
105
+ original_values.each do |val|
106
+ return false unless self_values.include?(val)
107
+ end
108
+ else
109
+ return false unless value == self_link_params_hash[key]
110
+ end
111
+ end
112
+ true
113
+ end
114
+
115
+ # Parse a query string into a hash of parameters
116
+ def parse_query_string(query_string)
117
+ result = {}
118
+ query_string.split('&').each do |param|
119
+ key, value = param.split('=')
120
+ result[key] = URI.decode_www_form_component(value) if key && value
121
+ end
122
+ result
123
+ end
124
+ end
125
+ end
File without changes
@@ -0,0 +1,21 @@
1
+ # Note on this IGs folder
2
+
3
+ There are three reasons why it would be necessary to put an IG package.tgz in this folder. If none of these apply, you do not need to put any files here, or can consider removing any existing files to make it clear they are unused.
4
+
5
+ ## 1. Generated Test Suites
6
+ Some test kits use a "generator" to automatically generate the contents of a test suite for an IG. The IG files are required every time the test suites need to be regenerated. Examples of test kits that use this approach are the US Core Test Kit and CARIN IG for Blue Button® Test Kit.
7
+
8
+
9
+ ## 2. Non-published IG
10
+ If your IG, or the specific version of the IG you want to test against, is not published, then the validator service needs to load the IG from file in order to be able to validate resources with it. The IG must be referenced in the `fhir_resource_validator` block in the test suite definition by filename, ie:
11
+
12
+ ```ruby
13
+ fhir_resource_validator do
14
+ igs 'igs/filename.tgz'
15
+
16
+ ...
17
+ end
18
+ ```
19
+
20
+ ## 3. Inferno Validator UI
21
+ The Inferno Validator UI is configured to auto-load any IGs present in the igs folder and include them in all validations. In general, the Inferno team is currently leaving IGs in this folder even if not otherwise necessary to make it easy to re-enable the validator UI.
File without changes
@@ -0,0 +1,18 @@
1
+ require_relative 'version'
2
+
3
+ module AusCVDRisk
4
+ class Metadata < Inferno::TestKit
5
+ id :auscvdrisk
6
+ title 'Aus CVD Risk-i Test Kit'
7
+ description <<~DESCRIPTION
8
+ Provides tests to aid in the integration with the Aus CVD Risk-i Calculator application.
9
+ DESCRIPTION
10
+ suite_ids [:auscvdrisk]
11
+ # tags ['SMART App Launch', 'US Core']
12
+ # last_updated '2024-03-07'
13
+ version VERSION
14
+ maturity 'Low'
15
+ authors ['Australian e-Health Research Centre, CSIRO']
16
+ # repo 'TODO'
17
+ end
18
+ end
@@ -0,0 +1,58 @@
1
+ require_relative '../helpers'
2
+
3
+ module AusCVDRisk
4
+ module PrePopulation
5
+ class Demographics < Inferno::TestGroup
6
+ include AusCVDRisk::Helpers
7
+
8
+ title 'Pre-population: Demographics'
9
+ id :prepop_demographics
10
+
11
+ test do
12
+ optional
13
+ title 'Server declares support for CVD Risk Patient profile'
14
+
15
+ run do
16
+ fhir_get_capability_statement
17
+
18
+ assert_response_status(200)
19
+ assert_resource_type(:capability_statement)
20
+ capability_statement = resource
21
+
22
+ resource_type = 'Patient'
23
+ profile_url = 'https://www.cvdcheck.org.au/fhir/StructureDefinition/CVDRiskPatient'
24
+
25
+ has_profile = check_capability_statement_for_profile(capability_statement, resource_type, profile_url)
26
+
27
+ if has_profile
28
+ pass "Server declares support for CVD Risk Patient profile"
29
+ else
30
+ assert false, "CapabilityStatement does not declare support for CVD Risk Patient profile"
31
+ end
32
+ end
33
+ end
34
+
35
+ test do
36
+ optional
37
+ title 'Test Patient conforms to CVD Risk Patient profile'
38
+
39
+ input :patient_id,
40
+ title: 'Patient ID',
41
+ description: 'ID of a patient resource on the server'
42
+
43
+ run do
44
+ skip_if patient_id.blank?, 'No patient ID provided'
45
+
46
+ fhir_read(:patient, patient_id)
47
+
48
+ assert_response_status(200)
49
+ assert_resource_type(:patient)
50
+
51
+ assert_valid_resource(profile_url: 'https://www.cvdcheck.org.au/fhir/StructureDefinition/CVDRiskPatient')
52
+
53
+ pass 'Test Patient has no validation errors'
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end