subscriptions_test_kit 0.9.3 → 0.9.4

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.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/lib/subscriptions_test_kit/common/notification_conformance_verification.rb +7 -10
  3. data/lib/subscriptions_test_kit/common/subscription_conformance_verification.rb +14 -2
  4. data/lib/subscriptions_test_kit/docs/samples/Subscription_empty.json +1 -1
  5. data/lib/subscriptions_test_kit/docs/samples/Subscription_full-resource.json +1 -1
  6. data/lib/subscriptions_test_kit/docs/samples/Subscription_id-only.json +1 -1
  7. data/lib/subscriptions_test_kit/docs/subscriptions_r5_backport_r4_client_suite_description.md +4 -1
  8. data/lib/subscriptions_test_kit/docs/subscriptions_r5_backport_r4_server_suite_description.md +4 -1
  9. data/lib/subscriptions_test_kit/endpoints/subscription_status_endpoint.rb +3 -2
  10. data/lib/subscriptions_test_kit/jobs/send_subscription_notifications.rb +7 -2
  11. data/lib/subscriptions_test_kit/requirements/generated/subscriptions-test-kit_requirements_coverage.csv +7 -7
  12. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/common/subscription_simulation_utils.rb +41 -13
  13. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/conformance_verification/notification_input_payload_verification_test.rb +14 -7
  14. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/conformance_verification/notification_input_verification_test.rb +7 -4
  15. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/conformance_verification/subscription_verification_test.rb +1 -0
  16. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/interaction_test.rb +1 -0
  17. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/common/interaction/subscription_conformance_test.rb +2 -6
  18. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/common/subscription_creation.rb +10 -1
  19. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/event_notification/full_resource_content/full_resource_conformance_test.rb +1 -2
  20. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/event_notification/id_only_content/id_only_conformance_test.rb +1 -2
  21. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/subscription_rejection/reject_subscription_channel_endpoint_test.rb +65 -0
  22. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/subscription_rejection/reject_subscription_channel_payload_combo_test.rb +76 -0
  23. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/subscription_rejection/reject_subscription_channel_type_test.rb +68 -0
  24. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/subscription_rejection/reject_subscription_cross_version_extension_test.rb +59 -0
  25. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/subscription_rejection/reject_subscription_filter_test.rb +66 -0
  26. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/subscription_rejection/reject_subscription_payload_type_test.rb +66 -0
  27. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/subscription_rejection/reject_subscription_topic_test.rb +64 -0
  28. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/subscription_rejection_group.rb +14 -2
  29. data/lib/subscriptions_test_kit/version.rb +1 -1
  30. metadata +9 -3
  31. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/subscription_rejection/reject_subscriptions_test.rb +0 -185
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ad5fae1148d468463f60e61a0e7c273b90eac5294b1c8d19b588288d3d53ca77
4
- data.tar.gz: 62507f2c4a5cc9e39c1906bbb10032d1baa00b8ec33055762016c5ce2d22722c
3
+ metadata.gz: 5a807454f459add0f7fd19401c70a5a3c190c5003c375c0b4eefe1e4103c8410
4
+ data.tar.gz: e284a813940aed69d0cfb3dffef7f1ab034c2fbf799182fe5b200d7edcb1285d
5
5
  SHA512:
6
- metadata.gz: bad58bc3cdcb1c451bcb28f5dfbe8a5492e5cc8fff49b00f99d35d93588cec7936feeedee3c24984d6c1090ade8f92b35da4c89d83fd8036586f539cd0296ad7
7
- data.tar.gz: f26d5875e051b95b24dabc7f45cdba4b9bda8631f76f022aa1e753569e89be8fd264b052ac9662855023c2f685ad9b4ac5473732b8d7538b32d7a2db819e2e6b
6
+ metadata.gz: 248c63937da747106d20cbb41dbfd80728de783757a322160882d651ef7f43c30b4192fdf83f036803ef8e50eae082348284fcd30c3e537ae99385df080baf68
7
+ data.tar.gz: 89d5e860a4fa25b362d5a5d55054ec729dfd4395aa09d453bf71123c7b381120a0510509ad6fea2803665931ccd515c844f652442c1c6b8965b58a4fc6f6a0d6
@@ -150,8 +150,14 @@ module SubscriptionsTestKit
150
150
  end
151
151
 
152
152
  def check_bundle_entry_reference(bundle_entries, reference)
153
+ check_full_url = reference.start_with?('urn:')
154
+
153
155
  referenced_entry = bundle_entries.find do |entry|
154
- reference.include?("#{entry.resource.resourceType}/#{entry.resource.id}")
156
+ if check_full_url
157
+ reference == entry.fullUrl
158
+ else
159
+ reference.include?("#{entry.resource.resourceType}/#{entry.resource.id}")
160
+ end
155
161
  end
156
162
  referenced_entry.present?
157
163
  end
@@ -226,15 +232,6 @@ module SubscriptionsTestKit
226
232
  resource in the entry.resource element.))
227
233
  end
228
234
 
229
- def subscription_criteria(subscription)
230
- return unless subscription['_criteria']
231
-
232
- criteria_extension = subscription['_criteria']['extension'].find do |ext|
233
- ext['url'].ends_with?('/backport-filter-criteria')
234
- end
235
- criteria_extension['valueString'].split('?').first
236
- end
237
-
238
235
  def empty_event_notification_verification(notification_bundle)
239
236
  assert_valid_json(notification_bundle)
240
237
  bundle = FHIR.from_contents(notification_bundle)
@@ -37,6 +37,13 @@ module SubscriptionsTestKit
37
37
  end
38
38
  end
39
39
 
