onc_certification_g10_test_kit 2.0.0.rc3 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (27) hide show
  1. checksums.yaml +4 -4
  2. data/lib/inferno/terminology/tasks/check_built_terminology.rb +14 -12
  3. data/lib/onc_certification_g10_test_kit/bulk_data_authorization.rb +7 -4
  4. data/lib/onc_certification_g10_test_kit/bulk_data_group_export.rb +60 -17
  5. data/lib/onc_certification_g10_test_kit/bulk_data_group_export_validation.rb +10 -6
  6. data/lib/onc_certification_g10_test_kit/bulk_export_validation_tester.rb +48 -18
  7. data/lib/onc_certification_g10_test_kit/configuration_checker.rb +6 -5
  8. data/lib/onc_certification_g10_test_kit/multi_patient_api.rb +11 -0
  9. data/lib/onc_certification_g10_test_kit/onc_program_procedure.yml +1451 -0
  10. data/lib/onc_certification_g10_test_kit/profile_guesser.rb +2 -2
  11. data/lib/onc_certification_g10_test_kit/restricted_resource_type_access_group.rb +13 -13
  12. data/lib/onc_certification_g10_test_kit/single_patient_api_group.rb +89 -0
  13. data/lib/onc_certification_g10_test_kit/smart_app_launch_invalid_aud_group.rb +13 -12
  14. data/lib/onc_certification_g10_test_kit/smart_ehr_practitioner_app_group.rb +11 -5
  15. data/lib/onc_certification_g10_test_kit/smart_invalid_launch_group.rb +13 -16
  16. data/lib/onc_certification_g10_test_kit/smart_invalid_token_group.rb +11 -4
  17. data/lib/onc_certification_g10_test_kit/smart_limited_app_group.rb +18 -4
  18. data/lib/onc_certification_g10_test_kit/smart_public_standalone_launch_group.rb +15 -3
  19. data/lib/onc_certification_g10_test_kit/smart_standalone_patient_app_group.rb +8 -3
  20. data/lib/onc_certification_g10_test_kit/tasks/generate_matrix.rb +247 -0
  21. data/lib/onc_certification_g10_test_kit/tasks/test_procedure.rb +65 -0
  22. data/lib/onc_certification_g10_test_kit/token_revocation_group.rb +60 -60
  23. data/lib/onc_certification_g10_test_kit/unrestricted_resource_type_access_group.rb +13 -13
  24. data/lib/onc_certification_g10_test_kit/version.rb +1 -1
  25. data/lib/onc_certification_g10_test_kit/visual_inspection_and_attestations_group.rb +7 -6
  26. data/lib/onc_certification_g10_test_kit.rb +15 -82
  27. metadata +16 -12
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 428f977576be3ec320ca1bc66fe540d2c8003345b37dce99191ad20bc45f703a
4
- data.tar.gz: a2fb07e84cab07aaa9f35a273e7d35c48b81ac1d9e6ebedc8340982b3348683a
3
+ metadata.gz: 645d73a288a5f76e9b94634ed2be17253ce34f0e0eb6df7df6b7410e7a1d9175
4
+ data.tar.gz: f299ae93813a1b05ef838824bfbb4f7f7734e8695118e37f0eb7b3c08e28a2c1
5
5
  SHA512:
6
- metadata.gz: 9236ae11a6b6c9f7db9cbff2fe0824e3a5bcd5a3db9b2b11690157fc616181f9667737b2781efae9b452f93f1f5c8de389b78f2e3d4a2cee46f3c88d0ed40f9b
7
- data.tar.gz: 97dc283bcab7e28a7f799e77b121010933ab527f1244f9fea65d38b9a2c3c0cf75622c25f27cf32de2fef6d4bf47470958e06ea99561d53a926202ac198a3f78
6
+ metadata.gz: 46773dc8eb92ee96afb593506a1b16b5f6af23c62f9ff7f988789d27a38b7a54bab21f69e03f336df1d9c8d3e4f3929b69028a9d99fffebdeb2eda12f66fbce7
7
+ data.tar.gz: 87c04c10d334d9c469af26d8618cfa7ec83246b008f0f05fae632f8f2029a11f89e00dda164b2aedc318aab02055f4e928d8bb11545d84f9c32f2be70477116a
@@ -4,9 +4,11 @@ module Inferno
4
4
  module Terminology
