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,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SubscriptionsTestKit
4
+ module SubscriptionsR5BackportR4Client
5
+ class InteractionTest < Inferno::Test
6
+ id :subscriptions_r5_backport_r4_client_interaction
7
+ description %(
8
+ During this test, the client under test will interact with Inferno following the Subscription
9
+ workflow over a `rest-hook` channel. This includes the following steps
10
+ 1. The client under test sends a Subscription request to Inferno
11
+ 2. Inferno sends a handshake notification request to the endpoint specified in the Subscription.
12
+ 3. Inferno sends an event notification request to the endpoint specified in the Subscription.
13
+
14
+ While these steps are taking place and after, Inferno will be waiting for the user to indicate that
15
+ the interaction has completed successfully or failed for some reason. Additionally, the client
16
+ system may make additional requests, such as `$status` checks, while the test is waiting.
17
+ Afterwards, Inferno will no longer respond to requests.
18
+
19
+ To create the handshake and event notifications, Inferno uses the contents of the *Event
20
+ Notification Bundle* input. The provided notification will be modified as appropriate for
21
+ the request Inferno is making:
22
+ - General changes for all notification types
23
+ - update the `subscription` parameter entry reference.
24
+ - update the `status` parameter entry based on the previous interactions.
25
+ - update the `type` parameter entry based on the notification type (e.g., `event-notification` or `handshake`).
26
+ - update the number of notifications sent in the `events-since-subscription-start` parameter entry.
27
+ - `handshake`-specific changes:
28
+ - clear the `events` parameter entry.
29
+ - clear the `errors` parameter entry.
30
+
31
+ While the provided Notification must be conformant to the
32
+ [R4 Topic-Based Subscription Notification Bundle
33
+ profile](https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/StructureDefinition-backport-subscription-notification-r4.html)
34
+ for the tests to pass, the tests can run as long as the notification meets the
35
+ following minimal requirements:
36
+ 1. The provided content must be a valid json representation of a FHIR Bundle resource.
37
+ 2. The first instance in the Bundle is a Parameters resource.
38
+ 3. The first Parameters instance has a `subscription` parameter entry.
39
+ )
40
+ title 'Subscription Workflow Interaction'
41
+
42
+ input :access_token,
43
+ title: 'Access Token',
44
+ description: %(
45
+ The bearer token that the client under test will use when making Subscription creation, $status, and other
46
+ requests to Inferno's simulated Subscriptions server.
47
+ )
48
+ input :client_endpoint_access_token,
49
+ optional: true,
50
+ title: 'Client Notification Access Token',
51
+ description: %(
52
+ The bearer token that Inferno will send on requests to the client under test's rest-hook notification endpoint. Not
53
+ needed if the client under test will create a Subscription with an appropriate header value in the
54
+ `channel.header` element. If a value for the `authorization` header is provided in `channel.header`, this
55
+ value will override it.
56
+ )
57
+ input :notification_bundle,
58
+ title: 'Event Notification Bundle',
59
+ type: 'textarea',
60
+ description: %(
61
+ The event notification bundle from which Inferno will derive a handshake notification, an event
62
+ notification to send to the client endpoint, and responses to $status operation requests. The provided
63
+ Bundle must conform to the R4 Topic-Based Subscription Notification Bundle profile.
64
+ )
65
+
66
+ verifies_requirements 'hl7.fhir.uv.subscriptions_1.1.0@23'
67
+
68
+ run do
69
+ minimally_validate_notification(notification_bundle)
70
+ assert(messages.none? { |m| m[:type] == 'error' }, 'Notification Bundle input is invalid for use by Inferno, see error message(s)')
71
+
72
+ wait(
73
+ identifier: access_token,
74
+ timeout: 600,
75
+ message: %(
76
+ Inferno will wait until the the event notification workflow is complete. The steps in the workflow are:
77
+
78
+ 1. Inferno expects a Subscription POST request at:
79
+
80
+ `#{fhir_subscription_url}`
81
+
82
+ with the Authorization header set to:
83
+
84
+ `Bearer #{access_token}`
85
+
86
+ 2. Inferno will send a handshake notification to the rest-hook endpoint specified in the subscription.
87
+
88
+ 3. After a 5–10 second delay, Inferno will send an event notification to the rest-hook endpoint.
89
+
90
+ At any point while this test is waiting, Inferno will respond to Subscription GET and $status requests.
91
+
92
+ Once the client has received an event notification and has made any additional requests,
93
+ [click here to complete the test](#{resume_pass_url}?test_run_identifier=#{access_token})
94
+
95
+ If at any point something has gone wrong and the client is unable to continue,
96
+ [click here to fail the test](#{resume_fail_url}?test_run_identifier=#{access_token})
97
+
98
+ NOTE: The test must be completed or failed using the links above within 10 minutes. After that,
99
+ attempts to send requests or to complete or fail the tests using the links above
100
+ will result in a *"session not found"* error.
101
+ )
102
+ )
103
+ end
104
+
105
+ # Perform only the verification necessary for the Inferno test to function
106
+ def minimally_validate_notification(notification_bundle)
107
+ assert_valid_json(notification_bundle)
108
+ begin
109
+ bundle = FHIR.from_contents(notification_bundle)
110
+ rescue StandardError
111
+ assert(false, 'Notification bundle input is not a conformant FHIR Bundle')
112
+ end
113
+ assert_resource_type(:bundle, resource: bundle)
114
+ subscription_status = bundle.entry&.first&.resource
115
+ assert(subscription_status.present?, 'Notification bundle input must contain a subscription status entry')
116
+ assert_resource_type(:parameters, resource: subscription_status)
117
+
118
+ # Require the subscription param, just because we need something to later identify the subscription status
119
+ # bundle entry. Note we could just as easily use a different required param, like status or type.
120
+ subscription_param = subscription_status.parameter&.find { |p| p.name == 'subscription' }
121
+ assert(subscription_param.present?, 'Subscription status entry in notification bundle input must contain a'\
122
+ 'subscription parameter')
123
+ rescue Inferno::Exceptions::AssertionException => e
124
+ add_message('error', e.message)
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../common/subscription_simulation_utils'
4
+
5
+ module SubscriptionsTestKit
6
+ module SubscriptionsR5BackportR4Client
7
+ class EventNotificationVerificationTest < Inferno::Test
8
+ include SubscriptionSimulationUtils
9
+
10
+ id :subscriptions_r5_backport_r4_client_event_notification_verification
11
+ title 'Rest-Hook Event Notification Verification'
12
+ description %(
13
+ This test verifies that the client's response to the event notification
14
+ was conformant.
15
+ )
16
+ verifies_requirements 'hl7.fhir.uv.subscriptions_1.1.0@24',
17
+ 'hl7.fhir.uv.subscriptions_1.1.0@71'
18
+
19
+ run do
20
+ load_tagged_requests(REST_HOOK_EVENT_NOTIFICATION_TAG)
21
+ skip_if(requests.none?, 'Inferno did not send an event notification')
22
+
23
+ # The SendSubscriptionNotifications job saves a nil status if the request fails entirely
24
+ assert(request.status.present?, "Handshake notification request failed with error: #{request.response_body}")
25
+
26
+ assert(request.status.between?(200, 299), "Event notification was not successful, status code #{request.status}")
27
+
28
+ subscription = find_subscription(test_session_id)
29
+ if subscription.present?
30
+ mime_type = subscription&.channel&.payload
31
+ unless ALLOWED_MIME_TYPES.include?(mime_type)
32
+ add_message('warning', %(Subscription specified '#{mime_type}' for `Subscription.channel.payload`, but Inferno
33
+ only supports: #{ALLOWED_MIME_TYPES.map { |type| "'#{type}'" }.join(', ')}.
34
+ Event notification was sent with Content-Type: '#{DEFAULT_MIME_TYPE}'.))
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../common/subscription_simulation_utils'
4
+
5
+ module SubscriptionsTestKit
6
+ module SubscriptionsR5BackportR4Client
7
+ class HandshakeNotificationVerificationTest < Inferno::Test
8
+ include SubscriptionSimulationUtils
9
+
10
+ id :subscriptions_r5_backport_r4_client_handshake_notification_verification
11
+ title 'Rest-Hook Handshake Notification Verification'
12
+ description %(
13
+ This test verifies that the client's response to the handshake notification
14
+ was conformant.
15
+ )
16
+ verifies_requirements 'hl7.fhir.uv.subscriptions_1.1.0@71'
17
+
18
+ run do
19
+ load_tagged_requests(REST_HOOK_HANDSHAKE_NOTIFICATION_TAG)
20
+ skip_if(requests.none?, 'Inferno did not send a handshake notification')
21
+
22
+ # The SendSubscriptionNotifications job saves a nil status if the request fails entirely
23
+ assert(request.status.present?, "Handshake notification request failed with error: #{request.response_body}")
24
+
25
+ assert(request.status.between?(200, 299),
26
+ "Handshake notification was not successful, status code #{request.status}")
27
+
28
+ subscription = find_subscription(test_session_id)
29
+ if subscription.present?
30
+ mime_type = subscription&.channel&.payload
31
+ unless ALLOWED_MIME_TYPES.include?(mime_type)
32
+ add_message('warning', %(Subscription specified '#{mime_type}' for `Subscription.channel.payload`, but Inferno
33
+ only supports: #{ALLOWED_MIME_TYPES.map { |type| "'#{type}'" }.join(', ')}.
34
+ Handshake notification was sent with Content-Type: '#{DEFAULT_MIME_TYPE}'.))
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'interaction_verification/handshake_notification_verification_test'
4
+ require_relative 'interaction_verification/event_notification_verification_test'
5
+
6
+ module SubscriptionsTestKit
7
+ module SubscriptionsR5BackportR4Client
8
+ class InteractionVerificationGroup < Inferno::TestGroup
9
+ id :subscriptions_r5_backport_r4_client_interaction_verification
10
+ title 'Rest-Hook Subscription Interaction Verification'
11
+
12
+ test from: :subscriptions_r5_backport_r4_client_handshake_notification_verification
13
+ test from: :subscriptions_r5_backport_r4_client_event_notification_verification
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'workflow/interaction_test'
4
+ require_relative 'workflow/interaction_verification_group'
5
+ require_relative 'workflow/conformance_verification_group'
6
+
7
+ module SubscriptionsTestKit
8
+ module SubscriptionsR5BackportR4Client
9
+ class WorkflowGroup < Inferno::TestGroup
10
+ include URLs
11
+
12
+ id :subscriptions_r5_backport_r4_client_workflow
13
+ title 'Demonstrate the Rest-Hook Subscription Workflow'
14
+ description %(
15
+ Demonstrate the ability of the client to request the
16
+ creation of a FHIR Subscription instance and receive a notification
17
+ for that Subscription. The tester must provide the body of a Notification
18
+ that it expects to receive. Inferno will act as a server,
19
+ waiting for the Subscription creation request and then sending the
20
+ notification. Inferno will then verify that the provided Subscription
21
+ and notification match and that the exchange is conformant.
22
+ )
23
+ run_as_group
24
+
25
+ group 'Rest-Hook Subscription Interaction' do
26
+ test from: :subscriptions_r5_backport_r4_client_interaction
27
+ end
28
+
29
+ group from: :subscriptions_r5_backport_r4_client_interaction_verification
30
+ group from: :subscriptions_r5_backport_r4_client_conformance_verification
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'subscriptions_r5_backport_r4_client/workflow_group'
4
+ require_relative '../endpoints/subscription_create_endpoint'
5
+ require_relative '../endpoints/subscription_read_endpoint'
6
+ require_relative '../endpoints/subscription_status_endpoint'
7
+ require_relative '../version'
8
+
9
+ module SubscriptionsTestKit
10
+ module SubscriptionsR5BackportR4Client
11
+ class SubscriptionsR5BackportR4ClientSuite < Inferno::TestSuite
12
+ id :subscriptions_r5_backport_r4_client
13
+ title 'Subscriptions R5 Backport IG v1.1.0 FHIR R4 Client Test Suite'
14
+ short_title 'Subscriptions R4 Client'
15
+ version VERSION
16
+ description File.read(File.join(__dir__, '..', 'docs', 'subscriptions_r5_backport_r4_client_suite_description.md'))
17
+
18
+ links [
19
+ {
20
+ label: 'Report Issue',
21
+ url: 'https://github.com/inferno-framework/subscriptions-test-kit/issues'
22
+ },
23
+ {
24
+ label: 'Open Source',
25
+ url: 'https://github.com/inferno-framework/subscriptions-test-kit'
26
+ },
27
+ {
28
+ label: 'Download',
29
+ url: 'https://github.com/inferno-framework/subscriptions-test-kit/releases'
30
+ },
31
+ {
32
+ label: 'Implementation Guide',
33
+ url: 'https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/'
34
+ }
35
+ ]
36
+
37
+ # All FHIR validation requests will use this FHIR validator
38
+ fhir_resource_validator do
39
+ igs 'hl7.fhir.uv.subscriptions-backport#1.1.0'
40
+
41
+ exclude_message do |message|
42
+ message.message.match?(/\A\S+: \S+: URL value '.*' does not resolve/)
43
+ end
44
+ end
45
+
46
+ capability_statement = File.read(File.join(__dir__, 'subscriptions_r5_backport_r4_client', 'fixtures', 'capability_statement.json'))
47
+ route(:get, '/fhir/metadata', proc { [200, { 'Content-Type' => 'application/json' }, [capability_statement]] })
48
+
49
+ suite_endpoint :post, FHIR_SUBSCRIPTION_PATH, SubscriptionCreateEndpoint
50
+ suite_endpoint :get, FHIR_SUBSCRIPTION_INSTANCE_PATH, SubscriptionReadEndpoint
51
+ suite_endpoint :post, FHIR_SUBSCRIPTION_INSTANCE_STATUS_PATH, SubscriptionStatusEndpoint
52
+ suite_endpoint :get, FHIR_SUBSCRIPTION_INSTANCE_STATUS_PATH, SubscriptionStatusEndpoint
53
+ suite_endpoint :post, FHIR_SUBSCRIPTION_RESOURCE_STATUS_PATH, SubscriptionStatusEndpoint
54
+
55
+ resume_test_route :get, RESUME_PASS_PATH do |request|
56
+ request.query_parameters['test_run_identifier']
57
+ end
58
+
59
+ resume_test_route :get, RESUME_FAIL_PATH, result: 'fail' do |request|
60
+ request.query_parameters['test_run_identifier']
61
+ end
62
+
63
+ group from: :subscriptions_r5_backport_r4_client_workflow
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,51 @@
1
+ module SubscriptionsTestKit
2
+ module SubscriptionsR5BackportR4Server
3
+ class CreationResponseConformanceTest < Inferno::Test
4
+ id :subscriptions_r5_backport_r4_server_creation_response_conformance
5
+ title 'Verify Subscription Creation Response'
6
+ description %(
7
+ This test ensures that the server responded to the Subscription creation test with the new created Subscription
8
+ resource. If the Subscription's channel type is set to 'rest-hook', the test will ensure that the Subscription's
9
+ status is set to 'requested'.
10
+ )
11
+
12
+ verifies_requirements 'hl7.fhir.uv.subscriptions_1.1.0@7',
13
+ 'hl7.fhir.uv.subscriptions_1.1.0@25',
14
+ 'hl7.fhir.uv.subscriptions_1.1.0@49',
15
+ 'hl7.fhir.uv.subscriptions_1.1.0@29'
16
+
17
+ def subscription_type
18
+ config.options[:subscription_type]
19
+ end
20
+
21
+ run do
22
+ if subscription_type.present?
23
+ subscription_requests = load_tagged_requests('subscription_creation', subscription_type)
24
+ requests =
25
+ subscription_requests
26
+ .select { |request| request.status == 201 }
27
+ skip_if requests.empty?, 'No successful Subscription creation request was made in the previous test.'
28
+ else
29
+ all_requests = load_tagged_requests('subscription_creation')
30
+ all_subscription_requests =
31
+ all_requests
32
+ .select { |request| request.status == 201 }
33
+ skip_if all_subscription_requests.empty?,
34
+ 'No successful Subscription creation request was made in the previous test.'
35
+ requests = [all_subscription_requests.first]
36
+ end
37
+
38
+ requests.each do |subscription_request|
39
+ assert_valid_json(subscription_request.response_body)
40
+ subscription = FHIR.from_contents(subscription_request.response_body)
41
+ assert subscription.present?, 'Not a FHIR resource'
42
+
43
+ assert_resource_type('Subscription', resource: subscription)
44
+
45
+ assert(subscription.channel.type == 'rest-hook' && subscription.status == 'requested',
46
+ "The Subscription resource should have it's status set to 'requested', was '#{subscription.status}'")
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,56 @@
1
+ require_relative '../subscription_creation'
2
+ require_relative '../../../../urls'
3
+
4
+ module SubscriptionsTestKit
5
+ module SubscriptionsR5BackportR4Server
6
+ class NotificationDeliveryTest < Inferno::Test
7
+ include SubscriptionCreation
8
+ include URLs
9
+
10
+ id :subscriptions_r5_backport_r4_server_notification_delivery
11
+ title 'Send Subscription and Receive Notification Requests from Server'
12
+ description %(
13
+ This test sends a request to create the Subscription resource to the Subscriptions Backport FHIR Server.
14
+ If successful, it then waits for [notification](https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/notifications.html#notifications)
15
+ requests of the following types:
16
+ - handshake (required for `rest-hook` notifications)
17
+ - heartbeat (required if `heartbeatPeriod` field is populated in Subscription resource)
18
+ - event-notification
19
+ )
20
+ config options: { accepts_multiple_requests: true }
21
+
22
+ verifies_requirements 'hl7.fhir.uv.subscriptions_1.1.0@133'
23
+
24
+ input :updated_subscription
25
+ input :access_token,
26
+ title: 'Notification Access Token',
27
+ description: %(
28
+ An access token that the server under test will send to Inferno on notifications
29
+ so that the request gets associated with this test session. The token must be
30
+ provided as a `Bearer` token in the `Authorization` header of HTTP requests
31
+ sent to Inferno.
32
+ )
33
+
34
+ run do
35
+ subscription = JSON.parse(updated_subscription)
36
+ subscription_type = send_subscription(subscription)
37
+
38
+ wait(
39
+ identifier: "notification #{access_token}",
40
+ message: %(
41
+ **Subscription `#{subscription['id']}`: `#{subscription_type}` Notification Test**
42
+
43
+ Send any handshake, heartbeat, and `#{subscription_type}` event-notification requests for the Subscription
44
+ with id `#{subscription['id']}` to:
45
+
46
+ `#{subscription_channel_url}`
47
+
48
+ [Click here](#{resume_pass_url}?token=notification%20#{access_token}) when you have finished submitting
49
+ requests.
50
+
51
+ )
52
+ )
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,72 @@
1
+ require_relative '../../../../common/subscription_conformance_verification'
2
+
3
+ module SubscriptionsTestKit
4
+ module SubscriptionsR5BackportR4Server
5
+ class SubscriptionConformanceTest < Inferno::Test
6
+ include SubscriptionConformanceVerification
7
+
8
+ id :subscriptions_r5_backport_r4_server_subscription_conformance
9
+ title '[USER INPUT VERIFICATION] Verify Subscription to Send to Server'
10
+ description %(
11
+ The Subscription resource is used to request notifications for a specific client about a specific topic
12
+ Conceptually, a subscription is a concrete request for a single client to receive notifications per a single
13
+ topic. In order to support topic-based subscriptions in R4, this guide defines several extensions for use on the
14
+ [R4 Subscription resource](http://hl7.org/fhir/R4/subscription.html). A list of extensions defined by this guide can
15
+ be found on the [Subscriptions R5 Backport IG's Artifacts page](https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/artifacts.html#5).
16
+
17
+ This test accepts a Subscription resource as an input and verifies that it is conformant to the
18
+ [R4/B Topic-Based Subscription profile](https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/StructureDefinition-backport-subscription.html).
19
+
20
+ The Subscription channel should have it's fields populated with the following information:
21
+ - The `endpoint` field must be set to
22
+ `#{Inferno::Application['base_url']}/custom/subscriptions_r5_backport_r4_server/subscription/channel/notification_listener`.
23
+ The test will add the correct url to this field if it is not properly set.
24
+ - The `type` field must be set to `rest-hook`, as the Inferno subscription workflow tests use a `rest-hook`
25
+ subscription channel to receive incoming notifications. The test will add the correct type to this field if it
26
+ is not properly set.
27
+ - The `payload` field must be set to `application/json`, as Inferno will only accept resources in requests with
28
+ this content type.
29
+ - The `header` field must include the `Authorization` header with a Bearer token set to the inputted Inferno
30
+ access token.
31
+ )
32
+
33
+ verifies_requirements 'hl7.fhir.uv.subscriptions_1.1.0@72',
34
+ 'hl7.fhir.uv.subscriptions_1.1.0@86'
35
+
36
+ input :subscription_resource,
37
+ title: 'Workflow Subscription Resource',
38
+ type: 'textarea',
39
+ description: %(
40
+ A Subscription resource in JSON format that Inferno will send to the server under test
41
+ so that it can demonstrate its ability to perform the Subscription creation and Notification
42
+ response workflow. The instance must be conformant to the R4/B Topic-Based Subscription profile.
43
+ Inferno may modify the Subscription before submission, e.g., to point to Inferno's notification endpoint.
44
+ This input is also used by the unsupported Subscription test as the base on which to add unsupported element
45
+ values to test for server rejection.
46
+ )
47
+ input :access_token,
48
+ title: 'Notification Access Token',
49
+ description: %(
50
+ An access token that the server under test will send to Inferno on notifications
51
+ so that the request gets associated with this test session. The token must be
52
+ provided as a `Bearer` token in the `Authorization` header of HTTP requests
53
+ sent to Inferno.
54
+ )
55
+
56
+ output :updated_subscription, :subscription_topic
57
+
58
+ run do
59
+ omit_if subscription_resource.blank?, 'Did not input a Subscription resource of this type.'
60
+ subscription = subscription_verification(subscription_resource)
61
+ no_error_verification('Subscription resource is not conformant.')
62
+
63
+ assert(subscription['criteria'].present?,
64
+ 'The `criteria` field SHALL be populated and contain the canonical URL for the Subscription Topic.')
65
+ output subscription_topic: subscription['criteria']
66
+
67
+ subscription = server_check_channel(subscription, access_token)
68
+ output updated_subscription: subscription.to_json
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,24 @@
1
+ require_relative 'interaction/subscription_conformance_test'
2
+ require_relative 'interaction/notification_delivery_test'
3
+ require_relative 'interaction/creation_response_conformance_test'
4
+
5
+ module SubscriptionsTestKit
6
+ module SubscriptionsR5BackportR4Server
7
+ class InteractionGroup < Inferno::TestGroup
8
+ id :subscriptions_r5_backport_r4_server_interaction
9
+ title 'Subscription Workflow Interaction'
10
+ description %(
11
+ Verify that the Subscription instance the tester provided is conformant, and then demonstrate the ability of the
12
+ server under test to accept a request for the creation of a FHIR Subscription instance and deliver a notification
13
+ for that Subscription. Inferno will act as a client, creating the Subscription and waiting for a notification
14
+ based on it.
15
+ )
16
+
17
+ run_as_group
18
+
19
+ test from: :subscriptions_r5_backport_r4_server_subscription_conformance
20
+ test from: :subscriptions_r5_backport_r4_server_notification_delivery
21
+ test from: :subscriptions_r5_backport_r4_server_creation_response_conformance
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,73 @@
1
+ require_relative '../../../../common/notification_conformance_verification'
2
+
3
+ module SubscriptionsTestKit
4
+ module SubscriptionsR5BackportR4Server
5
+ class NotificationConformanceTest < Inferno::Test
6
+ include NotificationConformanceVerification
7
+
8
+ id :subscriptions_r5_backport_r4_server_notification_conformance
9
+ title 'Subscription Notification Verification'
10
+ description %(
11
+ As described in [Topic-Based Subscription Components](https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/components.html#subscription-notifications),
12
+ all notifications are enclosed in a Bundle with the type of history. Additionally, the first entry of the bundle
13
+ SHALL be the SubscriptionStatus information, encoded as a Parameters resource using the
14
+ [Backport SubscriptionStatus Profile](https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/StructureDefinition-backport-subscription-status-r4.html)
15
+ in FHIR R4.
16
+
17
+ This test takes the received notification bundle and ensures it is conformant to the
18
+ [R4 Topic-Based Subscription Notification Bundle](https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/StructureDefinition-backport-subscription-notification-r4.html)
19
+ profle.
20
+ )
21
+
22
+ verifies_requirements 'hl7.fhir.uv.subscriptions_1.1.0@14',
23
+ 'hl7.fhir.uv.subscriptions_1.1.0@15',
24
+ 'hl7.fhir.uv.subscriptions_1.1.0@28',
25
+ 'hl7.fhir.uv.subscriptions_1.1.0@69',
26
+ 'hl7.fhir.uv.subscriptions_1.1.0@70',
27
+ 'hl7.fhir.uv.subscriptions_1.1.0@138',
28
+ 'hl7.fhir.uv.subscriptions_1.1.0@139'
29
+
30
+ def subscription_type
31
+ config.options[:subscription_type]
32
+ end
33
+
34
+ run do
35
+ if subscription_type.present?
36
+ requests = load_tagged_requests('subscription_creation', subscription_type)
37
+ subscription_requests =
38
+ requests
39
+ .select { |request| request.status == 201 }
40
+ skip_if subscription_requests.empty?,
41
+ 'No successful Subscription creation request was made in the previous test.'
42
+ else
43
+ all_requests = load_tagged_requests('subscription_creation')
44
+ all_subscription_requests =
45
+ all_requests
46
+ .select { |request| request.status == 201 }
47
+ skip_if all_subscription_requests.empty?,
48
+ 'No successful Subscription creation request was made in the previous test.'
49
+ subscription_requests = [all_subscription_requests.first]
50
+ end
51
+
52
+ subscription_requests.each do |subscription_request|
53
+ assert_valid_json(subscription_request.response_body)
54
+ subscription = JSON.parse(subscription_request.response_body)
55
+
56
+ requests = load_tagged_requests('event-notification', subscription['id'])
57
+ skip_if requests.empty?, 'No event-notification requests were made in a previous test as expected.'
58
+
59
+ requests = requests.uniq(&:request_body)
60
+ requests.each do |request|
61
+ notification_verification(
62
+ request.request_body,
63
+ 'event-notification',
64
+ subscription_id: subscription['id'],
65
+ status: 'active'
66
+ )
67
+ end
68
+ end
69
+ no_error_verification('Received event-notifications are not conformant.')
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,19 @@
1
+ require_relative 'interaction_verification/notification_conformance_test'
2
+
3
+ module SubscriptionsTestKit
4
+ module SubscriptionsR5BackportR4Server
5
+ class InteractionVerificationGroup < Inferno::TestGroup
6
+ id :subscriptions_r5_backport_r4_server_interaction_verification
7
+ title 'Subscription Workflow Interaction Verification'
8
+ description %(
9
+ Inferno takes the received event-notification Bundle and verifies that it is conformant to the
10
+ [R4 Topic-Based Subscription Notification Bundle](https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/StructureDefinition-backport-subscription-notification-r4.html)
11
+ profle.
12
+ )
13
+
14
+ run_as_group
15
+
16
+ test from: :subscriptions_r5_backport_r4_server_notification_conformance
17
+ end
18
+ end
19
+ end