committee 3.0.3 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
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