committee 3.3.0 → 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 +4 -4
- data/lib/committee/drivers/open_api_2/driver.rb +1 -2
- data/lib/committee/drivers/open_api_2/parameter_schema_builder.rb +1 -1
- data/lib/committee/drivers.rb +22 -10
- data/lib/committee/errors.rb +12 -0
- data/lib/committee/middleware/base.rb +5 -4
- data/lib/committee/middleware/request_validation.rb +4 -18
- data/lib/committee/middleware/response_validation.rb +15 -16
- data/lib/committee/request_unpacker.rb +46 -60
- data/lib/committee/schema_validator/hyper_schema/response_validator.rb +8 -2
- data/lib/committee/schema_validator/hyper_schema.rb +41 -27
- data/lib/committee/schema_validator/open_api_3/operation_wrapper.rb +44 -37
- data/lib/committee/schema_validator/open_api_3/request_validator.rb +11 -2
- data/lib/committee/schema_validator/open_api_3/router.rb +3 -1
- data/lib/committee/schema_validator/open_api_3.rb +52 -26
- data/lib/committee/schema_validator/option.rb +14 -3
- data/lib/committee/schema_validator.rb +1 -1
- data/lib/committee/test/methods.rb +27 -16
- data/lib/committee/test/schema_coverage.rb +101 -0
- data/lib/committee/utils.rb +28 -0
- data/lib/committee/validation_error.rb +3 -2
- data/lib/committee/version.rb +5 -0
- data/lib/committee.rb +11 -4
- data/test/bin/committee_stub_test.rb +5 -1
- data/test/committee_test.rb +29 -3
- data/test/drivers/open_api_3/driver_test.rb +1 -1
- data/test/drivers_test.rb +20 -7
- data/test/middleware/base_test.rb +9 -10
- data/test/middleware/request_validation_open_api_3_test.rb +175 -18
- data/test/middleware/request_validation_test.rb +20 -28
- data/test/middleware/response_validation_open_api_3_test.rb +96 -7
- data/test/middleware/response_validation_test.rb +21 -26
- data/test/middleware/stub_test.rb +4 -0
- data/test/request_unpacker_test.rb +51 -110
- data/test/schema_validator/hyper_schema/response_validator_test.rb +10 -0
- data/test/schema_validator/hyper_schema/router_test.rb +4 -0
- data/test/schema_validator/hyper_schema/string_params_coercer_test.rb +1 -1
- data/test/schema_validator/open_api_3/operation_wrapper_test.rb +72 -20
- data/test/schema_validator/open_api_3/request_validator_test.rb +27 -0
- data/test/schema_validator/open_api_3/response_validator_test.rb +26 -5
- data/test/test/methods_new_version_test.rb +17 -5
- data/test/test/methods_test.rb +155 -31
- data/test/test/schema_coverage_test.rb +216 -0
- data/test/test_helper.rb +34 -4
- metadata +47 -15
@@ -9,8 +9,18 @@ describe Committee::RequestUnpacker do
|
|
9
9
|
"rack.input" => StringIO.new('{"x":"y"}'),
|
10
10
|
}
|
11
11
|
request = Rack::Request.new(env)
|
12
|
-
|
13
|
-
assert_equal({ "x" => "y" },
|
12
|
+
unpacker = Committee::RequestUnpacker.new
|
13
|
+
assert_equal([{ "x" => "y" }, false], unpacker.unpack_request_params(request))
|
14
|
+
end
|
15
|
+
|
16
|
+
it "unpacks JSON on Content-Type: application/vnd.api+json" do
|
17
|
+
env = {
|
18
|
+
"CONTENT_TYPE" => "application/vnd.api+json",
|
19
|
+
"rack.input" => StringIO.new('{"x":"y"}'),
|
20
|
+
}
|
21
|
+
request = Rack::Request.new(env)
|
22
|
+
unpacker = Committee::RequestUnpacker.new
|
23
|
+
assert_equal([{ "x" => "y" }, false], unpacker.unpack_request_params(request))
|
14
24
|
end
|
15
25
|
|
16
26
|
it "unpacks JSON on no Content-Type" do
|
@@ -18,8 +28,18 @@ describe Committee::RequestUnpacker do
|
|
18
28
|
"rack.input" => StringIO.new('{"x":"y"}'),
|
19
29
|
}
|
20
30
|
request = Rack::Request.new(env)
|
21
|
-
|
22
|
-
assert_equal({ "x" => "y" },
|
31
|
+
unpacker = Committee::RequestUnpacker.new
|
32
|
+
assert_equal([{ "x" => "y" }, false], unpacker.unpack_request_params(request))
|
33
|
+
end
|
34
|
+
|
35
|
+
it "doesn't unpack JSON on application/x-ndjson" do
|
36
|
+
env = {
|
37
|
+
"CONTENT_TYPE" => "application/x-ndjson",
|
38
|
+
"rack.input" => StringIO.new('{"x":"y"}\n{"a":"b"}'),
|
39
|
+
}
|
40
|
+
request = Rack::Request.new(env)
|
41
|
+
unpacker = Committee::RequestUnpacker.new
|
42
|
+
assert_equal([{}, false], unpacker.unpack_request_params(request))
|
23
43
|
end
|
24
44
|
|
25
45
|
it "doesn't unpack JSON under other Content-Types" do
|
@@ -29,8 +49,8 @@ describe Committee::RequestUnpacker do
|
|
29
49
|
"rack.input" => StringIO.new('{"x":"y"}'),
|
30
50
|
}
|
31
51
|
request = Rack::Request.new(env)
|
32
|
-
|
33
|
-
assert_equal({},
|
52
|
+
unpacker = Committee::RequestUnpacker.new
|
53
|
+
assert_equal([{}, false], unpacker.unpack_request_params(request))
|
34
54
|
end
|
35
55
|
end
|
36
56
|
|
@@ -41,8 +61,8 @@ describe Committee::RequestUnpacker do
|
|
41
61
|
"rack.input" => StringIO.new('{"x":"y"}'),
|
42
62
|
}
|
43
63
|
request = Rack::Request.new(env)
|
44
|
-
|
45
|
-
assert_equal({ "x" => "y" },
|
64
|
+
unpacker = Committee::RequestUnpacker.new(optimistic_json: true)
|
65
|
+
assert_equal([{ "x" => "y" }, false], unpacker.unpack_request_params(request))
|
46
66
|
end
|
47
67
|
end
|
48
68
|
|
@@ -53,8 +73,8 @@ describe Committee::RequestUnpacker do
|
|
53
73
|
"rack.input" => StringIO.new('x=y&foo=42'),
|
54
74
|
}
|
55
75
|
request = Rack::Request.new(env)
|
56
|
-
|
57
|
-
assert_equal({},
|
76
|
+
unpacker = Committee::RequestUnpacker.new(optimistic_json: true)
|
77
|
+
assert_equal([{}, false], unpacker.unpack_request_params(request))
|
58
78
|
end
|
59
79
|
end
|
60
80
|
|
@@ -64,8 +84,8 @@ describe Committee::RequestUnpacker do
|
|
64
84
|
"rack.input" => StringIO.new(""),
|
65
85
|
}
|
66
86
|
request = Rack::Request.new(env)
|
67
|
-
|
68
|
-
assert_equal({},
|
87
|
+
unpacker = Committee::RequestUnpacker.new
|
88
|
+
assert_equal([{}, false], unpacker.unpack_request_params(request))
|
69
89
|
end
|
70
90
|
|
71
91
|
it "doesn't unpack form params" do
|
@@ -75,8 +95,8 @@ describe Committee::RequestUnpacker do
|
|
75
95
|
"rack.input" => StringIO.new("x=y"),
|
76
96
|
}
|
77
97
|
request = Rack::Request.new(env)
|
78
|
-
|
79
|
-
assert_equal({},
|
98
|
+
unpacker = Committee::RequestUnpacker.new
|
99
|
+
assert_equal([{}, false], unpacker.unpack_request_params(request))
|
80
100
|
end
|
81
101
|
end
|
82
102
|
|
@@ -87,87 +107,8 @@ describe Committee::RequestUnpacker do
|
|
87
107
|
"rack.input" => StringIO.new("x=y"),
|
88
108
|
}
|
89
109
|
request = Rack::Request.new(env)
|
90
|
-
|
91
|
-
assert_equal({ "x" => "y" },
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
it "coerces form params with coerce_form_params and a schema" do
|
96
|
-
%w[application/x-www-form-urlencoded multipart/form-data].each do |content_type|
|
97
|
-
env = {
|
98
|
-
"CONTENT_TYPE" => content_type,
|
99
|
-
"rack.input" => StringIO.new("x=1"),
|
100
|
-
}
|
101
|
-
request = Rack::Request.new(env)
|
102
|
-
|
103
|
-
router = hyper_schema.build_router({})
|
104
|
-
validator = router.build_schema_validator(request)
|
105
|
-
|
106
|
-
schema = JsonSchema::Schema.new
|
107
|
-
schema.properties = { "x" => JsonSchema::Schema.new }
|
108
|
-
schema.properties["x"].type = ["integer"]
|
109
|
-
|
110
|
-
link_class = Struct.new(:schema)
|
111
|
-
link_object = link_class.new(schema)
|
112
|
-
|
113
|
-
validator.instance_variable_set(:@link, link_object)
|
114
|
-
|
115
|
-
params, _ = Committee::RequestUnpacker.new(
|
116
|
-
request,
|
117
|
-
allow_form_params: true,
|
118
|
-
coerce_form_params: true,
|
119
|
-
schema_validator: validator,
|
120
|
-
).call
|
121
|
-
assert_equal({ "x" => 1 }, params)
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
it "coerces form params with coerce_form_params and an OpenAPI3 schema" do
|
126
|
-
%w[application/x-www-form-urlencoded multipart/form-data].each do |content_type|
|
127
|
-
env = {
|
128
|
-
"CONTENT_TYPE" => content_type,
|
129
|
-
"rack.input" => StringIO.new("limit=20"),
|
130
|
-
"PATH_INFO" => "/characters",
|
131
|
-
"SCRIPT_NAME" => "",
|
132
|
-
"REQUEST_METHOD" => "GET",
|
133
|
-
}
|
134
|
-
request = Rack::Request.new(env)
|
135
|
-
|
136
|
-
router = open_api_3_schema.build_router({})
|
137
|
-
validator = router.build_schema_validator(request)
|
138
|
-
|
139
|
-
params, _ = Committee::RequestUnpacker.new(
|
140
|
-
request,
|
141
|
-
allow_form_params: true,
|
142
|
-
coerce_form_params: true,
|
143
|
-
schema_validator: validator,
|
144
|
-
).call
|
145
|
-
# openapi3 not support coerce in request unpacker
|
146
|
-
assert_equal({ "limit" => '20' }, params)
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
it "coerces error params with coerce_form_params and a OpenAPI3 schema" do
|
151
|
-
%w[application/x-www-form-urlencoded multipart/form-data].each do |content_type|
|
152
|
-
env = {
|
153
|
-
"CONTENT_TYPE" => content_type,
|
154
|
-
"rack.input" => StringIO.new("limit=twenty"),
|
155
|
-
"PATH_INFO" => "/characters",
|
156
|
-
"SCRIPT_NAME" => "",
|
157
|
-
"REQUEST_METHOD" => "GET",
|
158
|
-
}
|
159
|
-
request = Rack::Request.new(env)
|
160
|
-
|
161
|
-
router = open_api_3_schema.build_router({})
|
162
|
-
validator = router.build_schema_validator(request)
|
163
|
-
|
164
|
-
params, _ = Committee::RequestUnpacker.new(
|
165
|
-
request,
|
166
|
-
allow_form_params: true,
|
167
|
-
coerce_form_params: true,
|
168
|
-
schema_validator: validator,
|
169
|
-
).call
|
170
|
-
assert_equal({ "limit" => "twenty" }, params)
|
110
|
+
unpacker = Committee::RequestUnpacker.new(allow_form_params: true)
|
111
|
+
assert_equal([{ "x" => "y" }, true], unpacker.unpack_request_params(request))
|
171
112
|
end
|
172
113
|
end
|
173
114
|
|
@@ -179,8 +120,8 @@ describe Committee::RequestUnpacker do
|
|
179
120
|
"QUERY_STRING" => "a=b"
|
180
121
|
}
|
181
122
|
request = Rack::Request.new(env)
|
182
|
-
|
183
|
-
assert_equal({ "x" => "y",
|
123
|
+
unpacker = Committee::RequestUnpacker.new(allow_form_params: true, allow_query_params: true)
|
124
|
+
assert_equal([ { "x" => "y"}, true], unpacker.unpack_request_params(request))
|
184
125
|
end
|
185
126
|
end
|
186
127
|
|
@@ -190,8 +131,8 @@ describe Committee::RequestUnpacker do
|
|
190
131
|
"QUERY_STRING" => "a=b"
|
191
132
|
}
|
192
133
|
request = Rack::Request.new(env)
|
193
|
-
|
194
|
-
assert_equal({ "a" => "b" },
|
134
|
+
unpacker = Committee::RequestUnpacker.new(allow_query_params: true)
|
135
|
+
assert_equal({ "a" => "b" }, unpacker.unpack_query_params(request))
|
195
136
|
end
|
196
137
|
|
197
138
|
it "errors if JSON is not an object" do
|
@@ -201,7 +142,7 @@ describe Committee::RequestUnpacker do
|
|
201
142
|
}
|
202
143
|
request = Rack::Request.new(env)
|
203
144
|
assert_raises(Committee::BadRequest) do
|
204
|
-
Committee::RequestUnpacker.new(request)
|
145
|
+
Committee::RequestUnpacker.new.unpack_request_params(request)
|
205
146
|
end
|
206
147
|
end
|
207
148
|
|
@@ -211,8 +152,8 @@ describe Committee::RequestUnpacker do
|
|
211
152
|
"rack.input" => StringIO.new('{"x":"y"}'),
|
212
153
|
}
|
213
154
|
request = Rack::Request.new(env)
|
214
|
-
|
215
|
-
assert_equal({},
|
155
|
+
unpacker = Committee::RequestUnpacker.new
|
156
|
+
assert_equal([{}, false], unpacker.unpack_request_params(request))
|
216
157
|
end
|
217
158
|
|
218
159
|
# this is mostly here for line coverage
|
@@ -221,8 +162,8 @@ describe Committee::RequestUnpacker do
|
|
221
162
|
"rack.input" => StringIO.new('{"x":[]}'),
|
222
163
|
}
|
223
164
|
request = Rack::Request.new(env)
|
224
|
-
|
225
|
-
assert_equal({ "x" => [] },
|
165
|
+
unpacker = Committee::RequestUnpacker.new
|
166
|
+
assert_equal([{ "x" => [] }, false], unpacker.unpack_request_params(request))
|
226
167
|
end
|
227
168
|
|
228
169
|
it "unpacks http header" do
|
@@ -231,8 +172,8 @@ describe Committee::RequestUnpacker do
|
|
231
172
|
"rack.input" => StringIO.new(""),
|
232
173
|
}
|
233
174
|
request = Rack::Request.new(env)
|
234
|
-
|
235
|
-
assert_equal({ "FOO-BAR" => "some header value" },
|
175
|
+
unpacker = Committee::RequestUnpacker.new({ allow_header_params: true })
|
176
|
+
assert_equal({ "FOO-BAR" => "some header value" }, unpacker.unpack_headers(request))
|
236
177
|
end
|
237
178
|
|
238
179
|
it "includes request body when`use_get_body` is true" do
|
@@ -242,8 +183,8 @@ describe Committee::RequestUnpacker do
|
|
242
183
|
"QUERY_STRING"=>"data=value&x=aaa",
|
243
184
|
}
|
244
185
|
request = Rack::Request.new(env)
|
245
|
-
|
246
|
-
assert_equal({ '
|
186
|
+
unpacker = Committee::RequestUnpacker.new({ allow_query_params: true, allow_get_body: true })
|
187
|
+
assert_equal([{ 'x' => 1, 'y' => 2 }, false], unpacker.unpack_request_params(request))
|
247
188
|
end
|
248
189
|
|
249
190
|
it "doesn't include request body when `use_get_body` is false" do
|
@@ -253,7 +194,7 @@ describe Committee::RequestUnpacker do
|
|
253
194
|
"QUERY_STRING"=>"data=value&x=aaa",
|
254
195
|
}
|
255
196
|
request = Rack::Request.new(env)
|
256
|
-
|
257
|
-
assert_equal({ 'data' => 'value', 'x' => 'aaa' },
|
197
|
+
unpacker = Committee::RequestUnpacker.new({ allow_query_params: true, use_get_body: false })
|
198
|
+
assert_equal({ 'data' => 'value', 'x' => 'aaa' }, unpacker.unpack_query_params(request))
|
258
199
|
end
|
259
200
|
end
|
@@ -38,6 +38,11 @@ describe Committee::SchemaValidator::HyperSchema::ResponseValidator do
|
|
38
38
|
call
|
39
39
|
end
|
40
40
|
|
41
|
+
it "passes through a 304 Not Modified response" do
|
42
|
+
@status, @headers, @data = 304, {}, nil
|
43
|
+
call
|
44
|
+
end
|
45
|
+
|
41
46
|
it "passes through a valid list response for for rel instances links" do
|
42
47
|
@link = @list_link
|
43
48
|
|
@@ -91,6 +96,11 @@ describe Committee::SchemaValidator::HyperSchema::ResponseValidator do
|
|
91
96
|
call
|
92
97
|
end
|
93
98
|
|
99
|
+
it "allows no Content-Type for 304 Not Modified" do
|
100
|
+
@status, @headers = 304, {}
|
101
|
+
call
|
102
|
+
end
|
103
|
+
|
94
104
|
it "raises errors generated by json_schema" do
|
95
105
|
@data.merge!("name" => "%@!")
|
96
106
|
e = assert_raises(Committee::InvalidResponse) { call }
|
@@ -69,6 +69,8 @@ describe Committee::SchemaValidator::HyperSchema::Router do
|
|
69
69
|
end
|
70
70
|
|
71
71
|
def hyper_schema_router(options = {})
|
72
|
+
# TODO: delete when 5.0.0 released because default value changed
|
73
|
+
options[:parse_response_by_content_type] = true if options[:parse_response_by_content_type] == nil
|
72
74
|
schema = Committee::Drivers::HyperSchema::Driver.new.parse(hyper_schema_data)
|
73
75
|
validator_option = Committee::SchemaValidator::Option.new(options, schema, :hyper_schema)
|
74
76
|
|
@@ -76,6 +78,8 @@ describe Committee::SchemaValidator::HyperSchema::Router do
|
|
76
78
|
end
|
77
79
|
|
78
80
|
def open_api_2_router(options = {})
|
81
|
+
# TODO: delete when 5.0.0 released because default value changed
|
82
|
+
options[:parse_response_by_content_type] = true if options[:parse_response_by_content_type] == nil
|
79
83
|
schema = Committee::Drivers::OpenAPI2::Driver.new.parse(open_api_2_data)
|
80
84
|
validator_option = Committee::SchemaValidator::Option.new(options, schema, :hyper_schema)
|
81
85
|
|
@@ -11,7 +11,7 @@ describe Committee::SchemaValidator::HyperSchema::StringParamsCoercer do
|
|
11
11
|
end
|
12
12
|
|
13
13
|
it "doesn't coerce params not in the schema" do
|
14
|
-
check_convert("
|
14
|
+
check_convert("owner", "admin", "admin")
|
15
15
|
end
|
16
16
|
|
17
17
|
it "skips values for string param" do
|
@@ -9,7 +9,12 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
|
|
9
9
|
before do
|
10
10
|
@path = '/validate'
|
11
11
|
@method = 'post'
|
12
|
-
|
12
|
+
|
13
|
+
# TODO: delete when 5.0.0 released because default value changed
|
14
|
+
options = {}
|
15
|
+
options[:parse_response_by_content_type] = true if options[:parse_response_by_content_type] == nil
|
16
|
+
|
17
|
+
@validator_option = Committee::SchemaValidator::Option.new(options, open_api_3_schema, :open_api_3)
|
13
18
|
end
|
14
19
|
|
15
20
|
def operation_object
|
@@ -27,12 +32,15 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
|
|
27
32
|
]
|
28
33
|
|
29
34
|
it 'correct data' do
|
30
|
-
operation_object.validate_request_params(SCHEMA_PROPERTIES_PAIR.to_h, HEADER, @validator_option)
|
35
|
+
operation_object.validate_request_params({}, {}, SCHEMA_PROPERTIES_PAIR.to_h, HEADER, @validator_option)
|
31
36
|
assert true
|
32
37
|
end
|
33
38
|
|
34
39
|
it 'correct object data' do
|
35
|
-
operation_object.validate_request_params(
|
40
|
+
operation_object.validate_request_params(
|
41
|
+
{},
|
42
|
+
{},
|
43
|
+
{
|
36
44
|
"object_1" =>
|
37
45
|
{
|
38
46
|
"string_1" => nil,
|
@@ -49,38 +57,39 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
|
|
49
57
|
|
50
58
|
it 'invalid params' do
|
51
59
|
e = assert_raises(Committee::InvalidRequest) {
|
52
|
-
operation_object.validate_request_params({"string" => 1}, HEADER, @validator_option)
|
60
|
+
operation_object.validate_request_params({}, {}, {"string" => 1}, HEADER, @validator_option)
|
53
61
|
}
|
54
62
|
|
55
|
-
|
56
|
-
|
63
|
+
assert_match(/expected string, but received Integer: 1/i, e.message)
|
64
|
+
assert_kind_of(OpenAPIParser::OpenAPIError, e.original_error)
|
57
65
|
end
|
58
66
|
|
59
67
|
it 'support put method' do
|
60
68
|
@method = "put"
|
61
|
-
operation_object.validate_request_params({"string" => "str"}, HEADER, @validator_option)
|
69
|
+
operation_object.validate_request_params({}, {}, {"string" => "str"}, HEADER, @validator_option)
|
62
70
|
|
63
71
|
e = assert_raises(Committee::InvalidRequest) {
|
64
|
-
operation_object.validate_request_params({"string" => 1}, HEADER, @validator_option)
|
72
|
+
operation_object.validate_request_params({}, {}, {"string" => 1}, HEADER, @validator_option)
|
65
73
|
}
|
66
74
|
|
67
|
-
|
68
|
-
|
75
|
+
assert_match(/expected string, but received Integer: 1/i, e.message)
|
76
|
+
assert_kind_of(OpenAPIParser::OpenAPIError, e.original_error)
|
69
77
|
end
|
70
78
|
|
71
79
|
it 'support patch method' do
|
72
80
|
@method = "patch"
|
73
|
-
operation_object.validate_request_params({"integer" => 1}, HEADER, @validator_option)
|
81
|
+
operation_object.validate_request_params({}, {}, {"integer" => 1}, HEADER, @validator_option)
|
74
82
|
|
75
83
|
e = assert_raises(Committee::InvalidRequest) {
|
76
|
-
operation_object.validate_request_params({"integer" => "str"}, HEADER, @validator_option)
|
84
|
+
operation_object.validate_request_params({}, {}, {"integer" => "str"}, HEADER, @validator_option)
|
77
85
|
}
|
78
86
|
|
79
|
-
assert_match(/expected integer, but received String: str/i, e.message)
|
87
|
+
assert_match(/expected integer, but received String: "str"/i, e.message)
|
88
|
+
assert_kind_of(OpenAPIParser::OpenAPIError, e.original_error)
|
80
89
|
end
|
81
90
|
|
82
91
|
it 'unknown param' do
|
83
|
-
operation_object.validate_request_params({"unknown" => 1}, HEADER, @validator_option)
|
92
|
+
operation_object.validate_request_params({}, {}, {"unknown" => 1}, HEADER, @validator_option)
|
84
93
|
end
|
85
94
|
|
86
95
|
describe 'support get method' do
|
@@ -90,13 +99,17 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
|
|
90
99
|
|
91
100
|
it 'correct' do
|
92
101
|
operation_object.validate_request_params(
|
102
|
+
{},
|
93
103
|
{"query_string" => "query", "query_integer_list" => [1, 2]},
|
104
|
+
{},
|
94
105
|
HEADER,
|
95
106
|
@validator_option
|
96
107
|
)
|
97
108
|
|
98
109
|
operation_object.validate_request_params(
|
110
|
+
{},
|
99
111
|
{"query_string" => "query", "query_integer_list" => [1, 2], "optional_integer" => 1},
|
112
|
+
{},
|
100
113
|
HEADER,
|
101
114
|
@validator_option
|
102
115
|
)
|
@@ -106,23 +119,26 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
|
|
106
119
|
|
107
120
|
it 'not exist required' do
|
108
121
|
e = assert_raises(Committee::InvalidRequest) {
|
109
|
-
operation_object.validate_request_params({"query_integer_list" => [1, 2]}, HEADER, @validator_option)
|
122
|
+
operation_object.validate_request_params({}, {"query_integer_list" => [1, 2]}, {}, HEADER, @validator_option)
|
110
123
|
}
|
111
124
|
|
112
125
|
assert_match(/missing required parameters: query_string/i, e.message)
|
126
|
+
assert_kind_of(OpenAPIParser::OpenAPIError, e.original_error)
|
113
127
|
end
|
114
128
|
|
115
129
|
it 'invalid type' do
|
116
130
|
e = assert_raises(Committee::InvalidRequest) {
|
117
131
|
operation_object.validate_request_params(
|
132
|
+
{},
|
118
133
|
{"query_string" => 1, "query_integer_list" => [1, 2], "optional_integer" => 1},
|
134
|
+
{},
|
119
135
|
HEADER,
|
120
136
|
@validator_option
|
121
137
|
)
|
122
138
|
}
|
123
139
|
|
124
|
-
|
125
|
-
|
140
|
+
assert_match(/expected string, but received Integer: 1/i, e.message)
|
141
|
+
assert_kind_of(OpenAPIParser::OpenAPIError, e.original_error)
|
126
142
|
end
|
127
143
|
end
|
128
144
|
|
@@ -133,20 +149,56 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
|
|
133
149
|
end
|
134
150
|
|
135
151
|
it 'correct' do
|
136
|
-
operation_object.validate_request_params({"limit" => "1"}, HEADER, @validator_option)
|
152
|
+
operation_object.validate_request_params({}, {"limit" => "1"}, {}, HEADER, @validator_option)
|
137
153
|
|
138
154
|
assert true
|
139
155
|
end
|
140
156
|
|
141
157
|
it 'invalid type' do
|
142
158
|
e = assert_raises(Committee::InvalidRequest) {
|
143
|
-
operation_object.validate_request_params({"limit" => "a"}, HEADER, @validator_option)
|
159
|
+
operation_object.validate_request_params({}, {"limit" => "a"}, {}, HEADER, @validator_option)
|
144
160
|
}
|
145
161
|
|
146
|
-
assert_match(/expected integer, but received String: a/i, e.message)
|
162
|
+
assert_match(/expected integer, but received String: "a"/i, e.message)
|
163
|
+
assert_kind_of(OpenAPIParser::OpenAPIError, e.original_error)
|
147
164
|
end
|
148
165
|
end
|
149
166
|
|
167
|
+
describe 'support head method' do
|
168
|
+
before do
|
169
|
+
@path = '/characters'
|
170
|
+
@method = 'head'
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'correct' do
|
174
|
+
operation_object.validate_request_params({}, {"limit" => "1"}, {}, HEADER, @validator_option)
|
175
|
+
|
176
|
+
assert true
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'invalid type' do
|
180
|
+
e = assert_raises(Committee::InvalidRequest) {
|
181
|
+
operation_object.validate_request_params({}, {"limit" => "a"}, {}, HEADER, @validator_option)
|
182
|
+
}
|
183
|
+
|
184
|
+
assert_match(/expected integer, but received String: "a"/i, e.message)
|
185
|
+
assert_kind_of(OpenAPIParser::OpenAPIError, e.original_error)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
it 'support options method' do
|
190
|
+
@method = "options"
|
191
|
+
operation_object.validate_request_params({}, {}, {"integer" => 1}, HEADER, @validator_option)
|
192
|
+
|
193
|
+
e = assert_raises(Committee::InvalidRequest) {
|
194
|
+
operation_object.validate_request_params({}, {}, {"integer" => "str"}, HEADER, @validator_option)
|
195
|
+
}
|
196
|
+
|
197
|
+
assert_match(/expected integer, but received String: "str"/i, e.message)
|
198
|
+
assert_kind_of(OpenAPIParser::OpenAPIError, e.original_error)
|
199
|
+
end
|
200
|
+
|
201
|
+
|
150
202
|
describe '#content_types' do
|
151
203
|
it 'returns supported content types' do
|
152
204
|
@path = '/validate_content_types'
|
@@ -71,7 +71,34 @@ describe Committee::SchemaValidator::OpenAPI3::RequestValidator do
|
|
71
71
|
assert_equal 200, last_response.status
|
72
72
|
end
|
73
73
|
|
74
|
+
it "skips content_type check with an empty body" do
|
75
|
+
@app = new_rack_app(check_content_type: true, schema: open_api_3_schema)
|
76
|
+
header "Content-Type", "application/x-www-form-urlencoded"
|
77
|
+
patch "/validate_empty_optional_body"
|
78
|
+
assert_equal 200, last_response.status
|
79
|
+
end
|
80
|
+
|
81
|
+
it "does not mix up parameters and requestBody" do
|
82
|
+
@app = new_rack_app(check_content_type: true, schema: open_api_3_schema)
|
83
|
+
params = {
|
84
|
+
"last_name" => "Skywalker"
|
85
|
+
}
|
86
|
+
header "Content-Type", "application/json"
|
87
|
+
post "/additional_properties?first_name=Luke", JSON.generate(params)
|
88
|
+
assert_equal 200, last_response.status
|
89
|
+
end
|
90
|
+
|
91
|
+
it "error because content_type check with body" do
|
92
|
+
@app = new_rack_app(check_content_type: true, schema: open_api_3_schema)
|
93
|
+
header "Content-Type", "application/x-www-form-urlencoded"
|
94
|
+
patch "/validate_empty_optional_body", "{}"
|
95
|
+
assert_equal 400, last_response.status
|
96
|
+
end
|
97
|
+
|
74
98
|
def new_rack_app(options = {})
|
99
|
+
# TODO: delete when 5.0.0 released because default value changed
|
100
|
+
options[:parse_response_by_content_type] = true if options[:parse_response_by_content_type] == nil
|
101
|
+
|
75
102
|
Rack::Builder.new {
|
76
103
|
use Committee::Middleware::RequestValidation, options
|
77
104
|
run lambda { |_|
|
@@ -12,7 +12,12 @@ describe Committee::SchemaValidator::OpenAPI3::ResponseValidator do
|
|
12
12
|
|
13
13
|
@path = '/validate'
|
14
14
|
@method = 'post'
|
15
|
-
|
15
|
+
|
16
|
+
# TODO: delete when 5.0.0 released because default value changed
|
17
|
+
options = {}
|
18
|
+
options[:parse_response_by_content_type] = true if options[:parse_response_by_content_type] == nil
|
19
|
+
|
20
|
+
@validator_option = Committee::SchemaValidator::Option.new(options, open_api_3_schema, :open_api_3)
|
16
21
|
end
|
17
22
|
|
18
23
|
it "passes through a valid response" do
|
@@ -29,11 +34,21 @@ describe Committee::SchemaValidator::OpenAPI3::ResponseValidator do
|
|
29
34
|
call_response_validator
|
30
35
|
end
|
31
36
|
|
32
|
-
it "
|
37
|
+
it "raises InvalidResponse when a valid response with no registered body with strict option" do
|
33
38
|
@headers = { "Content-Type" => "application/xml" }
|
34
|
-
assert_raises(Committee::InvalidResponse) {
|
39
|
+
e = assert_raises(Committee::InvalidResponse) {
|
35
40
|
call_response_validator(true)
|
36
41
|
}
|
42
|
+
assert_kind_of(OpenAPIParser::OpenAPIError, e.original_error)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "raises InvalidResponse when a invalid status code with strict option" do
|
46
|
+
@status = 201
|
47
|
+
e = assert_raises(Committee::InvalidResponse) {
|
48
|
+
call_response_validator(true)
|
49
|
+
}
|
50
|
+
|
51
|
+
assert_kind_of(OpenAPIParser::OpenAPIError, e.original_error)
|
37
52
|
end
|
38
53
|
|
39
54
|
it "passes through a valid response with no Content-Type" do
|
@@ -41,11 +56,12 @@ describe Committee::SchemaValidator::OpenAPI3::ResponseValidator do
|
|
41
56
|
call_response_validator
|
42
57
|
end
|
43
58
|
|
44
|
-
it "
|
59
|
+
it "raises InvalidResponse when a valid response with no Content-Type headers with strict option" do
|
45
60
|
@headers = {}
|
46
|
-
assert_raises(Committee::InvalidResponse) {
|
61
|
+
e = assert_raises(Committee::InvalidResponse) {
|
47
62
|
call_response_validator(true)
|
48
63
|
}
|
64
|
+
assert_kind_of(OpenAPIParser::OpenAPIError, e.original_error)
|
49
65
|
end
|
50
66
|
|
51
67
|
it "passes through a valid list response" do
|
@@ -60,6 +76,11 @@ describe Committee::SchemaValidator::OpenAPI3::ResponseValidator do
|
|
60
76
|
call_response_validator
|
61
77
|
end
|
62
78
|
|
79
|
+
it "passes through a 304 Not Modified response" do
|
80
|
+
@status, @headers, @data = 304, {}, nil
|
81
|
+
call_response_validator
|
82
|
+
end
|
83
|
+
|
63
84
|
private
|
64
85
|
|
65
86
|
def call_response_validator(strict = false)
|
@@ -30,13 +30,16 @@ describe Committee::Test::Methods do
|
|
30
30
|
@committee_schema = nil
|
31
31
|
|
32
32
|
@committee_options = {schema: hyper_schema}
|
33
|
+
|
34
|
+
# TODO: delete when 5.0.0 released because default value changed
|
35
|
+
@committee_options[:parse_response_by_content_type] = false
|
33
36
|
end
|
34
37
|
|
35
38
|
describe "#assert_schema_conform" do
|
36
39
|
it "passes through a valid response" do
|
37
40
|
@app = new_rack_app(JSON.generate([ValidApp]))
|
38
41
|
get "/apps"
|
39
|
-
assert_schema_conform
|
42
|
+
assert_schema_conform(200)
|
40
43
|
end
|
41
44
|
|
42
45
|
it "passes with prefix" do
|
@@ -44,30 +47,39 @@ describe Committee::Test::Methods do
|
|
44
47
|
|
45
48
|
@app = new_rack_app(JSON.generate([ValidApp]))
|
46
49
|
get "/v1/apps"
|
47
|
-
assert_schema_conform
|
50
|
+
assert_schema_conform(200)
|
48
51
|
end
|
49
52
|
|
50
53
|
it "detects an invalid response Content-Type" do
|
51
54
|
@app = new_rack_app(JSON.generate([ValidApp]), 200, {})
|
52
55
|
get "/apps"
|
53
56
|
e = assert_raises(Committee::InvalidResponse) do
|
54
|
-
assert_schema_conform
|
57
|
+
assert_schema_conform(200)
|
55
58
|
end
|
56
59
|
assert_match(/response header must be set to/i, e.message)
|
57
60
|
end
|
58
61
|
|
62
|
+
it "it detects unexpected response code" do
|
63
|
+
@app = new_rack_app(JSON.generate([ValidApp]), 400)
|
64
|
+
get "/apps"
|
65
|
+
e = assert_raises(Committee::InvalidResponse) do
|
66
|
+
assert_schema_conform(200)
|
67
|
+
end
|
68
|
+
assert_match(/Expected `200` status code, but it was `400`/i, e.message)
|
69
|
+
end
|
70
|
+
|
59
71
|
it "detects an invalid response Content-Type but ignore because it's not success status code" do
|
60
72
|
@committee_options.merge!(validate_success_only: true)
|
61
73
|
@app = new_rack_app(JSON.generate([ValidApp]), 400, {})
|
62
74
|
get "/apps"
|
63
|
-
assert_schema_conform
|
75
|
+
assert_schema_conform(400)
|
64
76
|
end
|
65
77
|
|
66
78
|
it "detects an invalid response Content-Type and check all status code" do
|
67
79
|
@app = new_rack_app(JSON.generate([ValidApp]), 400, {})
|
68
80
|
get "/apps"
|
69
81
|
e = assert_raises(Committee::InvalidResponse) do
|
70
|
-
assert_schema_conform
|
82
|
+
assert_schema_conform(400)
|
71
83
|
end
|
72
84
|
assert_match(/response header must be set to/i, e.message)
|
73
85
|
end
|