subscriptions_test_kit 0.9.3 → 0.9.4

Sign up to get free protection for your applications and to get access to all the features.
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