subscriptions_test_kit 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +201 -0
  3. data/lib/inferno_requirements_tools/ext/inferno_core/runnable.rb +22 -0
  4. data/lib/inferno_requirements_tools/tasks/collect_requirements.rb +222 -0
  5. data/lib/inferno_requirements_tools/tasks/requirements_coverage.rb +264 -0
  6. data/lib/subscriptions_test_kit/common/notification_conformance_verification.rb +310 -0
  7. data/lib/subscriptions_test_kit/common/subscription_conformance_verification.rb +87 -0
  8. data/lib/subscriptions_test_kit/docs/samples/Subscription_empty.json +37 -0
  9. data/lib/subscriptions_test_kit/docs/samples/Subscription_full-resource.json +37 -0
  10. data/lib/subscriptions_test_kit/docs/samples/Subscription_id-only.json +38 -0
  11. data/lib/subscriptions_test_kit/docs/subscriptions_r5_backport_r4_client_suite_description.md +120 -0
  12. data/lib/subscriptions_test_kit/docs/subscriptions_r5_backport_r4_server_suite_description.md +170 -0
  13. data/lib/subscriptions_test_kit/endpoints/subscription_create_endpoint.rb +90 -0
  14. data/lib/subscriptions_test_kit/endpoints/subscription_read_endpoint.rb +32 -0
  15. data/lib/subscriptions_test_kit/endpoints/subscription_rest_hook_endpoint.rb +66 -0
  16. data/lib/subscriptions_test_kit/endpoints/subscription_status_endpoint.rb +70 -0
  17. data/lib/subscriptions_test_kit/igs/README.md +21 -0
  18. data/lib/subscriptions_test_kit/jobs/send_subscription_notifications.rb +130 -0
  19. data/lib/subscriptions_test_kit/requirements/generated/subscriptions-test-kit_requirements_coverage.csv +136 -0
  20. data/lib/subscriptions_test_kit/requirements/subscriptions-test-kit_out_of_scope_requirements.csv +23 -0
  21. data/lib/subscriptions_test_kit/requirements/subscriptions-test-kit_requirements.csv +145 -0
  22. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/common/subscription_simulation_utils.rb +140 -0
  23. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/fixtures/capability_statement.json +57 -0
  24. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/conformance_verification/notification_input_payload_verification_test.rb +50 -0
  25. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/conformance_verification/notification_input_verification_test.rb +25 -0
  26. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/conformance_verification/processing_attestation_test.rb +38 -0
  27. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/conformance_verification/subscription_verification_test.rb +28 -0
  28. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/conformance_verification_group.rb +20 -0
  29. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/interaction_test.rb +128 -0
  30. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/interaction_verification/event_notification_verification_test.rb +40 -0
  31. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/interaction_verification/handshake_notification_verification_test.rb +40 -0
  32. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/interaction_verification_group.rb +16 -0
  33. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow_group.rb +33 -0
  34. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client_suite.rb +66 -0
  35. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/common/interaction/creation_response_conformance_test.rb +51 -0
  36. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/common/interaction/notification_delivery_test.rb +56 -0
  37. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/common/interaction/subscription_conformance_test.rb +72 -0
  38. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/common/interaction_group.rb +24 -0
  39. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/common/interaction_verification/notification_conformance_test.rb +73 -0
  40. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/common/interaction_verification_group.rb +19 -0
  41. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/common/subscription_creation.rb +63 -0
  42. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/common/subscription_status_operation.rb +58 -0
  43. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/capability_statement/cs_conformance_test.rb +49 -0
  44. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/capability_statement/topic_discovery_test.rb +106 -0
  45. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/capability_statement_group.rb +21 -0
  46. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/event_notification/empty_content/empty_conformance_test.rb +63 -0
  47. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/event_notification/empty_content_group.rb +58 -0
  48. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/event_notification/full_resource_content/full_resource_conformance_test.rb +68 -0
  49. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/event_notification/full_resource_content_group.rb +58 -0
  50. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/event_notification/id_only_content/id_only_conformance_test.rb +66 -0
  51. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/event_notification/id_only_content_group.rb +58 -0
  52. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/event_notification_group.rb +25 -0
  53. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/handshake_heartbeat/handshake_conformance_test.rb +67 -0
  54. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/handshake_heartbeat/heartbeat_conformance_test.rb +74 -0
  55. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/handshake_heartbeat_group.rb +19 -0
  56. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/status_operation/status_invocation_test.rb +43 -0
  57. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/status_operation_group.rb +15 -0
  58. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/subscription_rejection/reject_subscriptions_test.rb +181 -0
  59. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/subscription_rejection_group.rb +21 -0
  60. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage_group.rb +26 -0
  61. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/workflow_group.rb +27 -0
  62. data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server_suite.rb +79 -0
  63. data/lib/subscriptions_test_kit/tags.rb +10 -0
  64. data/lib/subscriptions_test_kit/urls.rb +37 -0
  65. data/lib/subscriptions_test_kit/version.rb +5 -0
  66. data/lib/subscriptions_test_kit.rb +3 -0
  67. metadata +194 -0
