subscriptions_test_kit 0.9.2 → 0.9.3
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 +4 -2
- data/lib/subscriptions_test_kit/endpoints/subscription_create_endpoint.rb +7 -3
- data/lib/subscriptions_test_kit/endpoints/subscription_status_endpoint.rb +16 -11
- data/lib/subscriptions_test_kit/requirements/generated/subscriptions-test-kit_requirements_coverage.csv +50 -50
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/common/subscription_simulation_utils.rb +9 -6
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/conformance_verification/notification_input_payload_verification_test.rb +2 -2
- data/lib/subscriptions_test_kit/suites/subscriptions_r5_backport_r4_client/workflow/conformance_verification/notification_input_verification_test.rb +1 -1
- 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 +2 -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 +14 -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 +10 -9
- 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_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 +2 -2
- 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 +2 -2
- 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_subscriptions_test.rb +29 -25
- 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 +4 -74
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ad5fae1148d468463f60e61a0e7c273b90eac5294b1c8d19b588288d3d53ca77
|
4
|
+
data.tar.gz: 62507f2c4a5cc9e39c1906bbb10032d1baa00b8ec33055762016c5ce2d22722c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bad58bc3cdcb1c451bcb28f5dfbe8a5492e5cc8fff49b00f99d35d93588cec7936feeedee3c24984d6c1090ade8f92b35da4c89d83fd8036586f539cd0296ad7
|
7
|
+
data.tar.gz: f26d5875e051b95b24dabc7f45cdba4b9bda8631f76f022aa1e753569e89be8fd264b052ac9662855023c2f685ad9b4ac5473732b8d7538b32d7a2db819e2e6b
|
@@ -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',
|
@@ -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,18 +30,9 @@ 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
|
|
@@ -54,6 +45,16 @@ module SubscriptionsTestKit
|
|
54
45
|
request.url).to_json
|
55
46
|
end
|
56
47
|
|
48
|
+
def subscription_params_match?(params)
|
49
|
+
id_params = find_params(params, 'id')
|
50
|
+
|
51
|
+
return false if id_params&.any? && id_params&.none? { |p| p.valueString == subscription.id }
|
52
|
+
|
53
|
+
status_params = find_params(params, 'status')
|
54
|
+
subscription_status = determine_subscription_status_code(subscription.id)
|
55
|
+
status_params.nil? || status_params.none? || status_params.any { p.valueString == subscription_status }
|
56
|
+
end
|
57
|
+
|
57
58
|
def tags
|
58
59
|
[SUBSCRIPTION_STATUS_TAG]
|
59
60
|
end
|
@@ -63,8 +64,12 @@ module SubscriptionsTestKit
|
|
63
64
|
response.body = operation_outcome('error', 'not-found').to_json
|
64
65
|
end
|
65
66
|
|
67
|
+
def find_params(params, name)
|
68
|
+
params&.parameter&.filter { |p| p.name == name }
|
69
|
+
end
|
70
|
+
|
66
71
|
def base_subscription_url
|
67
|
-
request.url.sub(
|
72
|
+
request.url.sub(/(#{Regexp.escape(FHIR_SUBSCRIPTION_PATH)}).*/, '\1')
|
68
73
|
end
|
69
74
|
end
|
70
75
|
end
|