razorrisk-cassini-common 0.26.24

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +22 -0
  3. data/LICENSE +5 -0
  4. data/README.md +2 -0
  5. data/Rakefile +102 -0
  6. data/lib/razor_risk/cassini/applications/microservice.rb +318 -0
  7. data/lib/razor_risk/cassini/applications/rest_framework/route_verb_dispatcher.rb +120 -0
  8. data/lib/razor_risk/cassini/applications/rest_framework/verb_handler.rb +117 -0
  9. data/lib/razor_risk/cassini/applications/route_verb_adaptors/utilities/collection_get_helper.rb +86 -0
  10. data/lib/razor_risk/cassini/applications/securable_microservice.rb +164 -0
  11. data/lib/razor_risk/cassini/applications/secured_microservice.rb +63 -0
  12. data/lib/razor_risk/cassini/applications/unsecured_microservice.rb +77 -0
  13. data/lib/razor_risk/cassini/authorisation/header_helpers.rb +271 -0
  14. data/lib/razor_risk/cassini/authorisation/security_model_helpers.rb +93 -0
  15. data/lib/razor_risk/cassini/authorisation.rb +27 -0
  16. data/lib/razor_risk/cassini/cli.rb +19 -0
  17. data/lib/razor_risk/cassini/common/version.rb +44 -0
  18. data/lib/razor_risk/cassini/common.rb +32 -0
  19. data/lib/razor_risk/cassini/constants.rb +68 -0
  20. data/lib/razor_risk/cassini/diagnostics/util_functions.rb +248 -0
  21. data/lib/razor_risk/cassini/diagnostics/zeroth_include.rb +35 -0
  22. data/lib/razor_risk/cassini/extensions/libclimate/common_options.rb +267 -0
  23. data/lib/razor_risk/cassini/extensions/libclimate.rb +26 -0
  24. data/lib/razor_risk/cassini/header_functions.rb +59 -0
  25. data/lib/razor_risk/cassini/main.rb +238 -0
  26. data/lib/razor_risk/cassini/mixin/razor_response_validator.rb +176 -0
  27. data/lib/razor_risk/cassini/testing/suppress_pantheios_logging.rb +31 -0
  28. data/lib/razor_risk/cassini/util/conversion_util.rb +176 -0
  29. data/lib/razor_risk/cassini/util/program_execution_util.rb +379 -0
  30. data/lib/razor_risk/cassini/util/secrets_util.rb +229 -0
  31. data/lib/razor_risk/cassini/util/version_util.rb +88 -0
  32. data/lib/razor_risk/sinatra/helpers/check_auth_helper.rb +209 -0
  33. data/lib/razor_risk/sinatra/helpers/validate_accept_helper.rb +69 -0
  34. data/lib/razor_risk/sinatra/helpers/validate_content_type_helper.rb +74 -0
  35. data/lib/razor_risk/sinatra/helpers/validate_query_parameters_helper.rb +198 -0
  36. data/test/scratch/cassini/util/convert_XML.rb +54 -0
  37. data/test/unit/applications/route_verb_adaptors/utilities/tc_collection_get_helper.rb +236 -0
  38. data/test/unit/applications/tc_verb_handler.rb +130 -0
  39. data/test/unit/mixin/tc_razor_response_validator.rb +328 -0
  40. data/test/unit/sinatra/helpers/tc_validate_query_parameters_helper.rb +134 -0
  41. data/test/unit/tc_authorisation_util.rb +265 -0
  42. data/test/unit/tc_load_secrets.rb +95 -0
  43. data/test/unit/util/tc_conversion_util.rb +393 -0
  44. data/test/unit/util/tc_program_execution_util.rb +462 -0
  45. metadata +380 -0
