committee 2.5.1 → 3.0.0.alpha

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 (50) hide show
  1. checksums.yaml +5 -5
  2. data/lib/committee.rb +16 -5
  3. data/lib/committee/bin/committee_stub.rb +4 -0
  4. data/lib/committee/drivers.rb +12 -29
  5. data/lib/committee/drivers/hyper_schema.rb +9 -0
  6. data/lib/committee/drivers/open_api_2.rb +9 -20
  7. data/lib/committee/drivers/open_api_3.rb +70 -0
  8. data/lib/committee/errors.rb +3 -0
  9. data/lib/committee/middleware/base.rb +20 -62
  10. data/lib/committee/middleware/request_validation.rb +5 -62
  11. data/lib/committee/middleware/response_validation.rb +5 -19
  12. data/lib/committee/middleware/stub.rb +5 -1
  13. data/lib/committee/parameter_coercer.rb +1 -0
  14. data/lib/committee/request_unpacker.rb +2 -5
  15. data/lib/committee/schema_validator/hyper_schema.rb +92 -0
  16. data/lib/committee/{request_validator.rb → schema_validator/hyper_schema/request_validator.rb} +1 -1
  17. data/lib/committee/{response_generator.rb → schema_validator/hyper_schema/response_generator.rb} +1 -1
  18. data/lib/committee/{response_validator.rb → schema_validator/hyper_schema/response_validator.rb} +6 -6
  19. data/lib/committee/{router.rb → schema_validator/hyper_schema/router.rb} +10 -4
  20. data/lib/committee/{string_params_coercer.rb → schema_validator/hyper_schema/string_params_coercer.rb} +1 -1
  21. data/lib/committee/schema_validator/open_api_3.rb +67 -0
  22. data/lib/committee/schema_validator/open_api_3/operation_wrapper.rb +98 -0
  23. data/lib/committee/schema_validator/open_api_3/request_validator.rb +17 -0
  24. data/lib/committee/schema_validator/open_api_3/response_validator.rb +35 -0
  25. data/lib/committee/schema_validator/open_api_3/router.rb +26 -0
  26. data/lib/committee/schema_validator/option.rb +31 -0
  27. data/lib/committee/test/methods.rb +14 -117
  28. data/test/bin/committee_stub_test.rb +6 -0
  29. data/test/drivers/open_api_2_test.rb +0 -81
  30. data/test/drivers/open_api_3_test.rb +81 -0
  31. data/test/drivers_test.rb +2 -42
  32. data/test/middleware/base_test.rb +42 -21
  33. data/test/middleware/request_validation_open_api_3_test.rb +499 -0
  34. data/test/middleware/request_validation_test.rb +18 -0
  35. data/test/middleware/response_validation_open_api_3_test.rb +96 -0
  36. data/test/middleware/response_validation_test.rb +7 -30
  37. data/test/middleware/stub_test.rb +9 -0
  38. data/test/request_unpacker_test.rb +55 -21
  39. data/test/{request_validator_test.rb → schema_validator/hyper_schema/request_validator_test.rb} +4 -4
  40. data/test/{response_generator_test.rb → schema_validator/hyper_schema/response_generator_test.rb} +11 -11
  41. data/test/{response_validator_test.rb → schema_validator/hyper_schema/response_validator_test.rb} +3 -3
  42. data/test/{router_test.rb → schema_validator/hyper_schema/router_test.rb} +8 -10
  43. data/test/{string_params_coercer_test.rb → schema_validator/hyper_schema/string_params_coercer_test.rb} +3 -3
  44. data/test/schema_validator/open_api_3/operation_wrapper_test.rb +132 -0
  45. data/test/schema_validator/open_api_3/request_validator_test.rb +151 -0
  46. data/test/schema_validator/open_api_3/response_validator_test.rb +55 -0
  47. data/test/test/methods_new_version_test.rb +11 -20
  48. data/test/test/methods_test.rb +51 -55
  49. data/test/test_helper.rb +22 -8
  50. metadata +46 -18
