committee 1.15.0 → 2.0.0.pre
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 +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 { |_|
|