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,626 @@
|
|
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
|
+
it "OpenAPI3 pass through a valid request" do
|
13
|
+
@app = new_rack_app(schema: open_api_3_schema)
|
14
|
+
params = {
|
15
|
+
"string_post_1" => "cloudnasium"
|
16
|
+
}
|
17
|
+
header "Content-Type", "application/json"
|
18
|
+
post "/characters", JSON.generate(params)
|
19
|
+
|
20
|
+
assert_equal 200, last_response.status
|
21
|
+
end
|
22
|
+
|
23
|
+
it "not parameter request" do
|
24
|
+
check_parameter_string = lambda { |_|
|
25
|
+
[200, {integer: 1}, []]
|
26
|
+
}
|
27
|
+
|
28
|
+
@app = new_rack_app_with_lambda(check_parameter_string, schema: open_api_3_schema)
|
29
|
+
|
30
|
+
put "/validate_no_parameter", {no_schema: 'no'}
|
31
|
+
end
|
32
|
+
|
33
|
+
it "passes given a datetime and with coerce_date_times enabled on GET endpoint" do
|
34
|
+
params = { "datetime_string" => "2016-04-01T16:00:00.000+09:00" }
|
35
|
+
|
36
|
+
check_parameter = lambda { |env|
|
37
|
+
assert_equal DateTime, env['test.query_hash']["datetime_string"].class
|
38
|
+
assert_equal String, env['rack.request.query_hash']["datetime_string"].class
|
39
|
+
[200, {}, []]
|
40
|
+
}
|
41
|
+
|
42
|
+
@app = new_rack_app_with_lambda(check_parameter, schema: open_api_3_schema, coerce_date_times: true, query_hash_key: "test.query_hash")
|
43
|
+
|
44
|
+
get "/string_params_coercer", params
|
45
|
+
assert_equal 200, last_response.status
|
46
|
+
end
|
47
|
+
|
48
|
+
it "passes given a datetime and with coerce_date_times enabled on GET endpoint overwrite query_hash" do
|
49
|
+
params = { "datetime_string" => "2016-04-01T16:00:00.000+09:00" }
|
50
|
+
|
51
|
+
check_parameter = lambda { |env|
|
52
|
+
assert_nil env['committee.query_hash']
|
53
|
+
assert_equal DateTime, env['rack.request.query_hash']["datetime_string"].class
|
54
|
+
[200, {}, []]
|
55
|
+
}
|
56
|
+
|
57
|
+
@app = new_rack_app_with_lambda(check_parameter, schema: open_api_3_schema, coerce_date_times: true, query_hash_key: "rack.request.query_hash")
|
58
|
+
|
59
|
+
get "/string_params_coercer", params
|
60
|
+
assert_equal 200, last_response.status
|
61
|
+
end
|
62
|
+
|
63
|
+
it "passes given a valid parameter on GET endpoint with request body and allow_get_body=true" do
|
64
|
+
params = { "data" => "abc" }
|
65
|
+
|
66
|
+
@app = new_rack_app(schema: open_api_3_schema, allow_get_body: true)
|
67
|
+
|
68
|
+
get "/get_endpoint_with_required_parameter", { no_problem: true }, { input: params.to_json }
|
69
|
+
assert_equal 200, last_response.status
|
70
|
+
end
|
71
|
+
|
72
|
+
it "errors given valid parameter on GET endpoint with request body and allow_get_body=false" do
|
73
|
+
params = { "data" => "abc" }
|
74
|
+
|
75
|
+
@app = new_rack_app(schema: open_api_3_schema, allow_get_body: false)
|
76
|
+
|
77
|
+
get "/get_endpoint_with_required_parameter", { no_problem: true }, { input: params.to_json }
|
78
|
+
assert_equal 400, last_response.status
|
79
|
+
end
|
80
|
+
|
81
|
+
it "passes given a datetime and with coerce_date_times enabled on GET endpoint with request body" do
|
82
|
+
params = { "datetime_string" => "2016-04-01T16:00:00.000+09:00" }
|
83
|
+
|
84
|
+
check_parameter = lambda { |env|
|
85
|
+
assert_equal DateTime, env['committee.params']["datetime_string"].class
|
86
|
+
[200, {}, []]
|
87
|
+
}
|
88
|
+
|
89
|
+
@app = new_rack_app_with_lambda(check_parameter,
|
90
|
+
schema: open_api_3_schema,
|
91
|
+
coerce_date_times: true,
|
92
|
+
allow_get_body: true)
|
93
|
+
|
94
|
+
get "/string_params_coercer", { no_problem: true }, { input: params.to_json }
|
95
|
+
assert_equal 200, last_response.status
|
96
|
+
end
|
97
|
+
|
98
|
+
it "passes given a datetime and with coerce_date_times enabled on POST endpoint" do
|
99
|
+
params = {
|
100
|
+
"nested_array" => [
|
101
|
+
{
|
102
|
+
"update_time" => "2016-04-01T16:00:00.000+09:00",
|
103
|
+
"nested_coercer_object" => {
|
104
|
+
"update_time" => "2016-04-01T16:00:00.000+09:00",
|
105
|
+
},
|
106
|
+
"nested_no_coercer_object" => {
|
107
|
+
"update_time" => "2016-04-01T16:00:00.000+09:00",
|
108
|
+
},
|
109
|
+
"nested_coercer_array" => [
|
110
|
+
{
|
111
|
+
"update_time" => "2016-04-01T16:00:00.000+09:00",
|
112
|
+
}
|
113
|
+
],
|
114
|
+
"nested_no_coercer_array" => [
|
115
|
+
{
|
116
|
+
"update_time" => "2016-04-01T16:00:00.000+09:00",
|
117
|
+
}
|
118
|
+
]
|
119
|
+
},
|
120
|
+
{
|
121
|
+
"update_time" => "2016-04-01T16:00:00.000+09:00",
|
122
|
+
}
|
123
|
+
]
|
124
|
+
}
|
125
|
+
|
126
|
+
check_parameter = lambda { |env|
|
127
|
+
nested_array = env['committee.params']["nested_array"]
|
128
|
+
first_data = nested_array[0]
|
129
|
+
assert_kind_of DateTime, first_data["update_time"]
|
130
|
+
|
131
|
+
second_data = nested_array[1]
|
132
|
+
assert_kind_of DateTime, second_data["update_time"]
|
133
|
+
|
134
|
+
assert_kind_of DateTime, first_data["nested_coercer_object"]["update_time"]
|
135
|
+
|
136
|
+
assert_kind_of String, first_data["nested_no_coercer_object"]["update_time"]
|
137
|
+
|
138
|
+
assert_kind_of DateTime, first_data["nested_coercer_array"].first["update_time"]
|
139
|
+
assert_kind_of String, first_data["nested_no_coercer_array"].first["update_time"]
|
140
|
+
[200, {}, []]
|
141
|
+
}
|
142
|
+
|
143
|
+
@app = new_rack_app_with_lambda(check_parameter, schema: open_api_3_schema, coerce_date_times: true, coerce_recursive: true)
|
144
|
+
|
145
|
+
header "Content-Type", "application/json"
|
146
|
+
post "/string_params_coercer", JSON.generate(params)
|
147
|
+
|
148
|
+
assert_equal 200, last_response.status
|
149
|
+
end
|
150
|
+
|
151
|
+
it "passes given an invalid datetime string with coerce_date_times enabled" do
|
152
|
+
@app = new_rack_app(schema: open_api_3_schema, coerce_date_times: true)
|
153
|
+
params = {
|
154
|
+
"datetime_string" => "invalid_datetime_format"
|
155
|
+
}
|
156
|
+
get "/string_params_coercer", params
|
157
|
+
|
158
|
+
assert_equal 400, last_response.status
|
159
|
+
assert_match(/invalid_datetime/i, last_response.body)
|
160
|
+
end
|
161
|
+
|
162
|
+
it "passes a nested object with recursive option" do
|
163
|
+
params = {
|
164
|
+
"nested_array" => [
|
165
|
+
{
|
166
|
+
"update_time" => "2016-04-01T16:00:00.000+09:00",
|
167
|
+
"per_page" => "1",
|
168
|
+
}
|
169
|
+
],
|
170
|
+
}
|
171
|
+
|
172
|
+
check_parameter = lambda { |env|
|
173
|
+
hash = env["committee.query_hash"]
|
174
|
+
assert_equal DateTime, hash['nested_array'].first['update_time'].class
|
175
|
+
assert_equal 1, hash['nested_array'].first['per_page']
|
176
|
+
|
177
|
+
[200, {}, []]
|
178
|
+
}
|
179
|
+
|
180
|
+
@app = new_rack_app_with_lambda(check_parameter,
|
181
|
+
coerce_query_params: true,
|
182
|
+
coerce_recursive: true,
|
183
|
+
coerce_date_times: true,
|
184
|
+
schema: open_api_3_schema)
|
185
|
+
|
186
|
+
get "/string_params_coercer", params
|
187
|
+
|
188
|
+
assert_equal 200, last_response.status
|
189
|
+
end
|
190
|
+
|
191
|
+
it "passes given a nested datetime and with coerce_recursive=true and coerce_date_times=true on POST endpoint" do
|
192
|
+
params = {
|
193
|
+
"nested_array" => [
|
194
|
+
{
|
195
|
+
"update_time" => "2016-04-01T16:00:00.000+09:00",
|
196
|
+
"per_page" => 1,
|
197
|
+
"nested_coercer_object" => {
|
198
|
+
"update_time" => "2016-04-01T16:00:00.000+09:00",
|
199
|
+
"threshold" => 1.5
|
200
|
+
},
|
201
|
+
"nested_no_coercer_object" => {
|
202
|
+
"per_page" => 1,
|
203
|
+
"threshold" => 1.5
|
204
|
+
},
|
205
|
+
"nested_coercer_array" => [
|
206
|
+
{
|
207
|
+
"update_time" => "2016-04-01T16:00:00.000+09:00",
|
208
|
+
"threshold" => 1.5
|
209
|
+
}
|
210
|
+
],
|
211
|
+
"nested_no_coercer_array" => [
|
212
|
+
{
|
213
|
+
"per_page" => 1,
|
214
|
+
"threshold" => 1.5
|
215
|
+
}
|
216
|
+
],
|
217
|
+
"integer_array" => [
|
218
|
+
1, 2, 3
|
219
|
+
],
|
220
|
+
"datetime_array" => [
|
221
|
+
"2016-04-01T16:00:00.000+09:00",
|
222
|
+
"2016-04-01T17:00:00.000+09:00",
|
223
|
+
"2016-04-01T18:00:00.000+09:00"
|
224
|
+
]
|
225
|
+
},
|
226
|
+
{
|
227
|
+
"update_time" => "2016-04-01T16:00:00.000+09:00",
|
228
|
+
"per_page" => 1,
|
229
|
+
"threshold" => 1.5
|
230
|
+
},
|
231
|
+
{
|
232
|
+
"threshold" => 1.5,
|
233
|
+
"per_page" => 1
|
234
|
+
}
|
235
|
+
]
|
236
|
+
}
|
237
|
+
|
238
|
+
check_parameter = lambda { |env|
|
239
|
+
hash = env['committee.params']
|
240
|
+
array = hash['nested_array']
|
241
|
+
|
242
|
+
assert_equal DateTime, array.first['update_time'].class
|
243
|
+
assert_equal 1, array.first['per_page']
|
244
|
+
assert_equal DateTime, array.first['nested_coercer_object']['update_time'].class
|
245
|
+
assert_equal 1, array.first['nested_no_coercer_object']['per_page']
|
246
|
+
assert_equal 2, array.first['integer_array'][1]
|
247
|
+
assert_equal DateTime, array.first['datetime_array'][0].class
|
248
|
+
[200, {}, []]
|
249
|
+
}
|
250
|
+
|
251
|
+
@app = new_rack_app_with_lambda(check_parameter,
|
252
|
+
coerce_date_times: true,
|
253
|
+
schema: open_api_3_schema)
|
254
|
+
|
255
|
+
header "Content-Type", "application/json"
|
256
|
+
post "/string_params_coercer", JSON.generate(params)
|
257
|
+
assert_equal 200, last_response.status
|
258
|
+
end
|
259
|
+
|
260
|
+
it "OpenAPI3 detects an invalid request" do
|
261
|
+
@app = new_rack_app(schema: open_api_3_schema, strict: true)
|
262
|
+
header "Content-Type", "application/json"
|
263
|
+
params = {
|
264
|
+
"string_post_1" => 1
|
265
|
+
}
|
266
|
+
post "/characters", JSON.generate(params)
|
267
|
+
assert_equal 400, last_response.status
|
268
|
+
assert_match(/expected string, but received Integer:/i, last_response.body)
|
269
|
+
end
|
270
|
+
|
271
|
+
it "rescues JSON errors" do
|
272
|
+
@app = new_rack_app(schema: open_api_3_schema)
|
273
|
+
header "Content-Type", "application/json"
|
274
|
+
post "/characters", "{x:y}"
|
275
|
+
assert_equal 400, last_response.status
|
276
|
+
assert_match(/valid json/i, last_response.body)
|
277
|
+
end
|
278
|
+
|
279
|
+
it "take a prefix" do
|
280
|
+
@app = new_rack_app(prefix: "/v1", schema: open_api_3_schema)
|
281
|
+
params = {
|
282
|
+
"string_post_1" => "cloudnasium"
|
283
|
+
}
|
284
|
+
header "Content-Type", "application/json"
|
285
|
+
post "/v1/characters", JSON.generate(params)
|
286
|
+
assert_equal 200, last_response.status
|
287
|
+
end
|
288
|
+
|
289
|
+
it "take a prefix with invalid data" do
|
290
|
+
@app = new_rack_app(prefix: "/v1", schema: open_api_3_schema)
|
291
|
+
params = {
|
292
|
+
"string_post_1" => 1
|
293
|
+
}
|
294
|
+
header "Content-Type", "application/json"
|
295
|
+
post "/v1/characters", JSON.generate(params)
|
296
|
+
assert_equal 400, last_response.status
|
297
|
+
assert_match(/expected string, but received Integer: /i, last_response.body)
|
298
|
+
end
|
299
|
+
|
300
|
+
it "ignores paths outside the prefix" do
|
301
|
+
@app = new_rack_app(prefix: "/v1", schema: open_api_3_schema)
|
302
|
+
params = {
|
303
|
+
"string_post_1" => 1
|
304
|
+
}
|
305
|
+
header "Content-Type", "application/json"
|
306
|
+
post "/characters", JSON.generate(params)
|
307
|
+
assert_equal 200, last_response.status
|
308
|
+
end
|
309
|
+
|
310
|
+
it "don't check prefix with no option" do
|
311
|
+
@app = new_rack_app(schema: open_api_3_schema)
|
312
|
+
params = {
|
313
|
+
"string_post_1" => 1
|
314
|
+
}
|
315
|
+
header "Content-Type", "application/json"
|
316
|
+
post "/v1/characters", JSON.generate(params)
|
317
|
+
assert_equal 200, last_response.status
|
318
|
+
end
|
319
|
+
|
320
|
+
it "OpenAPI3 pass not exist href" do
|
321
|
+
@app = new_rack_app(schema: open_api_3_schema)
|
322
|
+
get "/unknown"
|
323
|
+
assert_equal 200, last_response.status
|
324
|
+
end
|
325
|
+
|
326
|
+
it "OpenAPI3 pass not exist href in strict mode" do
|
327
|
+
@app = new_rack_app(schema: open_api_3_schema, strict: true)
|
328
|
+
get "/unknown"
|
329
|
+
assert_equal 404, last_response.status
|
330
|
+
end
|
331
|
+
|
332
|
+
it "OpenAPI3 parser not exist required key" do
|
333
|
+
@app = new_rack_app(raise: true, schema: open_api_3_schema)
|
334
|
+
|
335
|
+
e = assert_raises(Committee::InvalidRequest) do
|
336
|
+
get "/validate", nil
|
337
|
+
end
|
338
|
+
|
339
|
+
assert_match(/missing required parameters: query_string/i, e.message)
|
340
|
+
end
|
341
|
+
|
342
|
+
it "raises error when required path parameter is invalid" do
|
343
|
+
@app = new_rack_app(raise: true, schema: open_api_3_schema)
|
344
|
+
|
345
|
+
e = assert_raises(Committee::InvalidRequest) do
|
346
|
+
not_an_integer = 'abc'
|
347
|
+
get "/coerce_path_params/#{not_an_integer}", nil
|
348
|
+
end
|
349
|
+
|
350
|
+
assert_match(/expected integer, but received String: \"abc\"/i, e.message)
|
351
|
+
end
|
352
|
+
|
353
|
+
it "optionally raises an error" do
|
354
|
+
@app = new_rack_app(raise: true, schema: open_api_3_schema)
|
355
|
+
header "Content-Type", "application/json"
|
356
|
+
assert_raises(Committee::InvalidRequest) do
|
357
|
+
post "/characters", "{x:y}"
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
it "optionally coerces query params" do
|
362
|
+
@app = new_rack_app(coerce_query_params: true, schema: open_api_3_schema)
|
363
|
+
header "Content-Type", "application/json"
|
364
|
+
get "/string_params_coercer", {"integer_1" => "1"}
|
365
|
+
assert_equal 200, last_response.status
|
366
|
+
end
|
367
|
+
|
368
|
+
it "still raises an error if query param coercion is not possible" do
|
369
|
+
@app = new_rack_app(coerce_query_params: false, schema: open_api_3_schema)
|
370
|
+
header "Content-Type", "application/json"
|
371
|
+
get "/string_params_coercer", {"integer_1" => "1"}
|
372
|
+
|
373
|
+
assert_equal 400, last_response.status
|
374
|
+
assert_match(/expected integer, but received String:/i, last_response.body)
|
375
|
+
end
|
376
|
+
|
377
|
+
it "passes through a valid request for OpenAPI3" do
|
378
|
+
check_parameter = lambda { |env|
|
379
|
+
assert_equal 3, env['committee.query_hash']['limit'] #5.0.x-
|
380
|
+
[200, {}, []]
|
381
|
+
}
|
382
|
+
|
383
|
+
@app = new_rack_app_with_lambda(check_parameter, schema: open_api_3_schema)
|
384
|
+
get "/characters?limit=3"
|
385
|
+
assert_equal 200, last_response.status
|
386
|
+
end
|
387
|
+
|
388
|
+
it "detects an invalid request for OpenAPI" do
|
389
|
+
@app = new_rack_app(schema: open_api_3_schema)
|
390
|
+
get "/characters?limit=foo"
|
391
|
+
|
392
|
+
assert_equal 400, last_response.status
|
393
|
+
assert_match(/expected integer, but received String: \\"foo\\"/i, last_response.body)
|
394
|
+
end
|
395
|
+
|
396
|
+
it "ignores errors when ignore_error: true" do
|
397
|
+
@app = new_rack_app(schema: open_api_3_schema, ignore_error: true)
|
398
|
+
get "/characters?limit=foo"
|
399
|
+
|
400
|
+
assert_equal 200, last_response.status
|
401
|
+
end
|
402
|
+
|
403
|
+
it "coerce string to integer" do
|
404
|
+
check_parameter_string = lambda { |env|
|
405
|
+
assert env['committee.params']['integer'].is_a?(Integer)
|
406
|
+
[200, {}, []]
|
407
|
+
}
|
408
|
+
|
409
|
+
@app = new_rack_app_with_lambda(check_parameter_string, schema: open_api_3_schema, coerce_path_params: true)
|
410
|
+
get "/coerce_path_params/1"
|
411
|
+
end
|
412
|
+
|
413
|
+
describe "overwrite same parameter (old rule)" do
|
414
|
+
# (high priority) path_hash_key -> request_body_hash -> query_param
|
415
|
+
it "set query parameter to committee.params and query hash" do
|
416
|
+
@app = new_rack_app_with_lambda(lambda do |env|
|
417
|
+
assert_equal env['committee.params']['integer'], 42
|
418
|
+
assert_equal env['committee.params'][:integer], 42
|
419
|
+
assert_equal env['committee.query_hash']['integer'], 42
|
420
|
+
#assert_equal env['rack.request.query_hash'][:integer], 42 # this isn't hash indifferent hash because we use rack.request.query_hash
|
421
|
+
[204, {}, []]
|
422
|
+
end, schema: open_api_3_schema, parameter_overwite_by_rails_rule: false)
|
423
|
+
|
424
|
+
header "Content-Type", "application/json"
|
425
|
+
post '/overwrite_same_parameter?integer=42'
|
426
|
+
assert_equal 204, last_response.status
|
427
|
+
end
|
428
|
+
|
429
|
+
it "request body precedence over query parameter" do
|
430
|
+
@app = new_rack_app_with_lambda(lambda do |env|
|
431
|
+
assert_equal env['committee.params']['integer'], 21
|
432
|
+
assert_equal env['committee.params'][:integer], 21
|
433
|
+
assert_equal env['committee.request_body_hash']['integer'], 21
|
434
|
+
assert_equal env['committee.request_body_hash'][:integer], 21
|
435
|
+
assert_equal env['committee.query_hash']['integer'], 42
|
436
|
+
[204, {}, []]
|
437
|
+
end, schema: open_api_3_schema, parameter_overwite_by_rails_rule: false)
|
438
|
+
|
439
|
+
params = {integer: 21}
|
440
|
+
|
441
|
+
header "Content-Type", "application/json"
|
442
|
+
post '/overwrite_same_parameter?integer=42', JSON.generate(params)
|
443
|
+
assert_equal 204, last_response.status
|
444
|
+
end
|
445
|
+
|
446
|
+
it "path parameter precedence over request body" do
|
447
|
+
@app = new_rack_app_with_lambda(lambda do |env|
|
448
|
+
assert_equal env['committee.params']['integer'], 84
|
449
|
+
assert_equal env['committee.params'][:integer], 84
|
450
|
+
assert_equal env['committee.path_hash']['integer'], 84
|
451
|
+
assert_equal env['committee.path_hash'][:integer], 84
|
452
|
+
assert_equal env['committee.request_body_hash']['integer'], 21
|
453
|
+
assert_equal env['committee.request_body_hash'][:integer], 21
|
454
|
+
assert_equal env['committee.query_hash']['integer'], 84 # we can't use query_parameter :(
|
455
|
+
#assert_equal env['rack.request.query_hash'][:integer], 21 # this isn't hash indifferent hash because we use rack.request.query_hash
|
456
|
+
[204, {}, []]
|
457
|
+
end, schema: open_api_3_schema, parameter_overwite_by_rails_rule: false)
|
458
|
+
|
459
|
+
params = {integer: 21}
|
460
|
+
|
461
|
+
header "Content-Type", "application/json"
|
462
|
+
post '/overwrite_same_parameter/84?integer=42', JSON.generate(params)
|
463
|
+
assert_equal 204, last_response.status
|
464
|
+
end
|
465
|
+
end
|
466
|
+
|
467
|
+
describe "overwrite same parameter (new rule and seme to Rails)" do
|
468
|
+
# (high priority) path_hash_key -> query_param -> request_body_hash
|
469
|
+
it "set request body to committee.params and query hash" do
|
470
|
+
@app = new_rack_app_with_lambda(lambda do |env|
|
471
|
+
assert_equal env['committee.params']['integer'], 21
|
472
|
+
assert_equal env['committee.params'][:integer], 21
|
473
|
+
assert_equal env['committee.request_body_hash']['integer'], 21
|
474
|
+
assert_equal env['committee.request_body_hash'][:integer], 21
|
475
|
+
[204, {}, []]
|
476
|
+
end, schema: open_api_3_schema)
|
477
|
+
|
478
|
+
params = {integer: 21}
|
479
|
+
|
480
|
+
header "Content-Type", "application/json"
|
481
|
+
post '/overwrite_same_parameter', JSON.generate(params)
|
482
|
+
assert_equal 204, last_response.status
|
483
|
+
end
|
484
|
+
|
485
|
+
it "query parameter precedence over request body" do
|
486
|
+
@app = new_rack_app_with_lambda(lambda do |env|
|
487
|
+
assert_equal env['committee.params']['integer'], 42
|
488
|
+
assert_equal env['committee.params'][:integer], 42
|
489
|
+
assert_equal env['committee.request_body_hash']['integer'], 21
|
490
|
+
assert_equal env['committee.request_body_hash'][:integer], 21
|
491
|
+
assert_equal env['committee.query_hash']['integer'], 42
|
492
|
+
[204, {}, []]
|
493
|
+
end, schema: open_api_3_schema)
|
494
|
+
|
495
|
+
params = {integer: 21}
|
496
|
+
|
497
|
+
header "Content-Type", "application/json"
|
498
|
+
post '/overwrite_same_parameter?integer=42', JSON.generate(params)
|
499
|
+
assert_equal 204, last_response.status
|
500
|
+
end
|
501
|
+
|
502
|
+
it "path path parameter precedence over query parameter" do
|
503
|
+
@app = new_rack_app_with_lambda(lambda do |env|
|
504
|
+
assert_equal env['committee.params']['integer'], 84
|
505
|
+
assert_equal env['committee.params'][:integer], 84
|
506
|
+
assert_equal env['committee.request_body_hash']['integer'], 21
|
507
|
+
assert_equal env['committee.request_body_hash'][:integer], 21
|
508
|
+
assert_equal env['committee.query_hash']['integer'], 84 # we can't use query_parameter :(
|
509
|
+
assert_equal env['committee.path_hash']['integer'], 84
|
510
|
+
assert_equal env['committee.path_hash'][:integer], 84
|
511
|
+
[204, {}, []]
|
512
|
+
end, schema: open_api_3_schema)
|
513
|
+
|
514
|
+
params = {integer: 21}
|
515
|
+
|
516
|
+
header "Content-Type", "application/json"
|
517
|
+
post '/overwrite_same_parameter/84?integer=42', JSON.generate(params)
|
518
|
+
assert_equal 204, last_response.status
|
519
|
+
end
|
520
|
+
end
|
521
|
+
|
522
|
+
it "unpacker test" do
|
523
|
+
@app = new_rack_app_with_lambda(lambda do |env|
|
524
|
+
assert_equal '21', env['committee.params']['integer'] # query parameter has precedence
|
525
|
+
assert_equal '21', env['committee.params'][:integer]
|
526
|
+
assert_equal '21', env['rack.request.query_hash']['integer']
|
527
|
+
assert_equal 42, env['committee.request_body_hash']['integer']
|
528
|
+
[204, {}, []]
|
529
|
+
end, schema: open_api_3_schema, raise: true)
|
530
|
+
|
531
|
+
header "Content-Type", "application/x-www-form-urlencoded"
|
532
|
+
post '/validate?integer=21', "integer=42"
|
533
|
+
assert_equal 204, last_response.status
|
534
|
+
end
|
535
|
+
|
536
|
+
it "OpenAPI3 raise not support method" do
|
537
|
+
@app = new_rack_app(schema: open_api_3_schema)
|
538
|
+
|
539
|
+
e = assert_raises(RuntimeError) {
|
540
|
+
custom_request('TRACE', "/characters")
|
541
|
+
}
|
542
|
+
|
543
|
+
assert_equal 'Committee OpenAPI3 not support trace method', e.message
|
544
|
+
end
|
545
|
+
|
546
|
+
describe 'check header' do
|
547
|
+
[
|
548
|
+
{ check_header: true, description: 'valid value', value: 1, expected: { status: 200 } },
|
549
|
+
{ check_header: true, description: 'missing value', value: nil, expected: { status: 400, error: 'missing required parameters: integer' } },
|
550
|
+
{ check_header: true, description: 'invalid value', value: 'x', expected: { status: 400, error: 'expected integer, but received String: \\"x\\"' } },
|
551
|
+
|
552
|
+
{ check_header: false, description: 'valid value', value: 1, expected: { status: 200 } },
|
553
|
+
{ check_header: false, description: 'missing value', value: nil, expected: { status: 200 } },
|
554
|
+
{ check_header: false, description: 'invalid value', value: 'x', expected: { status: 200 } },
|
555
|
+
].each do |h|
|
556
|
+
check_header = h[:check_header]
|
557
|
+
description = h[:description]
|
558
|
+
value = h[:value]
|
559
|
+
expected = h[:expected]
|
560
|
+
describe "when #{check_header}" do
|
561
|
+
%w(get post put patch delete options).each do |method|
|
562
|
+
describe method do
|
563
|
+
describe description do
|
564
|
+
it (expected[:error].nil? ? 'should pass' : 'should fail') do
|
565
|
+
@app = new_rack_app(schema: open_api_3_schema, check_header: check_header)
|
566
|
+
|
567
|
+
header 'integer', value
|
568
|
+
send(method, "/header")
|
569
|
+
|
570
|
+
assert_equal expected[:status], last_response.status
|
571
|
+
assert_match(expected[:error], last_response.body) if expected[:error]
|
572
|
+
end
|
573
|
+
end
|
574
|
+
end
|
575
|
+
end
|
576
|
+
end
|
577
|
+
end
|
578
|
+
end
|
579
|
+
|
580
|
+
describe ':accept_request_filter' do
|
581
|
+
[
|
582
|
+
{ description: 'when not specified, includes everything', accept_request_filter: nil, expected: { status: 400 } },
|
583
|
+
{ description: 'when predicate matches, performs validation', accept_request_filter: -> (request) { request.path.start_with?('/v1/c') }, expected: { status: 400 } },
|
584
|
+
{ description: 'when predicate does not match, skips validation', accept_request_filter: -> (request) { request.path.start_with?('/v1/x') }, expected: { status: 200 } },
|
585
|
+
].each do |h|
|
586
|
+
description = h[:description]
|
587
|
+
accept_request_filter = h[:accept_request_filter]
|
588
|
+
expected = h[:expected]
|
589
|
+
it description do
|
590
|
+
@app = new_rack_app(prefix: '/v1', schema: open_api_3_schema, accept_request_filter: accept_request_filter)
|
591
|
+
|
592
|
+
post 'v1/characters', JSON.generate(string_post_1: 1)
|
593
|
+
|
594
|
+
assert_equal expected[:status], last_response.status
|
595
|
+
end
|
596
|
+
end
|
597
|
+
end
|
598
|
+
|
599
|
+
it 'does not suppress application error' do
|
600
|
+
@app = new_rack_app_with_lambda(lambda { |_|
|
601
|
+
JSON.load('-') # invalid json
|
602
|
+
}, schema: open_api_3_schema, raise: true)
|
603
|
+
|
604
|
+
assert_raises(JSON::ParserError) do
|
605
|
+
get "/error", nil
|
606
|
+
end
|
607
|
+
end
|
608
|
+
|
609
|
+
private
|
610
|
+
|
611
|
+
def new_rack_app(options = {})
|
612
|
+
new_rack_app_with_lambda(lambda { |_|
|
613
|
+
[200, {}, []]
|
614
|
+
}, options)
|
615
|
+
end
|
616
|
+
|
617
|
+
def new_rack_app_with_lambda(check_lambda, options = {})
|
618
|
+
# TODO: delete when 5.0.0 released because default value changed
|
619
|
+
options[:parse_response_by_content_type] = true if options[:parse_response_by_content_type] == nil
|
620
|
+
|
621
|
+
Rack::Builder.new {
|
622
|
+
use Committee::Middleware::RequestValidation, options
|
623
|
+
run check_lambda
|
624
|
+
}
|
625
|
+
end
|
626
|
+
end
|