committee 5.6.1 → 5.6.3

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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/lib/committee/drivers/open_api_3/driver.rb +7 -1
  3. data/lib/committee/drivers.rb +2 -3
  4. data/lib/committee/errors.rb +11 -0
  5. data/lib/committee/middleware/base.rb +11 -5
  6. data/lib/committee/middleware/options/base.rb +107 -0
  7. data/lib/committee/middleware/options/request_validation.rb +80 -0
  8. data/lib/committee/middleware/options/response_validation.rb +46 -0
  9. data/lib/committee/middleware/options.rb +12 -0
  10. data/lib/committee/middleware/request_validation.rb +7 -1
  11. data/lib/committee/middleware/response_validation.rb +6 -2
  12. data/lib/committee/middleware.rb +1 -0
  13. data/lib/committee/schema_validator/hyper_schema/response_generator.rb +1 -3
  14. data/lib/committee/schema_validator/hyper_schema/response_validator.rb +14 -1
  15. data/lib/committee/schema_validator/hyper_schema/router.rb +1 -1
  16. data/lib/committee/schema_validator/hyper_schema.rb +3 -14
  17. data/lib/committee/schema_validator/open_api_3/operation_wrapper.rb +43 -13
  18. data/lib/committee/schema_validator/open_api_3/parameter_deserializer.rb +556 -0
  19. data/lib/committee/schema_validator/open_api_3/response_validator.rb +16 -2
  20. data/lib/committee/schema_validator/open_api_3.rb +19 -13
  21. data/lib/committee/schema_validator/option.rb +6 -17
  22. data/lib/committee/schema_validator.rb +12 -1
  23. data/lib/committee/test/except_parameter.rb +416 -0
  24. data/lib/committee/test/methods.rb +38 -2
  25. data/lib/committee/version.rb +1 -1
  26. data/lib/committee.rb +1 -1
  27. data/test/drivers/open_api_2/driver_test.rb +4 -16
  28. data/test/drivers/open_api_2/parameter_schema_builder_test.rb +4 -50
  29. data/test/drivers_test.rb +35 -21
  30. data/test/middleware/options/base_test.rb +120 -0
  31. data/test/middleware/options/request_validation_test.rb +177 -0
  32. data/test/middleware/options/response_validation_test.rb +121 -0
  33. data/test/middleware/request_validation_open_api_3_test.rb +200 -80
  34. data/test/middleware/request_validation_test.rb +13 -70
  35. data/test/middleware/response_validation_open_api_3_test.rb +40 -17
  36. data/test/middleware/response_validation_test.rb +3 -14
  37. data/test/request_unpacker_test.rb +2 -10
  38. data/test/schema_validator/hyper_schema/parameter_coercer_test.rb +1 -37
  39. data/test/schema_validator/hyper_schema/request_validator_test.rb +6 -30
  40. data/test/schema_validator/hyper_schema/router_test.rb +5 -0
  41. data/test/schema_validator/hyper_schema/string_params_coercer_test.rb +1 -37
  42. data/test/schema_validator/open_api_3/operation_wrapper_test.rb +58 -43
  43. data/test/schema_validator/open_api_3/parameter_deserializer_test.rb +457 -0
  44. data/test/schema_validator/open_api_3/request_validator_test.rb +1 -2
  45. data/test/schema_validator/open_api_3/response_validator_test.rb +3 -11
  46. data/test/schema_validator_test.rb +41 -0
  47. data/test/test/methods_test.rb +238 -105
  48. data/test/test/schema_coverage_test.rb +8 -155
  49. metadata +11 -1
@@ -11,11 +11,7 @@ describe Committee::SchemaValidator::HyperSchema::RequestValidator do
11
11
  @schema.expand_references!
12
12
  # POST /apps/:id
13
13
  @link = @schema.properties["app"].links[0]
14
- @request = Rack::Request.new({
15
- "CONTENT_TYPE" => "application/json",
16
- "rack.input" => StringIO.new("{}"),
17
- "REQUEST_METHOD" => "POST"
18
- })
14
+ @request = Rack::Request.new({ "CONTENT_TYPE" => "application/json", "rack.input" => StringIO.new("{}"), "REQUEST_METHOD" => "POST" })
19
15
  end
