committee 1.15.0 → 2.0.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/committee-stub +10 -36
- data/lib/committee/bin/committee_stub.rb +61 -0
- data/lib/committee/drivers/hyper_schema.rb +151 -0
- data/lib/committee/drivers/open_api_2.rb +297 -0
- data/lib/committee/drivers.rb +57 -0
- data/lib/committee/middleware/base.rb +52 -13
- data/lib/committee/middleware/request_validation.rb +33 -10
- data/lib/committee/middleware/response_validation.rb +2 -1
- data/lib/committee/middleware/stub.rb +24 -8
- data/lib/committee/request_validator.rb +1 -1
- data/lib/committee/response_generator.rb +58 -13
- data/lib/committee/response_validator.rb +32 -8
- data/lib/committee/router.rb +5 -33
- data/lib/committee/{query_params_coercer.rb → string_params_coercer.rb} +11 -6
- data/lib/committee/test/methods.rb +49 -12
- data/lib/committee.rb +15 -1
- data/test/bin/committee_stub_test.rb +45 -0
- data/test/bin_test.rb +20 -0
- data/test/committee_test.rb +49 -0
- data/test/drivers/hyper_schema_test.rb +95 -0
- data/test/drivers/open_api_2_test.rb +255 -0
- data/test/drivers_test.rb +60 -0
- data/test/middleware/base_test.rb +49 -5
- data/test/middleware/request_validation_test.rb +39 -25
- data/test/middleware/response_validation_test.rb +32 -20
- data/test/middleware/stub_test.rb +50 -19
- data/test/request_unpacker_test.rb +10 -0
- data/test/request_validator_test.rb +4 -3
- data/test/response_generator_test.rb +50 -6
- data/test/response_validator_test.rb +29 -4
- data/test/router_test.rb +40 -13
- data/test/{query_params_coercer_test.rb → string_params_coercer_test.rb} +3 -4
- data/test/test/methods_test.rb +44 -5
- data/test/test_helper.rb +59 -1
- metadata +62 -10
@@ -0,0 +1,49 @@
|
|
1
|
+
require_relative "test_helper"
|
2
|
+
|
3
|
+
describe Committee do
|
4
|
+
it "debugs based off env" do
|
5
|
+
old = ENV["COMMITTEE_DEBUG"]
|
6
|
+
begin
|
7
|
+
ENV["COMMITTEE_DEBUG"] = nil
|
8
|
+
refute Committee.debug?
|
9
|
+
ENV["COMMITTEE_DEBUG"] = "true"
|
10
|
+
assert Committee.debug?
|
11
|
+
ensure
|
12
|
+
ENV["COMMITTEE_DEBUG"] = old
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
it "logs debug messages to stderr" do
|
17
|
+
old_stderr = $stderr
|
18
|
+
$stderr = StringIO.new
|
19
|
+
begin
|
20
|
+
stub(Committee).debug? { false }
|
21
|
+
Committee.log_debug "blah"
|
22
|
+
assert_equal "", $stderr.string
|
23
|
+
|
24
|
+
stub(Committee).debug? { true }
|
25
|
+
Committee.log_debug "blah"
|
26
|
+
assert_equal "blah\n", $stderr.string
|
27
|
+
ensure
|
28
|
+
$stderr = old_stderr
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
it "warns on deprecated unless $VERBOSE is nil" do
|
33
|
+
old_stderr = $stderr
|
34
|
+
old_verbose = $VERBOSE
|
35
|
+
$stderr = StringIO.new
|
36
|
+
begin
|
37
|
+
$VERBOSE = nil
|
38
|
+
Committee.warn_deprecated "blah"
|
39
|
+
assert_equal "", $stderr.string
|
40
|
+
|
41
|
+
$VERBOSE = true
|
42
|
+
Committee.warn_deprecated "blah"
|
43
|
+
assert_equal "blah\n", $stderr.string
|
44
|
+
ensure
|
45
|
+
$stderr = old_stderr
|
46
|
+
$VERBOSE = old_verbose
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require_relative "../test_helper"
|
2
|
+
|
3
|
+
describe Committee::Drivers::HyperSchema do
|
4
|
+
before do
|
5
|
+
@driver = Committee::Drivers::HyperSchema.new
|
6
|
+
end
|
7
|
+
|
8
|
+
it "has a name" do
|
9
|
+
assert_equal :hyper_schema, @driver.name
|
10
|
+
end
|
11
|
+
|
12
|
+
it "has a schema class" do
|
13
|
+
assert_equal Committee::Drivers::HyperSchema::Schema, @driver.schema_class
|
14
|
+
end
|
15
|
+
|
16
|
+
it "parses a hyper-schema and builds routes" do
|
17
|
+
schema = @driver.parse(hyper_schema_data)
|
18
|
+
assert_kind_of Committee::Drivers::HyperSchema::Schema, schema
|
19
|
+
assert_equal @driver, schema.driver
|
20
|
+
|
21
|
+
assert_kind_of Hash, schema.routes
|
22
|
+
refute schema.routes.empty?
|
23
|
+
assert(schema.routes.keys.all? { |m|
|
24
|
+
["DELETE", "GET", "PATCH", "POST", "PUT"].include?(m)
|
25
|
+
})
|
26
|
+
|
27
|
+
schema.routes.each do |(_, method_routes)|
|
28
|
+
method_routes.each do |regex, link|
|
29
|
+
assert_kind_of Regexp, regex
|
30
|
+
assert_kind_of Committee::Drivers::HyperSchema::Link, link
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it "defaults to no path parameters" do
|
36
|
+
assert_equal false, @driver.default_path_params
|
37
|
+
end
|
38
|
+
|
39
|
+
it "defaults to no query parameters" do
|
40
|
+
assert_equal false, @driver.default_query_params
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe Committee::Drivers::HyperSchema::Link do
|
45
|
+
before do
|
46
|
+
@hyper_schema_link = JsonSchema::Schema::Link.new
|
47
|
+
@hyper_schema_link.enc_type = "application/x-www-form-urlencoded"
|
48
|
+
@hyper_schema_link.href = "/apps"
|
49
|
+
@hyper_schema_link.media_type = "application/json"
|
50
|
+
@hyper_schema_link.method = "GET"
|
51
|
+
@hyper_schema_link.parent = { "title" => "parent" }
|
52
|
+
@hyper_schema_link.rel = "instances"
|
53
|
+
@hyper_schema_link.schema = { "title" => "input" }
|
54
|
+
@hyper_schema_link.target_schema = { "title" => "target" }
|
55
|
+
|
56
|
+
@link = Committee::Drivers::HyperSchema::Link.new(@hyper_schema_link)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "proxies #enc_type" do
|
60
|
+
assert_equal "application/x-www-form-urlencoded", @link.enc_type
|
61
|
+
end
|
62
|
+
|
63
|
+
it "proxies #href" do
|
64
|
+
assert_equal "/apps", @link.href
|
65
|
+
end
|
66
|
+
|
67
|
+
it "proxies #media_type" do
|
68
|
+
assert_equal "application/json", @link.media_type
|
69
|
+
end
|
70
|
+
|
71
|
+
it "proxies #method" do
|
72
|
+
assert_equal "GET", @link.method
|
73
|
+
end
|
74
|
+
|
75
|
+
it "proxies #rel" do
|
76
|
+
assert_equal "instances", @link.rel
|
77
|
+
end
|
78
|
+
|
79
|
+
it "proxies #schema" do
|
80
|
+
assert_equal @hyper_schema_link.schema, @link.schema
|
81
|
+
end
|
82
|
+
|
83
|
+
it "generates 200 #status_success for non-create" do
|
84
|
+
assert_equal 200, @link.status_success
|
85
|
+
end
|
86
|
+
|
87
|
+
it "generates 201 #status_success for create" do
|
88
|
+
@hyper_schema_link.rel = "create"
|
89
|
+
assert_equal 201, @link.status_success
|
90
|
+
end
|
91
|
+
|
92
|
+
it "proxies #target_schema" do
|
93
|
+
assert_equal @hyper_schema_link.target_schema, @link.target_schema
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,255 @@
|
|
1
|
+
require_relative "../test_helper"
|
2
|
+
|
3
|
+
describe Committee::Drivers::OpenAPI2 do
|
4
|
+
before do
|
5
|
+
@driver = Committee::Drivers::OpenAPI2.new
|
6
|
+
end
|
7
|
+
|
8
|
+
it "has a name" do
|
9
|
+
assert_equal :open_api_2, @driver.name
|
10
|
+
end
|
11
|
+
|
12
|
+
it "has a schema class" do
|
13
|
+
assert_equal Committee::Drivers::OpenAPI2::Schema, @driver.schema_class
|
14
|
+
end
|
15
|
+
|
16
|
+
it "parses an OpenAPI 2 spec" do
|
17
|
+
schema = @driver.parse(open_api_2_data)
|
18
|
+
assert_kind_of Committee::Drivers::OpenAPI2::Schema, schema
|
19
|
+
assert_kind_of JsonSchema::Schema, schema.definitions
|
20
|
+
assert_equal @driver, schema.driver
|
21
|
+
|
22
|
+
assert_kind_of Hash, schema.routes
|
23
|
+
refute schema.routes.empty?
|
24
|
+
assert(schema.routes.keys.all? { |m|
|
25
|
+
["DELETE", "GET", "PATCH", "POST", "PUT"].include?(m)
|
26
|
+
})
|
27
|
+
|
28
|
+
schema.routes.each do |(_, method_routes)|
|
29
|
+
method_routes.each do |regex, link|
|
30
|
+
assert_kind_of Regexp, regex
|
31
|
+
assert_kind_of Committee::Drivers::OpenAPI2::Link, link
|
32
|
+
|
33
|
+
# verify that we've correct generated a parameters schema for each link
|
34
|
+
if link.target_schema
|
35
|
+
assert_kind_of JsonSchema::Schema, link.schema if link.schema
|
36
|
+
end
|
37
|
+
|
38
|
+
if link.target_schema
|
39
|
+
assert_kind_of JsonSchema::Schema, link.target_schema
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it "names capture groups into href regexes" do
|
46
|
+
schema = @driver.parse(open_api_2_data)
|
47
|
+
assert_equal %r{^\/api\/pets\/(?<id>[^\/]+)$}.inspect,
|
48
|
+
schema.routes["DELETE"][0][0].inspect
|
49
|
+
end
|
50
|
+
|
51
|
+
it "prefers a 200 response first" do
|
52
|
+
schema_data = schema_data_with_responses({
|
53
|
+
'201' => { 'schema' => { 'description' => '201 response' } },
|
54
|
+
'200' => { 'schema' => { 'description' => '200 response' } },
|
55
|
+
})
|
56
|
+
|
57
|
+
schema = @driver.parse(schema_data)
|
58
|
+
link = schema.routes['GET'][0][1]
|
59
|
+
assert_equal 200, link.status_success
|
60
|
+
assert_equal({ 'description' => '200 response' }, link.target_schema.data)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "prefers a 201 response next" do
|
64
|
+
schema_data = schema_data_with_responses({
|
65
|
+
'302' => { 'schema' => { 'description' => '302 response' } },
|
66
|
+
'201' => { 'schema' => { 'description' => '201 response' } },
|
67
|
+
})
|
68
|
+
|
69
|
+
schema = @driver.parse(schema_data)
|
70
|
+
link = schema.routes['GET'][0][1]
|
71
|
+
assert_equal 201, link.status_success
|
72
|
+
assert_equal({ 'description' => '201 response' }, link.target_schema.data)
|
73
|
+
end
|
74
|
+
|
75
|
+
it "prefers any three-digit response next" do
|
76
|
+
schema_data = schema_data_with_responses({
|
77
|
+
'default' => { 'schema' => { 'description' => 'default response' } },
|
78
|
+
'302' => { 'schema' => { 'description' => '302 response' } },
|
79
|
+
})
|
80
|
+
|
81
|
+
schema = @driver.parse(schema_data)
|
82
|
+
link = schema.routes['GET'][0][1]
|
83
|
+
assert_equal 302, link.status_success
|
84
|
+
assert_equal({ 'description' => '302 response' }, link.target_schema.data)
|
85
|
+
end
|
86
|
+
|
87
|
+
it "falls back to no response" do
|
88
|
+
schema_data = schema_data_with_responses({})
|
89
|
+
|
90
|
+
schema = @driver.parse(schema_data)
|
91
|
+
link = schema.routes['GET'][0][1]
|
92
|
+
assert_equal nil, link.status_success
|
93
|
+
assert_equal nil, link.target_schema
|
94
|
+
end
|
95
|
+
|
96
|
+
it "refuses to parse other version of OpenAPI" do
|
97
|
+
data = open_api_2_data
|
98
|
+
data['swagger'] = '3.0'
|
99
|
+
e = assert_raises(ArgumentError) do
|
100
|
+
@driver.parse(data)
|
101
|
+
end
|
102
|
+
assert_equal "Committee: driver requires OpenAPI 2.0.", e.message
|
103
|
+
end
|
104
|
+
|
105
|
+
it "refuses to parse a spec without mandatory fields" do
|
106
|
+
data = open_api_2_data
|
107
|
+
data['definitions'] = nil
|
108
|
+
e = assert_raises(ArgumentError) do
|
109
|
+
@driver.parse(data)
|
110
|
+
end
|
111
|
+
assert_equal "Committee: no definitions section in spec data.", e.message
|
112
|
+
end
|
113
|
+
|
114
|
+
it "defaults to path parameters" do
|
115
|
+
assert_equal true, @driver.default_path_params
|
116
|
+
end
|
117
|
+
|
118
|
+
it "defaults to query parameters" do
|
119
|
+
assert_equal true, @driver.default_query_params
|
120
|
+
end
|
121
|
+
|
122
|
+
def schema_data_with_responses(response_data)
|
123
|
+
{
|
124
|
+
'swagger' => '2.0',
|
125
|
+
'consumes' => ['application/json'],
|
126
|
+
'produces' => ['application/json'],
|
127
|
+
'paths' => {
|
128
|
+
'/foos' => {
|
129
|
+
'get' => {
|
130
|
+
'responses' => response_data,
|
131
|
+
},
|
132
|
+
},
|
133
|
+
},
|
134
|
+
'definitions' => {},
|
135
|
+
}
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe Committee::Drivers::OpenAPI2::Link do
|
140
|
+
before do
|
141
|
+
@link = Committee::Drivers::OpenAPI2::Link.new
|
142
|
+
@link.enc_type = "application/x-www-form-urlencoded"
|
143
|
+
@link.href = "/apps"
|
144
|
+
@link.media_type = "application/json"
|
145
|
+
@link.method = "GET"
|
146
|
+
@link.status_success = 200
|
147
|
+
@link.schema = { "title" => "input" }
|
148
|
+
@link.target_schema = { "title" => "target" }
|
149
|
+
end
|
150
|
+
|
151
|
+
it "uses set #enc_type" do
|
152
|
+
assert_equal "application/x-www-form-urlencoded", @link.enc_type
|
153
|
+
end
|
154
|
+
|
155
|
+
it "uses set #href" do
|
156
|
+
assert_equal "/apps", @link.href
|
157
|
+
end
|
158
|
+
|
159
|
+
it "uses set #media_type" do
|
160
|
+
assert_equal "application/json", @link.media_type
|
161
|
+
end
|
162
|
+
|
163
|
+
it "uses set #method" do
|
164
|
+
assert_equal "GET", @link.method
|
165
|
+
end
|
166
|
+
|
167
|
+
it "proxies #rel" do
|
168
|
+
e = assert_raises do
|
169
|
+
@link.rel
|
170
|
+
end
|
171
|
+
assert_equal "Committee: rel not implemented for OpenAPI", e.message
|
172
|
+
end
|
173
|
+
|
174
|
+
it "uses set #schema" do
|
175
|
+
assert_equal({ "title" => "input" }, @link.schema)
|
176
|
+
end
|
177
|
+
|
178
|
+
it "uses set #status_success" do
|
179
|
+
assert_equal 200, @link.status_success
|
180
|
+
end
|
181
|
+
|
182
|
+
it "uses set #target_schema" do
|
183
|
+
assert_equal({ "title" => "target" }, @link.target_schema)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
describe Committee::Drivers::OpenAPI2::ParameterSchemaBuilder do
|
188
|
+
before do
|
189
|
+
end
|
190
|
+
|
191
|
+
it "reflects a basic type into a schema" do
|
192
|
+
data = {
|
193
|
+
"parameters" => [
|
194
|
+
{
|
195
|
+
"name" => "limit",
|
196
|
+
"type" => "integer",
|
197
|
+
}
|
198
|
+
]
|
199
|
+
}
|
200
|
+
schema = call(data)
|
201
|
+
|
202
|
+
assert_equal ["limit"], schema.properties.keys
|
203
|
+
assert_equal [], schema.required
|
204
|
+
assert_equal ["integer"], schema.properties["limit"].type
|
205
|
+
end
|
206
|
+
|
207
|
+
it "reflects a required property into a schema" do
|
208
|
+
data = {
|
209
|
+
"parameters" => [
|
210
|
+
{
|
211
|
+
"name" => "limit",
|
212
|
+
"required" => true,
|
213
|
+
}
|
214
|
+
]
|
215
|
+
}
|
216
|
+
schema = call(data)
|
217
|
+
|
218
|
+
assert_equal ["limit"], schema.required
|
219
|
+
end
|
220
|
+
|
221
|
+
it "reflects an array with an items schema into a schema" do
|
222
|
+
data = {
|
223
|
+
"parameters" => [
|
224
|
+
{
|
225
|
+
"name" => "tags",
|
226
|
+
"type" => "array",
|
227
|
+
"items" => {
|
228
|
+
"type" => "string"
|
229
|
+
}
|
230
|
+
}
|
231
|
+
]
|
232
|
+
}
|
233
|
+
schema = call(data)
|
234
|
+
|
235
|
+
assert_equal ["array"], schema.properties["tags"].type
|
236
|
+
assert_equal({ "type" => "string" }, schema.properties["tags"].items)
|
237
|
+
end
|
238
|
+
|
239
|
+
it "requires that certain fields are present" do
|
240
|
+
data = {
|
241
|
+
"parameters" => [
|
242
|
+
{
|
243
|
+
}
|
244
|
+
]
|
245
|
+
}
|
246
|
+
e = assert_raises ArgumentError do
|
247
|
+
call(data)
|
248
|
+
end
|
249
|
+
assert_equal "Committee: no name section in link data.", e.message
|
250
|
+
end
|
251
|
+
|
252
|
+
def call(data)
|
253
|
+
Committee::Drivers::OpenAPI2::ParameterSchemaBuilder.new(data).call
|
254
|
+
end
|
255
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require_relative "test_helper"
|
2
|
+
|
3
|
+
describe Committee::Drivers do
|
4
|
+
DRIVERS = [
|
5
|
+
:hyper_schema,
|
6
|
+
:open_api_2,
|
7
|
+
].freeze
|
8
|
+
|
9
|
+
it "gets driver with .driver_from_name" do
|
10
|
+
DRIVERS.each do |name|
|
11
|
+
driver = Committee::Drivers.driver_from_name(name)
|
12
|
+
assert_kind_of Committee::Drivers::Driver, driver
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
it "raises an ArgumentError for an unknown driver with .driver_from_name" do
|
17
|
+
e = assert_raises(ArgumentError) do
|
18
|
+
Committee::Drivers.driver_from_name(:blueprint)
|
19
|
+
end
|
20
|
+
assert_equal %{Committee: unknown driver "blueprint".}, e.message
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe Committee::Drivers::Driver do
|
25
|
+
DRIVER_METHODS = {
|
26
|
+
:default_path_params => [],
|
27
|
+
:default_query_params => [],
|
28
|
+
:name => [],
|
29
|
+
:parse => [nil],
|
30
|
+
:schema_class => [],
|
31
|
+
}
|
32
|
+
|
33
|
+
it "has a set of abstract methods" do
|
34
|
+
driver = Committee::Drivers::Driver.new
|
35
|
+
DRIVER_METHODS.each do |name, args|
|
36
|
+
e = assert_raises do
|
37
|
+
driver.send(name, *args)
|
38
|
+
end
|
39
|
+
assert_equal "needs implementation", e.message,
|
40
|
+
"Incorrect error message while sending #{name}: #{e.message}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe Committee::Drivers::Schema do
|
46
|
+
SCHEMA_METHODS = {
|
47
|
+
:driver => [],
|
48
|
+
}
|
49
|
+
|
50
|
+
it "has a set of abstract methods" do
|
51
|
+
schema = Committee::Drivers::Schema.new
|
52
|
+
SCHEMA_METHODS.each do |name, args|
|
53
|
+
e = assert_raises do
|
54
|
+
schema.send(name, *args)
|
55
|
+
end
|
56
|
+
assert_equal "needs implementation", e.message,
|
57
|
+
"Incorrect error message while sending #{name}: #{e.message}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -7,8 +7,10 @@ describe Committee::Middleware::Base do
|
|
7
7
|
@app
|
8
8
|
end
|
9
9
|
|
10
|
-
it "accepts schema
|
11
|
-
@app = new_rack_app(
|
10
|
+
it "accepts just a schema object" do
|
11
|
+
@app = new_rack_app(
|
12
|
+
schema: hyper_schema
|
13
|
+
)
|
12
14
|
params = {
|
13
15
|
"name" => "cloudnasium"
|
14
16
|
}
|
@@ -17,9 +19,11 @@ describe Committee::Middleware::Base do
|
|
17
19
|
assert_equal 200, last_response.status
|
18
20
|
end
|
19
21
|
|
20
|
-
it "accepts schema
|
21
|
-
|
22
|
-
@app = new_rack_app(
|
22
|
+
it "accepts schema string (legacy behavior)" do
|
23
|
+
mock(Committee).warn_deprecated.with_any_args
|
24
|
+
@app = new_rack_app(
|
25
|
+
schema: JSON.dump(hyper_schema_data)
|
26
|
+
)
|
23
27
|
params = {
|
24
28
|
"name" => "cloudnasium"
|
25
29
|
}
|
@@ -28,6 +32,46 @@ describe Committee::Middleware::Base do
|
|
28
32
|
assert_equal 200, last_response.status
|
29
33
|
end
|
30
34
|
|
35
|
+
it "accepts schema hash (legacy behavior)" do
|
36
|
+
mock(Committee).warn_deprecated.with_any_args
|
37
|
+
@app = new_rack_app(
|
38
|
+
schema: hyper_schema_data
|
39
|
+
)
|
40
|
+
params = {
|
41
|
+
"name" => "cloudnasium"
|
42
|
+
}
|
43
|
+
header "Content-Type", "application/json"
|
44
|
+
post "/apps", JSON.generate(params)
|
45
|
+
assert_equal 200, last_response.status
|
46
|
+
end
|
47
|
+
|
48
|
+
it "accepts schema JsonSchema::Schema object (legacy behavior)" do
|
49
|
+
# Note we don't warn here because this is a recent deprecation and passing
|
50
|
+
# a schema object will not be a huge performance hit. We should probably
|
51
|
+
# start warning on the next version.
|
52
|
+
|
53
|
+
@app = new_rack_app(
|
54
|
+
schema: JsonSchema.parse!(hyper_schema_data)
|
55
|
+
)
|
56
|
+
params = {
|
57
|
+
"name" => "cloudnasium"
|
58
|
+
}
|
59
|
+
header "Content-Type", "application/json"
|
60
|
+
post "/apps", JSON.generate(params)
|
61
|
+
assert_equal 200, last_response.status
|
62
|
+
end
|
63
|
+
|
64
|
+
it "doesn't accept other schema types" do
|
65
|
+
@app = new_rack_app(
|
66
|
+
schema: 7,
|
67
|
+
)
|
68
|
+
e = assert_raises(ArgumentError) do
|
69
|
+
post "/apps"
|
70
|
+
end
|
71
|
+
assert_equal "Committee: schema expected to be a hash or an instance " +
|
72
|
+
"of Committee::Drivers::Schema.", e.message
|
73
|
+
end
|
74
|
+
|
31
75
|
private
|
32
76
|
|
33
77
|
def new_rack_app(options = {})
|
@@ -8,7 +8,7 @@ describe Committee::Middleware::RequestValidation do
|
|
8
8
|
end
|
9
9
|
|
10
10
|
it "passes through a valid request" do
|
11
|
-
@app = new_rack_app
|
11
|
+
@app = new_rack_app(schema: hyper_schema)
|
12
12
|
params = {
|
13
13
|
"name" => "cloudnasium"
|
14
14
|
}
|
@@ -18,7 +18,7 @@ describe Committee::Middleware::RequestValidation do
|
|
18
18
|
end
|
19
19
|
|
20
20
|
it "detects an invalid request" do
|
21
|
-
@app = new_rack_app
|
21
|
+
@app = new_rack_app(schema: hyper_schema)
|
22
22
|
header "Content-Type", "application/json"
|
23
23
|
params = {
|
24
24
|
"name" => 1
|
@@ -29,7 +29,7 @@ describe Committee::Middleware::RequestValidation do
|
|
29
29
|
end
|
30
30
|
|
31
31
|
it "rescues JSON errors" do
|
32
|
-
@app = new_rack_app
|
32
|
+
@app = new_rack_app(schema: hyper_schema)
|
33
33
|
header "Content-Type", "application/json"
|
34
34
|
post "/apps", "{x:y}"
|
35
35
|
assert_equal 400, last_response.status
|
@@ -37,7 +37,7 @@ describe Committee::Middleware::RequestValidation do
|
|
37
37
|
end
|
38
38
|
|
39
39
|
it "takes a prefix" do
|
40
|
-
@app = new_rack_app(prefix: "/v1")
|
40
|
+
@app = new_rack_app(prefix: "/v1", schema: hyper_schema)
|
41
41
|
params = {
|
42
42
|
"name" => "cloudnasium"
|
43
43
|
}
|
@@ -47,37 +47,26 @@ describe Committee::Middleware::RequestValidation do
|
|
47
47
|
end
|
48
48
|
|
49
49
|
it "ignores paths outside the prefix" do
|
50
|
-
@app = new_rack_app(prefix: "/v1")
|
50
|
+
@app = new_rack_app(prefix: "/v1", schema: hyper_schema)
|
51
51
|
header "Content-Type", "text/html"
|
52
52
|
get "/hello"
|
53
53
|
assert_equal 200, last_response.status
|
54
54
|
end
|
55
55
|
|
56
|
-
it "warns when sending a deprecated string" do
|
57
|
-
mock(Committee).warn_deprecated.with_any_args
|
58
|
-
@app = new_rack_app(schema: File.read("./test/data/schema.json"))
|
59
|
-
params = {
|
60
|
-
"name" => "cloudnasium"
|
61
|
-
}
|
62
|
-
header "Content-Type", "application/json"
|
63
|
-
post "/apps", JSON.generate(params)
|
64
|
-
assert_equal 200, last_response.status
|
65
|
-
end
|
66
|
-
|
67
56
|
it "routes to paths not in schema" do
|
68
|
-
@app = new_rack_app
|
57
|
+
@app = new_rack_app(schema: hyper_schema)
|
69
58
|
get "/not-a-resource"
|
70
59
|
assert_equal 200, last_response.status
|
71
60
|
end
|
72
61
|
|
73
62
|
it "doesn't route to paths not in schema when in strict mode" do
|
74
|
-
@app = new_rack_app(strict: true)
|
63
|
+
@app = new_rack_app(schema: hyper_schema, strict: true)
|
75
64
|
get "/not-a-resource"
|
76
65
|
assert_equal 404, last_response.status
|
77
66
|
end
|
78
67
|
|
79
68
|
it "optionally raises an error" do
|
80
|
-
@app = new_rack_app(raise: true)
|
69
|
+
@app = new_rack_app(raise: true, schema: hyper_schema)
|
81
70
|
header "Content-Type", "application/json"
|
82
71
|
assert_raises(Committee::InvalidRequest) do
|
83
72
|
post "/apps", "{x:y}"
|
@@ -85,7 +74,7 @@ describe Committee::Middleware::RequestValidation do
|
|
85
74
|
end
|
86
75
|
|
87
76
|
it "optionally skip content_type check" do
|
88
|
-
@app = new_rack_app(check_content_type: false)
|
77
|
+
@app = new_rack_app(check_content_type: false, schema: hyper_schema)
|
89
78
|
params = {
|
90
79
|
"name" => "cloudnasium"
|
91
80
|
}
|
@@ -95,26 +84,51 @@ describe Committee::Middleware::RequestValidation do
|
|
95
84
|
end
|
96
85
|
|
97
86
|
it "optionally coerces query params" do
|
98
|
-
@app = new_rack_app(coerce_query_params: true)
|
87
|
+
@app = new_rack_app(coerce_query_params: true, schema: hyper_schema)
|
99
88
|
header "Content-Type", "application/json"
|
100
89
|
get "/search/apps", {"per_page" => "10", "query" => "cloudnasium"}
|
101
90
|
assert_equal 200, last_response.status
|
102
91
|
end
|
103
92
|
|
104
93
|
it "still raises an error if query param coercion is not possible" do
|
105
|
-
@app = new_rack_app(coerce_query_params: true)
|
94
|
+
@app = new_rack_app(coerce_query_params: true, schema: hyper_schema)
|
106
95
|
header "Content-Type", "application/json"
|
107
96
|
get "/search/apps", {"per_page" => "foo", "query" => "cloudnasium"}
|
108
97
|
assert_equal 400, last_response.status
|
109
98
|
assert_match /invalid request/i, last_response.body
|
110
99
|
end
|
111
100
|
|
101
|
+
it "passes through a valid request for OpenAPI" do
|
102
|
+
@app = new_rack_app(schema: open_api_2_schema)
|
103
|
+
get "/api/pets?limit=3"
|
104
|
+
assert_equal 200, last_response.status
|
105
|
+
end
|
106
|
+
|
107
|
+
it "detects an invalid request for OpenAPI" do
|
108
|
+
@app = new_rack_app(schema: open_api_2_schema)
|
109
|
+
get "/api/pets?limit=foo"
|
110
|
+
assert_equal 400, last_response.status
|
111
|
+
assert_match /invalid request/i, last_response.body
|
112
|
+
end
|
113
|
+
|
114
|
+
it "passes through a valid request for OpenAPI including path parameters" do
|
115
|
+
@app = new_rack_app(schema: open_api_2_schema)
|
116
|
+
# not that ID is expect to be an integer
|
117
|
+
get "/api/pets/123"
|
118
|
+
assert_equal 200, last_response.status
|
119
|
+
end
|
120
|
+
|
121
|
+
it "detects an invalid request for OpenAPI including path parameters" do
|
122
|
+
@app = new_rack_app(schema: open_api_2_schema)
|
123
|
+
# not that ID is expect to be an integer
|
124
|
+
get "/api/pets/not-integer"
|
125
|
+
assert_equal 400, last_response.status
|
126
|
+
assert_match /invalid request/i, last_response.body
|
127
|
+
end
|
128
|
+
|
112
129
|
private
|
113
130
|
|
114
131
|
def new_rack_app(options = {})
|
115
|
-
options = {
|
116
|
-
schema: JSON.parse(File.read("./test/data/schema.json"))
|
117
|
-
}.merge(options)
|
118
132
|
Rack::Builder.new {
|
119
133
|
use Committee::Middleware::RequestValidation, options
|
120
134
|
run lambda { |_|
|