committee 3.0.3 → 3.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: be1585b55c1dafdac14680670df3b8a25797c934dc7bbc8f37da20d1d36115dc
4
- data.tar.gz: 4e1e8ccf4c4c5fc2a59d9b34cf5b7080b971536c2319ad153293d5b2794f1b70
3
+ metadata.gz: 0261ef5b9991afdc79316a4aa67e05293b5cc0dc83a8b7dc80a330fcc2d633b9
4
+ data.tar.gz: a67badbaa49fa492e9bd562293666734a9c733a9d5fa8c54b6a7cf6b3a414305
5
5
  SHA512:
6
- metadata.gz: 5316997b460f9e3caf062932702c80108d669f9ba9aa125acb87f356c4208a57856e074aea64f6e219978f0ecaac9cebc2043f0c0cc99fd5a4b2636086001360
7
- data.tar.gz: 99335b314f5f6083b1078446f0984d53b96f27726246db430b28e8ba06104be97de8a67aef6e51b32c36db08ab6e1bbf3616f89bec554b08519a6ec5337b8ddc
6
+ metadata.gz: 8de3637d5059cb2dee41b9d78aa6b448d3c60fc246485bca06cbceb1e2f993c8b86f9d76a9388359c1f05b05e429eaf5949d6e6dfd587246ac4ab8c59f0f37bd
7
+ data.tar.gz: 510f84e62e9f52239845130b14a6f9432bc2c391c92ab5334b74b301c9119378a491add7f7cfb33fd711a522b727da325a045be31e04ac94fd8c0ead858042a6
@@ -4,6 +4,7 @@ module Committee::Middleware
4
4
  @app = app
5
5
 
6
6
  @error_class = options.fetch(:error_class, Committee::ValidationError)
7
+ @error_handler = options[:error_handler]
7
8
 
8
9
  @raise = options[:raise]
9
10
  @schema = self.class.get_schema(options)
@@ -17,6 +17,7 @@ module Committee::Middleware
17
17
 
18
18
  @app.call(request.env)
19
19
  rescue Committee::BadRequest, Committee::InvalidRequest
20
+ @error_handler.call($!) if @error_handler
20
21
  raise if @raise
21
22
  @error_class.new(400, :bad_request, $!.message).render
22
23
  rescue Committee::NotFound => e
@@ -27,6 +28,7 @@ module Committee::Middleware
27
28
  e.message
28
29
  ).render
29
30
  rescue JSON::ParserError
31
+ @error_handler.call($!) if @error_handler
30
32
  raise Committee::InvalidRequest if @raise
31
33
  @error_class.new(400, :bad_request, "Request body wasn't valid JSON.").render
32
34
  end
@@ -5,8 +5,6 @@ module Committee::Middleware
5
5
  def initialize(app, options = {})
6
6
  super
7
7
  @validate_success_only = @schema.validator_option.validate_success_only
8
-
9
- @error_handler = options[:error_handler]
10
8
  end
11
9
 
12
10
  def handle(request)
@@ -18,7 +18,7 @@ module Committee
18
18
  return {} unless options.coerce_value
19
19
 
20
20
  request_operation.validate_path_params(options)
21
- rescue OpenAPIParser::NotExistRequiredKey => e
21
+ rescue OpenAPIParser::OpenAPIError => e
22
22
  raise Committee::InvalidRequest.new(e.message)
23
23
  end
24
24
 
@@ -1,18 +1,27 @@
1
1
  module Committee::Test
2
2
  module Methods
3
3
  def assert_schema_conform
4
- @schema ||= Committee::Middleware::Base.get_schema(committee_options)
5
- @router ||= @schema.build_router(committee_options)
4
+ assert_request_schema_confirm unless old_behavior
5
+ assert_response_schema_confirm
6
+ end
7
+
8
+ def assert_request_schema_confirm
9
+ unless schema_validator.link_exist?
10
+ request = "`#{request_object.request_method} #{request_object.path_info}` undefined in schema."
11
+ raise Committee::InvalidRequest.new(request)
12
+ end
6
13
 