20
16
 
21
17
  it "passes through a valid request with Content-Type options" do
@@ -29,22 +25,14 @@ describe Committee::SchemaValidator::HyperSchema::RequestValidator do
29
25
  end
30
26
 
31
27
  it "passes through a valid request with Content-Type options" do
32
- @request =
33
- Rack::Request.new({
34
- "CONTENT_TYPE" => "application/json; charset=utf-8",
35
- "rack.input" => StringIO.new("{}"),
36
- })
28
+ @request = Rack::Request.new({ "CONTENT_TYPE" => "application/json; charset=utf-8", "rack.input" => StringIO.new("{}"), })
37
29
  data = { "name" => "heroku-api", }
38
30
  call(data)
39
31
  end
40
32
 
41
33
  it "detects an invalid request Content-Type" do
42
34
  e = assert_raises(Committee::InvalidRequest) {
43
- @request =
44
- Rack::Request.new({
45
- "CONTENT_TYPE" => "application/x-www-form-urlencoded",
46
- "rack.input" => StringIO.new("{}"),
47
- })
35
+ @request = Rack::Request.new({ "CONTENT_TYPE" => "application/x-www-form-urlencoded", "rack.input" => StringIO.new("{}"), })
48
36
  call({})
49
37
  }
50
38
  message = %{"Content-Type" request header must be set to "application/json".}
@@ -52,11 +40,7 @@ describe Committee::SchemaValidator::HyperSchema::RequestValidator do
52
40
  end
53
41
 
54
42
  it "allows skipping content_type check" do
55
- @request =
56
- Rack::Request.new({
57
- "CONTENT_TYPE" => "application/x-www-form-urlencoded",
58
- "rack.input" => StringIO.new("{}"),
59
- })
43
+ @request = Rack::Request.new({ "CONTENT_TYPE" => "application/x-www-form-urlencoded", "rack.input" => StringIO.new("{}"), })
60
44
  call({}, {}, check_content_type: false)
61
45
  end
62
46
 
@@ -73,11 +57,7 @@ describe Committee::SchemaValidator::HyperSchema::RequestValidator do
73
57
  end
74
58
 
75
59
  it "allows an invalid Content-Type with an empty body" do
76
- @request =
77
- Rack::Request.new({
78
- "CONTENT_TYPE" => "application/x-www-form-urlencoded",
79
- "rack.input" => StringIO.new(""),
80
- })
60
+ @request = Rack::Request.new({ "CONTENT_TYPE" => "application/x-www-form-urlencoded", "rack.input" => StringIO.new(""), })
81
61
  call({})
82
62
  end
83
63
 
@@ -103,11 +83,7 @@ describe Committee::SchemaValidator::HyperSchema::RequestValidator do
103
83
  before do
104
84
  @schema = open_api_2_schema
105
85
  @link = @schema.routes['GET'][0][1]
106
- @request = Rack::Request.new({
107
- "CONTENT_TYPE" => "application/json",
108
- "rack.input" => StringIO.new("{}"),
109
- "REQUEST_METHOD" => "POST"
110
- })
86
+ @request = Rack::Request.new({ "CONTENT_TYPE" => "application/json", "rack.input" => StringIO.new("{}"), "REQUEST_METHOD" => "POST" })
111
87
  end
112
88
 
113
89
  it "passes through a valid request" do
@@ -43,6 +43,11 @@ describe Committee::SchemaValidator::HyperSchema::Router do
43
43
  refute_nil link
44
44
  end
45
45
 
46
+ it "does not include a similar prefix path segment" do
47
+ link, _ = hyper_schema_router(prefix: "/kpi").includes?("/kpi2/apps")
48
+ assert_nil link
49
+ end
50
+
46
51
  it "provides named parameters" do
47
52
  link, param_matches = open_api_2_router.find_link("GET", "/api/pets/fido")
48
53
  refute_nil link
@@ -53,43 +53,7 @@ describe Committee::SchemaValidator::HyperSchema::StringParamsCoercer do
53
53
  end