@@ -0,0 +1,63 @@
1
+ module SubscriptionsTestKit
2
+ module SubscriptionsR5BackportR4Server
3
+ module SubscriptionCreation
4
+ def no_error_verification(message)
5
+ assert messages.none? { |msg| msg[:type] == 'error' }, message
6
+ end
7
+
8
+ def json_parse(json)
9
+ JSON.parse(json)
10
+ rescue JSON::ParserError
11
+ add_message('error', "#{request_number}Invalid JSON.")
12
+ false
13
+ end
14
+
15
+ def get_new_subscription_value(subscription, field_path)
16
+ field_path.reduce(subscription) { |obj, path| obj[path] }
17
+ end
18
+
19
+ def send_unsupported_subscription(subscription, unsupported_type, field_paths, subscription_field_old_values)
20
+ fhir_operation('/Subscription', body: subscription)
21
+
22
+ return if request.status != 201
23
+
24
+ new_subscription = json_parse(request.response_body)
25
+ return unless new_subscription
26
+
27
+ altered_field = false
28
+ field_paths.each_with_index do |field_path, index|
29
+ subscription_field_new_value = get_new_subscription_value(new_subscription, field_path)
30
+ if subscription_field_new_value != subscription_field_old_values[index]
31
+ altered_field = true
32
+ break
33
+ end
34
+ end
35
+
36
+ return if altered_field
37
+
38
+ add_message('error', %(
39
+ Sending a Subscription with #{unsupported_type} should be rejected, or the Subscription should be
40
+ altered to fix the unsupported value.))
41
+ end
42
+
43
+ def subscription_payload_type(subscription)
44
+ return unless subscription['channel']['_payload']
45
+
46
+ payload_extension = subscription['channel']['_payload']['extension'].find do |ext|
47
+ ext['url'].ends_with?('/backport-payload-content')
48
+ end
49
+ payload_extension['valueCode']
50
+ end
51
+
52
+ def send_subscription(subscription)
53
+ tags = ['subscription_creation']
54
+ payload_type = subscription_payload_type(subscription)
55
+ tags.append(payload_type) if payload_type.present?
56
+
57
+ fhir_operation('/Subscription', body: subscription, tags:)
58
+ assert_response_status(201)
59
+ payload_type
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,58 @@
1
+ module SubscriptionsTestKit
2
+ module SubscriptionsR5BackportR4Server
3
+ module SubscriptionStatusOperation
4
+ def no_error_verification(message)
5
+ assert messages.none? { |msg| msg[:type] == 'error' }, message
6
+ end
7
+
8
+ def find_elem(resource_array, param_name)
9
+ resource_array.find do |param|
10
+ param.name == param_name
11
+ end
12
+ end
13
+
14
+ def execute_subscription_status_operation(subscription_id)
15
+ fhir_operation("Subscription/#{subscription_id}/$status", operation_method: :get)
16
+ assert_response_status(200)
17
+ assert_resource_type('Bundle')
18
+
19
+ unless resource.type == 'searchset'
20
+ add_message('error', "Bundle returned from $status operation should be type 'searchset', was #{resource.type}")
21
+ end
22
+
23
+ assert_valid_resource
24
+
25
+ resource.entry
26
+ end
27
+
28
+ def subscription_ref_found?(entry, subscription_id)
29
+ subscription_param = find_elem(entry.resource.parameter, 'subscription')
30
+ subscription_ref = subscription_param.valueReference.reference
31
+ return false if subscription_ref.blank?
32
+
33
+ subscription_ref.split('/').last == subscription_id
34
+ end
35
+
36
+ def perform_subscription_status_test(subscription_id, status = nil)
37
+ bundle_entries = execute_subscription_status_operation(subscription_id)
38
+ subscription_status_entry = bundle_entries.find do |entry|
39
+ entry.resource.resourceType == 'Parameters' && subscription_ref_found?(entry, subscription_id)
40
+ end
41
+ assert(subscription_status_entry,
42
+ "No Subscription status with id #{subscription_id} returned from $status operation")
43
+
44
+ subscription_status_resource = subscription_status_entry.resource
45
+ assert_valid_resource(resource: subscription_status_resource,
46
+ profile_url: 'http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-subscription-status-r4')
47
+
48
+ subscription_status = find_elem(subscription_status_resource.parameter, 'status')
49
+
50
+ return unless status.present?
51
+
52
+ assert(subscription_status.valueCode == status, %(
53
+ The Subscription resource should have it's `status` set to #{status}, was
54
+ `#{subscription_status.valueCode}`))
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,49 @@
1
+ module SubscriptionsTestKit
2
+ module SubscriptionsR5BackportR4Server
3
+ class CSConformanceTest < Inferno::Test
4
+ id :subscriptions_r5_backport_r4_server_cs_conformance
5
+ title 'Capability Statement Conformance Verification'
6
+ description %(
7
+ This test attempts to retreive the server's Capability Statement in order to verify that it
8
+ declares support for the Backport Subscription Profile by including its official URL in the server's
9
+ CapabilityStatement.rest.resource.supportedProfile element: http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-subscription
10
+ )
11
+
12
+ verifies_requirements 'hl7.fhir.uv.subscriptions_1.1.0@52',
13
+ 'hl7.fhir.uv.subscriptions_1.1.0@114',
14
+ 'hl7.fhir.uv.subscriptions_1.1.0@120'
15
+
16
+ def subscription_profile_url
17
+ 'http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-subscription'
18
+ end
19
+
20
+ run do
21
+ fhir_get_capability_statement
22
+ assert_response_status(200)
23
+ assert_resource_type(:capability_statement)
24
+ assert_valid_resource
25
+
26
+ scratch[:capability_statement] ||= resource
27
+
28
+ assert(resource.rest.present?, 'Capability Statement missing the `rest` field')
29
+ rest_server = resource.rest.find { |elem| elem.mode == 'server' }
30
+ assert(rest_server.present?, "Capability Statement missing entry in `rest` with a `mode` set to 'server'")
31
+
32
+ rest_subscription = rest_server.resource.find { |elem| elem.type == 'Subscription' }
33
+ assert(rest_subscription.present?, 'Capability Statement missing `Subscription` resource in `rest` field')
34
+
35
+ assert(rest_subscription.supportedProfile.present?,
36
+ 'Capability Statement missing the `supportedProfile` field in `Subscription` resource')
37
+
38
+ subscription_profile_present = rest_subscription.supportedProfile.any? do |profile|
39
+ profile == subscription_profile_url
40
+ end
41
+ unless subscription_profile_present
42
+ add_message('warning', %(
43
+ Subscription resource should declare support for the Backport Subscription Profile by including its
44
+ official URL))
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,106 @@
1
+ require_relative '../../../../common/subscription_conformance_verification'
2
+
3
+ module SubscriptionsTestKit
4
+ module SubscriptionsR5BackportR4Server
5
+ class TopicDiscoveryTest < Inferno::Test
6
+ include SubscriptionConformanceVerification
7
+
8
+ id :subscriptions_r5_backport_r4_server_topic_discovery
9
+ title 'Attempt topic discovery'
10
+ description %(
11
+ This test attempts to perform topic discovery with the server. In order to allow for [discovery of supported
12
+ subscription topics in R4](https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/components.html#subscription-topics-in-r4),
13
+ the Subscriptions Backport IG defines the CapabilityStatement [SubscriptionTopic Canonical extension](https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/StructureDefinition-capabilitystatement-subscriptiontopic-canonical.html).
14
+ The extension allows server implementers to advertise the canonical URLs of topics available to clients and
15
+ allows clients to see the list of supported topics on a server.
16
+
17
+ The extension is expected to appear, if supported, on the Subscription resource entry. Note that servers are NOT
18
+ required to advertise supported topics via this extension, so this test it optional. Supported topics can also
19
+ be advertised, for example, by the CapabilityStatement.instantiates or CapabilityStatement.implementationGuide
20
+ elements of a CapabilityStatement, as defined by another Implementation Guide. Finally, FHIR R4 servers MAY
21
+ choose to leave topic discovery completely out-of-band and part of other steps, such as registration or
22
+ integration.
23
+
24
+ In order to claim conformance with this IG for R4, a server SHOULD support topic discovery
25
+ via the CapabilityStatement SubscriptionTopic Canonical extension.
26
+ )
27
+
28
+ verifies_requirements 'hl7.fhir.uv.subscriptions_1.1.0@2',
29
+ 'hl7.fhir.uv.subscriptions_1.1.0@48'
30
+
31
+ optional
32
+
33
+ def backport_subscription_server_url
34
+ 'http://hl7.org/fhir/uv/subscriptions-backport/CapabilityStatement/backport-subscription-server-r4'
35
+ end
36
+
37
+ def subscription_profile_url
38
+ 'http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-subscription'
39
+ end
40
+
41
+ def capability_statement_subscriptiontopic_extension
42
+ 'http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/capabilitystatement-subscriptiontopic-canonical'
43
+ end
44
+
45
+ def scratch_resource
46
+ scratch[:capability_statement] ||= {}
47
+ end
48
+
49
+ run do
50
+ resource = scratch_resource
51
+
52
+ skip_if resource.blank?, 'No Capability Statement received in previous test'
53
+
54
+ assert(resource.rest.present?, 'Capability Statement missing the `rest` field')
55
+ rest_server = resource.rest.find { |elem| elem.mode == 'server' }
56
+ assert(rest_server.present?, "Capability Statement missing entry in `rest` with a `mode` set to 'server'")
57
+
58
+ rest_subscription = rest_server.resource.find { |elem| elem.type == 'Subscription' }
59
+ assert(rest_subscription.present?, 'Capability Statement missing `Subscription` resource in `rest` field')
60
+
61
+ assert(rest_subscription.extension.present?,
62
+ 'Capability Statement missing the `extension` field on the Subscription resource')
63
+ subscription_topic_extension = rest_subscription.extension.select do |elem|
64
+ elem.url == capability_statement_subscriptiontopic_extension
65
+ end
66
+ assert(subscription_topic_extension.any?, %(
67
+ The server SHOULD support topic discovery via the CapabilityStatement SubscriptionTopic Canonical
68
+ extension))
69
+
70
+ subscription_requests = load_tagged_requests('subscription_creation')
71
+
72
+ if subscription_requests.any?
73
+ subscription_topics =
74
+ subscription_requests
75
+ .select { |request| request.status == 201 }
76
+ .uniq(&:response_body)
77
+ .map { |request| JSON.parse(request.response_body) }
78
+ .map { |subscription| subscription['criteria'] }
79
+ .uniq
80
+
81
+ if subscription_topics.any?
82
+ subscription_topics.each do |subscription_topic|
83
+ next if subscription_topic_extension.any? { |elem| elem.valueCanonical == subscription_topic }
84
+
85
+ add_message('error', %(
86
+ The SubscriptionTopic Canonical extension should include the Subscription Topic URLs found in
87
+ Subscription.criteria: #{subscription_topic}))
88
+ end
89
+ else
90
+ add_message('warning', %(
91
+ Subscriptions missing criteria field containing a Subscription topic URL. Could not verify any
92
+ topics found in the SubscriptionTopic Canonical extension))
93
+ end
94
+
95
+ no_error_verification(
96
+ "Subscription.criteria value(s) not found in Capability Statement's SubscriptionTopic Canonical extension"
97
+ )
98
+ else
99
+ add_message('warning', %(
100
+ No Subscription requests have been made in previous tests. Run the Subscription workflow tests first in order
101
+ to verify topics found in the SubscriptionTopic Canonical extension))
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,21 @@
1
+ require_relative 'capability_statement/cs_conformance_test'
2
+ require_relative 'capability_statement/topic_discovery_test'
3
+
4
+ module SubscriptionsTestKit
5
+ module SubscriptionsR5BackportR4Server
6
+ class CapabilityStatementGroup < Inferno::TestGroup
7
+ id :subscriptions_r5_backport_r4_server_capability_statement
8
+ title 'Capability Statement Verification'
9
+ description %(
10
+ Verify the Backport Subscriptions Server has a conformant Capability Statement and that it declares support for the
11
+ Backport Subscription Profile on the Subscription resource in the rest field. Then the group will verify if the
12
+ server supports topic discovert via the Capability Statement, which is an optional requirement.
13
+ )
14
+
15
+ run_as_group
16
+
17
+ test from: :subscriptions_r5_backport_r4_server_cs_conformance
18
+ test from: :subscriptions_r5_backport_r4_server_topic_discovery
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,63 @@
1
+ require_relative '../../../../../common/notification_conformance_verification'
2
+
3
+ module SubscriptionsTestKit
4
+ module SubscriptionsR5BackportR4Server
5
+ class EmptyConformanceTest < Inferno::Test
6
+ include NotificationConformanceVerification
7
+
8
+ id :subscriptions_r5_backport_r4_server_empty_conformance
9
+ title 'Subscription Empty Notification Verification'
10
+ description %(
11
+ This test takes the received empty notification bundle and ensures it is conformant to the
12
+ [R4 Topic-Based Subscription Notification Bundle](https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/StructureDefinition-backport-subscription-notification-r4.html)
13
+ profle and to the requirements listed for empty notifications.
14
+
15
+ With the content type of empty, no information about the resources involved in triggering the notification is
16
+ available via the subscription channel. When populating the SubscriptionStatus.notificationEvent structure for a
17
+ notification with an empty payload, a server SHALL NOT include references to resources
18
+ (e.g., SubscriptionStatus.notificationEvent.focus and SubscriptionStatus.notificationEvent.additionalContext
19
+ SHALL NOT be present).
20
+
21
+ When the content type is empty, notification bundles SHALL not contain Bundle.entry
22
+ elements other than the SubscriptionStatus for the notification.
23
+ )
24
+
25
+ verifies_requirements 'hl7.fhir.uv.subscriptions_1.1.0@14',
26
+ 'hl7.fhir.uv.subscriptions_1.1.0@15',
27
+ 'hl7.fhir.uv.subscriptions_1.1.0@28',
28
+ 'hl7.fhir.uv.subscriptions_1.1.0@69',
29
+ 'hl7.fhir.uv.subscriptions_1.1.0@70',
30
+ 'hl7.fhir.uv.subscriptions_1.1.0@38',
31
+ 'hl7.fhir.uv.subscriptions_1.1.0@39',
32
+ 'hl7.fhir.uv.subscriptions_1.1.0@35',
33
+ 'hl7.fhir.uv.subscriptions_1.1.0@67',
34
+ 'hl7.fhir.uv.subscriptions_1.1.0@51',
35
+ 'hl7.fhir.uv.subscriptions_1.1.0@53',
36
+ 'hl7.fhir.uv.subscriptions_1.1.0@65',
37
+ 'hl7.fhir.uv.subscriptions_1.1.0@99',
38
+ 'hl7.fhir.uv.subscriptions_1.1.0@138',
39
+ 'hl7.fhir.uv.subscriptions_1.1.0@139'
40
+
41
+ run do
42
+ subscription_requests = load_tagged_requests('subscription_creation', 'empty')
43
+ omit_if subscription_requests.empty?, 'No Subscriptions sent with notification payload type of `empty`'
44
+
45
+ subscription_requests.each do |subscription_request|
46
+ assert_valid_json(subscription_request.response_body)
47
+ subscription = JSON.parse(subscription_request.response_body)
48
+
49
+ requests = load_tagged_requests('event-notification', subscription['id'])
50
+ skip_if requests.empty?, 'No event-notification requests were made in a previous test as expected.'
51
+
52
+ requests = requests.uniq(&:request_body)
53
+
54
+ requests.each do |request|
55
+ empty_event_notification_verification(request.request_body)
56
+ end
57
+ end
58
+
59
+ no_error_verification('Received empty notification-events are not conformant.')
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,58 @@
1
+ require_relative '../../common/interaction_group'
2
+ require_relative '../../common/interaction_verification_group'
3
+ require_relative 'empty_content/empty_conformance_test'
4
+
5
+ module SubscriptionsTestKit
6
+ module SubscriptionsR5BackportR4Server
7
+ class EmptyContentGroup < Inferno::TestGroup
8
+ id :subscriptions_r5_backport_r4_server_empty_content
9
+ title 'Empty Notification Verification'
10
+ description %(
11
+ Verify that the received Notifications are conformant to the
12
+ [R4 Topic-Based Subscription Notification Bundle](https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/StructureDefinition-backport-subscription-notification-r4.html)
13
+ profile, including additional requirements around the `empty` content type ([example empty
14
+ Subscription](https://github.com/inferno-framework/subscriptions-test-kit/blob/main/lib/subscriptions_test_kit/docs/samples/Subscription_empty.json)).
15
+ )
16
+ run_as_group
17
+ optional
18
+
19
+ input_order :url, :credentials, :access_token, :empty_subscription_resource
20
+
21
+ group from: :subscriptions_r5_backport_r4_server_interaction do
22
+ id :subscriptions_r5_backport_r4_server_empty_content_interaction
23
+ optional
24
+
25
+ config(
26
+ options: { subscription_type: 'empty' },
27
+ inputs: {
28
+ subscription_resource: {
29
+ name: :empty_subscription_resource,
30
+ title: 'Empty Notification Subscription Resource',
31
+ type: 'textarea',
32
+ description: %(
33
+ A Subscription resource in JSON format that Inferno will send to the server under test
34
+ so that it can demonstrate its ability to send an empty Notification.
35
+ The instance must be conformant to the R4/B Topic-Based Subscription profile.
36
+ Inferno may modify the Subscription before submission, e.g., to point to Inferno's notification endpoint.
37
+ ),
38
+ optional: true
39
+ },
40
+ updated_subscription: { name: :empty_updated_subscription }
41
+ },
42
+ outputs: {
43
+ updated_subscription: { name: :empty_updated_subscription }
44
+ }
45
+ )
46
+ end
47
+ group from: :subscriptions_r5_backport_r4_server_interaction_verification do
48
+ id :subscriptions_r5_backport_r4_server_empty_content_interaction_verification
49
+ optional
50
+
51
+ config(
52
+ options: { subscription_type: 'empty' }
53
+ )
54
+ test from: :subscriptions_r5_backport_r4_server_empty_conformance
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,68 @@
1
+ require_relative '../../../../../common/notification_conformance_verification'
2
+
3
+ module SubscriptionsTestKit
4
+ module SubscriptionsR5BackportR4Server
5
+ class FullResourceConformanceTest < Inferno::Test
6
+ include NotificationConformanceVerification
7
+
8
+ id :subscriptions_r5_backport_r4_server_full_resource_conformance
9
+ title 'Subscription Full-Resource Notification Verification'
10
+ description %(
11
+ This test takes the received notification bundle and ensures it is conformant to the
12
+ [R4 Topic-Based Subscription Notification Bundle](https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/StructureDefinition-backport-subscription-notification-r4.html)
13
+ profle.
14
+
15
+ With the content type of full-resource, the resources involved in triggering the notification are included in the
16
+ notification bundle.
17
+
18
+ When the content type is full-resource, notification bundles SHALL include references to the
19
+ appropriate focus resources in the SubscriptionStatus.notificationEvent.focus element.
20
+
21
+ Notification bundles for full-resource subscriptions SHALL contain, in addition to the SubscriptionStatus, at
22
+ least one Bundle.entry for each resource relevant to the notification.
23
+
24
+ Each Bundle.entry for a full-resource notification SHALL contain a relevant resource in the
25
+ entry.resource element. If a server cannot include the resource contents due to an issue with a specific
26
+ notification, the server SHALL populate the entry.request and/or entry.response elements.
27
+ )
28
+
29
+ verifies_requirements 'hl7.fhir.uv.subscriptions_1.1.0@14',
30
+ 'hl7.fhir.uv.subscriptions_1.1.0@15',
31
+ 'hl7.fhir.uv.subscriptions_1.1.0@28',
32
+ 'hl7.fhir.uv.subscriptions_1.1.0@69',
33
+ 'hl7.fhir.uv.subscriptions_1.1.0@70',
34
+ 'hl7.fhir.uv.subscriptions_1.1.0@43',
35
+ 'hl7.fhir.uv.subscriptions_1.1.0@44',
36
+ 'hl7.fhir.uv.subscriptions_1.1.0@45',
37
+ 'hl7.fhir.uv.subscriptions_1.1.0@35',
38
+ 'hl7.fhir.uv.subscriptions_1.1.0@67',
39
+ 'hl7.fhir.uv.subscriptions_1.1.0@51',
40
+ 'hl7.fhir.uv.subscriptions_1.1.0@53',
41
+ 'hl7.fhir.uv.subscriptions_1.1.0@65',
42
+ 'hl7.fhir.uv.subscriptions_1.1.0@101',
43
+ 'hl7.fhir.uv.subscriptions_1.1.0@138',
44
+ 'hl7.fhir.uv.subscriptions_1.1.0@139'
45
+
46
+ run do
47
+ subscription_requests = load_tagged_requests('subscription_creation', 'full-resource')
48
+ omit_if subscription_requests.empty?, 'No Subscriptions sent with notification payload type of `full-resource`'
49
+
50
+ subscription_requests.each do |subscription_request|
51
+ assert_valid_json(subscription_request.response_body)
52
+ subscription = JSON.parse(subscription_request.response_body)
53
+
54
+ requests = load_tagged_requests('event-notification', subscription['id'])
55
+ skip_if requests.empty?, 'No event-notification requests were made in a previous test as expected.'
56
+
57
+ criteria_resource_type = subscription_criteria(subscription)
58
+ requests = requests.uniq(&:request_body)
59
+
60
+ requests.each do |request|
61
+ full_resource_event_notification_verification(request.request_body, criteria_resource_type)
62
+ end
63
+ end
64
+ no_error_verification('Received notification-events are not conformant.')
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,58 @@
1
+ require_relative '../../common/interaction_group'
2
+ require_relative '../../common/interaction_verification_group'
3
+ require_relative 'full_resource_content/full_resource_conformance_test'
4
+
5
+ module SubscriptionsTestKit
6
+ module SubscriptionsR5BackportR4Server
7
+ class FullResourceContentGroup < Inferno::TestGroup
8
+ id :subscriptions_r5_backport_r4_server_full_resource_content
9
+ title 'Full Resource Notification Verification'
10
+ description %(
11
+ Verify that the received Notifications are conformant to the
12
+ [R4 Topic-Based Subscription Notification Bundle](https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/StructureDefinition-backport-subscription-notification-r4.html)
13
+ profile, including additional requirements around the `full-resource` content type ([example full-resource
14
+ Subscription](https://github.com/inferno-framework/subscriptions-test-kit/blob/main/lib/subscriptions_test_kit/docs/samples/Subscription_full-resource.json)).
15
+ )
16
+ run_as_group
17
+ optional
18
+
19
+ input_order :url, :credentials, :access_token, :full_resource_subscription_resource
20
+
21
+ group from: :subscriptions_r5_backport_r4_server_interaction do
22
+ id :subscriptions_r5_backport_r4_server_full_resource_content_interaction
23
+ optional
24
+
25
+ config(
26
+ options: { subscription_type: 'full-resource' },
27
+ inputs: {
28
+ subscription_resource: {
29
+ name: :full_resource_subscription_resource,
30
+ title: 'Full-Resource Notification Subscription Resource',
31
+ type: 'textarea',
32
+ description: %(
33
+ A Subscription resource in JSON format that Inferno will send to the server under test
34
+ so that it can demonstrate its ability to send a full-resource Notification.
35
+ The instance must be conformant to the R4/B Topic-Based Subscription profile.
36
+ Inferno may modify the Subscription before submission, e.g., to point to Inferno's notification endpoint.
37
+ ),
38
+ optional: true
39
+ },
40
+ updated_subscription: { name: :full_resource_updated_subscription }
41
+ },
42
+ outputs: {
43
+ updated_subscription: { name: :full_resource_updated_subscription }
44
+ }
45
+ )
46
+ end
47
+ group from: :subscriptions_r5_backport_r4_server_interaction_verification do
48
+ id :subscriptions_r5_backport_r4_server_full_resource_content_interaction_verification
49
+ optional
50
+
51
+ config(
52
+ options: { subscription_type: 'full-resource' }
53
+ )
54
+ test from: :subscriptions_r5_backport_r4_server_full_resource_conformance
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,66 @@
1
+ require_relative '../../../../../common/notification_conformance_verification'
2
+
3
+ module SubscriptionsTestKit
4
+ module SubscriptionsR5BackportR4Server
5
+ class IdOnlyConformanceTest < Inferno::Test
6
+ include NotificationConformanceVerification
7
+
8
+ id :subscriptions_r5_backport_r4_server_id_only_conformance
9
+ title 'Subscription Id-Only Notification Verification'
10
+ description %(
11
+ This test takes the received notification bundle and ensures it is conformant to the
12
+ [R4 Topic-Based Subscription Notification Bundle](https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/StructureDefinition-backport-subscription-notification-r4.html)
13
+ profle.
14
+
15
+ With the content type of id-only, the resources involved in triggering the notification are only available
16
+ through other channels, but notifications include URLs which can be used to access those resources.
17
+
18
+ When the content type is id-only, notification bundles SHALL include references to the appropriate focus resources
19
+ in the SubscriptionStatus.notificationEvent.focus element.
20
+
21
+ Additionally, notification bundles MAY contain, in addition to the SubscriptionStatus used to convey status
22
+ information, at least one Bundle.entry for each resource relevant to the notification.
23
+
24
+ Each Bundle.entry for id-only notification SHALL contain a relevant resource URL in the fullUrl and request
25
+ elements, as is required for history bundles.
26
+ )
27
+
28
+ verifies_requirements 'hl7.fhir.uv.subscriptions_1.1.0@14',
29
+ 'hl7.fhir.uv.subscriptions_1.1.0@15',
30
+ 'hl7.fhir.uv.subscriptions_1.1.0@28',
31
+ 'hl7.fhir.uv.subscriptions_1.1.0@69',
32
+ 'hl7.fhir.uv.subscriptions_1.1.0@70',
33
+ 'hl7.fhir.uv.subscriptions_1.1.0@40',
34
+ 'hl7.fhir.uv.subscriptions_1.1.0@42',
35
+ 'hl7.fhir.uv.subscriptions_1.1.0@35',
36
+ 'hl7.fhir.uv.subscriptions_1.1.0@67',
37
+ 'hl7.fhir.uv.subscriptions_1.1.0@51',
38
+ 'hl7.fhir.uv.subscriptions_1.1.0@53',
39
+ 'hl7.fhir.uv.subscriptions_1.1.0@65',
40
+ 'hl7.fhir.uv.subscriptions_1.1.0@100',
41
+ 'hl7.fhir.uv.subscriptions_1.1.0@138',
42
+ 'hl7.fhir.uv.subscriptions_1.1.0@139'
43
+
44
+ run do
45
+ subscription_requests = load_tagged_requests('subscription_creation', 'id-only')
46
+ omit_if subscription_requests.empty?, 'No Subscriptions sent with notification payload type of `id-only`'
47
+
48
+ subscription_requests.each do |subscription_request|
49
+ assert_valid_json(subscription_request.response_body)
50
+ subscription = JSON.parse(subscription_request.response_body)
51
+
52
+ requests = load_tagged_requests('event-notification', subscription['id'])
53
+ skip_if requests.empty?, 'No event-notification requests were made in a previous test as expected.'
54
+
55
+ criteria_resource_type = subscription_criteria(subscription)
56
+ requests = requests.uniq(&:request_body)
57
+
58
+ requests.each do |request|
59
+ id_only_event_notification_verification(request.request_body, criteria_resource_type)
60
+ end
61
+ end
62
+ no_error_verification('Received notification-events are not conformant.')
63
+ end
64
+ end
65
+ end
66
+ end