7
- v = @router.build_schema_validator(request_object)
14
+ schema_validator.request_validate(request_object)
15
+ end
8
16
 
9
- unless v.link_exist?
17
+ def assert_response_schema_confirm
18
+ unless schema_validator.link_exist?
10
19
  response = "`#{request_object.request_method} #{request_object.path_info}` undefined in schema."
11
20
  raise Committee::InvalidResponse.new(response)
12
21
  end
13
22
 
14
23
  status, headers, body = response_data
15
- v.response_validate(status, headers, [body], true) if validate_response?(status)
24
+ schema_validator.response_validate(status, headers, [body], true) if validate_response?(status)
16
25
  end
17
26
 
18
27
  def committee_options
@@ -30,5 +39,31 @@ module Committee::Test
30
39
  def validate_response?(status)
31
40
  Committee::Middleware::ResponseValidation.validate?(status, committee_options.fetch(:validate_success_only, false))
32
41
  end
42
+
43
+ def schema
44
+ @schema ||= Committee::Middleware::Base.get_schema(committee_options)
45
+ end
46
+
47
+ def router
48
+ @router ||= schema.build_router(committee_options)
49
+ end
50
+
51
+ def schema_validator
52
+ @schema_validator ||= router.build_schema_validator(request_object)
53
+ end
54
+
55
+ def old_behavior
56
+ old_assert_behavior = committee_options.fetch(:old_assert_behavior, nil)
57
+ if old_assert_behavior.nil?
58
+ warn <<-MSG
59
+ [DEPRECATION] now assert_schema_confirm check response schema only.
60
+ but we will change check request and response in future major version.
61
+ so if you want to conform response only, please use assert_response_schema_confirm,
62
+ or you can suppress this message and keep old behavior by setting old_assert_behavior=true.
63
+ MSG
64
+ old_assert_behavior = true
65
+ end
66
+ old_assert_behavior
67
+ end
33
68
  end
34
69
  end
@@ -322,6 +322,17 @@ describe Committee::Middleware::RequestValidation do
322
322
  assert_match(/required parameters query_string not exist in/i, e.message)
323
323
  end
324
324
 