54
54
 
55
55
  it "pass array property" do
56
- params = {
57
- "array_property" => [
58
- {
59
- "update_time" => "2016-04-01T16:00:00.000+09:00",
60
- "per_page" => "1",
61
- "nested_coercer_object" => {
62
- "update_time" => "2016-04-01T16:00:00.000+09:00",
63
- "threshold" => "1.5"
64
- },
65
- "nested_no_coercer_object" => {
66
- "per_page" => "1",
67
- "threshold" => "1.5"
68
- },
69
- "nested_coercer_array" => [
70
- {
71
- "update_time" => "2016-04-01T16:00:00.000+09:00",
72
- "threshold" => "1.5"
73
- }
74
- ],
75
- "nested_no_coercer_array" => [
76
- {
77
- "per_page" => "1",
78
- "threshold" => "1.5"
79
- }
80
- ]
81
- },
82
- {
83
- "update_time" => "2016-04-01T16:00:00.000+09:00",
84
- "per_page" => "1",
85
- "threshold" => "1.5"
86
- },
87
- {
88
- "threshold" => "1.5",
89
- "per_page" => "1"
90
- }
91
- ],
92
- }
56
+ params = { "array_property" => [{ "update_time" => "2016-04-01T16:00:00.000+09:00", "per_page" => "1", "nested_coercer_object" => { "update_time" => "2016-04-01T16:00:00.000+09:00", "threshold" => "1.5" }, "nested_no_coercer_object" => { "per_page" => "1", "threshold" => "1.5" }, "nested_coercer_array" => [{ "update_time" => "2016-04-01T16:00:00.000+09:00", "threshold" => "1.5" }], "nested_no_coercer_array" => [{ "per_page" => "1", "threshold" => "1.5" }] }, { "update_time" => "2016-04-01T16:00:00.000+09:00", "per_page" => "1", "threshold" => "1.5" }, { "threshold" => "1.5", "per_page" => "1" }], }
93
57
  call(params, coerce_recursive: true)
94
58
 
95
59
  first_data = params["array_property"][0]
@@ -18,13 +18,7 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
18
18
 
19
19
  HEADER = { 'Content-Type' => 'application/json' }
20
20
 
21
- SCHEMA_PROPERTIES_PAIR = [
22
- ['string', 'str'],
23
- ['integer', 1],
24
- ['boolean', true],
25
- ['boolean', false],
26
- ['number', 0.1],
27
- ]
21
+ SCHEMA_PROPERTIES_PAIR = [['string', 'str'], ['integer', 1], ['boolean', true], ['boolean', false], ['number', 0.1],]
28
22
 
29
23
  it 'correct data' do
30
24
  operation_object.validate_request_params({}, {}, SCHEMA_PROPERTIES_PAIR.to_h, HEADER, @validator_option)
@@ -32,20 +26,7 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
32
26
  end
33
27
 
34
28
  it 'correct object data' do
35
- operation_object.validate_request_params(
36
- {},
37
- {},
38
- {
39
- "object_1" =>
40
- {
41
- "string_1" => nil,
42
- "integer_1" => nil,
43
- "boolean_1" => nil,
44
- "number_1" => nil
45
- }
46
- },
47
- HEADER,
48
- @validator_option)
29
+ operation_object.validate_request_params({}, {}, { "object_1" => { "string_1" => nil, "integer_1" => nil, "boolean_1" => nil, "number_1" => nil } }, HEADER, @validator_option)
49
30
 
50
31
  assert true
51
32
  end
@@ -93,21 +74,9 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
93
74
  end
94
75
 
95
76
  it 'correct' do
96
- operation_object.validate_request_params(
97
- {},
98
- { "query_string" => "query", "query_integer_list" => [1, 2] },
99
- {},
100
- HEADER,
101
- @validator_option
102
- )
103
-
104
- operation_object.validate_request_params(
105
- {},
106
- { "query_string" => "query", "query_integer_list" => [1, 2], "optional_integer" => 1 },
107
- {},
108
- HEADER,
109
- @validator_option
110
- )
77
+ operation_object.validate_request_params({}, { "query_string" => "query", "query_integer_list" => [1, 2] }, {}, HEADER, @validator_option)
78
+
79
+ operation_object.validate_request_params({}, { "query_string" => "query", "query_integer_list" => [1, 2], "optional_integer" => 1 }, {}, HEADER, @validator_option)
111
80
 