5
5
  module Tasks
6
6
  class CheckBuiltTerminology
7
- MIME_TYPE_SYSTEMS = [
7
+ NON_UMLS_SYSTEMS = [
8
8
  'http://hl7.org/fhir/ValueSet/mimetypes',
9
- 'urn:ietf:bcp:13'
9
+ 'urn:ietf:bcp:13',
10
+ 'http://hl7.org/fhir/us/core/ValueSet/simple-language',
11
+ 'urn:ietf:bcp:47'
10
12
  ].freeze
11
13
 
12
14
  def run
@@ -15,16 +17,16 @@ module Inferno
15
17
  return
16
18
  end
17
19
 
18
- if only_mime_types_mismatch?
19
- Inferno.logger.info <<~MIME
20
+ if only_non_umls_mismatch?
21
+ Inferno.logger.info <<~NON_UMLS
20
22
  Terminology built successfully.
21
23
 
22
- Mime-type based terminology did not match, but this can be a
23
- result of using a newer version of the `mime-types-data` gem and
24
- does not necessarily reflect a problem with the terminology build.
25
- The expected mime-types codes were generated with version
26
- `mime-types-data` version `3.2021.0901`.
27
- MIME
24
+ Some terminology not based on UMLS did not match, but this can be
25
+ a result of these terminologies having a different update schedule
26
+ than UMLS. As long as the actual number of codes is close to the
27
+ expected number, this does not does not reflect a problem with the
28
+ terminology build.
29
+ NON_UMLS
28
30
  else
29
31
  Inferno.logger.info 'Terminology build results different than expected.'
30
32
  end
@@ -61,8 +63,8 @@ module Inferno
61
63
  new_manifest.find { |value_set| value_set[:url] == url }
62
64
  end
63
65
 
64
- def only_mime_types_mismatch?
65
- mismatched_value_sets.all? { |value_set| MIME_TYPE_SYSTEMS.include? value_set[:url] }
66
+ def only_non_umls_mismatch?
67
+ mismatched_value_sets.all? { |value_set| NON_UMLS_SYSTEMS.include? value_set[:url] }
66
68
  end
67
69
 
68
70
  def mismatched_value_set_message(expected_value_set)
@@ -21,8 +21,9 @@ module ONCCertificationG10TestKit
21
21
 
22
22
  input :bulk_token_endpoint,
23
23
  title: 'Backend Services Token Endpoint',
24
- description: 'The OAuth 2.0 Token Endpoint used by the Backend Services specification
25
- to provide bearer tokens.'
24
+ description: <<~DESCRIPTION
25
+ The OAuth 2.0 Token Endpoint used by the Backend Services specification to provide bearer tokens.
26
+ DESCRIPTION
26
27
  input :bulk_client_id,
27
28
  title: 'Bulk Data Client ID',
28
29
  description: 'Client ID provided at registration to the Inferno application.'
@@ -32,8 +33,10 @@ module ONCCertificationG10TestKit
32
33
  default: 'system/*.read'
33
34
  input :bulk_encryption_method,
34
35
  title: 'Encryption Method',
35
- description: 'The server is required to suport either ES384 or RS384 encryption methods
36
- for JWT signature verification. Select which method to use.',
36
+ description: <<~DESCRIPTION,
37
+ The server is required to suport either ES384 or RS384 encryption methods for JWT signature verification.
38
+ Select which method to use.
39
+ DESCRIPTION
37
40
  type: 'radio',
38
41
  default: 'ES384',
39
42
  options: {
@@ -19,11 +19,12 @@ module ONCCertificationG10TestKit
19
19
  description: 'The Group ID associated with the group of patients to be exported.'
20
20
  input :bulk_timeout,
21
21
  title: 'Export Times Out after (1-600)',
22
- description: 'While testing, Inferno waits for the server to complete the exporting task.
23
- If the calculated totalTime is greater than the timeout value specified here,
24
- Inferno bulk client stops testing. Please enter an integer for the maximum wait time in seconds.
25
- If timeout is less than 1, Inferno uses default value 180.
26
- If the timeout is greater than 600 (10 minutes), Inferno uses the maximum value 600.',
22
+ description: <<~DESCRIPTION,
23
+ While testing, Inferno waits for the server to complete the exporting task. If the calculated totalTime is
24
+ greater than the timeout value specified here, Inferno bulk client stops testing. Please enter an integer
25
+ for the maximum wait time in seconds. If timeout is less than 1, Inferno uses default value 180. If the
26
+ timeout is greater than 600 (10 minutes), Inferno uses the maximum value 600.
27
+ DESCRIPTION
27
28
  default: 180
28
29
 
29
30
  output :requires_access_token, :status_output, :bulk_download_url
@@ -56,9 +57,30 @@ module ONCCertificationG10TestKit
56
57
  test do
57
58
  title 'Bulk Data Server declares support for Group export operation in CapabilityStatement'
58
59
  description <<~DESCRIPTION
59
- The Bulk Data Server SHALL declare support for Group/[id]/$export operation in its server CapabilityStatement
60
+ This test verifies that the Bulk Data Server declares support for
61
+ Group/[id]/$export operation in its server CapabilityStatement.
62
+
63
+ Given flexibility in the FHIR specification for declaring constrained
64
+ OperationDefinitions, this test only verifies that the server declares
65
+ any operation on the Group resource. It does not verify that it
66
+ declares the standard group export OperationDefinition provided in the
67
+ Bulk Data specification, nor does it attempt to resolve any non-standard
68
+ OperationDefinitions to verify if it is a constrained version of the
69
+ standard OperationDefintion.
70
+
71
+ This test will provide a warning if no operations are declared at
72
+ `Group/[id]/$export`, via the
73
+ `CapabilityStatement.rest.resource.operation.name` element. It will
74
+ also provide an informational message if an operation on the Group
75
+ resource exists, but does not point to the standard OperationDefinition
76
+ canonical URL:
77
+ http://hl7.org/fhir/uv/bulkdata/OperationDefinition/group-export
78
+
79
+ Additionally, this test provides a warning if the bulk data server does
80
+ not include the following URL in its `CapabilityStatement.instantiates`
81
+ element: http://hl7.org/fhir/uv/bulkdata/CapabilityStatement/bulk-data
82
+
60
83
  DESCRIPTION
61
- # link 'http://hl7.org/fhir/uv/bulkdata/STU1/OperationDefinition-group-export.html'
62
84
 
63
85
  run do
64
86
  fhir_get_capability_statement(client: :bulk_server)
@@ -67,18 +89,39 @@ module ONCCertificationG10TestKit
67
89
  assert_valid_json(request.response_body)
68
90
  capability_statement = FHIR.from_contents(request.response_body)
69
91
 
70
- has_export_operation = capability_statement&.rest&.any? do |rest|
71
- rest.resource&.any? do |resource|
72
- resource.type == 'Group' &&
73
- resource.respond_to?(:operation) &&
74
- resource.operation&.find do |operation|
75
- operation.definition&.match(%r{^http://hl7.org/fhir/uv/bulkdata/OperationDefinition/group-export(\|\S+)?})
76
- end
92
+ warning do
93
+ has_instantiates = capability_statement&.instantiates&.any? do |canonical|
94
+ canonical.match(%r{^http://hl7.org/fhir/uv/bulkdata/CapabilityStatement/bulk-data(\|\S+)?$})
95
+ end
96
+ assert has_instantiates,
97
+ 'Server did not declare conformance to the Bulk Data IG by including ' \
98
+ "'http://hl7.org/fhir/uv/bulkdata/CapabilityStatement/bulk-data' in " \
99
+ " CapabilityStatement.instantiates element (#{capability_statement&.instantiates})"
100
+ end
101
+
102
+ group_resource_capabilities = nil
103
+
104
+ capability_statement&.rest&.each do |rest|
105
+ group_resource_capabilities = rest.resource&.find do |resource|
106
+ resource.type == 'Group'
77
107
  end
78
108
  end
79
109
 
80
- assert has_export_operation,
81
- 'Server CapabilityStatement did not declare support for export operation in Group resource'
110
+ assert group_resource_capabilities.respond_to?(:operation) && group_resource_capabilities.operation&.any?,
111
+ 'Server CapabilityStatement did not declare support for any operations on the Group resource'
112
+
113
+ has_export_operation = group_resource_capabilities.operation&.any? do |operation|
114
+ name_match = (operation.name == 'export')
115
+ if name_match && !operation.definition&.match(%r{^http://hl7.org/fhir/uv/bulkdata/OperationDefinition/group-export(\|\S+)?$})
116
+ info('Server CapabilityStatement does not include export operation with definition http://hl7.org/fhir/uv/bulkdata/OperationDefinition/group-export')
117
+ end
118
+ name_match
119
+ end
120
+ warning do
121
+ assert has_export_operation,
122
+ 'Server CapabilityStatement did not declare support for an operation named "export" in the Group ' \
123
+ ' resource (operation.name should be "export")'
124
+ end
82
125
  end
83
126
  end
84
127
 
@@ -161,7 +204,7 @@ module ONCCertificationG10TestKit
161
204
  start = Time.now
162
205
 
163
206
  loop do
164
- get(polling_url, headers: { authorization: "Bearer #{bearer_token}" })
207
+ get(polling_url, headers: { authorization: "Bearer #{bearer_token}", accept: 'application/json' })
165
208
 
166
209
  retry_after_val = request.response_header('retry-after')&.value.to_i
167
210
 
@@ -17,14 +17,18 @@ module ONCCertificationG10TestKit
17
17
  optional: true
18
18
  input :bulk_patient_ids_in_group,
19
19
  title: 'Patient IDs in exported Group',
20
- description: 'Comma separated list of every Patient ID that is in the specified Group. This information is
21
- provided by the system under test to verify that data returned matches expectations. Leave blank to not
22
- verify Group inclusion.'
20
+ description: <<~DESCRIPTION
21
+ Comma separated list of every Patient ID that is in the specified Group. This information is provided by
22
+ the system under test to verify that data returned matches expectations. Leave blank to not verify Group
23
+ inclusion.
24
+ DESCRIPTION
23
25
  input :bulk_device_types_in_group,
24
26
  title: 'Implantable Device Type Codes in exported Group',
25
- description: 'Comma separated list of every Implantable Device type that is in the specified Group. This
26
- information is provided by the system under test to verify that data returned matches expectations. Leave
27
- blank to verify all Device resources against the Implantable Device profile.',
27
+ description: <<~DESCRIPTION,
28
+ Comma separated list of every Implantable Device type that is in the specified Group. This information is
29
+ provided by the system under test to verify that data returned matches expectations. Leave blank to verify
30
+ all Device resources against the Implantable Device profile.
31
+ DESCRIPTION
28
32
  optional: true
29
33
 
30
34
  test from: :tls_version_test do
@@ -13,23 +13,26 @@ module ONCCertificationG10TestKit
13
13
 
14
14
  def observation_metadata
15
15
  [
16
- USCoreTestKit::PediatricBmiForAgeGroup.metadata,
17
- USCoreTestKit::PediatricWeightForHeightGroup.metadata,
18
- USCoreTestKit::ObservationLabGroup.metadata,
19
- USCoreTestKit::PulseOximetryGroup.metadata,
20
- USCoreTestKit::SmokingstatusGroup.metadata,
21
- USCoreTestKit::HeadCircumferenceGroup.metadata,
22
- USCoreTestKit::BpGroup.metadata,
23
- USCoreTestKit::BodyheightGroup.metadata,
24
- USCoreTestKit::BodytempGroup.metadata,
25
- USCoreTestKit::BodyweightGroup.metadata,
26
- USCoreTestKit::HeartrateGroup.metadata,
27
- USCoreTestKit::ResprateGroup.metadata
16
+ USCoreTestKit::USCoreV311::PediatricBmiForAgeGroup.metadata,
17
+ USCoreTestKit::USCoreV311::PediatricWeightForHeightGroup.metadata,
18
+ USCoreTestKit::USCoreV311::ObservationLabGroup.metadata,
19
+ USCoreTestKit::USCoreV311::PulseOximetryGroup.metadata,
20
+ USCoreTestKit::USCoreV311::SmokingstatusGroup.metadata,
21
+ USCoreTestKit::USCoreV311::HeadCircumferenceGroup.metadata,
22
+ USCoreTestKit::USCoreV311::BpGroup.metadata,
23
+ USCoreTestKit::USCoreV311::BodyheightGroup.metadata,
24
+ USCoreTestKit::USCoreV311::BodytempGroup.metadata,
25
+ USCoreTestKit::USCoreV311::BodyweightGroup.metadata,
26
+ USCoreTestKit::USCoreV311::HeartrateGroup.metadata,
27
+ USCoreTestKit::USCoreV311::ResprateGroup.metadata
28
28
  ]
29
29
  end
30
30
 
31
31
  def diagnostic_metadata
32
- [USCoreTestKit::DiagnosticReportLabGroup.metadata, USCoreTestKit::DiagnosticReportNoteGroup.metadata]
32
+ [
33
+ USCoreTestKit::USCoreV311::DiagnosticReportLabGroup.metadata,
34
+ USCoreTestKit::USCoreV311::DiagnosticReportNoteGroup.metadata
35
+ ]
33
36
  end
34
37
 
35
38
  def determine_metadata
@@ -37,17 +40,21 @@ module ONCCertificationG10TestKit
37
40
  return diagnostic_metadata if resource_type == 'DiagnosticReport'
38
41
 
39
42
  if resource_type == 'Location' || resource_type == 'Medication'
40
- return Array.wrap(USCoreTestKit::USCoreTestSuite.metadata.find do |meta|
43
+ return Array.wrap(USCoreTestKit::USCoreV311::USCoreTestSuite.metadata.find do |meta|
41
44
  meta.resource == resource_type
42
45
  end)
43
46
  end
44
- ["USCoreTestKit::#{resource_type}Group".constantize.metadata]
47
+ ["USCoreTestKit::USCoreV311::#{resource_type}Group".constantize.metadata]
45
48
  end
46
49
 
47
50
  def metadata_list
48
51
  @metadata_list ||= determine_metadata
49
52
  end
50
53
 
54
+ def resources_from_all_files
55
+ @resources_from_all_files ||= {}
56
+ end
57
+
51
58
  def patient_ids_seen
52
59
  scratch[:patient_ids_seen] ||= []
53
60
  end
@@ -58,7 +65,7 @@ module ONCCertificationG10TestKit
58
65
  headers
59
66
  end
60
67
 
61
- def stream_ndjson(endpoint, headers, process_chunk_line, process_response)
68
+ def stream_ndjson(endpoint, headers, process_chunk_line, process_response) # rubocop:disable Metrics/CyclomaticComplexity
62
69
  hanging_chunk = String.new
63
70
 
64
71
  process_body = proc { |chunk|
@@ -74,6 +81,24 @@ module ONCCertificationG10TestKit
74
81
 
75
82
  stream(process_body, endpoint, headers: headers)
76
83
 
84
+ max_redirect = 5
85
+
86
+ while [301, 302, 303, 307].include?(response[:status]) &&
87
+ request.response_header('location')&.value.present? &&
88
+ max_redirect.positive?
89
+
90
+ max_redirect -= 1
91
+
92
+ redirect_url = request.response_header('location')&.value
93
+
94
+ # handle relative redirects
95
+ redirect_url = URI.parse(endpoint).merge(redirect_url).to_s unless redirect_url.start_with?('http')
96
+
97
+ redirect_headers = headers.reject { |key, _value| key == :authorization }
98
+
99
+ stream(process_body, redirect_url, headers: redirect_headers)
100
+ end
101
+
77
102
  process_chunk_line.call(hanging_chunk)
78
103
  process_response.call(response)
79
104
  end
@@ -105,6 +130,7 @@ module ONCCertificationG10TestKit
105
130
  @metadata = meta
106
131
  @missing_elements = nil
107
132
  @missing_slices = nil
133
+ @missing_extensions = nil
108
134
  begin
109
135
  perform_must_support_test(resources[meta.profile_url])
110
136
  rescue Inferno::Exceptions::PassException
@@ -152,8 +178,9 @@ module ONCCertificationG10TestKit
152
178
  }
153
179
 
154
180
  stream_ndjson(url, build_headers(requires_access_token), process_line, process_headers)
155
- validate_conformance(resources)
156
-
181
+ resources_from_all_files.merge!(resources) do |_key, all_resources, file_resources|
182
+ all_resources | file_resources
183
+ end
157
184
  line_count
158
185
  end
159
186
 
@@ -169,11 +196,14 @@ module ONCCertificationG10TestKit
169
196
  skip message
170
197
  end
171
198
 
199
+ @resources_from_all_files = {}
172
200
  success_count = 0
173
201
  file_list.each do |file|
174
202
  success_count += check_file_request(file['url'])
175
203
  end
176
204
 
205
+ validate_conformance(resources_from_all_files)
206
+
177
207
  pass "Successfully validated #{success_count} #{resource_type} resource(s)."
178
208
  end
179
209
  end
@@ -55,7 +55,7 @@ module ONCCertificationG10TestKit
55
55
  success_messages << "* `#{url}`: #{actual_value_set[:count]} codes"
56
56
  elsif actual_value_set.nil?
57
57
  error_messages << "* `#{url}`: Not loaded"
58
- elsif terminology_checker.class::MIME_TYPE_SYSTEMS.include? url
58
+ elsif terminology_checker.class::NON_UMLS_SYSTEMS.include? url
59
59
  warning_messages <<
60
60
  "* `#{url}`: Expected codes: #{expected_value_set[:count]} Actual codes: #{actual_value_set[:count]}"
61
61
  else
@@ -74,10 +74,11 @@ module ONCCertificationG10TestKit
74
74
 
75
75
  if warning_messages.present?
76
76
  warning_message = <<~WARNING
77
- Mime-type based terminology did not exactly match. This can be the
78
- result of using a slightly different version of the `mime-types-data`
79
- gem and does not reflect a problem with the terminology build as long
80
- as the expected and actual number of codes are close to each other.
77
+ Some terminology not based on UMLS did not match, but this can be a
78
+ result of these terminologies having a different update schedule than
79
+ UMLS. As long as the actual number of codes is close to the expected
80
+ number, this does not does not reflect a problem with the terminology
81
+ build.
81
82
  WARNING
82
83
  messages << {
83
84
  type: 'warning',
@@ -36,6 +36,17 @@ module ONCCertificationG10TestKit
36
36
  id :multi_patient_api
37
37
  run_as_group
38
38
 
39
+ input_order :bulk_server_url,
40
+ :bulk_token_endpoint,
41
+ :bulk_client_id,
42
+ :bulk_scope,
43
+ :bulk_encryption_method,
44
+ :group_id,
45
+ :bulk_patient_ids_in_group,
46
+ :bulk_device_types_in_group,
47
+ :lines_to_validate,
48
+ :bulk_timeout
49
+
39
50
  group from: :bulk_data_authorization
40
51
  group from: :bulk_data_group_export
41
52
  group from: :bulk_data_group_export_validation