@@ -4,6 +4,7 @@ describe Committee::Drivers do
4
4
  DRIVERS = [
5
5
  :hyper_schema,
6
6
  :open_api_2,
7
+ :open_api_3,
7
8
  ].freeze
8
9
 
9
10
  it "gets driver with .driver_from_name" do
@@ -19,48 +20,6 @@ describe Committee::Drivers do
19
20
  end
20
21
  assert_equal %{Committee: unknown driver "blueprint".}, e.message
21
22
  end
22
-
23
- describe 'load_from_file(schema_path)' do
24
- it 'load OpenAPI2' do
25
- s = Committee::Drivers.load_from_file(open_api_2_schema_path)
26
- assert_kind_of Committee::Drivers::Schema, s
27
- assert_kind_of Committee::Drivers::OpenAPI2::Schema, s
28
- end
29
-
30
- it 'load Hyper-Schema' do
31
- s = Committee::Drivers.load_from_file(hyper_schema_schema_path)
32
- assert_kind_of Committee::Drivers::Schema, s
33
- assert_kind_of Committee::Drivers::HyperSchema::Schema, s
34
- end
35
- end
36
-
37
- describe 'load_from_json(schema_path)' do
38
- it 'load OpenAPI2' do
39
- s = Committee::Drivers.load_from_json(open_api_2_schema_path)
40
- assert_kind_of Committee::Drivers::Schema, s
41
- assert_kind_of Committee::Drivers::OpenAPI2::Schema, s
42
- end
43
-
44
- it 'load Hyper-Schema' do
45
- s = Committee::Drivers.load_from_json(hyper_schema_schema_path)
46
- assert_kind_of Committee::Drivers::Schema, s
47
- assert_kind_of Committee::Drivers::HyperSchema::Schema, s
48
- end
49
- end
50
-
51
- describe 'load_from_data(schema_path)' do
52
- it 'load OpenAPI2' do
53
- s = Committee::Drivers.load_from_data(open_api_2_data)
54
- assert_kind_of Committee::Drivers::Schema, s
55
- assert_kind_of Committee::Drivers::OpenAPI2::Schema, s
56
- end
57
-
58
- it 'load Hyper-Schema' do
59
- s = Committee::Drivers.load_from_data(hyper_schema_data)
60
- assert_kind_of Committee::Drivers::Schema, s
61
- assert_kind_of Committee::Drivers::HyperSchema::Schema, s
62
- end
63
- end
64
23
  end
65
24
 
66
25
  describe Committee::Drivers::Driver do
@@ -88,6 +47,7 @@ end
88
47
  describe Committee::Drivers::Schema do
89
48
  SCHEMA_METHODS = {
90
49
  :driver => [],
50
+ :build_router => [validator_option: nil, prefix: nil]
91
51
  }
92
52
 
93
53
  it "has a set of abstract methods" do
@@ -19,8 +19,17 @@ describe Committee::Middleware::Base do
19
19
  assert_equal 200, last_response.status
20
20
  end
21
21
 
22
- it "accepts schema string (legacy behavior)" do
23
- mock(Committee).warn_deprecated.with_any_args
22
+ it "accepts just a OpenAPI3 schema object" do
23
+ @app = new_rack_app(open_api_3: open_api_3_schema)
24
+ params = {
25
+ "name" => "cloudnasium"
26
+ }
27
+ header "Content-Type", "application/json"
28
+ post "/apps", JSON.generate(params)
29
+ assert_equal 200, last_response.status
30
+ end
31
+
32
+ it "don't accepts schema string" do
24
33
  @app = new_rack_app(
25
34
  schema: JSON.dump(hyper_schema_data)
26
35
  )
@@ -28,12 +37,16 @@ describe Committee::Middleware::Base do
28
37
  "name" => "cloudnasium"
29
38
  }
30
39
  header "Content-Type", "application/json"
31
- post "/apps", JSON.generate(params)
32
- assert_equal 200, last_response.status
40
+
41
+ e = assert_raises(ArgumentError) do
42
+ post "/apps", JSON.generate(params)
43
+ end
44
+
45
+ assert_equal "Committee: schema expected to be an instance " +
46
+ "of Committee::Drivers::Schema.", e.message
33
47
  end
