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.
- checksums.yaml +5 -5
- data/lib/committee.rb +16 -5
- data/lib/committee/bin/committee_stub.rb +4 -0
- data/lib/committee/drivers.rb +12 -29
- data/lib/committee/drivers/hyper_schema.rb +9 -0
- data/lib/committee/drivers/open_api_2.rb +9 -20
- data/lib/committee/drivers/open_api_3.rb +70 -0
- data/lib/committee/errors.rb +3 -0
- data/lib/committee/middleware/base.rb +20 -62
- data/lib/committee/middleware/request_validation.rb +5 -62
- data/lib/committee/middleware/response_validation.rb +5 -19
- data/lib/committee/middleware/stub.rb +5 -1
- data/lib/committee/parameter_coercer.rb +1 -0
- data/lib/committee/request_unpacker.rb +2 -5
- data/lib/committee/schema_validator/hyper_schema.rb +92 -0
- data/lib/committee/{request_validator.rb → schema_validator/hyper_schema/request_validator.rb} +1 -1
- data/lib/committee/{response_generator.rb → schema_validator/hyper_schema/response_generator.rb} +1 -1
- data/lib/committee/{response_validator.rb → schema_validator/hyper_schema/response_validator.rb} +6 -6
- data/lib/committee/{router.rb → schema_validator/hyper_schema/router.rb} +10 -4
- data/lib/committee/{string_params_coercer.rb → schema_validator/hyper_schema/string_params_coercer.rb} +1 -1
- data/lib/committee/schema_validator/open_api_3.rb +67 -0
- data/lib/committee/schema_validator/open_api_3/operation_wrapper.rb +98 -0
- data/lib/committee/schema_validator/open_api_3/request_validator.rb +17 -0
- data/lib/committee/schema_validator/open_api_3/response_validator.rb +35 -0
- data/lib/committee/schema_validator/open_api_3/router.rb +26 -0
- data/lib/committee/schema_validator/option.rb +31 -0
- data/lib/committee/test/methods.rb +14 -117
- data/test/bin/committee_stub_test.rb +6 -0
- data/test/drivers/open_api_2_test.rb +0 -81
- data/test/drivers/open_api_3_test.rb +81 -0
- data/test/drivers_test.rb +2 -42
- data/test/middleware/base_test.rb +42 -21
- data/test/middleware/request_validation_open_api_3_test.rb +499 -0
- data/test/middleware/request_validation_test.rb +18 -0
- data/test/middleware/response_validation_open_api_3_test.rb +96 -0
- data/test/middleware/response_validation_test.rb +7 -30
- data/test/middleware/stub_test.rb +9 -0
- data/test/request_unpacker_test.rb +55 -21
- data/test/{request_validator_test.rb → schema_validator/hyper_schema/request_validator_test.rb} +4 -4
- data/test/{response_generator_test.rb → schema_validator/hyper_schema/response_generator_test.rb} +11 -11
- data/test/{response_validator_test.rb → schema_validator/hyper_schema/response_validator_test.rb} +3 -3
- data/test/{router_test.rb → schema_validator/hyper_schema/router_test.rb} +8 -10
- data/test/{string_params_coercer_test.rb → schema_validator/hyper_schema/string_params_coercer_test.rb} +3 -3
- data/test/schema_validator/open_api_3/operation_wrapper_test.rb +132 -0
- data/test/schema_validator/open_api_3/request_validator_test.rb +151 -0
- data/test/schema_validator/open_api_3/response_validator_test.rb +55 -0
- data/test/test/methods_new_version_test.rb +11 -20
- data/test/test/methods_test.rb +51 -55
- data/test/test_helper.rb +22 -8
- metadata +46 -18
data/test/drivers_test.rb
CHANGED
@@ -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
|
23
|
-
|
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
|
-
|
32
|
-
|
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
|
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
|
-
|
45
|
-
|
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
|
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
|
-
|
58
|
-
|
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
|
-
|
90
|
+
|
91
|
+
assert_equal "Committee: schema expected to be an instance " +
|
92
|
+
"of Committee::Drivers::Schema.", e.message
|
69
93
|
end
|
70
94
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
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
|
-
|
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
|