committee_firetail 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. checksums.yaml +7 -0
  2. data/bin/committee-stub +23 -0
  3. data/lib/committee/bin/committee_stub.rb +67 -0
  4. data/lib/committee/drivers/driver.rb +47 -0
  5. data/lib/committee/drivers/hyper_schema/driver.rb +105 -0
  6. data/lib/committee/drivers/hyper_schema/link.rb +68 -0
  7. data/lib/committee/drivers/hyper_schema/schema.rb +22 -0
  8. data/lib/committee/drivers/hyper_schema.rb +12 -0
  9. data/lib/committee/drivers/open_api_2/driver.rb +252 -0
  10. data/lib/committee/drivers/open_api_2/header_schema_builder.rb +33 -0
  11. data/lib/committee/drivers/open_api_2/link.rb +36 -0
  12. data/lib/committee/drivers/open_api_2/parameter_schema_builder.rb +83 -0
  13. data/lib/committee/drivers/open_api_2/schema.rb +26 -0
  14. data/lib/committee/drivers/open_api_2/schema_builder.rb +33 -0
  15. data/lib/committee/drivers/open_api_2.rb +13 -0
  16. data/lib/committee/drivers/open_api_3/driver.rb +51 -0
  17. data/lib/committee/drivers/open_api_3/schema.rb +41 -0
  18. data/lib/committee/drivers/open_api_3.rb +11 -0
  19. data/lib/committee/drivers/schema.rb +23 -0
  20. data/lib/committee/drivers.rb +84 -0
  21. data/lib/committee/errors.rb +36 -0
  22. data/lib/committee/middleware/base.rb +57 -0
  23. data/lib/committee/middleware/request_validation.rb +41 -0
  24. data/lib/committee/middleware/response_validation.rb +58 -0
  25. data/lib/committee/middleware/stub.rb +75 -0
  26. data/lib/committee/middleware.rb +11 -0
  27. data/lib/committee/request_unpacker.rb +91 -0
  28. data/lib/committee/schema_validator/hyper_schema/parameter_coercer.rb +79 -0
  29. data/lib/committee/schema_validator/hyper_schema/request_validator.rb +55 -0
  30. data/lib/committee/schema_validator/hyper_schema/response_generator.rb +102 -0
  31. data/lib/committee/schema_validator/hyper_schema/response_validator.rb +89 -0
  32. data/lib/committee/schema_validator/hyper_schema/router.rb +46 -0
  33. data/lib/committee/schema_validator/hyper_schema/string_params_coercer.rb +105 -0
  34. data/lib/committee/schema_validator/hyper_schema.rb +119 -0
  35. data/lib/committee/schema_validator/open_api_3/operation_wrapper.rb +139 -0
  36. data/lib/committee/schema_validator/open_api_3/request_validator.rb +52 -0
  37. data/lib/committee/schema_validator/open_api_3/response_validator.rb +29 -0
  38. data/lib/committee/schema_validator/open_api_3/router.rb +45 -0
  39. data/lib/committee/schema_validator/open_api_3.rb +120 -0
  40. data/lib/committee/schema_validator/option.rb +60 -0
  41. data/lib/committee/schema_validator.rb +23 -0
  42. data/lib/committee/test/methods.rb +84 -0
  43. data/lib/committee/test/schema_coverage.rb +101 -0
  44. data/lib/committee/utils.rb +28 -0
  45. data/lib/committee/validation_error.rb +26 -0
  46. data/lib/committee/version.rb +5 -0
  47. data/lib/committee.rb +40 -0
  48. data/test/bin/committee_stub_test.rb +57 -0
  49. data/test/bin_test.rb +25 -0
  50. data/test/committee_test.rb +77 -0
  51. data/test/drivers/hyper_schema/driver_test.rb +49 -0
  52. data/test/drivers/hyper_schema/link_test.rb +56 -0
  53. data/test/drivers/open_api_2/driver_test.rb +156 -0
  54. data/test/drivers/open_api_2/header_schema_builder_test.rb +26 -0
  55. data/test/drivers/open_api_2/link_test.rb +52 -0
  56. data/test/drivers/open_api_2/parameter_schema_builder_test.rb +195 -0
  57. data/test/drivers/open_api_3/driver_test.rb +84 -0
  58. data/test/drivers_test.rb +154 -0
  59. data/test/middleware/base_test.rb +130 -0
  60. data/test/middleware/request_validation_open_api_3_test.rb +626 -0
  61. data/test/middleware/request_validation_test.rb +516 -0
  62. data/test/middleware/response_validation_open_api_3_test.rb +291 -0
  63. data/test/middleware/response_validation_test.rb +189 -0
  64. data/test/middleware/stub_test.rb +145 -0
  65. data/test/request_unpacker_test.rb +200 -0
  66. data/test/schema_validator/hyper_schema/parameter_coercer_test.rb +111 -0
  67. data/test/schema_validator/hyper_schema/request_validator_test.rb +151 -0
  68. data/test/schema_validator/hyper_schema/response_generator_test.rb +142 -0
  69. data/test/schema_validator/hyper_schema/response_validator_test.rb +118 -0
  70. data/test/schema_validator/hyper_schema/router_test.rb +88 -0
  71. data/test/schema_validator/hyper_schema/string_params_coercer_test.rb +137 -0
  72. data/test/schema_validator/open_api_3/operation_wrapper_test.rb +218 -0
  73. data/test/schema_validator/open_api_3/request_validator_test.rb +110 -0
  74. data/test/schema_validator/open_api_3/response_validator_test.rb +92 -0
  75. data/test/test/methods_new_version_test.rb +97 -0
  76. data/test/test/methods_test.rb +363 -0
  77. data/test/test/schema_coverage_test.rb +216 -0
  78. data/test/test_helper.rb +120 -0
  79. data/test/validation_error_test.rb +25 -0
  80. metadata +328 -0
