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.
- checksums.yaml +7 -0
- data/bin/committee-stub +23 -0
- data/lib/committee/bin/committee_stub.rb +67 -0
- data/lib/committee/drivers/driver.rb +47 -0
- data/lib/committee/drivers/hyper_schema/driver.rb +105 -0
- data/lib/committee/drivers/hyper_schema/link.rb +68 -0
- data/lib/committee/drivers/hyper_schema/schema.rb +22 -0
- data/lib/committee/drivers/hyper_schema.rb +12 -0
- data/lib/committee/drivers/open_api_2/driver.rb +252 -0
- data/lib/committee/drivers/open_api_2/header_schema_builder.rb +33 -0
- data/lib/committee/drivers/open_api_2/link.rb +36 -0
- data/lib/committee/drivers/open_api_2/parameter_schema_builder.rb +83 -0
- data/lib/committee/drivers/open_api_2/schema.rb +26 -0
- data/lib/committee/drivers/open_api_2/schema_builder.rb +33 -0
- data/lib/committee/drivers/open_api_2.rb +13 -0
- data/lib/committee/drivers/open_api_3/driver.rb +51 -0
- data/lib/committee/drivers/open_api_3/schema.rb +41 -0
- data/lib/committee/drivers/open_api_3.rb +11 -0
- data/lib/committee/drivers/schema.rb +23 -0
- data/lib/committee/drivers.rb +84 -0
- data/lib/committee/errors.rb +36 -0
- data/lib/committee/middleware/base.rb +57 -0
- data/lib/committee/middleware/request_validation.rb +41 -0
- data/lib/committee/middleware/response_validation.rb +58 -0
- data/lib/committee/middleware/stub.rb +75 -0
- data/lib/committee/middleware.rb +11 -0
- data/lib/committee/request_unpacker.rb +91 -0
- data/lib/committee/schema_validator/hyper_schema/parameter_coercer.rb +79 -0
- data/lib/committee/schema_validator/hyper_schema/request_validator.rb +55 -0
- data/lib/committee/schema_validator/hyper_schema/response_generator.rb +102 -0
- data/lib/committee/schema_validator/hyper_schema/response_validator.rb +89 -0
- data/lib/committee/schema_validator/hyper_schema/router.rb +46 -0
- data/lib/committee/schema_validator/hyper_schema/string_params_coercer.rb +105 -0
- data/lib/committee/schema_validator/hyper_schema.rb +119 -0
- data/lib/committee/schema_validator/open_api_3/operation_wrapper.rb +139 -0
- data/lib/committee/schema_validator/open_api_3/request_validator.rb +52 -0
- data/lib/committee/schema_validator/open_api_3/response_validator.rb +29 -0
- data/lib/committee/schema_validator/open_api_3/router.rb +45 -0
- data/lib/committee/schema_validator/open_api_3.rb +120 -0
- data/lib/committee/schema_validator/option.rb +60 -0
- data/lib/committee/schema_validator.rb +23 -0
- data/lib/committee/test/methods.rb +84 -0
- data/lib/committee/test/schema_coverage.rb +101 -0
- data/lib/committee/utils.rb +28 -0
- data/lib/committee/validation_error.rb +26 -0
- data/lib/committee/version.rb +5 -0
- data/lib/committee.rb +40 -0
- data/test/bin/committee_stub_test.rb +57 -0
- data/test/bin_test.rb +25 -0
- data/test/committee_test.rb +77 -0
- data/test/drivers/hyper_schema/driver_test.rb +49 -0
- data/test/drivers/hyper_schema/link_test.rb +56 -0
- data/test/drivers/open_api_2/driver_test.rb +156 -0
- data/test/drivers/open_api_2/header_schema_builder_test.rb +26 -0
- data/test/drivers/open_api_2/link_test.rb +52 -0
- data/test/drivers/open_api_2/parameter_schema_builder_test.rb +195 -0
- data/test/drivers/open_api_3/driver_test.rb +84 -0
- data/test/drivers_test.rb +154 -0
- data/test/middleware/base_test.rb +130 -0
- data/test/middleware/request_validation_open_api_3_test.rb +626 -0
- data/test/middleware/request_validation_test.rb +516 -0
- data/test/middleware/response_validation_open_api_3_test.rb +291 -0
- data/test/middleware/response_validation_test.rb +189 -0
- data/test/middleware/stub_test.rb +145 -0
- data/test/request_unpacker_test.rb +200 -0
- data/test/schema_validator/hyper_schema/parameter_coercer_test.rb +111 -0
- data/test/schema_validator/hyper_schema/request_validator_test.rb +151 -0
- data/test/schema_validator/hyper_schema/response_generator_test.rb +142 -0
- data/test/schema_validator/hyper_schema/response_validator_test.rb +118 -0
- data/test/schema_validator/hyper_schema/router_test.rb +88 -0
- data/test/schema_validator/hyper_schema/string_params_coercer_test.rb +137 -0
- data/test/schema_validator/open_api_3/operation_wrapper_test.rb +218 -0
- data/test/schema_validator/open_api_3/request_validator_test.rb +110 -0
- data/test/schema_validator/open_api_3/response_validator_test.rb +92 -0
- data/test/test/methods_new_version_test.rb +97 -0
- data/test/test/methods_test.rb +363 -0
- data/test/test/schema_coverage_test.rb +216 -0
- data/test/test_helper.rb +120 -0
- data/test/validation_error_test.rb +25 -0
- 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
|