40
+ def valid_url?(url)
41
+ uri = URI.parse(url)
42
+ uri.is_a?(URI::HTTP) && !uri.host.nil?
43
+ rescue URI::InvalidURIError
44
+ false
45
+ end
46
+
40
47
  def subscription_verification(subscription_resource)
41
48
  assert_valid_json(subscription_resource)
42
49
  subscription = JSON.parse(subscription_resource)
@@ -46,6 +53,11 @@ module SubscriptionsTestKit
46
53
  The `type` field on the Subscription resource must be set to `rest-hook`, the `#{subscription_channel['type']}`
47
54
  channel type is unsupported.))
48
55
 
56
+ unless subscription['criteria'].present? && valid_url?(subscription['criteria'])
57
+ add_message('error', %(
58
+ 'The `criteria` field SHALL be populated and contain the canonical URL for the Subscription Topic.'
59
+ ))
60
+ end
49
61
  subscription_resource = FHIR.from_contents(subscription.to_json)
50
62
  assert_resource_type('Subscription', resource: subscription_resource)
51
63
  assert_valid_resource(resource: subscription_resource,
@@ -77,8 +89,8 @@ module SubscriptionsTestKit
77
89
  Added the Authorization header field with a Bearer token set to #{access_token} to the `header` field on the
78
90
  Subscription resource in order to connect successfully with the Inferno subscription channel.
79
91
  ))
80
- subscription['header'] = [] unless subscription['header'].present?
81
- subscription['header'].append("Authorization: Bearer #{access_token}")
92
+ subscription_channel['header'] = [] unless subscription_channel['header'].present?
93
+ subscription_channel['header'].append("Authorization: Bearer #{access_token}")
82
94
  end
83
95
  subscription['channel'] = subscription_channel
84
96
  subscription
@@ -11,7 +11,7 @@
11
11
  "_criteria" : {
12
12
  "extension" : [{
13
13
  "url" : "http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-filter-criteria",
14
- "valueString" : "Encounter?patient=Patient/123"
14
+ "valueString" : "Encounter.patient=Patient/123"
15
15
  }]
16
16
  },