325
+ it "raises error when required path parameter is invalid" do
326
+ @app = new_rack_app(raise: true, schema: open_api_3_schema)
327
+
328
+ e = assert_raises(Committee::InvalidRequest) do
329
+ not_an_integer = 'abc'
330
+ get "/coerce_path_params/#{not_an_integer}", nil
331
+ end
332
+
333
+ assert_match(/is String but it's not valid integer in/i, e.message)
334
+ end
335
+
325
336
  it "optionally raises an error" do
326
337
  @app = new_rack_app(raise: true, schema: open_api_3_schema)
327
338
  header "Content-Type", "application/json"
@@ -61,6 +61,18 @@ describe Committee::Middleware::RequestValidation do
61
61
  assert_equal 200, last_response.status
62
62
  end
63
63
 
64
+ it "doesn't call error_handler when request is valid" do
65
+ called_error = false
66
+ pr = ->(_) { called_error = true }
67
+ @app = new_rack_app(schema: hyper_schema, error_handler: pr)
68
+ params = {
69
+ "name" => "cloudnasium"
70
+ }
71
+ header "Content-Type", "application/json"
72
+ post "/apps", JSON.generate(params)
73
+ assert !called_error
74
+ end
75
+
64
76
  it "passes given a datetime and with coerce_date_times enabled on GET endpoint" do
65
77
  key_name = "update_time"
66
78
  params = {
@@ -270,6 +282,18 @@ describe Committee::Middleware::RequestValidation do
270
282
  assert_match(/invalid request/i, last_response.body)
271
283
  end
272
284
 
285
+ it "calls error_handler when request is invalid" do
286
+ called_err = nil
287
+ pr = ->(e) { called_err = e }
288
+ @app = new_rack_app(schema: hyper_schema, error_handler: pr)
289
+ header "Content-Type", "application/json"
290
+ params = {
291
+ "name" => 1
292
+ }
293
+ post "/apps", JSON.generate(params)
294
+ assert_kind_of Committee::InvalidRequest, called_err
295
+ end
296
+
273
297
  it "rescues JSON errors" do
274
298
  @app = new_rack_app(schema: hyper_schema)
275
299
  header "Content-Type", "application/json"
@@ -278,6 +302,15 @@ describe Committee::Middleware::RequestValidation do
278
302
  assert_match(/valid json/i, last_response.body)
279
303
  end
280
304
 
305
+ it "calls error_handler when it rescues JSON errors" do
306
+ called_err = nil
307
+ pr = ->(e) { called_err = e }
308
+ @app = new_rack_app(schema: hyper_schema, error_handler: pr)
309
+ header "Content-Type", "application/json"
310
+ post "/apps", "{x:y}"
311
+ assert_kind_of JSON::ParserError, called_err
312
+ end
313
+
281
314
  it "takes a prefix" do
282
315
  @app = new_rack_app(prefix: "/v1", schema: hyper_schema)
283
316
  params = {
@@ -43,7 +43,7 @@ describe Committee::SchemaValidator::HyperSchema::ResponseGenerator do
43
43
  data, _schema = call
44
44
 
45
45
  # We're testing for legacy behavior here: even without a `targetSchema` as
46
- # long as `rel` is set to `instances` we still wrap the the result in an
46
+ # long as `rel` is set to `instances` we still wrap the result in an
47
47
  # array.
48
48
  assert_equal "instances", @list_link.rel
49
49
 
@@ -43,7 +43,7 @@ describe Committee::SchemaValidator::HyperSchema::ResponseValidator do
43
43
  @link.target_schema = nil
44
44
 
45
45
  # We're testing for legacy behavior here: even without a `targetSchema` as
46
- # long as `rel` is set to `instances` we still wrap the the result in an
46
+ # long as `rel` is set to `instances` we still wrap the result in an
47
47
  # array.
48
48
  assert_equal "instances", @link.rel
49
49
 
@@ -59,7 +59,7 @@ describe Committee::SchemaValidator::HyperSchema::ResponseValidator do
59
59
  @link.target_schema = nil
60
60
 
61
61
  # We're testing for legacy behavior here: even without a `targetSchema` as
62
- # long as `rel` is set to `instances` we still wrap the the result in an
62
+ # long as `rel` is set to `instances` we still wrap the result in an
63
63
  # array.
64
64
  assert_equal "instances", @link.rel
65
65
 
@@ -52,6 +52,67 @@ describe Committee::Test::Methods do
52
52
  end
53
53
  assert_match(/response header must be set to/i, e.message)
54
54
  end
55
+
56
+ it "outputs deprecation warning" do
57
+ @app = new_rack_app(JSON.generate([ValidApp]))
58
+ get "/apps"
59
+ _, err = capture_io do
60
+ assert_schema_conform
61
+ end
62
+ assert_match(/\[DEPRECATION\]/i, err)
63
+ end
64
+ end
65
+
66
+ describe "assert_request_schema_confirm" do
67
+ it "passes through a valid request" do
68
+ @app = new_rack_app([])
69
+ get "/apps"
70
+ assert_request_schema_confirm
71
+ end
72
+
73
+ it "not exist required" do
74
+ @app = new_rack_app([])
75
+ get "/search/apps", {}
76
+ e = assert_raises(Committee::InvalidRequest) do
77
+ assert_request_schema_confirm
78
+ end
79
+ assert_match(/"query" wasn't supplied\./i, e.message)
80
+ end
81
+
82
+ it "path undefined in schema" do
83
+ @app = new_rack_app([])
84
+ get "/undefined"
85
+ e = assert_raises(Committee::InvalidRequest) do
86
+ assert_request_schema_confirm
87
+ end
88
+ assert_match(/`GET \/undefined` undefined in schema/i, e.message)
89
+ end
90
+ end
91
+
92
+ describe "#assert_response_schema_confirm" do
93
+ it "passes through a valid response" do
94
+ @app = new_rack_app(JSON.generate([ValidApp]))
95
+ get "/apps"
96
+ assert_response_schema_confirm
97
+ end
98
+
99
+ it "detects an invalid response Content-Type" do
100
+ @app = new_rack_app(JSON.generate([ValidApp]), {})
101
+ get "/apps"
102
+ e = assert_raises(Committee::InvalidResponse) do
103
+ assert_response_schema_confirm
104
+ end
105
+ assert_match(/response header must be set to/i, e.message)
106
+ end
107
+
108
+ it "path undefined in schema" do
109
+ @app = new_rack_app(JSON.generate([ValidApp]))
110
+ get "/undefined"
111
+ e = assert_raises(Committee::InvalidResponse) do
112
+ assert_response_schema_confirm
113
+ end
114
+ assert_match(/`GET \/undefined` undefined in schema/i, e.message)
115
+ end
55
116
  end
56
117
  end
57
118
 
@@ -88,6 +149,78 @@ describe Committee::Test::Methods do
88
149
  end
89
150
  assert_match(/don't exist status code definition/i, e.message)
90
151
  end
152
+
153
+ it "outputs deprecation warning" do
154
+ @app = new_rack_app(JSON.generate(@correct_response))
155
+ get "/characters"
156
+ _, err = capture_io do
157
+ assert_schema_conform
158
+ end
159
+ assert_match(/\[DEPRECATION\]/i, err)
160
+ end
161
+ end
162
+
163
+ describe "assert_request_schema_confirm" do
164
+ it "passes through a valid request" do
165
+ @app = new_rack_app([])
166
+ get "/characters"
167
+ assert_request_schema_confirm
168
+ end
169
+
170
+ it "not exist required" do
171
+ @app = new_rack_app([])
172
+ get "/validate", {"query_string" => "query", "query_integer_list" => [1, 2]}
173
+ e = assert_raises(Committee::InvalidRequest) do
174
+ assert_request_schema_confirm
175
+ end
176
+ assert_match(/required parameters query_string not exist in #\/paths/i, e.message)
177
+ end
178
+
179
+ it "path undefined in schema" do
180
+ @app = new_rack_app([])
181
+ get "/undefined"
182
+ e = assert_raises(Committee::InvalidRequest) do
183
+ assert_request_schema_confirm
184
+ end
185
+ assert_match(/`GET \/undefined` undefined in schema/i, e.message)
186
+ end
187
+ end
188
+
189
+ describe "#assert_response_schema_confirm" do
190
+ it "passes through a valid response" do
191
+ @app = new_rack_app(JSON.generate(@correct_response))
192
+ get "/characters"
193
+ assert_response_schema_confirm
194
+ end
195
+
196
+ it "detects an invalid response Content-Type" do
197
+ @app = new_rack_app(JSON.generate([@correct_response]), {})
198
+ get "/characters"
199
+ e = assert_raises(Committee::InvalidResponse) do
200
+ assert_response_schema_confirm
201
+ end
202
+ assert_match(/don't exist response definition/i, e.message)
203
+ end
204
+
205
+ it "detects an invalid response status code" do
206
+ @app = new_rack_app(JSON.generate([@correct_response]), {}, 419)
207
+
208
+ get "/characters"
209
+
210
+ e = assert_raises(Committee::InvalidResponse) do
211
+ assert_response_schema_confirm
212
+ end
213
+ assert_match(/don't exist status code definition/i, e.message)
214
+ end
215
+
216
+ it "path undefined in schema" do
217
+ @app = new_rack_app(JSON.generate(@correct_response))
218
+ get "/undefined"
219
+ e = assert_raises(Committee::InvalidResponse) do
220
+ assert_response_schema_confirm
221
+ end
222
+ assert_match(/`GET \/undefined` undefined in schema/i, e.message)
223
+ end
91
224
  end
92
225
  end
93
226
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: committee
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.3
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brandur
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2019-06-17 00:00:00.000000000 Z
13
+ date: 2019-08-07 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: json_schema