112
81
  assert true
113
82
  end
@@ -123,13 +92,7 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
123
92
 
124
93
  it 'invalid type' do
125
94
  e = assert_raises(Committee::InvalidRequest) {
126
- operation_object.validate_request_params(
127
- {},
128
- { "query_string" => 1, "query_integer_list" => [1, 2], "optional_integer" => 1 },
129
- {},
130
- HEADER,
131
- @validator_option
132
- )
95
+ operation_object.validate_request_params({}, { "query_string" => 1, "query_integer_list" => [1, 2], "optional_integer" => 1 }, {}, HEADER, @validator_option)
133
96
  }
134
97
 
135
98
  assert_match(/expected string, but received Integer: 1/i, e.message)
@@ -208,5 +171,57 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
208
171
  assert_equal [], operation_object.request_content_types
209
172
  end
210
173
  end
174
+
175
+ describe 'coercion option wiring' do
176
+ before do
177
+ @path = '/coerce_path_params/1'
178
+ @method = 'get'
179
+ end
180
+
181
+ it 'uses coerce_path_params for explicit path coercion' do
182
+ disabled = Committee::SchemaValidator::Option.new({ coerce_path_params: false, coerce_query_params: true }, open_api_3_schema, :open_api_3)
183
+ enabled = Committee::SchemaValidator::Option.new({ coerce_path_params: true, coerce_query_params: false }, open_api_3_schema, :open_api_3)
184
+
185
+ error = assert_raises(Committee::InvalidRequest) do
186
+ operation_object.coerce_path_parameter(disabled)
187
+ end
188
+ assert_match(/expected integer, but received String: "1"/i, error.message)
189
+
190
+ coerced = operation_object.coerce_path_parameter(enabled)
191
+ assert_kind_of(Integer, coerced['integer'])
192
+ end
193
+
194
+ it 'uses coerce_query_params for request parameter validation' do
195
+ query_coercion_disabled = Committee::SchemaValidator::Option.new({ coerce_query_params: false }, open_api_3_schema, :open_api_3)
196
+ query_coercion_enabled = Committee::SchemaValidator::Option.new({ coerce_query_params: true }, open_api_3_schema, :open_api_3)
197
+
198
+ error = assert_raises(Committee::InvalidRequest) do
199
+ @path = '/characters'
200
+ operation_object.validate_request_params({}, { "limit" => "1" }, {}, HEADER, query_coercion_disabled)
201
+ end
202
+ assert_match(/expected integer, but received String: "1"/i, error.message)
203
+
204
+ @path = '/characters'
205
+ operation_object.validate_request_params({}, { "limit" => "1" }, {}, HEADER, query_coercion_enabled)
206
+ end
207
+
208
+ it 'uses coerce_form_params for JSON request bodies too' do
209
+ @path = '/validate'
210
+ @method = 'post'
211
+
212
+ body_coercion_disabled = Committee::SchemaValidator::Option.new({ coerce_form_params: false }, open_api_3_schema, :open_api_3)
213
+ body_coercion_enabled = Committee::SchemaValidator::Option.new({ coerce_form_params: true }, open_api_3_schema, :open_api_3)
214
+
215
+ error = assert_raises(Committee::InvalidRequest) do
216
+ operation_object.validate_request_params({}, {}, { "integer" => "1" }, HEADER, body_coercion_disabled)
217
+ end
218
+ assert_match(/expected integer, but received String: "1"/i, error.message)
219
+
220
+ body_params = { "integer" => "1" }
221
+ operation_object.validate_request_params({}, {}, body_params, HEADER, body_coercion_enabled)
222
+
223
+ assert_kind_of(Integer, body_params["integer"])
224
+ end
225
+ end
211
226
  end
212
227
  end