@@ -0,0 +1,236 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), *(['..'] * 5), 'lib')
4
+
5
+ require 'simplecov'
6
+
7
+ require 'razor_risk/cassini/testing/suppress_pantheios_logging' unless $DEBUG
8
+
9
+ require 'razor_risk/cassini/applications/route_verb_adaptors/utilities/collection_get_helper'
10
+
11
+ require 'xqsr3/extensions/test/unit'
12
+ require 'test/unit'
13
+
14
+ class Test_CollectionGetHelper_validate_exclusive_search_parameters < Test::Unit::TestCase
15
+
16
+ include ::RazorRisk::Cassini::Applications::RouteVerbAdaptors::Utilities::CollectionGetHelper
17
+
18
+ def halt code, headers, body_lines
19
+
20
+ if code && headers.nil?
21
+
22
+ headers = {}
23
+ end
24
+
25
+ if code && body_lines.nil?
26
+
27
+ body_lines = []
28
+ end
29
+
30
+ if ::String === body_lines
31
+
32
+ body_lines = [ body_lines ]
33
+ end
34
+
35
+
36
+ @code = code
37
+ @headers = headers
38
+ @body_lines = body_lines
39
+
40
+ nil
41
+ end
42
+
43
+ attr_reader :code
44
+ attr_reader :headers
45
+ attr_reader :body_lines
46
+
47
+ def test_empty_params
48
+
49
+ halt nil, nil, nil
50
+
51
+ r = validate_exclusive_search_parameters({})
52
+
53
+ assert r
54
+
55
+
56
+ halt nil, nil, nil
57
+
58
+ r = validate_exclusive_search_parameters({}, 'filter-name')
59
+
60
+ assert r
61
+ assert_nil code
62
+ assert_nil headers
63
+ assert_nil body_lines
64
+
65
+
66
+ halt nil, nil, nil
67
+
68
+ r = validate_exclusive_search_parameters({}, 'field-search', 'filter-name', 'quick-search')
69
+
70
+ assert r
71
+ assert_nil code
72
+ assert_nil headers
73
+ assert_nil body_lines
74
+ end
75
+
76
+ def test_non_conflicts
77
+
78
+ param_names = [
79
+
80
+ 'field-search',
81
+ 'filter-name',
82
+ 'quick-search',
83
+ ]
84
+
85
+ halt nil, nil, nil
86
+
87
+ r = validate_exclusive_search_parameters({}, *param_names)
88
+
89
+ assert r
90
+ assert_nil code
91
+ assert_nil headers
92
+ assert_nil body_lines
93
+
94
+
95
+ halt nil, nil, nil
96
+
97
+ r = validate_exclusive_search_parameters({ 'field-search' => 'abc' }, *param_names)
98
+
99
+ assert r
100
+ assert_nil code
101
+ assert_nil headers
102
+ assert_nil body_lines
103
+
104
+
105
+ halt nil, nil, nil
106
+
107
+ r = validate_exclusive_search_parameters({ 'filter-name' => 'abc' }, *param_names)
108
+
109
+ assert r
110
+ assert_nil code
111
+ assert_nil headers
112
+ assert_nil body_lines
113
+
114
+
115
+ halt nil, nil, nil
116
+
117
+ r = validate_exclusive_search_parameters({ 'quick-search' => 'abc' }, *param_names)
118
+
119
+ assert r
120
+ assert_nil code
121
+ assert_nil headers
122
+ assert_nil body_lines
123
+
124
+
125
+ halt nil, nil, nil
126
+
127
+ r = validate_exclusive_search_parameters({ 'other-param' => 'xyz', 'field-search' => 'abc' }, *param_names)
128
+
129
+ assert r
130
+ assert_nil code
131
+ assert_nil headers
132
+ assert_nil body_lines
133
+
134
+
135
+ halt nil, nil, nil
136
+
137
+ r = validate_exclusive_search_parameters({ 'other-param' => 'xyz', 'filter-name' => 'abc' }, *param_names)
138
+
139
+ assert r
140
+ assert_nil code
141
+ assert_nil headers
142
+ assert_nil body_lines
143
+
144
+
145
+ halt nil, nil, nil
146
+
147
+ r = validate_exclusive_search_parameters({ 'other-param' => 'xyz', 'quick-search' => 'abc' }, *param_names)
148
+
149
+ assert r
150
+ assert_nil code
151
+ assert_nil headers
152
+ assert_nil body_lines
153
+ end
154
+
155
+ def test_conflicts
156
+
157
+ param_names = [
158
+
159
+ 'quick-search',
160
+ 'field-search',
161
+ 'filter-name',
162
+ ]
163
+
164
+
165
+ halt nil, nil, nil
166
+
167
+ validate_exclusive_search_parameters({ 'field-search' => 'abc', 'filter-name' => 'xyz' }, *param_names)
168
+
169
+ assert_equal 422, code
170
+ assert_not_nil headers
171
+ assert_empty headers
172
+ assert_match /invalid search specifier: cannot specify 'field-search' and 'filter-name' together/, body_lines[0]
173
+
174
+
175
+ halt nil, nil, nil
176
+
177
+ validate_exclusive_search_parameters({ 'filter-name' => 'abc', 'quick-search' => 'xyz' }, *param_names)
178
+
179
+ assert_equal 422, code
180
+ assert_not_nil headers
181
+ assert_empty headers
182
+ assert_match /invalid search specifier: cannot specify 'filter-name' and 'quick-search' together/, body_lines[0]
183
+
184
+
185
+ halt nil, nil, nil
186
+
187
+ validate_exclusive_search_parameters({ 'quick-search' => 'abc', 'field-search' => 'xyz' }, *param_names)
188
+
189
+ assert_equal 422, code
190
+ assert_not_nil headers
191
+ assert_empty headers
192
+ assert_match /invalid search specifier: cannot specify 'field-search' and 'quick-search' together/, body_lines[0]
193
+ end
194
+
195
+ def test_conflicts_with_custom_message_scope_and_halt_code
196
+
197
+ param_names = [
198
+
199
+ 'quick-search',
200
+ 'field-search',
201
+ 'filter-name',
202
+ ]
203
+
204
+
205
+ halt nil, nil, nil
206
+
207
+ validate_exclusive_search_parameters({ 'field-search' => 'abc', 'filter-name' => 'xyz' }, *param_names, halt_code: 555, message_scope: 'incompatible search specifiers')
208
+
209
+ assert_equal 555, code
210
+ assert_not_nil headers
211
+ assert_empty headers
212
+ assert_match /incompatible search specifiers: cannot specify 'field-search' and 'filter-name' together/, body_lines[0]
213
+
214
+
215
+ halt nil, nil, nil
216
+
217
+ validate_exclusive_search_parameters({ 'filter-name' => 'abc', 'quick-search' => 'xyz' }, *param_names, halt_code: 555, message_scope: '')
218
+
219
+ assert_equal 555, code
220
+ assert_not_nil headers
221
+ assert_empty headers
222
+ assert_match /cannot specify 'filter-name' and 'quick-search' together/, body_lines[0]
223
+
224
+
225
+ halt nil, nil, nil
226
+
227
+ validate_exclusive_search_parameters({ 'quick-search' => 'abc', 'field-search' => 'xyz' }, *param_names, halt_code: 555, message_scope: nil)
228
+
229
+ assert_equal 555, code
230
+ assert_not_nil headers
231
+ assert_empty headers
232
+ assert_match /invalid search specifier: cannot specify 'field-search' and 'quick-search' together/, body_lines[0]
233
+ end
234
+ end
235
+
236
+
@@ -0,0 +1,130 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # ######################################################################## #
4
+ #
5
+ # Copyright (c) 2019 Razor Risk Technologies Pty Limited. All rights reserved.
6
+ #
7
+ # ######################################################################## #
8
+
9
+ $:.unshift File.join(File.dirname(__FILE__), *(['..'] * 4), 'lib')
10
+
11
+ require 'simplecov'
12
+
13
+ unless $DEBUG
14
+
15
+ require 'pantheios/globals'
16
+ require 'pantheios/services/null_log_service'
17
+
18
+ ::Pantheios::Globals.INITIAL_SERVICE_CLASSES = [ ::Pantheios::Services::NullLogService ]
19
+ end
20
+
21
+ # ##########################################################
22
+ # requires
23
+
24
+ require 'razor_risk/cassini/applications/rest_framework/verb_handler'
25
+
26
+ require 'xqsr3/extensions/test/unit'
27
+ require 'test/unit'
28
+
29
+ # ##########################################################
30
+ # tests
31
+
32
+ class Test_VerbHandler < Test::Unit::TestCase
33
+
34
+ include ::RazorRisk::Cassini::Applications::RESTFramework
35
+
36
+ App = Struct.new(:credentials)
37
+ Settings = Struct.new(:authentication_scheme, :auth_test_mode)
38
+
39
+ def test_get_required_credentials_with_basic
40
+
41
+ username = 'name'
42
+ password = 'pass'
43
+ domain = 'dom'
44
+ app = App.new([
45
+ username,
46
+ password,
47
+ domain,
48
+ ])
49
+ settings = Settings.new(:basic)
50
+ vh = VerbHandler.new(app, settings)
51
+
52
+ cr = vh.get_required_credentials
53
+
54
+ assert_kind_of Hash, cr
55
+ assert_equal username, cr[:username]
56
+ assert_equal password, cr[:password]
57
+ assert_equal domain, cr[:domain]
58
+ assert_nil cr[:impersonatee]
59
+ end
60
+
61
+ def test_get_required_credentials_with_basic_in_auth_test_mode
62
+
63
+ username = 'name'
64
+ password = 'pass'
65
+ domain = 'dom'
66
+ app = App.new([
67
+ username,
68
+ password,
69
+ domain,
70
+ ])
71
+ settings = Settings.new(:basic, true)
72
+ vh = VerbHandler.new(app, settings)
73
+
74
+ cr = vh.get_required_credentials
75
+
76
+ assert_kind_of Hash, cr
77
+ assert_nil cr[:username]
78
+ assert_nil cr[:password]
79
+ assert_nil cr[:domain]
80
+ assert_equal username, cr[:impersonatee]
81
+ end
82
+
83
+ def test_get_required_credentials_with_jwt
84
+
85
+ user_id = 'name'
86
+ user_name = 'Name'
87
+ session_id = 'session'
88
+ app = App.new([
89
+ session_id,
90
+ user_id,
91
+ user_name,
92
+ ])
93
+ settings = Settings.new(:jwt)
94
+ vh = VerbHandler.new(app, settings)
95
+
96
+ cr = vh.get_required_credentials
97
+
98
+ assert_kind_of Hash, cr
99
+ assert_equal session_id, cr[:session_id]
100
+ assert_equal user_id, cr[:user_id]
101
+ assert_equal user_name, cr[:user_name]
102
+ assert_nil cr[:impersonatee]
103
+ end
104
+
105
+ def test_get_required_credentials_with_jwt_in_auth_test_mode
106
+
107
+ user_id = 'name'
108
+ user_name = 'Name'
109
+ session_id = 'session'
110
+ app = App.new([
111
+ session_id,
112
+ user_id,
113
+ user_name,
114
+ ])
115
+ settings = Settings.new(:jwt)
116
+ vh = VerbHandler.new(app, settings)
117
+
118
+ cr = vh.get_required_credentials
119
+
120
+ assert_kind_of Hash, cr
121
+ assert_equal session_id, cr[:session_id]
122
+ assert_equal user_id, cr[:user_id]
123
+ assert_equal user_name, cr[:user_name]
124
+ assert_nil cr[:impersonatee]
125
+ end
126
+ end
127
+
128
+ # ############################## end of file ############################# #
129
+
130
+
@@ -0,0 +1,328 @@
1
+ # encoding: utf-8
2
+
3
+ # ##########################################################################
4
+ #
5
+ # Copyright (c) 2019 Razor Risk Technologies Pty Limited. All rights reserved.
6
+ #
7
+ # ##########################################################################
8
+
9
+ # ##########################################################
10
+ # load path
11
+
12
+ $:.unshift File.join(File.dirname(__FILE__), *(['..'] * 3), 'lib')
13
+
14
+
15
+ # ##########################################################
16
+ # diagnostics
17
+
18
+ require 'razor_risk/cassini/testing/suppress_pantheios_logging' unless $DEBUG
19
+
20
+
21
+ # ##########################################################
22
+ # code coverage
23
+
24
+ require 'simplecov'
25
+
26
+
27
+ # ##########################################################
28
+ # requires
29
+
30
+ require 'razor_risk/cassini/mixin/razor_response_validator'
31
+
32
+ require 'xqsr3/extensions/test/unit'
33
+
34
+ require 'test/unit'
35
+
36
+
37
+ # ##########################################################
38
+ # tests
39
+
40
+ class Test_RazorResponseValidator < Test::Unit::TestCase
41
+
42
+ include ::RazorRisk::Cassini::Mixin
43
+
44
+ Reason = Struct.new(:code, :message, :details)
45
+ Reasons = Struct.new(:reasons) do
46
+ def lookup? code
47
+ reasons.select { |r| r.code == code }.first
48
+ end
49
+ def map &block
50
+ reasons.map(&block)
51
+ end
52
+ def empty?
53
+ reasons.empty?
54
+ end
55
+ end
56
+ FailureQualifier = Struct.new(:reasons)
57
+ QualifiedResult = Struct.new(:succeeded?, :failure_qualifier)
58
+
59
+ def test_is_a_module
60
+
61
+ assert_kind_of Module, RazorResponseValidator
62
+ end
63
+
64
+ def test_has_required_methods
65
+
66
+ assert_respond_to(
67
+ RazorResponseValidator,
68
+ :validate_qualified_razor_response
69
+ )
70
+ end
71
+
72
+ def test_can_be_called_on_module
73
+
74
+ assert_nothing_raised do
75
+ RazorResponseValidator.validate_qualified_razor_response nil
76
+ end
77
+ end
78
+
79
+ def test_can_be_called_when_included
80
+
81
+ assert_nothing_raised do
82
+
83
+ app = Struct.new(:dummy) do
84
+ include RazorResponseValidator
85
+ end.new
86
+
87
+ app.validate_qualified_razor_response nil
88
+ end
89
+ end
90
+
91
+ def test_adds_custom_error_handler
92
+
93
+ app_class = Struct.new(:dummy) do
94
+
95
+ @error_handler_called = false
96
+
97
+ def self.error_handler_called
98
+ @error_handler_called
99
+ end
100
+
101
+ def self.error *args
102
+ @error_handler_called = true
103
+ end
104
+ end
105
+
106
+ assert_false app_class.error_handler_called
107
+ app_class.include RazorResponseValidator
108
+ assert_true app_class.error_handler_called
109
+ end
110
+
111
+ def test_validates_RZ0002
112
+
113
+ qr = QualifiedResult.new(
114
+ false,
115
+ FailureQualifier.new(
116
+ Reasons.new([
117
+ Reason.new('RZ0002', 'test message', 'test details'),
118
+ Reason.new('RZ0008', 'anther test message', 'another test details'),
119
+ ])
120
+ )
121
+ )
122
+
123
+ exp = RazorResponseValidator::RazorErrorException.new(
124
+ 500,
125
+ 'test message: test details',
126
+ )
127
+
128
+ begin
129
+ RazorResponseValidator.validate_qualified_razor_response qr
130
+ rescue => x
131
+ assert_equal exp.message, x.message
132
+ assert_equal exp.http_status, x.http_status
133
+ end
134
+ end
135
+
136
+ def test_validates_RZ0007
137
+
138
+ qr = QualifiedResult.new(
139
+ false,
140
+ FailureQualifier.new(
141
+ Reasons.new([
142
+ Reason.new('RZ0007', 'test message', 'test details')
143
+ ])
144
+ )
145
+ )
146
+
147
+ exp = RazorResponseValidator::RazorErrorException.new(
148
+ 401,
149
+ 'Invalid credentials',
150
+ )
151
+
152
+ begin
153
+ RazorResponseValidator.validate_qualified_razor_response qr
154
+ rescue => x
155
+ assert_equal exp.message, x.message
156
+ assert_equal exp.http_status, x.http_status
157
+ end
158
+ end
159
+
160
+ def test_validates_RZ0008
161
+
162
+ qr = QualifiedResult.new(
163
+ false,
164
+ FailureQualifier.new(
165
+ Reasons.new([
166
+ Reason.new('RZ0008', 'anther test message', 'another test details'),
167
+ ])
168
+ )
169
+ )
170
+
171
+ exp = RazorResponseValidator::RazorErrorException.new(
172
+ 500,
173
+ 'Oops! Something went wrong!',
174
+ )
175
+
176
+ begin
177
+ RazorResponseValidator.validate_qualified_razor_response qr
178
+ rescue => x
179
+ assert_equal exp.message, x.message
180
+ assert_equal exp.http_status, x.http_status
181
+ end
182
+ end
183
+
184
+ def test_validates_RZ0009
185
+
186
+ qr = QualifiedResult.new(
187
+ false,
188
+ FailureQualifier.new(
189
+ Reasons.new([
190
+ Reason.new('RZ0009', 'test message', 'test details')
191
+ ])
192
+ )
193
+ )
194
+
195
+ exp = RazorResponseValidator::RazorErrorException.new(
196
+ 401,
197
+ 'Invalid credentials',
198
+ )
199
+
200
+ begin
201
+ RazorResponseValidator.validate_qualified_razor_response qr
202
+ rescue => x
203
+ assert_equal exp.message, x.message
204
+ assert_equal exp.http_status, x.http_status
205
+ end
206
+ end
207
+
208
+ def test_validates_RZ0010
209
+
210
+ qr = QualifiedResult.new(
211
+ false,
212
+ FailureQualifier.new(
213
+ Reasons.new([
214
+ Reason.new('RZ0010', 'test message', 'test details'),
215
+ ])
216
+ )
217
+ )
218
+
219
+ exp = RazorResponseValidator::RazorErrorException.new(
220
+ 400,
221
+ 'test message: test details',
222
+ )
223
+
224
+ begin
225
+ RazorResponseValidator.validate_qualified_razor_response qr
226
+ rescue => x
227
+ assert_equal exp.message, x.message
228
+ assert_equal exp.http_status, x.http_status
229
+ end
230
+ end
231
+
232
+ def test_validates_RZ0011
233
+
234
+ qr = QualifiedResult.new(
235
+ false,
236
+ FailureQualifier.new(
237
+ Reasons.new([
238
+ Reason.new('RZ0011', 'test message', 'test details')
239
+ ])
240
+ )
241
+ )
242
+
243
+ exp = RazorResponseValidator::RazorErrorException.new(
244
+ 404,
245
+ 'test message: test details',
246
+ )
247
+
248
+ begin
249
+ RazorResponseValidator.validate_qualified_razor_response qr
250
+ rescue => x
251
+ assert_equal exp.message, x.message
252
+ assert_equal exp.http_status, x.http_status
253
+ end
254
+ end
255
+
256
+ def test_validates_unsupported_error
257
+
258
+ qr = QualifiedResult.new(
259
+ false,
260
+ FailureQualifier.new(
261
+ Reasons.new([
262
+ Reason.new('RZ0015', 'anther test message', 'another test details'),
263
+ ])
264
+ )
265
+ )
266
+
267
+ exp = RazorResponseValidator::RazorErrorException.new(
268
+ 500,
269
+ 'Oops! Something went wrong!',
270
+ )
271
+
272
+ begin
273
+ RazorResponseValidator.validate_qualified_razor_response qr
274
+ rescue => x
275
+ assert_equal exp.message, x.message
276
+ assert_equal exp.http_status, x.http_status
277
+ end
278
+ end
279
+
280
+ def test_handles_erros_in_correct_priority
281
+
282
+ reasons = [
283
+ Reason.new('RZ0007', 'RZ0007', 'RZ0007'),
284
+ Reason.new('RZ0009', 'RZ0009', 'RZ0009'),
285
+ Reason.new('RZ0002', 'RZ0002', 'RZ0002'),
286
+ Reason.new('RZ0011', 'RZ0011', 'RZ0011'),
287
+ Reason.new('RZ0010', 'RZ0010', 'RZ0010'),
288
+ Reason.new('RZ0008', 'RZ0008', 'RZ0008'),
289
+ Reason.new('RZ0015', 'RZ0015', 'RZ0015'),
290
+ ]
291
+
292
+ exp = [
293
+ [ 'RZ0007', 401, 'Invalid credentials' ],
294
+ [ 'RZ0009', 401, 'Invalid credentials' ],
295
+ [ 'RZ0002', 500, 'RZ0002: RZ0002' ],
296
+ [ 'RZ0011', 404, 'RZ0011: RZ0011' ],
297
+ [ 'RZ0010', 400, 'RZ0010: RZ0010' ],
298
+ [ 'RZ0008', 500, 'Oops! Something went wrong!' ],
299
+ [ 'RZ0015', 500, 'Oops! Something went wrong!' ],
300
+ ]
301
+
302
+ exp.each do |error, code, message|
303
+ qr = QualifiedResult.new(
304
+ false,
305
+ FailureQualifier.new(Reasons.new(reasons))
306
+ )
307
+ begin
308
+ RazorResponseValidator.validate_qualified_razor_response qr
309
+ rescue => x
310
+ assert_equal(
311
+ code, x.http_status,
312
+ "Expected #{error} to be handled"
313
+ )
314
+ assert_equal(
315
+ message, x.message,
316
+ "Expected #{error} to be handled"
317
+ )
318
+ end
319
+
320
+ reasons.shift
321
+ end
322
+ end
323
+ end
324
+
325
+
326
+ # ############################## end of file ############################# #
327
+
328
+