34
48
 
35
- it "accepts schema hash (legacy behavior)" do
36
- mock(Committee).warn_deprecated.with_any_args
49
+ it "don't accepts schema hash" do
37
50
  @app = new_rack_app(
38
51
  schema: hyper_schema_data
39
52
  )
@@ -41,12 +54,16 @@ describe Committee::Middleware::Base do
41
54
  "name" => "cloudnasium"
42
55
  }
43
56
  header "Content-Type", "application/json"
44
- post "/apps", JSON.generate(params)
45
- assert_equal 200, last_response.status
57
+
58
+ e = assert_raises(ArgumentError) do
59
+ post "/apps", JSON.generate(params)
60
+ end
61
+
62
+ assert_equal "Committee: schema expected to be an instance " +
63
+ "of Committee::Drivers::Schema.", e.message
46
64
  end
47
65
 
48
- it "accepts schema JsonSchema::Schema object (legacy behavior)" do
49
- mock(Committee).warn_deprecated.with_any_args
66
+ it "don't accepts schema JsonSchema::Schema object" do
50
67
  @app = new_rack_app(
51
68
  schema: JsonSchema.parse!(hyper_schema_data)
52
69
  )
@@ -54,8 +71,13 @@ describe Committee::Middleware::Base do
54
71
  "name" => "cloudnasium"
55
72
  }
56
73
  header "Content-Type", "application/json"
57
- post "/apps", JSON.generate(params)
58
- assert_equal 200, last_response.status
74
+
75
+ e = assert_raises(ArgumentError) do
76
+ post "/apps", JSON.generate(params)
77
+ end
78
+
79
+ assert_equal "Committee: schema expected to be an instance " +
80
+ "of Committee::Drivers::Schema.", e.message
59
81
  end
60
82
 
61
83
  it "doesn't accept other schema types" do
@@ -65,19 +87,18 @@ describe Committee::Middleware::Base do
65
87
  e = assert_raises(ArgumentError) do
66
88
  post "/apps"
67
89
  end
68
- assert_equal "Committee: schema expected to be an instance of Committee::Drivers::Schema.", e.message
90
+
91
+ assert_equal "Committee: schema expected to be an instance " +
92
+ "of Committee::Drivers::Schema.", e.message
69
93
  end
70
94
 
71
- describe 'initialize option' do
72
- it "schema_path option with hyper-schema" do
73
- b = Committee::Middleware::Base.new(nil, schema_path: hyper_schema_schema_path)
74
- assert_kind_of Committee::Drivers::HyperSchema::Schema, b.instance_variable_get(:@schema)
95
+ it "schema not exist" do
96
+ @app = new_rack_app
97
+ e = assert_raises(ArgumentError) do
98
+ post "/apps"
75
99
  end
76
100
 
77
- it "schema_path option with OpenAPI2" do
78
- b = Committee::Middleware::Base.new(nil, schema_path: open_api_2_schema_path)
79
- assert_kind_of Committee::Drivers::OpenAPI2::Schema, b.instance_variable_get(:@schema)
80
- end
101
+ assert_equal "Committee: need option `schema` or `open_api_3`", e.message
81
102
  end
82
103
 
83
104
  private