@@ -0,0 +1,516 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ describe Committee::Middleware::RequestValidation do
6
+ include Rack::Test::Methods
7
+
8
+ def app
9
+ @app
10
+ end
11
+
12
+ ARRAY_PROPERTY = [
13
+ {
14
+ "update_time" => "2016-04-01T16:00:00.000+09:00",
15
+ "per_page" => 1,
16
+ "nested_coercer_object" => {
17
+ "update_time" => "2016-04-01T16:00:00.000+09:00",
18
+ "threshold" => 1.5
19
+ },
20
+ "nested_no_coercer_object" => {
21
+ "per_page" => 1,
22
+ "threshold" => 1.5
23
+ },
24
+ "nested_coercer_array" => [
25
+ {
26
+ "update_time" => "2016-04-01T16:00:00.000+09:00",
27
+ "threshold" => 1.5
28
+ }
29
+ ],
30
+ "nested_no_coercer_array" => [
31
+ {
32
+ "per_page" => 1,
33
+ "threshold" => 1.5
34
+ }
35
+ ],
36
+ "integer_array" => [
37
+ 1, 2, 3
38
+ ],
39
+ "datetime_array" => [
40
+ "2016-04-01T16:00:00.000+09:00",
41
+ "2016-04-01T17:00:00.000+09:00",
42
+ "2016-04-01T18:00:00.000+09:00"
43
+ ]
44
+ },
45
+ {
46
+ "update_time" => "2016-04-01T16:00:00.000+09:00",
47
+ "per_page" => 1,
48
+ "threshold" => 1.5
49
+ },
50
+ {
51
+ "threshold" => 1.5,
52
+ "per_page" => 1
53
+ }
54
+ ]
55
+
56
+ it "passes through a valid request" do
57
+ @app = new_rack_app(schema: hyper_schema)
58
+ params = {
59
+ "name" => "cloudnasium"
60
+ }
61
+ header "Content-Type", "application/json"
62
+ post "/apps", JSON.generate(params)
63
+ assert_equal 200, last_response.status
64
+ end
65
+
66
+ it "doesn't call error_handler (has a arg) when request is valid" do
67
+ called_error = false
68
+ pr = ->(_e) { called_error = true }
69
+ @app = new_rack_app(schema: hyper_schema, error_handler: pr)
70
+ params = {
71
+ "name" => "cloudnasium"
72
+ }
73
+ header "Content-Type", "application/json"
74
+ post "/apps", JSON.generate(params)
75
+ assert !called_error
76
+ end
77
+
78
+ it "doesn't call error_handler (has 2 args) when request is valid" do
79
+ called_error = false
80
+ pr = ->(_e, _env) { called_error = true }
81
+ @app = new_rack_app(schema: hyper_schema, error_handler: pr)
82
+ params = {
83
+ "name" => "cloudnasium"
84
+ }
85
+ header "Content-Type", "application/json"
86
+ post "/apps", JSON.generate(params)
87
+ assert !called_error
88
+ end
89
+
90
+ it "passes given a datetime and with coerce_date_times enabled on GET endpoint" do
91
+ key_name = "update_time"
92
+ params = {
93
+ key_name => "2016-04-01T16:00:00.000+09:00",
94
+ "query" => "cloudnasium"
95
+ }
96
+
97
+ check_parameter = lambda { |env|
98
+ assert_equal DateTime, env['rack.request.query_hash'][key_name].class
99
+ [200, {}, []]
100
+ }
101
+
102
+ @app = new_rack_app_with_lambda(check_parameter, coerce_date_times: true, schema: hyper_schema)
103
+
104
+ get "/search/apps", params
105
+ assert_equal 200, last_response.status
106
+ end
107
+
108
+ it "passes a nested object with recursive option" do
109
+ key_name = "update_time"
110
+ params = {
111
+ key_name => "2016-04-01T16:00:00.000+09:00",
112
+ "query" => "cloudnasium",
113
+ "array_property" => ARRAY_PROPERTY
114
+ }
115
+
116
+ check_parameter = lambda { |env|
117
+ hash = env['rack.request.query_hash']
118
+ assert_equal DateTime, hash['array_property'].first['update_time'].class
119
+ assert_equal 1, hash['array_property'].first['per_page']
120
+ assert_equal DateTime, hash['array_property'].first['nested_coercer_object']['update_time'].class
121
+ assert_equal 1, hash['array_property'].first['nested_no_coercer_object']['per_page']
122
+ assert_equal 2, hash['array_property'].first['integer_array'][1]
123
+ assert_equal DateTime, hash['array_property'].first['datetime_array'][0].class
124
+ assert_equal DateTime, hash[key_name].class
125
+ [200, {}, []]
126
+ }
127
+
128
+ @app = new_rack_app_with_lambda(check_parameter,
129
+ coerce_query_params: true,
130
+ coerce_recursive: true,
131
+ coerce_date_times: true,
132
+ schema: hyper_schema)
133
+
134
+ get "/search/apps", params
135
+ assert_equal 200, last_response.status
136
+ end
137
+
138
+ it "passes a nested object with coerce_recursive false" do
139
+ key_name = "update_time"
140
+ params = {
141
+ key_name => "2016-04-01T16:00:00.000+09:00",
142
+ "query" => "cloudnasium",
143
+ "array_property" => ARRAY_PROPERTY
144
+ }
145
+
146
+ @app = new_rack_app(coerce_query_params: true, coerce_date_times: true, coerce_recursive: false, schema: hyper_schema)
147
+
148
+ get "/search/apps", params
149
+ assert_equal 400, last_response.status # schema expect integer but we don't convert string to integer, so 400
150
+ end
151
+
152
+ it "passes a nested object with coerce_recursive default(true)" do
153
+ key_name = "update_time"
154
+ params = {
155
+ key_name => "2016-04-01T16:00:00.000+09:00",
156
+ "query" => "cloudnasium",
157
+ "array_property" => ARRAY_PROPERTY
158
+ }
159
+
160
+ @app = new_rack_app(coerce_query_params: true, coerce_date_times: true, schema: hyper_schema)
161
+
162
+ get "/search/apps", params
163
+ assert_equal 200, last_response.status # schema expect integer but we don't convert string to integer, so 400
164
+ end
165
+
166
+ it "passes given a nested datetime and with coerce_recursive=true and coerce_date_times=true on POST endpoint" do
167
+ key_name = "update_time"
168
+ params = {
169
+ key_name => "2016-04-01T16:00:00.000+09:00",
170
+ "array_property" => ARRAY_PROPERTY
171
+ }
172
+
173
+ check_parameter = lambda { |env|
174
+ hash = env['committee.params']
175
+ assert_equal DateTime, hash['array_property'].first['update_time'].class
176
+ assert_equal 1, hash['array_property'].first['per_page']
177
+ assert_equal DateTime, hash['array_property'].first['nested_coercer_object']['update_time'].class
178
+ assert_equal 1, hash['array_property'].first['nested_no_coercer_object']['per_page']
179
+ assert_equal 2, hash['array_property'].first['integer_array'][1]
180
+ assert_equal DateTime, hash['array_property'].first['datetime_array'][0].class
181
+ assert_equal DateTime, env['committee.params'][key_name].class
182
+ [200, {}, []]
183
+ }
184
+
185
+ @app = new_rack_app_with_lambda(check_parameter, coerce_date_times: true, coerce_recursive: true, schema: hyper_schema)
186
+
187
+ header "Content-Type", "application/json"
188
+ post "/apps", JSON.generate(params)
189
+ assert_equal 200, last_response.status
190
+ end
191
+
192
+ it "passes given a nested datetime and with coerce_recursive=true and coerce_date_times=true on POST endpoint" do
193
+ key_name = "update_time"
194
+ params = {
195
+ key_name => "2016-04-01T16:00:00.000+09:00",
196
+ "array_property" => ARRAY_PROPERTY
197
+ }
198
+
199
+ check_parameter = lambda { |env|
200
+ hash = env['committee.params']
201
+ assert_equal String, hash['array_property'].first['update_time'].class
202
+ assert_equal 1, hash['array_property'].first['per_page']
203
+ assert_equal String, hash['array_property'].first['nested_coercer_object']['update_time'].class
204
+ assert_equal 1, hash['array_property'].first['nested_no_coercer_object']['per_page']
205
+ assert_equal 2, hash['array_property'].first['integer_array'][1]
206
+ assert_equal String, hash['array_property'].first['datetime_array'][0].class
207
+ assert_equal String, env['committee.params'][key_name].class
208
+ [200, {}, []]
209
+ }
210
+
211
+ @app = new_rack_app_with_lambda(check_parameter, schema: hyper_schema)
212
+
213
+ header "Content-Type", "application/json"
214
+ post "/apps", JSON.generate(params)
215
+ assert_equal 200, last_response.status
216
+ end
217
+
218
+ it "passes given a nested datetime and with coerce_recursive=false and coerce_date_times=true on POST endpoint" do
219
+ key_name = "update_time"
220
+ params = {
221
+ key_name => "2016-04-01T16:00:00.000+09:00",
222
+ "array_property" => ARRAY_PROPERTY
223
+ }
224
+
225
+ check_parameter = lambda { |env|
226
+ hash = env['committee.params']
227
+ assert_equal String, hash['array_property'].first['update_time'].class
228
+ assert_equal 1, hash['array_property'].first['per_page']
229
+ assert_equal String, hash['array_property'].first['nested_coercer_object']['update_time'].class
230
+ assert_equal 1, hash['array_property'].first['nested_no_coercer_object']['per_page']
231
+ assert_equal 2, hash['array_property'].first['integer_array'][1]
232
+ assert_equal String, hash['array_property'].first['datetime_array'][0].class
233
+ assert_equal DateTime, env['committee.params'][key_name].class
234
+ [200, {}, []]
235
+ }
236
+
237
+ @app = new_rack_app_with_lambda(check_parameter, coerce_date_times: true, coerce_recursive: false, schema: hyper_schema)
238
+
239
+ header "Content-Type", "application/json"
240
+ post "/apps", JSON.generate(params)
241
+ assert_equal 200, last_response.status
242
+ end
243
+
244
+ it "passes given a nested datetime and with coerce_recursive=false and coerce_date_times=false on POST endpoint" do
245
+ key_name = "update_time"
246
+ params = {
247
+ key_name => "2016-04-01T16:00:00.000+09:00",
248
+ "array_property" => ARRAY_PROPERTY
249
+ }
250
+
251
+ check_parameter = lambda { |env|
252
+ hash = env['committee.params']
253
+ assert_equal String, hash['array_property'].first['update_time'].class
254
+ assert_equal 1, hash['array_property'].first['per_page']
255
+ assert_equal String, hash['array_property'].first['nested_coercer_object']['update_time'].class
256
+ assert_equal 1, hash['array_property'].first['nested_no_coercer_object']['per_page']
257
+ assert_equal 2, hash['array_property'].first['integer_array'][1]
258
+ assert_equal String, hash['array_property'].first['datetime_array'][0].class
259
+ assert_equal String, env['committee.params'][key_name].class
260
+ [200, {}, []]
261
+ }
262
+
263
+ @app = new_rack_app_with_lambda(check_parameter, schema: hyper_schema)
264
+
265
+ header "Content-Type", "application/json"
266
+ post "/apps", JSON.generate(params)
267
+ assert_equal 200, last_response.status
268
+ end
269
+
270
+ it "passes given an invalid datetime string with coerce_date_times enabled" do
271
+ @app = new_rack_app(coerce_date_times: true, schema: hyper_schema)
272
+ params = {
273
+ "update_time" => "invalid_datetime_format"
274
+ }
275
+ header "Content-Type", "application/json"
276
+ post "/apps", JSON.generate(params)
277
+ assert_equal 400, last_response.status
278
+ assert_match(/invalid request/i, last_response.body)
279
+ end
280
+
281
+ it "passes with coerce_date_times enabled and without a schema for a link" do
282
+ @app = new_rack_app(coerce_date_times: true, schema: hyper_schema)
283
+ header "Content-Type", "application/json"
284
+ get "/apps", JSON.generate({})
285
+ assert_equal 200, last_response.status
286
+ end
287
+
288
+ it "detects an invalid request" do
289
+ @app = new_rack_app(schema: hyper_schema)
290
+ header "Content-Type", "application/json"
291
+ params = {
292
+ "name" => 1
293
+ }
294
+ post "/apps", JSON.generate(params)
295
+ assert_equal 400, last_response.status
296
+ assert_match(/invalid request/i, last_response.body)
297
+ end
298
+
299
+ it "ignores errors when ignore_error: true" do
300
+ @app = new_rack_app(schema: hyper_schema, ignore_error: true)
301
+ header "Content-Type", "application/json"
302
+ params = {
303
+ "name" => 1
304
+ }
305
+ post "/apps", JSON.generate(params)
306
+ assert_equal 200, last_response.status
307
+ end
308
+
309
+ it "calls error_handler (has two args) when request is invalid" do
310
+ called_err = nil
311
+ pr = ->(e, _env) { called_err = e }
312
+ @app = new_rack_app(schema: hyper_schema, error_handler: pr)
313
+ header "Content-Type", "application/json"
314
+ params = {
315
+ "name" => 1
316
+ }
317
+ post "/apps", JSON.generate(params)
318
+ assert_kind_of Committee::InvalidRequest, called_err
319
+ end
320
+
321
+ it "rescues JSON errors" do
322
+ @app = new_rack_app(schema: hyper_schema)
323
+ header "Content-Type", "application/json"
324
+ post "/apps", "{x:y}"
325
+ assert_equal 400, last_response.status
326
+ assert_match(/valid json/i, last_response.body)
327
+ end
328
+
329
+ it "calls error_handler (has two args) when it rescues JSON errors" do
330
+ called_err = nil
331
+ pr = ->(e, _env) { called_err = e }
332
+ @app = new_rack_app(schema: hyper_schema, error_handler: pr)
333
+ header "Content-Type", "application/json"
334
+ post "/apps", "{x:y}"
335
+ assert_kind_of JSON::ParserError, called_err
336
+ end
337
+
338
+ it "takes a prefix" do
339
+ @app = new_rack_app(prefix: "/v1", schema: hyper_schema)
340
+ params = {
341
+ "name" => "cloudnasium"
342
+ }
343
+ header "Content-Type", "application/json"
344
+ post "/v1/apps", JSON.generate(params)
345
+ assert_equal 200, last_response.status
346
+ end
347
+
348
+ it "ignores paths outside the prefix" do
349
+ @app = new_rack_app(prefix: "/v1", schema: hyper_schema)
350
+ header "Content-Type", "text/html"
351
+ get "/hello"
352
+ assert_equal 200, last_response.status
353
+ end
354
+
355
+ it "routes to paths not in schema" do
356
+ @app = new_rack_app(schema: hyper_schema)
357
+ get "/not-a-resource"
358
+ assert_equal 200, last_response.status
359
+ end
360
+
361
+ it "doesn't route to paths not in schema when in strict mode" do
362
+ @app = new_rack_app(schema: hyper_schema, strict: true)
363
+ get "/not-a-resource"
364
+ assert_equal 404, last_response.status
365
+ end
366
+
367
+ it "optionally raises an error" do
368
+ @app = new_rack_app(raise: true, schema: hyper_schema)
369
+ header "Content-Type", "application/json"
370
+ assert_raises(Committee::InvalidRequest) do
371
+ post "/apps", "{x:y}"
372
+ end
373
+ end
374
+
375
+ it "optionally skip content_type check" do
376
+ @app = new_rack_app(check_content_type: false, schema: hyper_schema)
377
+ params = {
378
+ "name" => "cloudnasium"
379
+ }
380
+ header "Content-Type", "text/html"
381
+ post "/apps", JSON.generate(params)
382
+ assert_equal 200, last_response.status
383
+ end
384
+
385
+ it "optionally coerces query params" do
386
+ @app = new_rack_app(coerce_query_params: true, schema: hyper_schema)
387
+ header "Content-Type", "application/json"
388
+ get "/search/apps", {"per_page" => "10", "query" => "cloudnasium"}
389
+ assert_equal 200, last_response.status
390
+ end
391
+
392
+ it "still raises an error if query param coercion is not possible" do
393
+ @app = new_rack_app(coerce_query_params: true, schema: hyper_schema)
394
+ header "Content-Type", "application/json"
395
+ get "/search/apps", {"per_page" => "foo", "query" => "cloudnasium"}
396
+ assert_equal 400, last_response.status
397
+ assert_match(/invalid request/i, last_response.body)
398
+ end
399
+
400
+ it "passes through a valid request for OpenAPI" do
401
+ check_parameter = lambda { |env|
402
+ assert_equal 3, env['rack.request.query_hash']['limit']
403
+ [200, {}, []]
404
+ }
405
+
406
+ @app = new_rack_app_with_lambda(check_parameter, schema: open_api_2_schema)
407
+ get "/api/pets?limit=3", nil, { "HTTP_AUTH_TOKEN" => "xxx" }
408
+ assert_equal 200, last_response.status
409
+ end
410
+
411
+ it "coerce form params" do
412
+ check_parameter = lambda { |env|
413
+ assert_equal 3, env['committee.params']['age']
414
+ assert_equal 3, env['committee.request_body_hash']['age']
415
+ [200, {}, []]
416
+ }
417
+
418
+ @app = new_rack_app_with_lambda(check_parameter, schema: open_api_2_form_schema, raise: true, allow_form_params: true, coerce_form_params: true)
419
+ header "Content-Type", "application/x-www-form-urlencoded"
420
+ post "/api/pets", "age=3&name=ab"
421
+ assert_equal 200, last_response.status
422
+ end
423
+
424
+ it "detects an invalid request for OpenAPI" do
425
+ @app = new_rack_app(schema: open_api_2_schema)
426
+ get "/api/pets?limit=foo", nil, { "HTTP_AUTH_TOKEN" => "xxx" }
427
+ assert_equal 400, last_response.status
428
+ assert_match(/invalid request/i, last_response.body)
429
+ end
430
+
431
+ it "passes through a valid request for OpenAPI including path parameters" do
432
+ @app = new_rack_app(schema: open_api_2_schema)
433
+ # not that ID is expect to be an integer
434
+ get "/api/pets/123"
435
+ assert_equal 200, last_response.status
436
+ end
437
+
438
+ it "detects an invalid request for OpenAPI including path parameters" do
439
+ @app = new_rack_app(schema: open_api_2_schema)
440
+ # not that ID is expect to be an integer
441
+ get "/api/pets/not-integer"
442
+ assert_equal 400, last_response.status
443
+ assert_match(/invalid request/i, last_response.body)
444
+ end
445
+
446
+ it "OpenAPI3 pass through a valid request" do
447
+ @app = new_rack_app(schema: open_api_3_schema)
448
+ get "/characters"
449
+ assert_equal 200, last_response.status
450
+ end
451
+
452
+ it "OpenAPI3 pass not exist href" do
453
+ @app = new_rack_app(schema: open_api_3_schema)
454
+ get "/unknown"
455
+ assert_equal 200, last_response.status
456
+ end
457
+
458
+ it "OpenAPI3 pass not exist href in strict mode" do
459
+ @app = new_rack_app(schema: open_api_3_schema, strict: true)
460
+ get "/unknown"
461
+ assert_equal 404, last_response.status
462
+ end
463
+
464
+ it "not exist path and options" do
465
+ options = {
466
+ coerce_form_params: true,
467
+ coerce_date_times: true,
468
+ coerce_query_params: true,
469
+ coerce_path_params: true,
470
+ coerce_recursive: true
471
+ }
472
+
473
+ @app = new_rack_app({schema: hyper_schema}.merge(options))
474
+ header "Content-Type", "application/x-www-form-urlencoded"
475
+ post "/unknown"
476
+ assert_equal 200, last_response.status
477
+ end
478
+
479
+ describe ':accept_request_filter' do
480
+ [
481
+ { description: 'when not specified, includes everything', accept_request_filter: nil, expected: { status: 400 } },
482
+ { description: 'when predicate matches, performs validation', accept_request_filter: -> (request) { request.path.start_with?('/v1/a') }, expected: { status: 400 } },
483
+ { description: 'when predicate does not match, skips validation', accept_request_filter: -> (request) { request.path.start_with?('/v1/x') }, expected: { status: 200 } },
484
+ ].each do |h|
485
+ description = h[:description]
486
+ accept_request_filter = h[:accept_request_filter]
487
+ expected = h[:expected]
488
+ it description do
489
+ @app = new_rack_app(prefix: '/v1', schema: hyper_schema, accept_request_filter: accept_request_filter)
490
+
491
+ post '/v1/apps', '{x:y}'
492
+
493
+ assert_equal expected[:status], last_response.status
494
+ end
495
+ end
496
+ end
497
+
498
+ private
499
+
500
+ def new_rack_app(options = {})
501
+ new_rack_app_with_lambda(lambda { |_|
502
+ [200, {}, []]
503
+ }, options)
504
+ end
505
+
506
+
507
+ def new_rack_app_with_lambda(check_lambda, options = {})
508
+ # TODO: delete when 5.0.0 released because default value changed
509
+ options[:parse_response_by_content_type] = true if options[:parse_response_by_content_type] == nil
510
+
511
+ Rack::Builder.new {
512
+ use Committee::Middleware::RequestValidation, options
513
+ run check_lambda
514
+ }
515
+ end
516
+ end