subscriptions_test_kit 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +201 -0
- data/lib/inferno_requirements_tools/ext/inferno_core/runnable.rb +22 -0
- data/lib/inferno_requirements_tools/tasks/collect_requirements.rb +222 -0
- data/lib/inferno_requirements_tools/tasks/requirements_coverage.rb +264 -0
- data/lib/subscriptions_test_kit/common/notification_conformance_verification.rb +310 -0
- data/lib/subscriptions_test_kit/common/subscription_conformance_verification.rb +87 -0
- data/lib/subscriptions_test_kit/docs/samples/Subscription_empty.json +37 -0
- data/lib/subscriptions_test_kit/docs/samples/Subscription_full-resource.json +37 -0
- data/lib/subscriptions_test_kit/docs/samples/Subscription_id-only.json +38 -0
- data/lib/subscriptions_test_kit/docs/subscriptions_r5_backport_r4_client_suite_description.md +120 -0
- data/lib/subscriptions_test_kit/docs/subscriptions_r5_backport_r4_server_suite_description.md +170 -0
- data/lib/subscriptions_test_kit/endpoints/subscription_create_endpoint.rb +90 -0
- data/lib/subscriptions_test_kit/endpoints/subscription_read_endpoint.rb +32 -0
- data/lib/subscriptions_test_kit/endpoints/subscription_rest_hook_endpoint.rb +66 -0
- data/lib/subscriptions_test_kit/endpoints/subscription_status_endpoint.rb +70 -0
- data/lib/subscriptions_test_kit/igs/README.md +21 -0
- data/lib/subscriptions_test_kit/jobs/send_subscription_notifications.rb +130 -0
- data/lib/subscriptions_test_kit/requirements/generated/subscriptions-test-kit_requirements_coverage.csv +136 -0
- data/lib/subscriptions_test_kit/requirements/subscriptions-test-kit_out_of_scope_requirements.csv +23 -0
- data/lib/subscriptions_test_kit/requirements/subscriptions-test-kit_requirements.csv +145 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/common/subscription_simulation_utils.rb +140 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/fixtures/capability_statement.json +57 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/conformance_verification/notification_input_payload_verification_test.rb +50 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/conformance_verification/notification_input_verification_test.rb +25 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/conformance_verification/processing_attestation_test.rb +38 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/conformance_verification/subscription_verification_test.rb +28 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/conformance_verification_group.rb +20 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/interaction_test.rb +128 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/interaction_verification/event_notification_verification_test.rb +40 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/interaction_verification/handshake_notification_verification_test.rb +40 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/interaction_verification_group.rb +16 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow_group.rb +33 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client_suite.rb +66 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/common/interaction/creation_response_conformance_test.rb +51 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/common/interaction/notification_delivery_test.rb +56 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/common/interaction/subscription_conformance_test.rb +72 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/common/interaction_group.rb +24 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/common/interaction_verification/notification_conformance_test.rb +73 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/common/interaction_verification_group.rb +19 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/common/subscription_creation.rb +63 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/common/subscription_status_operation.rb +58 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/capability_statement/cs_conformance_test.rb +49 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/capability_statement/topic_discovery_test.rb +106 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/capability_statement_group.rb +21 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/event_notification/empty_content/empty_conformance_test.rb +63 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/event_notification/empty_content_group.rb +58 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/event_notification/full_resource_content/full_resource_conformance_test.rb +68 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/event_notification/full_resource_content_group.rb +58 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/event_notification/id_only_content/id_only_conformance_test.rb +66 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/event_notification/id_only_content_group.rb +58 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/event_notification_group.rb +25 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/handshake_heartbeat/handshake_conformance_test.rb +67 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/handshake_heartbeat/heartbeat_conformance_test.rb +74 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/handshake_heartbeat_group.rb +19 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/status_operation/status_invocation_test.rb +43 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/status_operation_group.rb +15 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/subscription_rejection/reject_subscriptions_test.rb +181 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage/subscription_rejection_group.rb +21 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/coverage_group.rb +26 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/workflow_group.rb +27 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server_suite.rb +79 -0
- data/lib/subscriptions_test_kit/tags.rb +10 -0
- data/lib/subscriptions_test_kit/urls.rb +37 -0
- data/lib/subscriptions_test_kit/version.rb +5 -0
- data/lib/subscriptions_test_kit.rb +3 -0
- metadata +194 -0
@@ -0,0 +1,58 @@
|
|
1
|
+
require_relative '../../common/interaction_group'
|
2
|
+
require_relative '../../common/interaction_verification_group'
|
3
|
+
require_relative 'id_only_content/id_only_conformance_test'
|
4
|
+
|
5
|
+
module SubscriptionsTestKit
|
6
|
+
module SubscriptionsR5BackportR4Server
|
7
|
+
class IdOnlyContentGroup < Inferno::TestGroup
|
8
|
+
id :subscriptions_r5_backport_r4_server_id_only_content
|
9
|
+
title 'Id Only 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 `id-only` content type ([example id-only
|
14
|
+
Subscription](https://github.com/inferno-framework/subscriptions-test-kit/blob/main/lib/subscriptions_test_kit/docs/samples/Subscription_id-only.json)).
|
15
|
+
)
|
16
|
+
run_as_group
|
17
|
+
optional
|
18
|
+
|
19
|
+
input_order :url, :credentials, :access_token, :id_only_subscription_resource
|
20
|
+
|
21
|
+
group from: :subscriptions_r5_backport_r4_server_interaction do
|
22
|
+
id :subscriptions_r5_backport_r4_server_id_only_content_interaction
|
23
|
+
optional
|
24
|
+
|
25
|
+
config(
|
26
|
+
options: { subscription_type: 'id-only' },
|
27
|
+
inputs: {
|
28
|
+
subscription_resource: {
|
29
|
+
name: :id_only_subscription_resource,
|
30
|
+
title: 'Id-Only 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 id-only 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: :id_only_updated_subscription }
|
41
|
+
},
|
42
|
+
outputs: {
|
43
|
+
updated_subscription: { name: :id_only_updated_subscription }
|
44
|
+
}
|
45
|
+
)
|
46
|
+
end
|
47
|
+
group from: :subscriptions_r5_backport_r4_server_interaction_verification do
|
48
|
+
id :subscriptions_r5_backport_r4_server_id_only_content_interaction_verification
|
49
|
+
optional
|
50
|
+
|
51
|
+
config(
|
52
|
+
options: { subscription_type: 'id-only' }
|
53
|
+
)
|
54
|
+
test from: :subscriptions_r5_backport_r4_server_id_only_conformance
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative 'event_notification/empty_content_group'
|
2
|
+
require_relative 'event_notification/full_resource_content_group'
|
3
|
+
require_relative 'event_notification/id_only_content_group'
|
4
|
+
|
5
|
+
module SubscriptionsTestKit
|
6
|
+
module SubscriptionsR5BackportR4Server
|
7
|
+
class EventNotificationGroup < Inferno::TestGroup
|
8
|
+
id :subscriptions_r5_backport_r4_server_event_notification
|
9
|
+
title 'Backport Subscription 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 content type. This group contains tests for the three options
|
14
|
+
available when specifying the contents of a Notification: empty, id-only, and full-resource.
|
15
|
+
)
|
16
|
+
|
17
|
+
input_order :url, :credentials, :access_token, :empty_subscription_resource,
|
18
|
+
:id_only_subscription_resource, :full_resource_subscription_resource
|
19
|
+
|
20
|
+
group from: :subscriptions_r5_backport_r4_server_empty_content
|
21
|
+
group from: :subscriptions_r5_backport_r4_server_id_only_content
|
22
|
+
group from: :subscriptions_r5_backport_r4_server_full_resource_content
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require_relative '../../../../common/notification_conformance_verification'
|
2
|
+
|
3
|
+
module SubscriptionsTestKit
|
4
|
+
module SubscriptionsR5BackportR4Server
|
5
|
+
class HandshakeConformanceTest < Inferno::Test
|
6
|
+
include NotificationConformanceVerification
|
7
|
+
|
8
|
+
id :subscriptions_r5_backport_r4_server_handshake_conformance
|
9
|
+
title 'Subscription Handshake Verification'
|
10
|
+
description %(
|
11
|
+
When a Subscription is created for a REST Hook channel type, the server SHALL set initial status to requested,
|
12
|
+
pending verification of the nominated endpoint URL. The Server will then send a handshake bundle to the endpoint.
|
13
|
+
After a successful handshake notification has been sent and accepted, the server SHALL update the status to
|
14
|
+
active. This test verifies that the incoming handshake request is a conformant
|
15
|
+
[R4 Topic-Based Subscription Notification Bundle](https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/StructureDefinition-backport-subscription-notification-r4.html).
|
16
|
+
)
|
17
|
+
|
18
|
+
verifies_requirements 'hl7.fhir.uv.subscriptions_1.1.0@14',
|
19
|
+
'hl7.fhir.uv.subscriptions_1.1.0@15',
|
20
|
+
'hl7.fhir.uv.subscriptions_1.1.0@28',
|
21
|
+
'hl7.fhir.uv.subscriptions_1.1.0@69',
|
22
|
+
'hl7.fhir.uv.subscriptions_1.1.0@70',
|
23
|
+
'hl7.fhir.uv.subscriptions_1.1.0@24',
|
24
|
+
'hl7.fhir.uv.subscriptions_1.1.0@25',
|
25
|
+
'hl7.fhir.uv.subscriptions_1.1.0@138',
|
26
|
+
'hl7.fhir.uv.subscriptions_1.1.0@139'
|
27
|
+
|
28
|
+
run do
|
29
|
+
subscription_requests = load_tagged_requests('subscription_creation')
|
30
|
+
skip_if(subscription_requests.empty?, %(
|
31
|
+
No Subscription creation requests were made in previous tests. Must run Subscription Workflow tests first in
|
32
|
+
order to run this test.))
|
33
|
+
|
34
|
+
subscription_request_ids =
|
35
|
+
subscription_requests
|
36
|
+
.select { |request| request.status == 201 }
|
37
|
+
.uniq(&:response_body)
|
38
|
+
.map { |request| JSON.parse(request.response_body) }
|
39
|
+
.select { |subscription| subscription['channel']['type'] == 'rest-hook' }
|
40
|
+
.map { |subscription| subscription['id'] }
|
41
|
+
|
42
|
+
requests = load_tagged_requests('handshake')
|
43
|
+
if requests.empty?
|
44
|
+
omit_if subscription_request_ids.empty?, 'No handshake requests were required or received in a previous tests.'
|
45
|
+
assert(subscription_request_ids.empty?,
|
46
|
+
'Handshake requests are required if a Subscription channel type is `rest-hook`')
|
47
|
+
end
|
48
|
+
|
49
|
+
requests = requests.uniq(&:request_body)
|
50
|
+
|
51
|
+
requests.each do |request|
|
52
|
+
tags = request.tags.dup
|
53
|
+
tags -= ['handshake']
|
54
|
+
subscription_id = tags.first
|
55
|
+
|
56
|
+
subscription_request_ids.delete(subscription_id)
|
57
|
+
|
58
|
+
notification_verification(request.request_body, 'handshake', subscription_id:, status: 'requested')
|
59
|
+
end
|
60
|
+
|
61
|
+
no_error_verification('Received handshakes are not conformant.')
|
62
|
+
assert(subscription_request_ids.empty?,
|
63
|
+
'Did not receive a handshake notification for some `rest-hook` subscriptions')
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require_relative '../../../../common/notification_conformance_verification'
|
2
|
+
|
3
|
+
module SubscriptionsTestKit
|
4
|
+
module SubscriptionsR5BackportR4Server
|
5
|
+
class HeartbeatConformanceTest < Inferno::Test
|
6
|
+
include NotificationConformanceVerification
|
7
|
+
|
8
|
+
id :subscriptions_r5_backport_r4_server_heartbeat_conformance
|
9
|
+
title 'Subscription Heartbeat Verification'
|
10
|
+
description %(
|
11
|
+
When a Subscription is created for a REST Hook channel type, the server Server may send notifications of type
|
12
|
+
heartbeat at any time. This test verifies that the incoming heartbeat request is a conformant
|
13
|
+
[R4 Topic-Based Subscription Notification Bundle](https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/StructureDefinition-backport-subscription-notification-r4.html).
|
14
|
+
)
|
15
|
+
|
16
|
+
verifies_requirements 'hl7.fhir.uv.subscriptions_1.1.0@14',
|
17
|
+
'hl7.fhir.uv.subscriptions_1.1.0@15',
|
18
|
+
'hl7.fhir.uv.subscriptions_1.1.0@28',
|
19
|
+
'hl7.fhir.uv.subscriptions_1.1.0@69',
|
20
|
+
'hl7.fhir.uv.subscriptions_1.1.0@70',
|
21
|
+
'hl7.fhir.uv.subscriptions_1.1.0@138',
|
22
|
+
'hl7.fhir.uv.subscriptions_1.1.0@139',
|
23
|
+
'hl7.fhir.uv.subscriptions_1.1.0@93',
|
24
|
+
'hl7.fhir.uv.subscriptions_1.1.0@94'
|
25
|
+
|
26
|
+
def heartbeat_period?(subscription_extensions)
|
27
|
+
return false if subscription_extensions.blank?
|
28
|
+
|
29
|
+
heartbeat = subscription_extensions.find { |extension| extension['url'].ends_with?('/backport-heartbeat-period') }
|
30
|
+
|
31
|
+
return false if heartbeat.blank?
|
32
|
+
|
33
|
+
heartbeat['valueUnsignedInt'].present?
|
34
|
+
end
|
35
|
+
|
36
|
+
run do
|
37
|
+
subscription_requests = load_tagged_requests('subscription_creation')
|
38
|
+
skip_if(subscription_requests.empty?, %(
|
39
|
+
No Subscription creation requests were made in previous tests. Must run Subscription Workflow tests first in
|
40
|
+
order to run this test.))
|
41
|
+
|
42
|
+
subscription_request_ids =
|
43
|
+
subscription_requests
|
44
|
+
.select { |request| request.status == 201 }
|
45
|
+
.uniq(&:response_body)
|
46
|
+
.map { |request| JSON.parse(request.response_body) }
|
47
|
+
.select { |subscription| heartbeat_period?(subscription['channel']['extension']) }
|
48
|
+
.map { |subscription| subscription['id'] }
|
49
|
+
|
50
|
+
requests = load_tagged_requests('heartbeat')
|
51
|
+
if requests.empty?
|
52
|
+
omit_if subscription_request_ids.empty?, 'No heartbeat requests requested or received in previous tests.'
|
53
|
+
assert(subscription_request_ids.empty?, %(
|
54
|
+
No Heartbeat notifications received when heartbeat was requested by the subscriber (`heartbeatPeriod` is
|
55
|
+
populated)))
|
56
|
+
end
|
57
|
+
|
58
|
+
requests = requests.uniq(&:request_body)
|
59
|
+
|
60
|
+
requests.each do |request|
|
61
|
+
tags = request.tags.dup
|
62
|
+
tags -= ['heartbeat']
|
63
|
+
subscription_id = tags.first
|
64
|
+
|
65
|
+
assert(subscription_request_ids.include?(subscription_id),
|
66
|
+
'If `heartbeatPeriod` field is not present in the Subscription, heartbeat should not be sent.')
|
67
|
+
|
68
|
+
notification_verification(request.request_body, 'heartbeat', subscription_id:)
|
69
|
+
no_error_verification('Received heartbeats are not conformant.')
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative 'handshake_heartbeat/handshake_conformance_test'
|
2
|
+
require_relative 'handshake_heartbeat/heartbeat_conformance_test'
|
3
|
+
|
4
|
+
module SubscriptionsTestKit
|
5
|
+
module SubscriptionsR5BackportR4Server
|
6
|
+
class HandshakeHeartbeatGroup < Inferno::TestGroup
|
7
|
+
id :subscriptions_r5_backport_r4_server_handshake_heartbeat
|
8
|
+
title 'Backport Subscription Handshake and Heartbeat Notification Verification'
|
9
|
+
description %(
|
10
|
+
Verify that the any received Handshake or Heartbeat Notifications are conformant to the
|
11
|
+
[R4 Topic-Based Subscription Notification Bundle](https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/StructureDefinition-backport-subscription-notification-r4.html)
|
12
|
+
profile.
|
13
|
+
)
|
14
|
+
|
15
|
+
test from: :subscriptions_r5_backport_r4_server_handshake_conformance
|
16
|
+
test from: :subscriptions_r5_backport_r4_server_heartbeat_conformance
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require_relative '../../common/subscription_status_operation'
|
2
|
+
|
3
|
+
module SubscriptionsTestKit
|
4
|
+
module SubscriptionsR5BackportR4Server
|
5
|
+
class StatusInvocationTest < Inferno::Test
|
6
|
+
include SubscriptionStatusOperation
|
7
|
+
|
8
|
+
id :subscriptions_r5_backport_r4_server_status_invocation
|
9
|
+
title 'Server supports subscription $status operation'
|
10
|
+
description %(
|
11
|
+
In order to claim conformance with this guide, a server: SHALL support the [$status operation](https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/OperationDefinition-backport-subscription-status.html)
|
12
|
+
on the Subscription resource. This operation is used to return the current status information about one or more
|
13
|
+
topic-based Subscriptions in R4. The operation returns a bundle containing one or more subscription status
|
14
|
+
resources, one per Subscription being queried. The Bundle type is "searchset". The status of the Subscription
|
15
|
+
should be set to 'active' after a successful handshake with the rest-hook endpoint.
|
16
|
+
|
17
|
+
This test ensures the server supports the $status operation by performing the operation and ensuring it receives a
|
18
|
+
valid response.
|
19
|
+
)
|
20
|
+
|
21
|
+
verifies_requirements 'hl7.fhir.uv.subscriptions_1.1.0@20',
|
22
|
+
'hl7.fhir.uv.subscriptions_1.1.0@30',
|
23
|
+
'hl7.fhir.uv.subscriptions_1.1.0@47'
|
24
|
+
|
25
|
+
run do
|
26
|
+
subscription_requests = load_tagged_requests('subscription_creation')
|
27
|
+
success_subscription_requests =
|
28
|
+
subscription_requests
|
29
|
+
.select { |request| request.status == 201 }
|
30
|
+
skip_if success_subscription_requests.empty?, %(
|
31
|
+
No successful Subscription creation requests were made in previous tests. Must run Subscription Workflow tests
|
32
|
+
first in order to run this test.
|
33
|
+
)
|
34
|
+
|
35
|
+
subscription = JSON.parse(success_subscription_requests.first.response_body)
|
36
|
+
subscription_id = subscription['id']
|
37
|
+
|
38
|
+
perform_subscription_status_test(subscription_id)
|
39
|
+
no_error_verification('Subscription status response was not conformant.')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require_relative 'status_operation/status_invocation_test'
|
2
|
+
|
3
|
+
module SubscriptionsTestKit
|
4
|
+
module SubscriptionsR5BackportR4Server
|
5
|
+
class StatusOperationGroup < Inferno::TestGroup
|
6
|
+
id :subscriptions_r5_backport_r4_server_status_operation
|
7
|
+
title 'Subscription $status Operation Verification'
|
8
|
+
description %(
|
9
|
+
This test group verifies that the Backport Subscriptions Server supports the $status operation.
|
10
|
+
)
|
11
|
+
|
12
|
+
test from: :subscriptions_r5_backport_r4_server_status_invocation
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,181 @@
|
|
1
|
+
require_relative '../../common/subscription_creation'
|
2
|
+
|
3
|
+
module SubscriptionsTestKit
|
4
|
+
module SubscriptionsR5BackportR4Server
|
5
|
+
class RejectSubscriptionsTest < Inferno::Test
|
6
|
+
include SubscriptionCreation
|
7
|
+
|
8
|
+
id :subscriptions_r5_backport_r4_server_reject_subscriptions
|
9
|
+
title 'Server Handles Unsupported Subscriptions'
|
10
|
+
description %(
|
11
|
+
When processing a request for a Subscription a server SHOULD verify that the Subscription is supported and does not
|
12
|
+
contain any information not implemented by the server. If the Subscription is no supported, the server should reject
|
13
|
+
the Subscription create request, or it should attempt to adjust the Subscription. This test checks that the server
|
14
|
+
correctly rejects or adjusts the Subscription in the following cases:
|
15
|
+
|
16
|
+
- The Subscription contains cross-version extension
|
17
|
+
- The Subscription contains a Subscription Topic not implemented by the server
|
18
|
+
- The Subscription contains a filtering criteria not implemented by the server
|
19
|
+
- The Subscription contains channel type not implemented by the server
|
20
|
+
- The Subscription contains an unsupported channel endpoint
|
21
|
+
- The Subscription contains a payload type not implemented by the server
|
22
|
+
- The Subscription contains an unsupported channel and payload type combination
|
23
|
+
|
24
|
+
The test will pass if the server either
|
25
|
+
1. rejects the Subscription by responding with a non-201 response, or
|
26
|
+
2. updates the Subscription resource to remove or replace the unsupported value.
|
27
|
+
)
|
28
|
+
|
29
|
+
verifies_requirements 'hl7.fhir.uv.subscriptions_1.1.0@8',
|
30
|
+
'hl7.fhir.uv.subscriptions_1.1.0@9',
|
31
|
+
'hl7.fhir.uv.subscriptions_1.1.0@10',
|
32
|
+
'hl7.fhir.uv.subscriptions_1.1.0@11',
|
33
|
+
'hl7.fhir.uv.subscriptions_1.1.0@12',
|
34
|
+
'hl7.fhir.uv.subscriptions_1.1.0@13'
|
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 :unsupported_subscription_topic,
|
48
|
+
title: 'Unsupported Subscription Topic',
|
49
|
+
description: 'A Subscription Topic for the `criteria` element that is not implemented by the server to test for Subscription rejection.',
|
50
|
+
optional: true
|
51
|
+
input :unsupported_subscription_filter,
|
52
|
+
title: 'Unsupported Subscription Filter',
|
53
|
+
description: 'A value for `filterCriteria` extension under the `criteria` that is not implemented by the server to test for Subscription rejection.',
|
54
|
+
optional: true
|
55
|
+
input :unsupported_subscription_channel_type,
|
56
|
+
title: 'Unsupported Subscription Channel Type',
|
57
|
+
description: 'A value for the `channel.type` element that is not implemented by the server to test for Subscription rejection.',
|
58
|
+
optional: true
|
59
|
+
input :unsupported_subscription_channel_endpoint,
|
60
|
+
title: 'Unsupported Subscription Channel Endpoint',
|
61
|
+
description: 'An unsupported value for the `channel.endpoint` element to test for Subscription rejection.',
|
62
|
+
optional: true
|
63
|
+
input :unsupported_subscription_payload_type,
|
64
|
+
title: 'Unsupported Subscription Payload Type',
|
65
|
+
description: 'A value for the `content` extension under the `channel.payload` element that is not implemented by the server to test for Subscription rejection.',
|
66
|
+
optional: true
|
67
|
+
input :unsupported_subscription_channel_payload_combo,
|
68
|
+
title: 'Unsupported Subscription Channel and Payload Combination',
|
69
|
+
description: %(
|
70
|
+
A channel (`channel.type`) and payload type (`content` extension under the `channel.payload` element)
|
71
|
+
combination not implemented by the server to test for Subscription
|
72
|
+
rejection. Provide in the json format e.g. {channel: <'channel_type'>, payload: <'payload_type'>}.
|
73
|
+
),
|
74
|
+
optional: true
|
75
|
+
|
76
|
+
def unsupported_subscriptions
|
77
|
+
[
|
78
|
+
{
|
79
|
+
'unsupported_title' => 'cross-version extensions',
|
80
|
+
'field_path' => ['_criteria'],
|
81
|
+
'field_value' => { 'extension' => [{
|
82
|
+
url: 'http://hl7.org/fhir/5.0/subscriptions-backport/StructureDefinition/backport-filter-criteria',
|
83
|
+
valueString: 'Encounter?patient=Patient/123'
|
84
|
+
}] }
|
85
|
+
},
|
86
|
+
{
|
87
|
+
'unsupported_title' => 'unsupported `SubscriptionTopic`',
|
88
|
+
'field_path' => ['criteria'],
|
89
|
+
'field_value' => unsupported_subscription_topic
|
90
|
+
},
|
91
|
+
{
|
92
|
+
'unsupported_title' => 'unsupported filter criteria',
|
93
|
+
'field_path' => ['_criteria'],
|
94
|
+
'field_value' => if unsupported_subscription_filter.nil?
|
95
|
+
unsupported_subscription_filter
|
96
|
+
else
|
97
|
+
{ 'extension' => [{
|
98
|
+
url: 'http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-filter-criteria',
|
99
|
+
valueString: unsupported_subscription_filter
|
100
|
+
}] }
|
101
|
+
end
|
102
|
+
},
|
103
|
+
{
|
104
|
+
'unsupported_title' => 'unsupported channel type',
|
105
|
+
'field_path' => ['channel', 'type'],
|
106
|
+
'field_value' => unsupported_subscription_channel_type
|
107
|
+
},
|
108
|
+
{
|
109
|
+
'unsupported_title' => 'unsupported channel URL',
|
110
|
+
'field_path' => ['channel', 'endpoint'],
|
111
|
+
'field_value' => unsupported_subscription_channel_endpoint
|
112
|
+
},
|
113
|
+
{
|
114
|
+
'unsupported_title' => 'unsupported channel type',
|
115
|
+
'field_path' => ['channel', 'type'],
|
116
|
+
'field_value' => unsupported_subscription_channel_type
|
117
|
+
},
|
118
|
+
{
|
119
|
+
'unsupported_title' => 'unsupported payload type',
|
120
|
+
'field_path' => ['channel', 'payload'],
|
121
|
+
'field_value' => unsupported_subscription_payload_type
|
122
|
+
}
|
123
|
+
]
|
124
|
+
end
|
125
|
+
|
126
|
+
run do
|
127
|
+
assert_valid_json(subscription_resource)
|
128
|
+
subscription = JSON.parse(subscription_resource)
|
129
|
+
|
130
|
+
unsupported_subscriptions.each do |unsupported_info|
|
131
|
+
next if unsupported_info['field_value'].blank?
|
132
|
+
|
133
|
+
field_name = unsupported_info['field_path'].last
|
134
|
+
|
135
|
+
if unsupported_info['field_path'].length > 1
|
136
|
+
outer_field_name = unsupported_info['field_path'].first
|
137
|
+
subscription_field = subscription[outer_field_name]
|
138
|
+
else
|
139
|
+
subscription_field = subscription
|
140
|
+
end
|
141
|
+
|
142
|
+
original_field_value = subscription_field[field_name]
|
143
|
+
subscription_field[field_name] = unsupported_info['field_value']
|
144
|
+
|
145
|
+
send_unsupported_subscription(subscription, unsupported_info['unsupported_title'], [unsupported_info['field_path']],
|
146
|
+
[unsupported_info['field_value']])
|
147
|
+
|
148
|
+
if original_field_value.nil?
|
149
|
+
subscription_field.delete(field_name)
|
150
|
+
else
|
151
|
+
subscription_field[field_name] = original_field_value
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
if unsupported_subscription_channel_payload_combo.present?
|
156
|
+
assert_valid_json(unsupported_subscription_channel_payload_combo)
|
157
|
+
channel_payload_combo = JSON.parse(unsupported_subscription_channel_payload_combo)
|
158
|
+
channel_value = channel_payload_combo['channel']
|
159
|
+
payload_value = channel_payload_combo['payload']
|
160
|
+
|
161
|
+
if channel_value.blank? || payload_value.blank?
|
162
|
+
add_message('error', %(
|
163
|
+
Channel and payload values are not populated correctly in unsupported channel and payload combination input.))
|
164
|
+
else
|
165
|
+
subscription_channel = subscription['channel']
|
166
|
+
subscription_channel['type'] = channel_value
|
167
|
+
subscription_channel['payload'] = payload_value
|
168
|
+
|
169
|
+
channel_path = ['channel', 'type']
|
170
|
+
payload_path = ['channel', 'payload']
|
171
|
+
|
172
|
+
send_unsupported_subscription(subscription, 'unsupported channel and payload combination', [channel_path, payload_path],
|
173
|
+
[channel_value, payload_value])
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
no_error_verification('Unsupported Subscription creation error handling failures.')
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative 'subscription_rejection/reject_subscriptions_test'
|
2
|
+
|
3
|
+
module SubscriptionsTestKit
|
4
|
+
module SubscriptionsR5BackportR4Server
|
5
|
+
class SubscriptionRejectionGroup < Inferno::TestGroup
|
6
|
+
id :subscriptions_r5_backport_r4_server_subscription_rejection
|
7
|
+
title 'Subscription Creation Rejection Verification'
|
8
|
+
description %(
|
9
|
+
This test group verifies that the Backport Subscriptions Server supports rejecting unsupported
|
10
|
+
Subscription creation requests.
|
11
|
+
)
|
12
|
+
|
13
|
+
input_order :url, :credentials, :subscription_resource, :unsupported_subscription_topic,
|
14
|
+
:unsupported_subscription_filter, :unsupported_subscription_channel_type,
|
15
|
+
:unsupported_subscription_channel_endpoint, :unsupported_subscription_payload_type,
|
16
|
+
:unsupported_subscription_channel_payload_combo
|
17
|
+
|
18
|
+
test from: :subscriptions_r5_backport_r4_server_reject_subscriptions
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require_relative 'coverage/capability_statement_group'
|
2
|
+
require_relative 'coverage/event_notification_group'
|
3
|
+
require_relative 'coverage/handshake_heartbeat_group'
|
4
|
+
require_relative 'coverage/status_operation_group'
|
5
|
+
require_relative 'coverage/subscription_rejection_group'
|
6
|
+
|
7
|
+
module SubscriptionsTestKit
|
8
|
+
module SubscriptionsR5BackportR4Server
|
9
|
+
module Coverage
|
10
|
+
class GroupForCoverage < Inferno::TestGroup
|
11
|
+
id :subscriptions_r5_backport_r4_server_coverage
|
12
|
+
title 'Demonstrate coverage of all Subscription Backport IG requirements'
|
13
|
+
description %(
|
14
|
+
Demonstrate that the server covers all requirements placed on
|
15
|
+
servers by the IG.
|
16
|
+
)
|
17
|
+
|
18
|
+
group from: :subscriptions_r5_backport_r4_server_capability_statement
|
19
|
+
group from: :subscriptions_r5_backport_r4_server_event_notification
|
20
|
+
group from: :subscriptions_r5_backport_r4_server_handshake_heartbeat
|
21
|
+
group from: :subscriptions_r5_backport_r4_server_status_operation
|
22
|
+
group from: :subscriptions_r5_backport_r4_server_subscription_rejection
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require_relative 'common/interaction_group'
|
2
|
+
require_relative 'common/interaction_verification_group'
|
3
|
+
|
4
|
+
module SubscriptionsTestKit
|
5
|
+
module SubscriptionsR5BackportR4Server
|
6
|
+
class WorkflowGroup < Inferno::TestGroup
|
7
|
+
id :subscriptions_r5_backport_r4_server_workflow
|
8
|
+
title 'Demonstrate the subscription workflow'
|
9
|
+
description %(
|
10
|
+
Demonstrate the ability of the server to accept a request for the
|
11
|
+
creation of a FHIR Subscription instance and deliver a notification
|
12
|
+
for that Subscription. The tester must provide a Subscription instance
|
13
|
+
that the server under test supports. Inferno will act as a client,
|
14
|
+
creating the Subscription and waiting for a notification based on it.
|
15
|
+
Inferno will then verify that the Subscription and the Notification
|
16
|
+
match and that the exchange is conformant.
|
17
|
+
)
|
18
|
+
|
19
|
+
run_as_group
|
20
|
+
|
21
|
+
input_order :url, :credentials, :access_token, :subscription_resource
|
22
|
+
|
23
|
+
group from: :subscriptions_r5_backport_r4_server_interaction
|
24
|
+
group from: :subscriptions_r5_backport_r4_server_interaction_verification
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require_relative 'subscriptions_r5_backport_r4_server/workflow_group'
|
2
|
+
require_relative 'subscriptions_r5_backport_r4_server/coverage_group'
|
3
|
+
require_relative '../endpoints/subscription_rest_hook_endpoint'
|
4
|
+
require_relative '../urls'
|
5
|
+
require_relative '../version'
|
6
|
+
|
7
|
+
module SubscriptionsTestKit
|
8
|
+
module SubscriptionsR5BackportR4Server
|
9
|
+
class SubscriptionsR5BackportR4ServerSuite < Inferno::TestSuite
|
10
|
+
id :subscriptions_r5_backport_r4_server
|
11
|
+
title 'Subscriptions R5 Backport IG v1.1.0 FHIR R4 Server Test Suite'
|
12
|
+
short_title 'Subscriptions R4 Server'
|
13
|
+
version VERSION
|
14
|
+
description File.read(File.join(__dir__, '..', 'docs', 'subscriptions_r5_backport_r4_server_suite_description.md'))
|
15
|
+
|
16
|
+
links [
|
17
|
+
{
|
18
|
+
label: 'Report Issue',
|
19
|
+
url: 'https://github.com/inferno-framework/subscriptions-test-kit/issues'
|
20
|
+
},
|
21
|
+
{
|
22
|
+
label: 'Open Source',
|
23
|
+
url: 'https://github.com/inferno-framework/subscriptions-test-kit'
|
24
|
+
},
|
25
|
+
{
|
26
|
+
label: 'Download',
|
27
|
+
url: 'https://github.com/inferno-framework/subscriptions-test-kit/releases'
|
28
|
+
},
|
29
|
+
{
|
30
|
+
label: 'Implementation Guide',
|
31
|
+
url: 'https://hl7.org/fhir/uv/subscriptions-backport/STU1.1/'
|
32
|
+
}
|
33
|
+
]
|
34
|
+
|
35
|
+
# These inputs will be available to all tests in this suite
|
36
|
+
input :url,
|
37
|
+
title: 'FHIR Server Base URL',
|
38
|
+
description: %(
|
39
|
+
FHIR base URL for the server under test where Inferno will send
|
40
|
+
Subscription Creation, $status, and other requests as a part of
|
41
|
+
these tests.
|
42
|
+
)
|
43
|
+
|
44
|
+
input :credentials,
|
45
|
+
title: 'OAuth Credentials',
|
46
|
+
description: 'Credentials for Inferno to include when making requests against the server under test.',
|
47
|
+
type: :oauth_credentials,
|
48
|
+
optional: true
|
49
|
+
|
50
|
+
# All FHIR requests in this suite will use this FHIR client
|
51
|
+
fhir_client do
|
52
|
+
url :url
|
53
|
+
oauth_credentials :credentials
|
54
|
+
end
|
55
|
+
|
56
|
+
# All FHIR validation requests will use this FHIR validator
|
57
|
+
fhir_resource_validator do
|
58
|
+
igs 'hl7.fhir.uv.subscriptions-backport#1.1.0'
|
59
|
+
|
60
|
+
exclude_message do |message|
|
61
|
+
message.message.match?(/\A\S+: \S+: URL value '.*' does not resolve/)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.extract_token_from_query_params(request)
|
66
|
+
request.query_parameters['token']
|
67
|
+
end
|
68
|
+
|
69
|
+
suite_endpoint :post, SUBSCRIPTION_CHANNEL_PATH, SubscriptionRestHookEndpoint
|
70
|
+
|
71
|
+
resume_test_route :get, RESUME_PASS_PATH do |request|
|
72
|
+
SubscriptionsR5BackportR4ServerSuite.extract_token_from_query_params(request)
|
73
|
+
end
|
74
|
+
|
75
|
+
group from: :subscriptions_r5_backport_r4_server_workflow
|
76
|
+
group from: :subscriptions_r5_backport_r4_server_coverage
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SubscriptionsTestKit
|
4
|
+
NOTIFICATION_TAG = 'subscription_notification'
|
5
|
+
SUBSCRIPTION_CREATE_TAG = 'subscription_create'
|
6
|
+
SUBSCRIPTION_READ_TAG = 'subscription_read'
|
7
|
+
SUBSCRIPTION_STATUS_TAG = 'subscription_status'
|
8
|
+
REST_HOOK_HANDSHAKE_NOTIFICATION_TAG = 'rest_hook_handshake_notification'
|
9
|
+
REST_HOOK_EVENT_NOTIFICATION_TAG = 'rest_hook_event_notification'
|
10
|
+
end
|