@@ -0,0 +1,499 @@
1
+ require_relative "../test_helper"
2
+
3
+ describe Committee::Middleware::RequestValidation do
4
+ include Rack::Test::Methods
5
+
6
+ def app
7
+ @app
8
+ end
9
+
10
+ ARRAY_PROPERTY = [
11
+ {
12
+ "update_time" => "2016-04-01T16:00:00.000+09:00",
13
+ "per_page" => 1,
14
+ "nested_coercer_object" => {
15
+ "update_time" => "2016-04-01T16:00:00.000+09:00",
16
+ "threshold" => 1.5
17
+ },
18
+ "nested_no_coercer_object" => {
19
+ "per_page" => 1,
20
+ "threshold" => 1.5
21
+ },
22
+ "nested_coercer_array" => [
23
+ {
24
+ "update_time" => "2016-04-01T16:00:00.000+09:00",
25
+ "threshold" => 1.5
26
+ }
27
+ ],
28
+ "nested_no_coercer_array" => [
29
+ {
30
+ "per_page" => 1,
31
+ "threshold" => 1.5
32
+ }
33
+ ],
34
+ "integer_array" => [
35
+ 1, 2, 3
36
+ ],
37
+ "datetime_array" => [
38
+ "2016-04-01T16:00:00.000+09:00",
39
+ "2016-04-01T17:00:00.000+09:00",
40
+ "2016-04-01T18:00:00.000+09:00"
41
+ ]
42
+ },
43
+ {
44
+ "update_time" => "2016-04-01T16:00:00.000+09:00",
45
+ "per_page" => 1,
46
+ "threshold" => 1.5
47
+ },
48
+ {
49
+ "threshold" => 1.5,
50
+ "per_page" => 1
51
+ }
52
+ ]
53
+
54
+
55
+ it "OpenAPI3 pass through a valid request" do
56
+ @app = new_rack_app(open_api_3: open_api_3_schema)
57
+ params = {
58
+ "string_post_1" => "cloudnasium"
59
+ }
60
+ header "Content-Type", "application/json"
61
+ post "/characters", JSON.generate(params)
62
+
63
+ assert_equal 200, last_response.status
64
+ end
65
+
66
+ it "not parameter requset" do
67
+ check_parameter_string = lambda { |_|
68
+ [200, {integer: 1}, []]
69
+ }
70
+
71
+ @app = new_rack_app_with_lambda(check_parameter_string, open_api_3: open_api_3_schema)
72
+
73
+ put "/validate_no_parameter", {no_schema: 'no'}
74
+ end
75
+
76
+ it "passes given a datetime and with coerce_date_times enabled on GET endpoint" do
77
+ params = { "datetime_string" => "2016-04-01T16:00:00.000+09:00" }
78
+
79
+ check_parameter = lambda { |env|
80
+ assert_equal DateTime, env['rack.request.query_hash']["datetime_string"].class
81
+ [200, {}, []]
82
+ }
83
+
84
+ @app = new_rack_app_with_lambda(check_parameter, open_api_3: open_api_3_schema, coerce_date_times: true)
85
+
86
+ get "/string_params_coercer", params
87
+ assert_equal 200, last_response.status
88
+ end
89
+
90
+ it "passes given a datetime and with coerce_date_times enabled on POST endpoint" do
91
+ params = {
92
+ "nested_array" => [
93
+ {
94
+ "update_time" => "2016-04-01T16:00:00.000+09:00",
95
+ "nested_coercer_object" => {
96
+ "update_time" => "2016-04-01T16:00:00.000+09:00",
97
+ },
98
+ "nested_no_coercer_object" => {
99
+ "update_time" => "2016-04-01T16:00:00.000+09:00",
100
+ },
101
+ "nested_coercer_array" => [
102
+ {
103
+ "update_time" => "2016-04-01T16:00:00.000+09:00",
104
+ }
105
+ ],
106
+ "nested_no_coercer_array" => [
107
+ {
108
+ "update_time" => "2016-04-01T16:00:00.000+09:00",
109
+ }
110
+ ]
111
+ },
112
+ {
113
+ "update_time" => "2016-04-01T16:00:00.000+09:00",
114
+ }
115
+ ]
116
+ }
117
+
118
+ check_parameter = lambda { |env|
119
+ nested_array = env['committee.params']["nested_array"]
120
+ first_data = nested_array[0]
121
+ assert_kind_of DateTime, first_data["update_time"]
122
+
123
+ second_data = nested_array[1]
124
+ assert_kind_of DateTime, second_data["update_time"]
125
+
126
+ assert_kind_of DateTime, first_data["nested_coercer_object"]["update_time"]
127
+
128
+ assert_kind_of String, first_data["nested_no_coercer_object"]["update_time"]
129
+
130
+ assert_kind_of DateTime, first_data["nested_coercer_array"].first["update_time"]
131
+ assert_kind_of String, first_data["nested_no_coercer_array"].first["update_time"]
132
+ [200, {}, []]
133
+ }
134
+
135
+ @app = new_rack_app_with_lambda(check_parameter, open_api_3: open_api_3_schema, coerce_date_times: true, coerce_recursive: true)
136
+
137
+ post "/string_params_coercer", params
138
+
139
+ assert_equal 200, last_response.status
140
+ end
141
+
142
+ # TODO: support date-time object format check
143
+ =begin
144
+ it "passes given an invalid datetime string with coerce_date_times enabled" do
145
+ @app = new_rack_app(open_api_3: open_api_3_schema, coerce_date_times: true)
146
+ params = {
147
+ "datetime_string" => "invalid_datetime_format"
148
+ }
149
+ get "/string_params_coercer", JSON.generate(params)
150
+
151
+ assert_equal 400, last_response.status
152
+ assert_match(/invalid request/i, last_response.body)
153
+ end
154
+ =end
155
+
156
+ it "passes a nested object with recursive option" do
157
+ params = {
158
+ "nested_array" => [
159
+ {
160
+ "update_time" => "2016-04-01T16:00:00.000+09:00",
161
+ "per_page" => "1",
162
+ }
163
+ ],
164
+ }
165
+
166
+ check_parameter = lambda { |env|
167
+ hash = env['rack.request.query_hash']
168
+ assert_equal DateTime, hash['nested_array'].first['update_time'].class
169
+ assert_equal 1, hash['nested_array'].first['per_page']
170
+
171
+ [200, {}, []]
172
+ }
173
+
174
+ @app = new_rack_app_with_lambda(check_parameter,
175
+ coerce_query_params: true,
176
+ coerce_recursive: true,
177
+ coerce_date_times: true,
178
+ open_api_3: open_api_3_schema)
179
+
180
+ get "/string_params_coercer", params
181
+
182
+ assert_equal 200, last_response.status
183
+ end
184
+
185
+ =begin
186
+ it "passes a nested object with coerce_recursive default(true)" do
187
+ key_name = "update_time"
188
+ params = {
189
+ key_name => "2016-04-01T16:00:00.000+09:00",
190
+ "query" => "cloudnasium",
191
+ "array_property" => ARRAY_PROPERTY
192
+ }
193
+
194
+ @app = new_rack_app(coerce_query_params: true, coerce_date_times: true, schema: hyper_schema)
195
+
196
+ get "/search/apps", params
197
+ assert_equal 200, last_response.status # schema expect integer but we don't convert string to integer, so 400
198
+ end
199
+
200
+ it "passes given a nested datetime and with coerce_recursive=true and coerce_date_times=true on POST endpoint" do
201
+ key_name = "update_time"
202
+ params = {
203
+ key_name => "2016-04-01T16:00:00.000+09:00",
204
+ "array_property" => ARRAY_PROPERTY
205
+ }
206
+
207
+ check_parameter = lambda { |env|
208
+ hash = env['committee.params']
209
+ assert_equal DateTime, hash['array_property'].first['update_time'].class
210
+ assert_equal 1, hash['array_property'].first['per_page']
211
+ assert_equal DateTime, hash['array_property'].first['nested_coercer_object']['update_time'].class
212
+ assert_equal 1, hash['array_property'].first['nested_no_coercer_object']['per_page']
213
+ assert_equal 2, hash['array_property'].first['integer_array'][1]
214
+ assert_equal DateTime, hash['array_property'].first['datetime_array'][0].class
215
+ assert_equal DateTime, env['committee.params'][key_name].class
216
+ [200, {}, []]
217
+ }
218
+
219
+ @app = new_rack_app_with_lambda(check_parameter, coerce_date_times: true, coerce_recursive: true, schema: hyper_schema)
220
+
221
+ header "Content-Type", "application/json"
222
+ post "/apps", JSON.generate(params)
223
+ assert_equal 200, last_response.status
224
+ end
225
+
226
+ it "passes given a nested datetime and with coerce_recursive=true and coerce_date_times=true on POST endpoint" do
227
+ key_name = "update_time"
228
+ params = {
229
+ key_name => "2016-04-01T16:00:00.000+09:00",
230
+ "array_property" => ARRAY_PROPERTY
231
+ }
232
+
233
+ check_parameter = lambda { |env|
234
+ hash = env['committee.params']
235
+ assert_equal String, hash['array_property'].first['update_time'].class
236
+ assert_equal 1, hash['array_property'].first['per_page']
237
+ assert_equal String, hash['array_property'].first['nested_coercer_object']['update_time'].class
238
+ assert_equal 1, hash['array_property'].first['nested_no_coercer_object']['per_page']
239
+ assert_equal 2, hash['array_property'].first['integer_array'][1]
240
+ assert_equal String, hash['array_property'].first['datetime_array'][0].class
241
+ assert_equal String, env['committee.params'][key_name].class
242
+ [200, {}, []]
243
+ }
244
+
245
+ @app = new_rack_app_with_lambda(check_parameter, schema: hyper_schema)
246
+
247
+ header "Content-Type", "application/json"
248
+ post "/apps", JSON.generate(params)
249
+ assert_equal 200, last_response.status
250
+ end
251
+
252
+ it "passes given a nested datetime and with coerce_recursive=false and coerce_date_times=true on POST endpoint" do
253
+ key_name = "update_time"
254
+ params = {
255
+ key_name => "2016-04-01T16:00:00.000+09:00",
256
+ "array_property" => ARRAY_PROPERTY
257
+ }
258
+
259
+ check_parameter = lambda { |env|
260
+ hash = env['committee.params']
261
+ assert_equal String, hash['array_property'].first['update_time'].class
262
+ assert_equal 1, hash['array_property'].first['per_page']
263
+ assert_equal String, hash['array_property'].first['nested_coercer_object']['update_time'].class
264
+ assert_equal 1, hash['array_property'].first['nested_no_coercer_object']['per_page']
265
+ assert_equal 2, hash['array_property'].first['integer_array'][1]
266
+ assert_equal String, hash['array_property'].first['datetime_array'][0].class
267
+ assert_equal DateTime, env['committee.params'][key_name].class
268
+ [200, {}, []]
269
+ }
270
+
271
+ @app = new_rack_app_with_lambda(check_parameter, coerce_date_times: true, coerce_recursive: false, schema: hyper_schema)
272
+
273
+ header "Content-Type", "application/json"
274
+ post "/apps", JSON.generate(params)
275
+ assert_equal 200, last_response.status
276
+ end
277
+
278
+
279
+ it "OpenAPI3 passes given a nested datetime and with coerce_recursive=false and coerce_date_times=false on POST endpoint" do
280
+ key_name = "update_time"
281
+ params = {
282
+ key_name => "2016-04-01T16:00:00.000+09:00",
283
+ "array_property" => ARRAY_PROPERTY
284
+ }
285
+
286
+ check_parameter = lambda { |env|
287
+ hash = env['committee.params']
288
+ assert_equal String, hash['array_property'].first['update_time'].class
289
+ assert_equal 1, hash['array_property'].first['per_page']
290
+ assert_equal String, hash['array_property'].first['nested_coercer_object']['update_time'].class
291
+ assert_equal 1, hash['array_property'].first['nested_no_coercer_object']['per_page']
292
+ assert_equal 2, hash['array_property'].first['integer_array'][1]
293
+ assert_equal String, hash['array_property'].first['datetime_array'][0].class
294
+ assert_equal String, env['committee.params'][key_name].class
295
+ [200, {}, []]
296
+ }
297
+
298
+ @app = new_rack_app_with_lambda(check_parameter, open_api_3: open_api_3_schema)
299
+
300
+ header "Content-Type", "application/json"
301
+ post "/apps", JSON.generate(params)
302
+ assert_equal 200, last_response.status
303
+ end
304
+ =end
305
+
306
+ it "OpenAPI3 detects an invalid request" do
307
+ @app = new_rack_app(open_api_3: open_api_3_schema, strict: true)
308
+ header "Content-Type", "application/json"
309
+ params = {
310
+ "string_post_1" => 1
311
+ }
312
+ post "/characters", JSON.generate(params)
313
+ assert_equal 400, last_response.status
314
+ # FIXME: when ruby 2.3 dropped, fix because ruby 2.3 return Fixnum, ruby 2.4 or later return Integer
315
+ assert_match(/1 class is #{1.class}/i, last_response.body)
316
+ end
317
+
318
+ it "rescues JSON errors" do
319
+ @app = new_rack_app(open_api_3: open_api_3_schema)
320
+ header "Content-Type", "application/json"
321
+ post "/apps", "{x:y}"
322
+ assert_equal 400, last_response.status
323
+ assert_match(/valid json/i, last_response.body)
324
+ end
325
+
326
+ it "take a prefix" do
327
+ @app = new_rack_app(prefix: "/v1", open_api_3: open_api_3_schema)
328
+ params = {
329
+ "string_post_1" => "cloudnasium"
330
+ }
331
+ header "Content-Type", "application/json"
332
+ post "/v1/characters", JSON.generate(params)
333
+ assert_equal 200, last_response.status
334
+ end
335
+
336
+ it "ignores paths outside the prefix" do
337
+ @app = new_rack_app(prefix: "/v1", open_api_3: open_api_3_schema)
338
+ header "Content-Type", "text/html"
339
+ get "/hello"
340
+ assert_equal 200, last_response.status
341
+ end
342
+
343
+ it "OpenAPI3 pass not exist href" do
344
+ @app = new_rack_app(open_api_3: open_api_3_schema)
345
+ get "/unknown"
346
+ assert_equal 200, last_response.status
347
+ end
348
+
349
+ it "OpenAPI3 pass not exist href in strict mode" do
350
+ @app = new_rack_app(open_api_3: open_api_3_schema, strict: true)
351
+ get "/unknown"
352
+ assert_equal 404, last_response.status
353
+ end
354
+
355
+ it "optionally raises an error" do
356
+ @app = new_rack_app(raise: true, open_api_3: open_api_3_schema)
357
+ header "Content-Type", "application/json"
358
+ assert_raises(Committee::InvalidRequest) do
359
+ post "/characters", "{x:y}"
360
+ end
361
+ end
362
+
363
+ # TODO: support check_content_type
364
+ it "OpenAPI not support check_content_type" do
365
+ @app = new_rack_app(open_api_3: open_api_3_schema, check_content_type: true)
366
+
367
+ e = assert_raises(RuntimeError) {
368
+ post "/characters", {}
369
+ }
370
+
371
+ assert_equal 'OpenAPI3 not support @check_content_type option', e.message
372
+ end
373
+ =begin
374
+ it "optionally content_type check" do
375
+ @app = new_rack_app(check_content_type: true, open_api_3: open_api_3_schema)
376
+ params = {
377
+ "string_post_1" => "cloudnasium"
378
+ }
379
+ header "Content-Type", "text/html"
380
+ post "/characters", JSON.generate(params)
381
+ assert_equal 400, last_response.status
382
+ end
383
+ =end
384
+
385
+ it "optionally skip content_type check" do
386
+ @app = new_rack_app(check_content_type: false, open_api_3: open_api_3_schema)
387
+ params = {
388
+ "string_post_1" => "cloudnasium"
389
+ }
390
+ header "Content-Type", "text/html"
391
+ post "/characters", JSON.generate(params)
392
+ assert_equal 200, last_response.status
393
+ end
394
+
395
+ it "optionally coerces query params" do
396
+ @app = new_rack_app(coerce_query_params: true, open_api_3: open_api_3_schema)
397
+ header "Content-Type", "application/json"
398
+ get "/string_params_coercer", {"integer_1" => "1"}
399
+ assert_equal 200, last_response.status
400
+ end
401
+
402
+ =begin
403
+ it "still raises an error if query param coercion is not possible" do
404
+ @app = new_rack_app(coerce_query_params: true, schema: hyper_schema)
405
+ header "Content-Type", "application/json"
406
+ get "/search/apps", {"per_page" => "foo", "query" => "cloudnasium"}
407
+ assert_equal 400, last_response.status
408
+ assert_match(/invalid request/i, last_response.body)
409
+ end
410
+
411
+ it "passes through a valid request for OpenAPI" do
412
+ check_parameter = lambda { |env|
413
+ assert_equal 3, env['rack.request.query_hash']['limit']
414
+ [200, {}, []]
415
+ }
416
+
417
+ @app = new_rack_app_with_lambda(check_parameter, schema: open_api_2_schema)
418
+ get "/api/pets?limit=3", nil, { "HTTP_AUTH_TOKEN" => "xxx" }
419
+ assert_equal 200, last_response.status
420
+ end
421
+
422
+ it "detects an invalid request for OpenAPI" do
423
+ @app = new_rack_app(schema: open_api_2_schema)
424
+ get "/api/pets?limit=foo", nil, { "HTTP_AUTH_TOKEN" => "xxx" }
425
+ assert_equal 400, last_response.status
426
+ assert_match(/invalid request/i, last_response.body)
427
+ end
428
+
429
+ it "passes through a valid request for OpenAPI including path parameters" do
430
+ @app = new_rack_app(schema: open_api_2_schema)
431
+ # not that ID is expect to be an integer
432
+ get "/api/pets/123"
433
+ assert_equal 200, last_response.status
434
+ end
435
+
436
+ it "detects an invalid request for OpenAPI including path parameters" do
437
+ @app = new_rack_app(schema: open_api_2_schema)
438
+ # not that ID is expect to be an integer
439
+ get "/api/pets/not-integer"
440
+ assert_equal 400, last_response.status
441
+ assert_match(/invalid request/i, last_response.body)
442
+ end
443
+ =end
444
+
445
+ describe "coerce_path_params" do
446
+ it "coerce string to integer" do
447
+ check_parameter_string = lambda { |env|
448
+ assert env['committee.params']['integer'].is_a?(Integer)
449
+ [200, {}, []]
450
+ }
451
+
452
+ @app = new_rack_app_with_lambda(check_parameter_string, open_api_3: open_api_3_schema, coerce_path_params: true)
453
+ get "/coerce_path_params/1"
454
+ end
455
+
456
+ # TODO: support parameter validation
457
+ it "path parameter validation" do
458
+ @app = new_rack_app(open_api_3: open_api_3_schema, coerce_path_params: false)
459
+ get "/coerce_path_params/1"
460
+
461
+ assert true
462
+ end
463
+ =begin
464
+ it "path parameter validation" do
465
+ @app = new_rack_app_with_lambda(check_parameter_string, open_api_3: open_api_3_schema, coerce_path_params: false)
466
+ e = assert_raises(RuntimeError) {
467
+ get "/coerce_path_params/1"
468
+ }
469
+
470
+ assert_equal 'OpenAPI3 not support @coerce_query_params option', e.message
471
+ end
472
+ =end
473
+ end
474
+
475
+ it "OpenAPI3 raise not support method" do
476
+ @app = new_rack_app(open_api_3: open_api_3_schema)
477
+
478
+ e = assert_raises(RuntimeError) {
479
+ head "/characters", {}
480
+ }
481
+
482
+ assert_equal 'Committee OpenAPI3 not support head method', e.message
483
+ end
484
+
485
+ private
486
+
487
+ def new_rack_app(options = {})
488
+ new_rack_app_with_lambda(lambda { |_|
489
+ [200, {}, []]
490
+ }, options)
491
+ end
492
+
493
+ def new_rack_app_with_lambda(check_lambda, options = {})
494
+ Rack::Builder.new {
495
+ use Committee::Middleware::RequestValidation, options
496
+ run check_lambda
497
+ }
498
+ end
499
+ end