subscriptions_test_kit 0.9.2 → 0.9.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/inferno_requirements_tools/tasks/collect_requirements.rb +51 -50
- data/lib/inferno_requirements_tools/tasks/requirements_coverage.rb +22 -19
- data/lib/subscriptions_test_kit/common/notification_conformance_verification.rb +11 -12
- data/lib/subscriptions_test_kit/common/subscription_conformance_verification.rb +14 -2
- data/lib/subscriptions_test_kit/docs/samples/Subscription_empty.json +1 -1
- data/lib/subscriptions_test_kit/docs/samples/Subscription_full-resource.json +1 -1
- data/lib/subscriptions_test_kit/docs/samples/Subscription_id-only.json +1 -1
- data/lib/subscriptions_test_kit/docs/subscriptions_r5_backport_r4_client_suite_description.md +4 -1
- data/lib/subscriptions_test_kit/docs/subscriptions_r5_backport_r4_server_suite_description.md +4 -1
- data/lib/subscriptions_test_kit/endpoints/subscription_create_endpoint.rb +7 -3
- data/lib/subscriptions_test_kit/endpoints/subscription_status_endpoint.rb +19 -13
- data/lib/subscriptions_test_kit/jobs/send_subscription_notifications.rb +7 -2
- data/lib/subscriptions_test_kit/requirements/generated/subscriptions-test-kit_requirements_coverage.csv +51 -51
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/common/subscription_simulation_utils.rb +47 -16
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/conformance_verification/notification_input_payload_verification_test.rb +15 -8
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/conformance_verification/notification_input_verification_test.rb +8 -5
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/conformance_verification/processing_attestation_test.rb +1 -1
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/conformance_verification/subscription_verification_test.rb +3 -2
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/conformance_verification_group.rb +1 -1
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/interaction_test.rb +15 -11
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/interaction_verification/event_notification_verification_test.rb +6 -5
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/interaction_verification/handshake_notification_verification_test.rb +5 -5
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/interaction_verification_group.rb +1 -1
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client_suite.rb +5 -3
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/capability_statement/cs_conformance_test.rb +1 -1
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/capability_statement/topic_discovery_test.rb +3 -3
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/capability_statement_group.rb +3 -3
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/common/interaction/creation_response_conformance_test.rb +1 -1
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/common/interaction/subscription_conformance_test.rb +11 -14
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/common/interaction_group.rb +3 -3
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/common/subscription_creation.rb +10 -1
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/common/subscription_status_operation.rb +3 -2
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/event_notification/empty_content_group.rb +3 -2
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/event_notification/full_resource_content/full_resource_conformance_test.rb +3 -4
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/event_notification/full_resource_content_group.rb +3 -2
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/event_notification/id_only_content/id_only_conformance_test.rb +3 -4
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/event_notification/id_only_content_group.rb +3 -2
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/event_notification_group.rb +2 -2
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/handshake_heartbeat/handshake_conformance_test.rb +7 -6
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/handshake_heartbeat/heartbeat_conformance_test.rb +4 -2
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/status_operation/status_invocation_test.rb +2 -2
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/status_operation_group.rb +1 -1
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/subscription_rejection/reject_subscription_channel_endpoint_test.rb +65 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/subscription_rejection/reject_subscription_channel_payload_combo_test.rb +76 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/subscription_rejection/reject_subscription_channel_type_test.rb +68 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/subscription_rejection/reject_subscription_cross_version_extension_test.rb +59 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/subscription_rejection/reject_subscription_filter_test.rb +66 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/subscription_rejection/reject_subscription_payload_type_test.rb +66 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/subscription_rejection/reject_subscription_topic_test.rb +64 -0
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/subscription_rejection_group.rb +14 -2
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server_suite.rb +3 -2
- data/lib/subscriptions_test_kit/version.rb +1 -3
- metadata +11 -75
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_server/subscription_rejection/reject_subscriptions_test.rb +0 -181
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5a807454f459add0f7fd19401c70a5a3c190c5003c375c0b4eefe1e4103c8410
|
4
|
+
data.tar.gz: e284a813940aed69d0cfb3dffef7f1ab034c2fbf799182fe5b200d7edcb1285d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 248c63937da747106d20cbb41dbfd80728de783757a322160882d651ef7f43c30b4192fdf83f036803ef8e50eae082348284fcd30c3e537ae99385df080baf68
|
7
|
+
data.tar.gz: 89d5e860a4fa25b362d5a5d55054ec729dfd4395aa09d453bf71123c7b381120a0510509ad6fea2803665931ccd515c844f652442c1c6b8965b58a4fc6f6a0d6
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'csv'
|
4
4
|
require 'roo'
|
5
5
|
|
6
6
|
module InfernoRequirementsTools
|
@@ -52,22 +52,26 @@ module InfernoRequirementsTools
|
|
52
52
|
PLANNED_NOT_TESTED_OUTPUT_FILE =
|
53
53
|
File.join('lib', TEST_KIT_CODE_FOLDER, 'requirements', PLANNED_NOT_TESTED_OUTPUT_FILE_NAME).freeze
|
54
54
|
|
55
|
-
def
|
56
|
-
@
|
55
|
+
def available_input_worksheets
|
56
|
+
@available_input_worksheets ||= Dir.glob(File.join(@input_directory, '*.xlsx')).reject { |f| f.include?('~$') }
|
57
57
|
end
|
58
58
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
59
|
+
# Of the form:
|
60
|
+
# {
|
61
|
+
# req_set_id_1: [row1, row2, row 3, ...],
|
62
|
+
# req_set_id_2: [row1, row2, row 3, ...]
|
63
|
+
# }
|
64
|
+
def input_requirement_sets
|
65
|
+
@input_requirement_sets ||= INPUT_SETS.each_with_object({}) do |req_set_id, hash|
|
66
|
+
req_set_file = available_input_worksheets.find { |worksheet_file| worksheet_file.include?(req_set_id) }
|
67
|
+
|
68
|
+
hash[req_set_id] =
|
69
|
+
unless req_set_file.nil?
|
70
|
+
CSV.parse(Roo::Spreadsheet.open(req_set_file).sheet('Requirements').to_csv,
|
71
|
+
headers: true).map do |row|
|
72
|
+
row.to_h.slice(*INPUT_HEADERS)
|
73
|
+
end
|
74
|
+
end
|
71
75
|
end
|
72
76
|
end
|
73
77
|
|
@@ -76,12 +80,11 @@ module InfernoRequirementsTools
|
|
76
80
|
CSV.generate(+"\xEF\xBB\xBF") do |csv| # start with an unnecessary BOM to make viewing in excel easier
|
77
81
|
csv << REQUIREMENTS_OUTPUT_HEADERS
|
78
82
|
|
79
|
-
|
80
|
-
input_rows
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
csv << REQUIREMENTS_OUTPUT_HEADERS.map { |header| row.key?(header) ? row[header] : row["#{header}*"]}
|
83
|
+
input_requirement_sets.each do |req_set_id, input_rows|
|
84
|
+
input_rows.each do |input_row| # NOTE: use row order from source file
|
85
|
+
csv << REQUIREMENTS_OUTPUT_HEADERS.map do |header|
|
86
|
+
header == 'Req Set' ? req_set_id : input_row[header] || input_row["#{header}*"]
|
87
|
+
end
|
85
88
|
end
|
86
89
|
end
|
87
90
|
end
|
@@ -96,19 +99,13 @@ module InfernoRequirementsTools
|
|
96
99
|
CSV.generate(+"\xEF\xBB\xBF") do |csv| # start with an unnecessary BOM to make viewing in excel easier
|
97
100
|
csv << PLANNED_NOT_TESTED_OUTPUT_HEADERS
|
98
101
|
|
99
|
-
|
100
|
-
input_rows
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
csv << [
|
107
|
-
req_set_id,
|
108
|
-
row['ID*'],
|
109
|
-
not_verifiable ? 'Not Verifiable' : 'Not Tested',
|
110
|
-
not_verifiable ? row['Verifiability Details'] : row['Planning To Test Details']
|
111
|
-
]
|
102
|
+
input_requirement_sets.each do |req_set_id, input_rows|
|
103
|
+
input_rows.each do |row|
|
104
|
+
if spreadsheet_value_falsy?(row['Verifiable?'])
|
105
|
+
csv << [req_set_id, row['ID*'], 'Not Verifiable', row['Verifiability Details']]
|
106
|
+
elsif spreadsheet_value_falsy?(row['Planning To Test?'])
|
107
|
+
csv << [req_set_id, row['ID*'], 'Not Tested', row['Planning To Test Details']]
|
108
|
+
end
|
112
109
|
end
|
113
110
|
end
|
114
111
|
end
|
@@ -118,22 +115,9 @@ module InfernoRequirementsTools
|
|
118
115
|
@old_planned_not_tested_csv ||= File.read(PLANNED_NOT_TESTED_OUTPUT_FILE)
|
119
116
|
end
|
120
117
|
|
121
|
-
def check_for_req_set_files(input_directory)
|
122
|
-
available_worksheets = Dir.glob(File.join(input_directory, '*.xlsx')).reject { |f| f.include?('~$') }
|
123
|
-
|
124
|
-
INPUT_SETS.each do |req_set_id|
|
125
|
-
req_set_file = available_worksheets&.find { |worksheet_file| worksheet_file.include?(req_set_id) }
|
126
|
-
|
127
|
-
if req_set_file&.empty?
|
128
|
-
puts "Could not find input file for set #{req_set_id} in directory #{input_directory}. Aborting requirements collection..."
|
129
|
-
exit(1)
|
130
|
-
end
|
131
|
-
input_file_map[req_set_id] = req_set_file
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
118
|
def run(input_directory)
|
136
|
-
|
119
|
+
@input_directory = input_directory
|
120
|
+
check_presence_of_input_files
|
137
121
|
|
138
122
|
update_requirements =
|
139
123
|
if File.exist?(REQUIREMENTS_OUTPUT_FILE)
|
@@ -177,7 +161,8 @@ module InfernoRequirementsTools
|
|
177
161
|
end
|
178
162
|
|
179
163
|
def run_check(input_directory)
|
180
|
-
|
164
|
+
@input_directory = input_directory
|
165
|
+
check_presence_of_input_files
|
181
166
|
|
182
167
|
requirements_ok =
|
183
168
|
if File.exist?(REQUIREMENTS_OUTPUT_FILE)
|
@@ -217,6 +202,22 @@ module InfernoRequirementsTools
|
|
217
202
|
MESSAGE
|
218
203
|
exit(1)
|
219
204
|
end
|
205
|
+
|
206
|
+
def check_presence_of_input_files
|
207
|
+
input_requirement_sets.each do |req_set_id, rows|
|
208
|
+
next unless rows.nil?
|
209
|
+
|
210
|
+
puts %(
|
211
|
+
Could not find input file for set #{req_set_id} in directory #{input_directory}. Aborting requirements
|
212
|
+
collection..."
|
213
|
+
)
|
214
|
+
exit(1)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def spreadsheet_value_falsy?(str)
|
219
|
+
str&.downcase == 'no' || str&.downcase == 'false'
|
220
|
+
end
|
220
221
|
end
|
221
222
|
end
|
222
223
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'csv'
|
4
4
|
require_relative '../ext/inferno_core/runnable'
|
5
5
|
|
6
6
|
module InfernoRequirementsTools
|
@@ -51,12 +51,15 @@ module InfernoRequirementsTools
|
|
51
51
|
INPUT_FILE = File.join('lib', TEST_KIT_CODE_FOLDER, 'requirements', INPUT_FILE_NAME).freeze
|
52
52
|
NOT_TESTED_FILE_NAME = "#{TEST_KIT_ID}_out_of_scope_requirements.csv".freeze
|
53
53
|
NOT_TESTED_FILE = File.join('lib', TEST_KIT_CODE_FOLDER, 'requirements', NOT_TESTED_FILE_NAME).freeze
|
54
|
+
OUTPUT_HEADERS = INPUT_HEADERS + TEST_SUITES.flat_map do |suite|
|
55
|
+
["#{suite.title} #{SHORT_ID_HEADER}", "#{suite.title} #{FULL_ID_HEADER}"]
|
56
|
+
end
|
54
57
|
OUTPUT_FILE_NAME = "#{TEST_KIT_ID}_requirements_coverage.csv".freeze
|
55
58
|
OUTPUT_FILE = File.join('lib', TEST_KIT_CODE_FOLDER, 'requirements', 'generated', OUTPUT_FILE_NAME).freeze
|
56
59
|
|
57
60
|
def input_rows
|
58
61
|
@input_rows ||=
|
59
|
-
CSV.parse(File.open(INPUT_FILE,
|
62
|
+
CSV.parse(File.open(INPUT_FILE, 'r:bom|utf-8'), headers: true).map do |row|
|
60
63
|
row.to_h.slice(*INPUT_HEADERS)
|
61
64
|
end
|
62
65
|
end
|
@@ -66,12 +69,12 @@ module InfernoRequirementsTools
|
|
66
69
|
end
|
67
70
|
|
68
71
|
def load_not_tested_requirements
|
69
|
-
return {} unless File.
|
72
|
+
return {} unless File.exist?(NOT_TESTED_FILE)
|
70
73
|
|
71
74
|
not_tested_requirements = {}
|
72
|
-
CSV.parse(File.open(NOT_TESTED_FILE,
|
75
|
+
CSV.parse(File.open(NOT_TESTED_FILE, 'r:bom|utf-8'), headers: true).each do |row|
|
73
76
|
row_hash = row.to_h
|
74
|
-
not_tested_requirements[
|
77
|
+
not_tested_requirements["#{row_hash['Req Set']}@#{row_hash['ID']}"] = row_hash
|
75
78
|
end
|
76
79
|
|
77
80
|
not_tested_requirements
|
@@ -95,26 +98,24 @@ module InfernoRequirementsTools
|
|
95
98
|
end
|
96
99
|
end
|
97
100
|
|
101
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
98
102
|
def new_csv
|
99
103
|
@new_csv ||=
|
100
104
|
CSV.generate(+"\xEF\xBB\xBF") do |csv|
|
101
|
-
|
102
|
-
|
103
|
-
headers << "#{suite.title} #{FULL_ID_HEADER}"
|
104
|
-
end
|
105
|
-
|
106
|
-
csv << output_headers
|
107
|
-
input_rows.each do |row| # note: use row order from source file
|
105
|
+
csv << OUTPUT_HEADERS
|
106
|
+
input_rows.each do |row| # NOTE: use row order from source file
|
108
107
|
next if row['Conformance'] == 'DEPRECATED' # filter out deprecated rows
|
109
|
-
|
108
|
+
|
110
109
|
TEST_SUITES.each do |suite|
|
111
110
|
suite_actor = SUITE_ID_TO_ACTOR_MAP[suite.id]
|
112
|
-
if
|
111
|
+
if row['Actor']&.include?(suite_actor)
|
113
112
|
set_and_req_id = "#{row['Req Set']}@#{row['ID']}"
|
114
|
-
suite_requirement_items = inferno_requirements_map[set_and_req_id]&.filter
|
113
|
+
suite_requirement_items = inferno_requirements_map[set_and_req_id]&.filter do |item|
|
114
|
+
item[:suite_id] == suite.id
|
115
|
+
end
|
115
116
|
short_ids = suite_requirement_items&.map { |item| item[:short_id] }
|
116
117
|
full_ids = suite_requirement_items&.map { |item| item[:full_id] }
|
117
|
-
if short_ids.blank? && not_tested_requirements_map.
|
118
|
+
if short_ids.blank? && not_tested_requirements_map.key?(set_and_req_id)
|
118
119
|
row["#{suite.title} #{SHORT_ID_HEADER}"] = 'Not Tested'
|
119
120
|
row["#{suite.title} #{FULL_ID_HEADER}"] = 'Not Tested'
|
120
121
|
else
|
@@ -131,6 +132,7 @@ module InfernoRequirementsTools
|
|
131
132
|
end
|
132
133
|
end
|
133
134
|
end
|
135
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
134
136
|
|
135
137
|
def input_requirement_ids
|
136
138
|
@input_requirement_ids ||= input_rows.map { |row| "#{row['Req Set']}@#{row['ID']}" }
|
@@ -138,9 +140,7 @@ module InfernoRequirementsTools
|
|
138
140
|
|
139
141
|
# The requirements present in Inferno that aren't in the input spreadsheet
|
140
142
|
def unmatched_requirements_map
|
141
|
-
@unmatched_requirements_map ||= inferno_requirements_map.
|
142
|
-
!input_requirement_ids.include?(requirement_id)
|
143
|
-
end
|
143
|
+
@unmatched_requirements_map ||= inferno_requirements_map.except(*input_requirement_ids)
|
144
144
|
end
|
145
145
|
|
146
146
|
def old_csv
|
@@ -233,6 +233,8 @@ module InfernoRequirementsTools
|
|
233
233
|
# ---------------+------------+----------
|
234
234
|
# req-id-1 | short-id-1 | full-id-1
|
235
235
|
# req-id-2 | short-id-2 | full-id-2
|
236
|
+
#
|
237
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
236
238
|
def output_requirements_map_table(requirements_map)
|
237
239
|
headers = %w[requirement_id short_id full_id]
|
238
240
|
col_widths = headers.map(&:length)
|
@@ -258,6 +260,7 @@ module InfernoRequirementsTools
|
|
258
260
|
end
|
259
261
|
puts
|
260
262
|
end
|
263
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
261
264
|
end
|
262
265
|
end
|
263
266
|
end
|
@@ -32,9 +32,11 @@ module SubscriptionsTestKit
|
|
32
32
|
|
33
33
|
unless subscription_status_entry.request.present? &&
|
34
34
|
(
|
35
|
-
subscription_id
|
36
|
-
subscription_status_entry.request.url.end_with?("Subscription/#{subscription_id}/$status")
|
35
|
+
if subscription_id
|
36
|
+
subscription_status_entry.request.url.end_with?("Subscription/#{subscription_id}/$status")
|
37
|
+
else
|
37
38
|
subscription_status_entry.request.url.match?(%r{Subscription/[^/]+/\$status\z})
|
39
|
+
end
|
38
40
|
)
|
39
41
|
|
40
42
|
add_message('error',
|
@@ -148,8 +150,14 @@ module SubscriptionsTestKit
|
|
148
150
|
end
|
149
151
|
|
150
152
|
def check_bundle_entry_reference(bundle_entries, reference)
|
153
|
+
check_full_url = reference.start_with?('urn:')
|
154
|
+
|
151
155
|
referenced_entry = bundle_entries.find do |entry|
|
152
|
-
|
156
|
+
if check_full_url
|
157
|
+
reference == entry.fullUrl
|
158
|
+
else
|
159
|
+
reference.include?("#{entry.resource.resourceType}/#{entry.resource.id}")
|
160
|
+
end
|
153
161
|
end
|
154
162
|
referenced_entry.present?
|
155
163
|
end
|
@@ -224,15 +232,6 @@ module SubscriptionsTestKit
|
|
224
232
|
resource in the entry.resource element.))
|
225
233
|
end
|
226
234
|
|
227
|
-
def subscription_criteria(subscription)
|
228
|
-
return unless subscription['_criteria']
|
229
|
-
|
230
|
-
criteria_extension = subscription['_criteria']['extension'].find do |ext|
|
231
|
-
ext['url'].ends_with?('/backport-filter-criteria')
|
232
|
-
end
|
233
|
-
criteria_extension['valueString'].split('?').first
|
234
|
-
end
|
235
|
-
|
236
235
|
def empty_event_notification_verification(notification_bundle)
|
237
236
|
assert_valid_json(notification_bundle)
|
238
237
|
bundle = FHIR.from_contents(notification_bundle)
|
@@ -37,6 +37,13 @@ module SubscriptionsTestKit
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
+
def valid_url?(url)
|
41
|
+
uri = URI.parse(url)
|
42
|
+
uri.is_a?(URI::HTTP) && !uri.host.nil?
|
43
|
+
rescue URI::InvalidURIError
|
44
|
+
false
|
45
|
+
end
|
46
|
+
|
40
47
|
def subscription_verification(subscription_resource)
|
41
48
|
assert_valid_json(subscription_resource)
|
42
49
|
subscription = JSON.parse(subscription_resource)
|
@@ -46,6 +53,11 @@ module SubscriptionsTestKit
|
|
46
53
|
The `type` field on the Subscription resource must be set to `rest-hook`, the `#{subscription_channel['type']}`
|
47
54
|
channel type is unsupported.))
|
48
55
|
|
56
|
+
unless subscription['criteria'].present? && valid_url?(subscription['criteria'])
|
57
|
+
add_message('error', %(
|
58
|
+
'The `criteria` field SHALL be populated and contain the canonical URL for the Subscription Topic.'
|
59
|
+
))
|
60
|
+
end
|
49
61
|
subscription_resource = FHIR.from_contents(subscription.to_json)
|
50
62
|
assert_resource_type('Subscription', resource: subscription_resource)
|
51
63
|
assert_valid_resource(resource: subscription_resource,
|
@@ -77,8 +89,8 @@ module SubscriptionsTestKit
|
|
77
89
|
Added the Authorization header field with a Bearer token set to #{access_token} to the `header` field on the
|
78
90
|
Subscription resource in order to connect successfully with the Inferno subscription channel.
|
79
91
|
))
|
80
|
-
|
81
|
-
|
92
|
+
subscription_channel['header'] = [] unless subscription_channel['header'].present?
|
93
|
+
subscription_channel['header'].append("Authorization: Bearer #{access_token}")
|
82
94
|
end
|
83
95
|
subscription['channel'] = subscription_channel
|
84
96
|
subscription
|
@@ -11,7 +11,7 @@
|
|
11
11
|
"_criteria" : {
|
12
12
|
"extension" : [{
|
13
13
|
"url" : "http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-filter-criteria",
|
14
|
-
"valueString" : "Encounter
|
14
|
+
"valueString" : "Encounter.patient=Patient/123"
|
15
15
|
}]
|
16
16
|
},
|
17
17
|
"channel" : {
|
@@ -11,7 +11,7 @@
|
|
11
11
|
"_criteria" : {
|
12
12
|
"extension" : [{
|
13
13
|
"url" : "http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-filter-criteria",
|
14
|
-
"valueString" : "Encounter
|
14
|
+
"valueString" : "Encounter.patient=Patient/123"
|
15
15
|
}]
|
16
16
|
},
|
17
17
|
"channel" : {
|
@@ -12,7 +12,7 @@
|
|
12
12
|
"_criteria" : {
|
13
13
|
"extension" : [{
|
14
14
|
"url" : "http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-filter-criteria",
|
15
|
-
"valueString" : "Encounter
|
15
|
+
"valueString" : "Encounter.patient=Patient/123"
|
16
16
|
}]
|
17
17
|
},
|
18
18
|
"channel" : {
|
data/lib/subscriptions_test_kit/docs/subscriptions_r5_backport_r4_client_suite_description.md
CHANGED
@@ -117,4 +117,7 @@ Specific limitations to highlight include
|
|
117
117
|
[provide feedback](https://github.com/inferno-framework/subscriptions-test-kit/issues) to that effect.
|
118
118
|
- Inferno does not test delivery error handling and recovery scenarios, including
|
119
119
|
the optional `$events` API and event numbering details.
|
120
|
-
- Inferno does not support sending heartbeat notifications.
|
120
|
+
- Inferno does not support sending heartbeat notifications.
|
121
|
+
- Inferno does not verify that the shape and content of notifications are appropriate for the triggering
|
122
|
+
Subscription because those details, e.g., the resource types that can be a focus of the notification,
|
123
|
+
are defined within the SubscriptionTopic which is not available in FHIR R4.
|
data/lib/subscriptions_test_kit/docs/subscriptions_r5_backport_r4_server_suite_description.md
CHANGED
@@ -167,4 +167,7 @@ Specific limitations to highlight include
|
|
167
167
|
If there is a channel type that you would like to see verified, please
|
168
168
|
[provide feedback](https://github.com/inferno-framework/subscriptions-test-kit/issues) to that effect.
|
169
169
|
- Inferno does not test delivery error handling and recovery scenarios, including
|
170
|
-
the optional `$events` API and event numbering details.
|
170
|
+
the optional `$events` API and event numbering details.
|
171
|
+
- Inferno does not verify that the shape and content of notifications are appropriate for the triggering
|
172
|
+
Subscription because those details, e.g., the resource types that can be a focus of the notification,
|
173
|
+
are defined within the SubscriptionTopic which is not available in FHIR R4.
|
@@ -32,7 +32,7 @@ module SubscriptionsTestKit
|
|
32
32
|
existing_subscription_request = requests.find { |r| r.status == 201 }
|
33
33
|
if existing_subscription_request.present?
|
34
34
|
subscription_hash = JSON.parse(existing_subscription_request.response_body)
|
35
|
-
error_text = 'Inferno only supports one subscription per test run. Subscription already created with '\
|
35
|
+
error_text = 'Inferno only supports one subscription per test run. Subscription already created with ' \
|
36
36
|
"ID #{subscription_hash['id']}"
|
37
37
|
response.body = operation_outcome('error', 'business-rule', error_text).to_json
|
38
38
|
return
|
@@ -74,10 +74,14 @@ module SubscriptionsTestKit
|
|
74
74
|
return operation_outcome('error', 'value', 'channel.endpoint is not recognized as a conformant URL')
|
75
75
|
end
|
76
76
|
|
77
|
-
heartbeat_period = subscription
|
77
|
+
heartbeat_period = find_heartbeat_period(subscription)
|
78
|
+
operation_outcome('error', 'not-supported', 'heartbeatPeriod is not supported') unless heartbeat_period.nil?
|
79
|
+
end
|
80
|
+
|
81
|
+
def find_heartbeat_period(subscription)
|
82
|
+
subscription&.channel&.extension&.find do |e|
|
78
83
|
e.url == 'http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-heartbeat-period'
|
79
84
|
end
|
80
|
-
operation_outcome('error', 'not-supported', 'heartbeatPeriod is not supported') unless heartbeat_period.nil?
|
81
85
|
end
|
82
86
|
|
83
87
|
def valid_url?(url)
|
@@ -30,28 +30,30 @@ module SubscriptionsTestKit
|
|
30
30
|
return
|
31
31
|
end
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
if id_params&.any? && id_params&.none? { |p| p.valueString == subscription.id }
|
33
|
+
unless subscription_params_match?(params)
|
36
34
|
not_found
|
37
35
|
return
|
38
|
-
else
|
39
|
-
status_params = params&.parameter&.filter { |p| p.name == 'status' }
|
40
|
-
subscription_status = determine_subscription_status_code(subscription.id)
|
41
|
-
if status_params&.any? && status_params.none? { |p| p.valueString == subscription_status }
|
42
|
-
not_found
|
43
|
-
return
|
44
|
-
end
|
45
36
|
end
|
46
37
|
end
|
47
38
|
|
48
39
|
notification_json = notification_bundle_input(result)
|
49
40
|
subscription_url = "#{base_subscription_url}/#{subscription.id}"
|
41
|
+
subscription_topic = subscription.criteria
|
50
42
|
status_code = determine_subscription_status_code(subscription_id)
|
51
43
|
event_count = determine_event_count(test_run.test_session_id)
|
52
44
|
response.status = 200
|
53
|
-
response.body = derive_status_bundle(notification_json, subscription_url,
|
54
|
-
request.url).to_json
|
45
|
+
response.body = derive_status_bundle(notification_json, subscription_url, subscription_topic, status_code,
|
46
|
+
event_count, request.url).to_json
|
47
|
+
end
|
48
|
+
|
49
|
+
def subscription_params_match?(params)
|
50
|
+
id_params = find_params(params, 'id')
|
51
|
+
|
52
|
+
return false if id_params&.any? && id_params&.none? { |p| p.valueString == subscription.id }
|
53
|
+
|
54
|
+
status_params = find_params(params, 'status')
|
55
|
+
subscription_status = determine_subscription_status_code(subscription.id)
|
56
|
+
status_params.nil? || status_params.none? || status_params.any { p.valueString == subscription_status }
|
55
57
|
end
|
56
58
|
|
57
59
|
def tags
|
@@ -63,8 +65,12 @@ module SubscriptionsTestKit
|
|
63
65
|
response.body = operation_outcome('error', 'not-found').to_json
|
64
66
|
end
|
65
67
|
|
68
|
+
def find_params(params, name)
|
69
|
+
params&.parameter&.filter { |p| p.name == name }
|
70
|
+
end
|
71
|
+
|
66
72
|
def base_subscription_url
|
67
|
-
request.url.sub(
|
73
|
+
request.url.sub(/(#{Regexp.escape(FHIR_SUBSCRIPTION_PATH)}).*/, '\1')
|
68
74
|
end
|
69
75
|
end
|
70
76
|
end
|
@@ -74,6 +74,10 @@ module SubscriptionsTestKit
|
|
74
74
|
@authorization_header ||= @bearer_token.present? ? { 'Authorization' => "Bearer #{@bearer_token}" } : {}
|
75
75
|
end
|
76
76
|
|
77
|
+
def subscription_topic
|
78
|
+
@subscription_topic ||= subscription&.criteria
|
79
|
+
end
|
80
|
+
|
77
81
|
def test_still_waiting?
|
78
82
|
results_repo.find_waiting_result(test_run_id: @test_run_id)
|
79
83
|
end
|
@@ -83,14 +87,15 @@ module SubscriptionsTestKit
|
|
83
87
|
end
|
84
88
|
|
85
89
|
def send_handshake_notification
|
86
|
-
handshake_json = derive_handshake_notification(@notification_json, @subscription_url
|
90
|
+
handshake_json = derive_handshake_notification(@notification_json, @subscription_url,
|
91
|
+
subscription_topic).to_json
|
87
92
|
response = send_notification(handshake_json)
|
88
93
|
persist_notification_request(response, [REST_HOOK_HANDSHAKE_NOTIFICATION_TAG])
|
89
94
|
resume_inferno_test unless response.status == 200
|
90
95
|
end
|
91
96
|
|
92
97
|
def send_event_notification
|
93
|
-
event_json = derive_event_notification(@notification_json, @subscription_url, 1).to_json
|
98
|
+
event_json = derive_event_notification(@notification_json, @subscription_url, subscription_topic, 1).to_json
|
94
99
|
response = send_notification(event_json)
|
95
100
|
persist_notification_request(response, [REST_HOOK_EVENT_NOTIFICATION_TAG])
|
96
101
|
end
|