17
17
  "channel" : {
@@ -11,7 +11,7 @@
11
11
  "_criteria" : {
12
12
  "extension" : [{
13
13
  "url" : "http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-filter-criteria",
14
- "valueString" : "Encounter?patient=Patient/123"
14
+ "valueString" : "Encounter.patient=Patient/123"
15
15
  }]
16
16
  },
17
17
  "channel" : {
@@ -12,7 +12,7 @@
12
12
  "_criteria" : {
13
13
  "extension" : [{
14
14
  "url" : "http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-filter-criteria",
15
- "valueString" : "Encounter?patient=Patient/123"
15
+ "valueString" : "Encounter.patient=Patient/123"
16
16
  }]
17
17
  },
18
18
  "channel" : {
@@ -117,4 +117,7 @@ Specific limitations to highlight include
117
117
  [provide feedback](https://github.com/inferno-framework/subscriptions-test-kit/issues) to that effect.
118
118
  - Inferno does not test delivery error handling and recovery scenarios, including
119
119
  the optional `$events` API and event numbering details.
120
- - Inferno does not support sending heartbeat notifications.
120
+ - Inferno does not support sending heartbeat notifications.
121
+ - Inferno does not verify that the shape and content of notifications are appropriate for the triggering
122
+ Subscription because those details, e.g., the resource types that can be a focus of the notification,
123
+ are defined within the SubscriptionTopic which is not available in FHIR R4.
@@ -167,4 +167,7 @@ Specific limitations to highlight include
167
167
  If there is a channel type that you would like to see verified, please
168
168
  [provide feedback](https://github.com/inferno-framework/subscriptions-test-kit/issues) to that effect.
169
169
  - Inferno does not test delivery error handling and recovery scenarios, including
170
- the optional `$events` API and event numbering details.
170
+ the optional `$events` API and event numbering details.
171
+ - Inferno does not verify that the shape and content of notifications are appropriate for the triggering
172
+ Subscription because those details, e.g., the resource types that can be a focus of the notification,
173
+ are defined within the SubscriptionTopic which is not available in FHIR R4.
@@ -38,11 +38,12 @@ module SubscriptionsTestKit
38
38
 
39
39
  notification_json = notification_bundle_input(result)
40
40
  subscription_url = "#{base_subscription_url}/#{subscription.id}"
41
+ subscription_topic = subscription.criteria
41
42
  status_code = determine_subscription_status_code(subscription_id)
42
43
  event_count = determine_event_count(test_run.test_session_id)
43
44
  response.status = 200
44
- response.body = derive_status_bundle(notification_json, subscription_url, status_code, event_count,
45
- request.url).to_json
45
+ response.body = derive_status_bundle(notification_json, subscription_url, subscription_topic, status_code,
46
+ event_count, request.url).to_json
46
47
  end
47
48
 
48
49
  def subscription_params_match?(params)
@@ -74,6 +74,10 @@ module SubscriptionsTestKit
74
74
  @authorization_header ||= @bearer_token.present? ? { 'Authorization' => "Bearer #{@bearer_token}" } : {}
75
75
  end
76
76
 
77
+ def subscription_topic
78
+ @subscription_topic ||= subscription&.criteria
79
+ end
80
+
77
81
  def test_still_waiting?
78
82
  results_repo.find_waiting_result(test_run_id: @test_run_id)
79
83
  end
@@ -83,14 +87,15 @@ module SubscriptionsTestKit
83
87
  end
84
88
 
85
89
  def send_handshake_notification
86
- handshake_json = derive_handshake_notification(@notification_json, @subscription_url).to_json
90
+ handshake_json = derive_handshake_notification(@notification_json, @subscription_url,
91
+ subscription_topic).to_json
87
92
  response = send_notification(handshake_json)
88
93
  persist_notification_request(response, [REST_HOOK_HANDSHAKE_NOTIFICATION_TAG])
89
94
  resume_inferno_test unless response.status == 200
90
95
  end
91
96
 
92
97
  def send_event_notification
93
- event_json = derive_event_notification(@notification_json, @subscription_url, 1).to_json
98
+ event_json = derive_event_notification(@notification_json, @subscription_url, subscription_topic, 1).to_json
94
99
  response = send_notification(event_json)
95
100
  persist_notification_request(response, [REST_HOOK_EVENT_NOTIFICATION_TAG])
96
101
  end
@@ -5,12 +5,12 @@ hl7.fhir.uv.subscriptions_1.1.0,4,https://hl7.org/fhir/uv/subscriptions-backport
5
5
  hl7.fhir.uv.subscriptions_1.1.0,7,https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/components.html#accepting-subscription-requests,"When a FHIR Server accepts a request to create a Subscription, the server is indicating to the client that the server:
6
6
  - is capable of detecting when events covered by the requested SubscriptionTopic occur, and
7
7
  - is willing to make a simple best effort attempt at delivering a notification for each occurrence of a matching event.",SHALL,Server,,,NA,NA,"1.1.03, 3.1.1.03, 3.2.1.03, 3.3.1.03","subscriptions_r5_backport_r4_server-subscriptions_r4_server_workflow-subscriptions_r4_server_interaction-subscriptions_r4_server_creation_response_conformance, subscriptions_r5_backport_r4_server-subscriptions_r4_server_event_notification-subscriptions_r4_server_empty_content-subscriptions_r4_server_empty_content_interaction-subscriptions_r4_server_creation_response_conformance, subscriptions_r5_backport_r4_server-subscriptions_r4_server_event_notification-subscriptions_r4_server_id_only_content-subscriptions_r4_server_id_only_content_interaction-subscriptions_r4_server_creation_response_conformance, subscriptions_r5_backport_r4_server-subscriptions_r4_server_event_notification-subscriptions_r4_server_full_resource_content-subscriptions_r4_server_full_resource_content_interaction-subscriptions_r4_server_creation_response_conformance"
8
- hl7.fhir.uv.subscriptions_1.1.0,8,https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/components.html#accepting-subscription-requests,When processing a request for a Subscription...a server SHOULD validate…that the SubscriptionTopic is valid and implemented by the server,SHOULD,Server,,,NA,NA,6.01,subscriptions_r5_backport_r4_server-subscriptions_r4_server_subscription_rejection-subscriptions_r4_server_reject_subscriptions
9
- hl7.fhir.uv.subscriptions_1.1.0,9,https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/components.html#accepting-subscription-requests,When processing a request for a Subscription...a server SHOULD validate…that all requested filters are defined in the requested topic and are implemented in the server,SHOULD,Server,,,NA,NA,6.01,subscriptions_r5_backport_r4_server-subscriptions_r4_server_subscription_rejection-subscriptions_r4_server_reject_subscriptions
10
- hl7.fhir.uv.subscriptions_1.1.0,10,https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/components.html#accepting-subscription-requests,When processing a request for a Subscription...a server SHOULD validate…that the channel type is known and implemented by the server,SHOULD,Server,,,NA,NA,6.01,subscriptions_r5_backport_r4_server-subscriptions_r4_server_subscription_rejection-subscriptions_r4_server_reject_subscriptions
11
- hl7.fhir.uv.subscriptions_1.1.0,11,https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/components.html#accepting-subscription-requests,"When processing a request for a Subscription...a server SHOULD validate…that the channel endpoint is valid for the channel provided (e.g., is it a valid URL of the expected type)",SHOULD,Server,,,NA,NA,6.01,subscriptions_r5_backport_r4_server-subscriptions_r4_server_subscription_rejection-subscriptions_r4_server_reject_subscriptions
12
- hl7.fhir.uv.subscriptions_1.1.0,12,https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/components.html#accepting-subscription-requests,When processing a request for a Subscription...a server SHOULD validate…that the payload configuration is known and implemented by the server,SHOULD,Server,,,NA,NA,6.01,subscriptions_r5_backport_r4_server-subscriptions_r4_server_subscription_rejection-subscriptions_r4_server_reject_subscriptions
13
- hl7.fhir.uv.subscriptions_1.1.0,13,https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/components.html#accepting-subscription-requests,"When processing a request for a Subscription...a server SHOULD validate…that the payload configuration is valid for the channel type requested (e.g., complies with the server’s security policy)",SHOULD,Server,,,NA,NA,6.01,subscriptions_r5_backport_r4_server-subscriptions_r4_server_subscription_rejection-subscriptions_r4_server_reject_subscriptions
8
+ hl7.fhir.uv.subscriptions_1.1.0,8,https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/components.html#accepting-subscription-requests,When processing a request for a Subscription...a server SHOULD validate…that the SubscriptionTopic is valid and implemented by the server,SHOULD,Server,,,NA,NA,6.02,subscriptions_r5_backport_r4_server-subscriptions_r4_server_subscription_rejection-subscriptions_r4_server_reject_subscription_topic
9
+ hl7.fhir.uv.subscriptions_1.1.0,9,https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/components.html#accepting-subscription-requests,When processing a request for a Subscription...a server SHOULD validate…that all requested filters are defined in the requested topic and are implemented in the server,SHOULD,Server,,,NA,NA,6.03,subscriptions_r5_backport_r4_server-subscriptions_r4_server_subscription_rejection-subscriptions_r4_server_reject_subscription_filter
10
+ hl7.fhir.uv.subscriptions_1.1.0,10,https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/components.html#accepting-subscription-requests,When processing a request for a Subscription...a server SHOULD validate…that the channel type is known and implemented by the server,SHOULD,Server,,,NA,NA,6.04,subscriptions_r5_backport_r4_server-subscriptions_r4_server_subscription_rejection-subscriptions_r4_server_reject_subscription_channel_type
11
+ hl7.fhir.uv.subscriptions_1.1.0,11,https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/components.html#accepting-subscription-requests,"When processing a request for a Subscription...a server SHOULD validate…that the channel endpoint is valid for the channel provided (e.g., is it a valid URL of the expected type)",SHOULD,Server,,,NA,NA,6.05,subscriptions_r5_backport_r4_server-subscriptions_r4_server_subscription_rejection-subscriptions_r4_server_reject_subscription_channel_endpoint
12
+ hl7.fhir.uv.subscriptions_1.1.0,12,https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/components.html#accepting-subscription-requests,When processing a request for a Subscription...a server SHOULD validate…that the payload configuration is known and implemented by the server,SHOULD,Server,,,NA,NA,6.06,subscriptions_r5_backport_r4_server-subscriptions_r4_server_subscription_rejection-subscriptions_r4_server_reject_subscription_payload_type
13
+ hl7.fhir.uv.subscriptions_1.1.0,13,https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/components.html#accepting-subscription-requests,"When processing a request for a Subscription...a server SHOULD validate…that the payload configuration is valid for the channel type requested (e.g., complies with the server’s security policy)",SHOULD,Server,,,NA,NA,6.07,subscriptions_r5_backport_r4_server-subscriptions_r4_server_subscription_rejection-subscriptions_r4_server_reject_subscription_channel_payload_combo
14
14
  hl7.fhir.uv.subscriptions_1.1.0,14,https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/components.html#subscription-notifications,"In ... FHIR R4 ... notifications are based on a history Bundle. The first entry always contains SubscriptionStatus information, encoded as ... a Parameters resource using the Backport SubscriptionStatus Profile in FHIR R4",SHALL,Server,,,NA,NA,"1.2.01, 3.1.2.01, 3.1.2.02, 3.2.2.01, 3.2.2.02, 3.3.2.01, 3.3.2.02, 4.01, 4.02","subscriptions_r5_backport_r4_server-subscriptions_r4_server_workflow-subscriptions_r4_server_interaction_verification-subscriptions_r4_server_notification_conformance, subscriptions_r5_backport_r4_server-subscriptions_r4_server_event_notification-subscriptions_r4_server_empty_content-subscriptions_r4_server_empty_content_interaction_verification-subscriptions_r4_server_notification_conformance, subscriptions_r5_backport_r4_server-subscriptions_r4_server_event_notification-subscriptions_r4_server_empty_content-subscriptions_r4_server_empty_content_interaction_verification-subscriptions_r4_server_empty_conformance, subscriptions_r5_backport_r4_server-subscriptions_r4_server_event_notification-subscriptions_r4_server_id_only_content-subscriptions_r4_server_id_only_content_interaction_verification-subscriptions_r4_server_notification_conformance, subscriptions_r5_backport_r4_server-subscriptions_r4_server_event_notification-subscriptions_r4_server_id_only_content-subscriptions_r4_server_id_only_content_interaction_verification-subscriptions_r4_server_id_only_conformance, subscriptions_r5_backport_r4_server-subscriptions_r4_server_event_notification-subscriptions_r4_server_full_resource_content-subscriptions_r4_server_full_resource_content_interaction_verification-subscriptions_r4_server_notification_conformance, subscriptions_r5_backport_r4_server-subscriptions_r4_server_event_notification-subscriptions_r4_server_full_resource_content-subscriptions_r4_server_full_resource_content_interaction_verification-subscriptions_r4_server_full_resource_conformance, subscriptions_r5_backport_r4_server-subscriptions_r4_server_handshake_heartbeat-subscriptions_r4_server_handshake_conformance, subscriptions_r5_backport_r4_server-subscriptions_r4_server_handshake_heartbeat-subscriptions_r4_server_heartbeat_conformance"
15
15
  hl7.fhir.uv.subscriptions_1.1.0,15,https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/components.html#subscription-notifications,"Note that since notifications use history type Bundles, all notifications need to comply with the requirements for that bundle type. Specifically, there are two invariants on Bundle (bdl-3 and bdl-4) that require a Bundle.entry.request element for every Bundle.entry.
16
16
  - For the status resource (entry[0]) the request SHALL be filled out to match a request to the $status operation.
@@ -68,7 +68,7 @@ hl7.fhir.uv.subscriptions_1.1.0,69,https://hl7.org/fhir/uv/subscriptions-backpor
68
68
  hl7.fhir.uv.subscriptions_1.1.0,70,https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/conformance.html#notification-entry-subscriptionstatus-1,The status entry SHALL be the first entry of each notification bundle.,SHALL,Server,,,NA,NA,"1.2.01, 3.1.2.01, 3.1.2.02, 3.2.2.01, 3.2.2.02, 3.3.2.01, 3.3.2.02, 4.01, 4.02","subscriptions_r5_backport_r4_server-subscriptions_r4_server_workflow-subscriptions_r4_server_interaction_verification-subscriptions_r4_server_notification_conformance, subscriptions_r5_backport_r4_server-subscriptions_r4_server_event_notification-subscriptions_r4_server_empty_content-subscriptions_r4_server_empty_content_interaction_verification-subscriptions_r4_server_notification_conformance, subscriptions_r5_backport_r4_server-subscriptions_r4_server_event_notification-subscriptions_r4_server_empty_content-subscriptions_r4_server_empty_content_interaction_verification-subscriptions_r4_server_empty_conformance, subscriptions_r5_backport_r4_server-subscriptions_r4_server_event_notification-subscriptions_r4_server_id_only_content-subscriptions_r4_server_id_only_content_interaction_verification-subscriptions_r4_server_notification_conformance, subscriptions_r5_backport_r4_server-subscriptions_r4_server_event_notification-subscriptions_r4_server_id_only_content-subscriptions_r4_server_id_only_content_interaction_verification-subscriptions_r4_server_id_only_conformance, subscriptions_r5_backport_r4_server-subscriptions_r4_server_event_notification-subscriptions_r4_server_full_resource_content-subscriptions_r4_server_full_resource_content_interaction_verification-subscriptions_r4_server_notification_conformance, subscriptions_r5_backport_r4_server-subscriptions_r4_server_event_notification-subscriptions_r4_server_full_resource_content-subscriptions_r4_server_full_resource_content_interaction_verification-subscriptions_r4_server_full_resource_conformance, subscriptions_r5_backport_r4_server-subscriptions_r4_server_handshake_heartbeat-subscriptions_r4_server_handshake_conformance, subscriptions_r5_backport_r4_server-subscriptions_r4_server_handshake_heartbeat-subscriptions_r4_server_heartbeat_conformance"
69
69
  hl7.fhir.uv.subscriptions_1.1.0,71,https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/conformance.html#notification-entry-subscriptionstatus-1,Clients supporting this guide SHALL be able to process a valid R4 Backported R5 SubscriptionStatus resource without errors.,SHALL,Client,,,"1.2.01, 1.2.02","subscriptions_r5_backport_r4_client-subscriptions_r4_client_workflow-subscriptions_r4_client_interaction_verification-subscriptions_r4_client_handshake_notification_verification, subscriptions_r5_backport_r4_client-subscriptions_r4_client_workflow-subscriptions_r4_client_interaction_verification-subscriptions_r4_client_event_notification_verification",NA,NA
70
70
  hl7.fhir.uv.subscriptions_1.1.0,72,https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/conformance.html#subscriptioncriteria-1,"The Subscription.criteria element is required (cardinality of 1..1), so any compatible implementation SHALL be able to read and/or write as necessary.",SHALL,Server,,,NA,NA,"1.1.01, 3.1.1.01, 3.2.1.01, 3.3.1.01","subscriptions_r5_backport_r4_server-subscriptions_r4_server_workflow-subscriptions_r4_server_interaction-subscriptions_r4_server_subscription_conformance, subscriptions_r5_backport_r4_server-subscriptions_r4_server_event_notification-subscriptions_r4_server_empty_content-subscriptions_r4_server_empty_content_interaction-subscriptions_r4_server_subscription_conformance, subscriptions_r5_backport_r4_server-subscriptions_r4_server_event_notification-subscriptions_r4_server_id_only_content-subscriptions_r4_server_id_only_content_interaction-subscriptions_r4_server_subscription_conformance, subscriptions_r5_backport_r4_server-subscriptions_r4_server_event_notification-subscriptions_r4_server_full_resource_content-subscriptions_r4_server_full_resource_content_interaction-subscriptions_r4_server_subscription_conformance"
71
- hl7.fhir.uv.subscriptions_1.1.0,73,https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/conformance.html#subscriptioncriteria-1,"Compared with the core specification, this guide specifies that the [Subscription.criteria] element SHALL contain the canonical URL for the Subscription Topic.",SHALL,Server,,,NA,NA,,
71
+ hl7.fhir.uv.subscriptions_1.1.0,73,https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/conformance.html#subscriptioncriteria-1,"Compared with the core specification, this guide specifies that the [Subscription.criteria] element SHALL contain the canonical URL for the Subscription Topic.",SHALL,Server,,,NA,NA,"1.1.01, 3.1.1.01, 3.2.1.01, 3.3.1.01","subscriptions_r5_backport_r4_server-subscriptions_r4_server_workflow-subscriptions_r4_server_interaction-subscriptions_r4_server_subscription_conformance, subscriptions_r5_backport_r4_server-subscriptions_r4_server_event_notification-subscriptions_r4_server_empty_content-subscriptions_r4_server_empty_content_interaction-subscriptions_r4_server_subscription_conformance, subscriptions_r5_backport_r4_server-subscriptions_r4_server_event_notification-subscriptions_r4_server_id_only_content-subscriptions_r4_server_id_only_content_interaction-subscriptions_r4_server_subscription_conformance, subscriptions_r5_backport_r4_server-subscriptions_r4_server_event_notification-subscriptions_r4_server_full_resource_content-subscriptions_r4_server_full_resource_content_interaction-subscriptions_r4_server_subscription_conformance"
72
72
  hl7.fhir.uv.subscriptions_1.1.0,74,https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/conformance.html#subscriptioncriteria-1,Servers supporting this guide SHALL be able to read values in this [Subscription.criteria] element and process requests for subscription topics referenced by it.,SHALL,Server,,,NA,NA,,
73
73
  hl7.fhir.uv.subscriptions_1.1.0,75,https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/conformance.html#subscriptioncriteria-1,"If a server does not support a requested topic [in the Subscription.criteria element] or will not honor the subscription otherwise, a server SHALL reject the subscription request.",SHALL,Server,,,NA,NA,,
74
74
  hl7.fhir.uv.subscriptions_1.1.0,76,https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/conformance.html#subscriptioncriteria-1,Clients supporting this guide SHALL be able to write subscription topic URLs into this [Subscription.criteria] element.,SHALL,Client,,,1.3.01,subscriptions_r5_backport_r4_client-subscriptions_r4_client_workflow-subscriptions_r4_client_conformance_verification-subscriptions_r4_client_subscription_verification,NA,NA
@@ -16,25 +16,32 @@ module SubscriptionsTestKit
16
16
  JSON.parse(test_result.input_json).find { |i| i['name'] == 'client_endpoint_access_token' }['value']
17
17
  end
18
18
 
19
- def derive_handshake_notification(notification_json, subscription_url)
19
+ def derive_handshake_notification(notification_json, subscription_url, subscription_topic)
20
20
  notification_bundle = FHIR.from_contents(notification_json)
21
- subscription_status = update_subscription_status(notification_bundle, subscription_url, 'requested', 0,
22
- 'handshake')
21
+ subscription_status = update_subscription_status(notification_bundle, subscription_url, subscription_topic,
22
+ 'requested', 0, 'handshake')
23
23
  subscription_status.parameter.delete(find_parameter(subscription_status, 'notification-event'))
24
24
  subscription_status.parameter.delete(find_parameter(subscription_status, 'error'))
25
+ notification_bundle.entry = [find_subscription_status_entry(notification_bundle)]
26
+ notification_bundle.timestamp = Time.now.utc.iso8601
25
27
  notification_bundle
26
28
  end
27
29
 
28
- def derive_event_notification(notification_json, subscription_url, event_count)
30
+ def derive_event_notification(notification_json, subscription_url, subscription_topic, event_count)
31
+ notification_timestamp = Time.now.utc.iso8601
29
32
  notification_bundle = FHIR.from_contents(notification_json)
30
- update_subscription_status(notification_bundle, subscription_url, 'active', event_count, 'event-notification')
33
+ subscription_status = update_subscription_status(notification_bundle, subscription_url, subscription_topic,
34
+ 'active', event_count, 'event-notification')
35
+ update_event_timestamps(subscription_status, notification_timestamp)
36
+ notification_bundle.timestamp = notification_timestamp
31
37
  notification_bundle
32
38
  end
33
39
 
34
- def derive_status_bundle(notification_json, subscription_url, status_code, event_count, request_url)
40
+ def derive_status_bundle(notification_json, subscription_url, subscription_topic,
41
+ status_code, event_count, request_url)
35
42
  notification_bundle = FHIR.from_contents(notification_json)
36
- subscription_status = update_subscription_status(notification_bundle, subscription_url, status_code,
37
- event_count, 'query-status')
43
+ subscription_status = update_subscription_status(notification_bundle, subscription_url, subscription_topic,
44
+ status_code, event_count, 'query-status')
38
45
  subscription_status.parameter.delete(find_parameter(subscription_status, 'notification-event'))
39
46
  subscription_status_entry = find_subscription_status_entry(notification_bundle)
40
47
  FHIR::Bundle.new(
@@ -45,7 +52,8 @@ module SubscriptionsTestKit
45
52
  ),
46
53
  link: FHIR::Bundle::Link.new(relation: 'self', url: request_url),
47
54
  total: 1,
48
- type: 'searchset'
55
+ type: 'searchset',
56
+ timestamp: Time.now.utc.iso8601
49
57
  )
50
58
  end
51
59
 
@@ -55,14 +63,19 @@ module SubscriptionsTestKit
55
63
  oo
56
64
  end
57
65
 
58
- def find_subscription(test_session_id)
66
+ def find_subscription(test_session_id, as_json: false)
59
67
  request = requests_repo.tagged_requests(test_session_id, [SUBSCRIPTION_CREATE_TAG])&.find do |r|
60
68
  r.status == 201
61
69
  end
62
70
  return unless request
63
71
 
64
72
  begin
65
- FHIR.from_contents(request.response_body)
73
+ if as_json
74
+ # needed to access primitive extensions
75
+ JSON.parse(request.response_body)
76
+ else
77
+ FHIR.from_contents(request.response_body)
78
+ end
66
79
  rescue StandardError
67
80
  nil
68
81
  end
@@ -106,18 +119,29 @@ module SubscriptionsTestKit
106
119
  subscription_url&.reference&.chomp('/')&.split('/')&.last
107
120
  end
108
121
 
109
- def update_subscription_status(notification_bundle, subscription_url, status_code, event_count, type)
122
+ def update_subscription_status(notification_bundle, subscription_url, subscription_topic, status_code,
123
+ event_count, type)
110
124
  subscription_status_entry = find_subscription_status_entry(notification_bundle)
111
- subscription_status_entry.request = FHIR::Bundle::Entry::Request.new(method: 'POST',
125
+ subscription_status_entry.request = FHIR::Bundle::Entry::Request.new(method: 'GET',
112
126
  url: "#{subscription_url}/$status")
127
+ subscription_status_entry.response = FHIR::Bundle::Entry::Response.new(status: '200')
113
128
  subscription_status = subscription_status_entry&.resource
114
129
  set_subscription_reference(subscription_status, subscription_url)
130
+ find_parameter(subscription_status, 'topic')&.valueCanonical = subscription_topic
115
131
  find_parameter(subscription_status, 'status')&.valueCode = status_code
116
132
  find_parameter(subscription_status, 'type')&.valueCode = type
117
133
  find_parameter(subscription_status, 'events-since-subscription-start')&.valueString = event_count.to_s
118
134
  subscription_status
119
135
  end
120
136
 
137
+ def update_event_timestamps(subscription_status, timestamp = nil)
138
+ timestamp = Time.now.utc.iso8601 unless timestamp.present?
139
+ event_list = find_all_parameters(subscription_status, 'notification-event')
140
+ event_list.each do |event|
141
+ event.part.find { |part| part.name == 'timestamp' }&.valueInstant = timestamp
142
+ end
143
+ end
144
+
121
145
  def find_subscription_status_entry(notification_bundle)
122
146
  notification_bundle.entry.find do |e|
123
147
  e.resource&.resourceType == 'Parameters' && e.resource.parameter&.any? { |p| p.name == 'subscription' }
@@ -138,6 +162,10 @@ module SubscriptionsTestKit
138
162
  def find_parameter(subscription_status, parameter_name)
139
163
  subscription_status.parameter&.find { |p| p.name == parameter_name }
140
164
  end
165
+
166
+ def find_all_parameters(subscription_status, parameter_name)
167
+ subscription_status.parameter&.select { |p| p.name == parameter_name }
168
+ end
141
169
  end
142
170
  end
143
171
  end
@@ -13,8 +13,11 @@ module SubscriptionsTestKit
13
13
 
14
14
  id :subscriptions_r4_client_notification_input_payload_verification
15
15
  title '[USER INPUT VERIFICATION] Notification Bundle Input Conformance Verification for Payload Content'
16
- description 'This test verifies that the notification bundle from the test input meets the requirements ' \
17
- 'of the payload indicated in the subscription created by the client under test.'
16
+ description %(
17
+ This test verifies that the notification bundle sent by Inferno meets the requirements
18
+ of the payload indicated in the subscription created by the client under test.
19
+ The content of the notification will be based on the Bundle provided by the tester.
20
+ )
18
21
  input :notification_bundle
19
22
 
20
23
  run do
@@ -30,20 +33,24 @@ module SubscriptionsTestKit
30
33
  payload_content_code = payload_ext['valueCode'] if payload_ext
31
34
  skip_if(payload_content_code.nil?, 'Subscription does not have a payload content code')
32
35
 
33
- criteria_resource_type = subscription_criteria(subscription.source_hash)
36
+ load_tagged_requests(REST_HOOK_EVENT_NOTIFICATION_TAG)
37
+ skip_if(requests.none?, 'Inferno did not send an event notification')
34
38
 
35
39
  case payload_content_code
36
40
  when 'empty'
37
- empty_event_notification_verification(notification_bundle)
41
+ empty_event_notification_verification(request.request_body)
38
42
  when 'id-only'
39
- id_only_event_notification_verification(notification_bundle, criteria_resource_type)
43
+ id_only_event_notification_verification(request.request_body, nil)
40
44
  when 'full-resource'
41
- full_resource_event_notification_verification(notification_bundle, criteria_resource_type)
45
+ full_resource_event_notification_verification(request.request_body, nil)
42
46
  else
43
47
  skip "Unrecognized payload content code: #{payload_content_code}"
44
48
  end
45
49
 
46
- no_error_verification('Notification bundle input payload content was not conformant, see error messages')
50
+ no_error_verification(%(
51
+ Notification bundle payload content was not conformant to requirements of the #{payload_content_code}
52
+ content type. See error messages for details.
53
+ ))
47
54
  end
48
55
  end
49
56
  end
@@ -10,15 +10,18 @@ module SubscriptionsTestKit
10
10
  id :subscriptions_r4_client_notification_input_verification
11
11
  title '[USER INPUT VERIFICATION] Notification Bundle Input Conformance Verification'
12
12
  description %(
13
- This test verifies that the notification bundle provided by the tester is conformant
13
+ This test verifies that the notification bundle sent is conformant
14
14
  to the [R4 Topic-Based Subscription Notification Bundle
15
15
  profile](https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/StructureDefinition-backport-subscription-notification-r4.html).
16
- )
16
+ The content of the notification will be based on the Bundle provided by the tester.
17
+ )
17
18
  input :notification_bundle
18
19
 
19
20
  run do
20
- notification_verification(notification_bundle, 'event-notification')
21
- no_error_verification('Notification bundle input was not conformant, see error messages')
21
+ load_tagged_requests(REST_HOOK_EVENT_NOTIFICATION_TAG)
22
+ skip_if(requests.none?, 'Inferno did not send an event notification')
23
+ notification_verification(request.request_body, 'event-notification')
24
+ no_error_verification('Notification bundle was not conformant, see error messages')
22
25
  end
23
26
  end
24
27
  end
@@ -22,6 +22,7 @@ module SubscriptionsTestKit
22
22
  load_tagged_requests(SUBSCRIPTION_CREATE_TAG)
23
23
  skip_if(requests.none?, 'Inferno did not receive a Subscription creation request')
24
24
  subscription_verification(request.request_body)
25
+ no_error_verification('Subscription resource is not conformant.')
25
26
  end
26
27
  end
27
28
  end
@@ -3,6 +3,7 @@
3
3
  module SubscriptionsTestKit
4
4
  module SubscriptionsR5BackportR4Client
5
5
  class InteractionTest < Inferno::Test
6
+ include URLs
6
7
  id :subscriptions_r4_client_interaction
7
8
  description %(
8
9
  During this test, the client under test will interact with Inferno following the Subscription
@@ -32,6 +32,7 @@ module SubscriptionsTestKit
32
32
  )
33
33
 
34
34
  verifies_requirements 'hl7.fhir.uv.subscriptions_1.1.0@72',
35
+ 'hl7.fhir.uv.subscriptions_1.1.0@73',
35
36
  'hl7.fhir.uv.subscriptions_1.1.0@86'
36
37
 
37
38
  input :subscription_resource,
@@ -54,17 +55,12 @@ module SubscriptionsTestKit
54
55
  sent to Inferno.
55
56
  )
56
57
 
57
- output :updated_subscription, :subscription_topic
58
+ output :updated_subscription
58
59
 
59
60
  run do
60
61
  omit_if subscription_resource.blank?, 'Did not input a Subscription resource of this type.'
61
62
  subscription = subscription_verification(subscription_resource)
62
63
  no_error_verification('Subscription resource is not conformant.')
63
-
64
- assert(subscription['criteria'].present?,
65
- 'The `criteria` field SHALL be populated and contain the canonical URL for the Subscription Topic.')
66
- output subscription_topic: subscription['criteria']
67
-
68
64
  subscription = server_check_channel(subscription, access_token)
69
65
  output updated_subscription: subscription.to_json
70
66
  end
@@ -16,6 +16,12 @@ module SubscriptionsTestKit
16
16
  field_path.reduce(subscription) { |obj, path| obj[path] }
17
17
  end
18
18
 
19
+ def normalize_value(value)
20
+ return value.deep_transform_keys(&:to_sym) if value.is_a?(Hash)
21
+
22
+ value
23
+ end
24
+
19
25
  def send_unsupported_subscription(subscription, unsupported_type, field_paths, subscription_field_old_values)
20
26
  fhir_operation('/Subscription', body: subscription)
21
27
 
@@ -27,7 +33,10 @@ module SubscriptionsTestKit
27
33
  altered_field = false
28
34
  field_paths.each_with_index do |field_path, index|
29
35
  subscription_field_new_value = get_new_subscription_value(new_subscription, field_path)
30
- if subscription_field_new_value != subscription_field_old_values[index]
36
+ new_value = normalize_value(subscription_field_new_value)
37
+ old_value = normalize_value(subscription_field_old_values[index])
38
+
39
+ if new_value != old_value
31
40
  altered_field = true
32
41
  break
33
42
  end
@@ -54,11 +54,10 @@ module SubscriptionsTestKit
54
54
  requests = load_tagged_requests('event-notification', subscription['id'])
55
55
  skip_if requests.empty?, 'No event-notification requests were made in a previous test as expected.'
56
56
 
57
- criteria_resource_type = subscription_criteria(subscription)
58
57
  requests = requests.uniq(&:request_body)
59
58
 
60
59
  requests.each do |request|
61
- full_resource_event_notification_verification(request.request_body, criteria_resource_type)
60
+ full_resource_event_notification_verification(request.request_body, nil)
62
61
  end
63
62
  end
64
63
  no_error_verification('Received notification-events are not conformant.')
@@ -52,11 +52,10 @@ module SubscriptionsTestKit
52
52
  requests = load_tagged_requests('event-notification', subscription['id'])
53
53
  skip_if requests.empty?, 'No event-notification requests were made in a previous test as expected.'
54
54
 
55
- criteria_resource_type = subscription_criteria(subscription)
56
55
  requests = requests.uniq(&:request_body)
57
56
 
58
57
  requests.each do |request|
59
- id_only_event_notification_verification(request.request_body, criteria_resource_type)
58
+ id_only_event_notification_verification(request.request_body, nil)
60
59
  end
61
60
  end
62
61
  no_error_verification('Received notification-events are not conformant.')
@@ -0,0 +1,65 @@
1
+ require_relative '../common/subscription_creation'
2
+
3
+ module SubscriptionsTestKit
4
+ module SubscriptionsR5BackportR4Server
5
+ class RejectSubscriptionChannelEndpointTest < Inferno::Test
6
+ include SubscriptionCreation
7
+
8
+ id :subscriptions_r4_server_reject_subscription_channel_endpoint
9
+ title 'Server Handles Unsupported Subscription Channel Endpoints'
10
+ description %(
11
+ When processing a request for a Subscription a server SHOULD verify that the Subscription is supported and does
12
+ not contain any information not implemented by the server. If the Subscription is not supported, the server
13
+ should reject the Subscription create request, or it should attempt to adjust the Subscription. When
14
+ processing a request for a Subscription, a server SHOULD validate that the channel endpoint is valid
15
+ for the channel provided (e.g., is it a valid URL of the expected type).
16
+
17
+ The test will pass if the server either
18
+ 1. rejects the Subscription by responding with a non-201 response, or
19
+ 2. updates the Subscription resource to remove or replace the unsupported value.
20
+ )
21
+
22
+ verifies_requirements 'hl7.fhir.uv.subscriptions_1.1.0@11'
23
+
24
+ input :subscription_resource,
25
+ title: 'Workflow Subscription Resource',
26
+ type: 'textarea',
27
+ description: %(
28
+ A Subscription resource in JSON format that Inferno will send to the server under test
29
+ so that it can demonstrate its ability to perform the Subscription creation and Notification
30
+ response workflow. The instance must be conformant to the R4/B Topic-Based Subscription profile.
31
+ Inferno may modify the Subscription before submission, e.g., to point to Inferno's notification endpoint.
32
+ This input is also used by the unsupported Subscription test as the base on which to add unsupported
33
+ element values to test for server rejection.
34
+ )
35
+ input :unsupported_subscription_channel_endpoint,
36
+ title: 'Unsupported Subscription Channel Endpoint',
37
+ description: 'An unsupported value for the `channel.endpoint` element to test for Subscription rejection.',
38
+ optional: true
39
+
40
+ run do
41
+ skip_if(unsupported_subscription_channel_endpoint.blank?, %(
42
+ Provide a value in the "Unsupported Subscription Channel Endpoint" input to run this test.))
43
+
44
+ assert_valid_json(subscription_resource)
45
+ subscription = JSON.parse(subscription_resource)
46
+
47
+ unsupported_info = {
48
+ 'unsupported_title' => 'unsupported channel URL',
49
+ 'field_path' => ['channel', 'endpoint'],
50
+ 'field_value' => unsupported_subscription_channel_endpoint
51
+ }
52
+
53
+ field_name = unsupported_info['field_path'].last
54
+ outer_field_name = unsupported_info['field_path'].first
55
+ subscription_field = subscription[outer_field_name]
56
+ subscription_field[field_name] = unsupported_info['field_value']
57
+
58
+ send_unsupported_subscription(subscription, unsupported_info['unsupported_title'],
59
+ [unsupported_info['field_path']], [unsupported_info['field_value']])
60
+
61
+ no_error_verification('Unsupported Subscription creation error handling failures.')
62
+ end
63
+ end
64
+ end
65
+ end