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
@@ -8,26 +8,34 @@ describe Committee::Middleware::ResponseValidation do
|
|
8
8
|
end
|
9
9
|
|
10
10
|
it "passes through a valid response" do
|
11
|
-
@app = new_rack_app(JSON.generate([ValidApp]))
|
11
|
+
@app = new_rack_app(JSON.generate([ValidApp]), {}, schema: hyper_schema)
|
12
12
|
get "/apps"
|
13
13
|
assert_equal 200, last_response.status
|
14
14
|
end
|
15
15
|
|
16
|
-
it "detects
|
17
|
-
@app = new_rack_app("")
|
16
|
+
it "detects a response invalid due to schema" do
|
17
|
+
@app = new_rack_app("{}", {}, schema: hyper_schema)
|
18
|
+
get "/apps"
|
19
|
+
assert_equal 500, last_response.status
|
20
|
+
assert_match /{} is not an array/i, last_response.body
|
21
|
+
end
|
22
|
+
|
23
|
+
it "detects a response invalid due to not being JSON" do
|
24
|
+
@app = new_rack_app("", {}, schema: hyper_schema)
|
18
25
|
get "/apps"
|
19
26
|
assert_equal 500, last_response.status
|
20
27
|
assert_match /valid JSON/i, last_response.body
|
21
28
|
end
|
22
29
|
|
23
30
|
it "ignores a non-2xx invalid response" do
|
24
|
-
@app = new_rack_app("[]", {}, app_status: 404)
|
31
|
+
@app = new_rack_app("[]", {}, app_status: 404, schema: hyper_schema)
|
25
32
|
get "/apps"
|
26
33
|
assert_equal 404, last_response.status
|
27
34
|
end
|
28
35
|
|
29
36
|
it "optionally validates non-2xx invalid responses" do
|
30
|
-
@app = new_rack_app("", {},
|
37
|
+
@app = new_rack_app("", {}, app_status: 404, validate_errors: true,
|
38
|
+
schema: hyper_schema)
|
31
39
|
|
32
40
|
get "/apps"
|
33
41
|
assert_equal 500, last_response.status
|
@@ -35,48 +43,52 @@ describe Committee::Middleware::ResponseValidation do
|
|
35
43
|
end
|
36
44
|
|
37
45
|
it "passes through a 204 (no content) response" do
|
38
|
-
@app = new_rack_app("", {}, app_status: 204)
|
46
|
+
@app = new_rack_app("", {}, app_status: 204, schema: hyper_schema)
|
39
47
|
get "/apps"
|
40
48
|
assert_equal 204, last_response.status
|
41
49
|
end
|
42
50
|
|
43
51
|
it "rescues JSON errors" do
|
44
|
-
@app = new_rack_app("[{x:y}]")
|
52
|
+
@app = new_rack_app("[{x:y}]", {}, schema: hyper_schema)
|
45
53
|
get "/apps"
|
46
54
|
assert_equal 500, last_response.status
|
47
55
|
assert_match /valid json/i, last_response.body
|
48
56
|
end
|
49
57
|
|
50
58
|
it "takes a prefix" do
|
51
|
-
@app = new_rack_app(JSON.generate([ValidApp]), {}, prefix: "/v1"
|
59
|
+
@app = new_rack_app(JSON.generate([ValidApp]), {}, prefix: "/v1",
|
60
|
+
schema: hyper_schema)
|
52
61
|
get "/v1/apps"
|
53
62
|
assert_equal 200, last_response.status
|
54
63
|
end
|
55
64
|
|
56
|
-
it "warns when sending a deprecated string" do
|
57
|
-
mock(Committee).warn_deprecated.with_any_args
|
58
|
-
@app = new_rack_app(JSON.generate([ValidApp]), {},
|
59
|
-
schema: File.read("./test/data/schema.json"))
|
60
|
-
get "/apps"
|
61
|
-
assert_equal 200, last_response.status
|
62
|
-
end
|
63
|
-
|
64
65
|
it "rescues JSON errors" do
|
65
|
-
@app = new_rack_app("[{x:y}]", {}, raise: true)
|
66
|
+
@app = new_rack_app("[{x:y}]", {}, raise: true, schema: hyper_schema)
|
66
67
|
assert_raises(Committee::InvalidResponse) do
|
67
68
|
get "/apps"
|
68
69
|
end
|
69
70
|
end
|
70
71
|
|
72
|
+
it "passes through a valid response for OpenAPI" do
|
73
|
+
@app = new_rack_app(JSON.generate([ValidPet]), {},
|
74
|
+
schema: open_api_2_schema)
|
75
|
+
get "/api/pets"
|
76
|
+
assert_equal 200, last_response.status
|
77
|
+
end
|
78
|
+
|
79
|
+
it "detects an invalid response for OpenAPI" do
|
80
|
+
@app = new_rack_app("", {}, schema: open_api_2_schema)
|
81
|
+
get "/api/pets"
|
82
|
+
assert_equal 500, last_response.status
|
83
|
+
assert_match /valid JSON/i, last_response.body
|
84
|
+
end
|
85
|
+
|
71
86
|
private
|
72
87
|
|
73
88
|
def new_rack_app(response, headers = {}, options = {})
|
74
89
|
headers = {
|
75
90
|
"Content-Type" => "application/json"
|
76
91
|
}.merge(headers)
|
77
|
-
options = {
|
78
|
-
schema: JSON.parse(File.read("./test/data/schema.json"))
|
79
|
-
}.merge(options)
|
80
92
|
Rack::Builder.new {
|
81
93
|
use Committee::Middleware::ResponseValidation, options
|
82
94
|
run lambda { |_|
|
@@ -8,7 +8,7 @@ describe Committee::Middleware::Stub do
|
|
8
8
|
end
|
9
9
|
|
10
10
|
it "responds with a stubbed response" do
|
11
|
-
@app = new_rack_app
|
11
|
+
@app = new_rack_app(schema: hyper_schema)
|
12
12
|
get "/apps/heroku-api"
|
13
13
|
assert_equal 200, last_response.status
|
14
14
|
data = JSON.parse(last_response.body)
|
@@ -16,13 +16,13 @@ describe Committee::Middleware::Stub do
|
|
16
16
|
end
|
17
17
|
|
18
18
|
it "responds with 201 on create actions" do
|
19
|
-
@app = new_rack_app
|
19
|
+
@app = new_rack_app(schema: hyper_schema)
|
20
20
|
post "/apps"
|
21
21
|
assert_equal 201, last_response.status
|
22
22
|
end
|
23
23
|
|
24
24
|
it "optionally calls into application" do
|
25
|
-
@app = new_rack_app(call: true)
|
25
|
+
@app = new_rack_app(call: true, schema: hyper_schema)
|
26
26
|
get "/apps/heroku-api"
|
27
27
|
assert_equal 200, last_response.status
|
28
28
|
assert_equal ValidApp,
|
@@ -30,37 +30,61 @@ describe Committee::Middleware::Stub do
|
|
30
30
|
end
|
31
31
|
|
32
32
|
it "optionally returns the application's response" do
|
33
|
-
@app = new_rack_app(call: true, suppress: true)
|
33
|
+
@app = new_rack_app(call: true, schema: hyper_schema, suppress: true)
|
34
34
|
get "/apps/heroku-api"
|
35
35
|
assert_equal 429, last_response.status
|
36
36
|
assert_equal ValidApp,
|
37
37
|
JSON.parse(last_response.headers["Committee-Response"])
|
38
|
-
|
38
|
+
assert_equal "", last_response.body
|
39
39
|
end
|
40
40
|
|
41
41
|
it "takes a prefix" do
|
42
|
-
@app = new_rack_app(prefix: "/v1")
|
42
|
+
@app = new_rack_app(prefix: "/v1", schema: hyper_schema)
|
43
43
|
get "/v1/apps/heroku-api"
|
44
44
|
assert_equal 200, last_response.status
|
45
45
|
data = JSON.parse(last_response.body)
|
46
46
|
assert_equal ValidApp.keys.sort, data.keys.sort
|
47
47
|
end
|
48
48
|
|
49
|
-
it "
|
50
|
-
|
51
|
-
@app = new_rack_app(schema:
|
49
|
+
it "allows the stub's response to be replaced" do
|
50
|
+
response = { replaced: true }
|
51
|
+
@app = new_rack_app(call: true, response: response, schema: hyper_schema)
|
52
52
|
get "/apps/heroku-api"
|
53
53
|
assert_equal 200, last_response.status
|
54
|
+
assert_equal response, JSON.parse(last_response.body, symbolize_names: true)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "responds with a stubbed response for OpenAPI" do
|
58
|
+
@app = new_rack_app(schema: open_api_2_schema)
|
59
|
+
get "/api/pets/fido"
|
60
|
+
assert_equal 200, last_response.status
|
54
61
|
data = JSON.parse(last_response.body)
|
55
|
-
assert_equal
|
62
|
+
assert_equal ValidPet.keys.sort, data.keys.sort
|
56
63
|
end
|
57
64
|
|
58
|
-
it "
|
59
|
-
|
60
|
-
|
65
|
+
it "calls into app for links that are undefined" do
|
66
|
+
@app = new_rack_app(call: false, schema: hyper_schema)
|
67
|
+
post "/foos"
|
68
|
+
assert_equal 429, last_response.status
|
69
|
+
end
|
70
|
+
|
71
|
+
it "caches the response if called multiple times" do
|
72
|
+
cache = {}
|
73
|
+
@app = new_rack_app(cache: cache, schema: hyper_schema)
|
74
|
+
|
61
75
|
get "/apps/heroku-api"
|
62
76
|
assert_equal 200, last_response.status
|
63
|
-
|
77
|
+
|
78
|
+
data = cache[cache.first[0]]
|
79
|
+
assert_equal ValidApp.keys.sort, data.keys.sort
|
80
|
+
|
81
|
+
# replace what we have in the cache
|
82
|
+
cache[cache.first[0]] = { "cached" => true }
|
83
|
+
|
84
|
+
get "/apps/heroku-api"
|
85
|
+
assert_equal 200, last_response.status
|
86
|
+
data = JSON.parse(last_response.body)
|
87
|
+
assert_equal({ "cached" => true }, data)
|
64
88
|
end
|
65
89
|
|
66
90
|
private
|
@@ -68,15 +92,22 @@ describe Committee::Middleware::Stub do
|
|
68
92
|
def new_rack_app(options = {})
|
69
93
|
response = options.delete(:response)
|
70
94
|
suppress = options.delete(:suppress)
|
71
|
-
options = {
|
72
|
-
schema: JSON.parse(File.read("./test/data/schema.json"))
|
73
|
-
}.merge(options)
|
74
95
|
Rack::Builder.new {
|
75
96
|
use Committee::Middleware::Stub, options
|
76
97
|
run lambda { |env|
|
77
|
-
|
78
|
-
|
98
|
+
if response
|
99
|
+
env["committee.response"] = response
|
100
|
+
end
|
101
|
+
|
102
|
+
headers = {}
|
103
|
+
if res = env["committee.response"]
|
104
|
+
headers.merge!({
|
105
|
+
"Committee-Response" => JSON.generate(res)
|
106
|
+
})
|
107
|
+
end
|
108
|
+
|
79
109
|
env["committee.suppress"] = suppress
|
110
|
+
|
80
111
|
[429, headers, []]
|
81
112
|
}
|
82
113
|
}
|
@@ -123,4 +123,14 @@ describe Committee::RequestUnpacker do
|
|
123
123
|
params = Committee::RequestUnpacker.new(request).call
|
124
124
|
assert_equal({}, params)
|
125
125
|
end
|
126
|
+
|
127
|
+
# this is mostly here for line coverage
|
128
|
+
it "unpacks JSON containing an array" do
|
129
|
+
env = {
|
130
|
+
"rack.input" => StringIO.new('{"x":[]}'),
|
131
|
+
}
|
132
|
+
request = Rack::Request.new(env)
|
133
|
+
params = Committee::RequestUnpacker.new(request).call
|
134
|
+
assert_equal({ "x" => [] }, params)
|
135
|
+
end
|
126
136
|
end
|
@@ -4,8 +4,7 @@ require "stringio"
|
|
4
4
|
|
5
5
|
describe Committee::RequestValidator do
|
6
6
|
before do
|
7
|
-
@schema =
|
8
|
-
JsonSchema.parse!(JSON.parse(File.read("./test/data/schema.json")))
|
7
|
+
@schema = JsonSchema.parse!(hyper_schema_data)
|
9
8
|
@schema.expand_references!
|
10
9
|
# POST /apps/:id
|
11
10
|
@link = @link = @schema.properties["app"].links[0]
|
@@ -98,6 +97,8 @@ describe Committee::RequestValidator do
|
|
98
97
|
private
|
99
98
|
|
100
99
|
def call(data, options={})
|
101
|
-
|
100
|
+
# hyper-schema link should be dropped into driver wrapper before it's used
|
101
|
+
link = Committee::Drivers::HyperSchema::Link.new(@link)
|
102
|
+
Committee::RequestValidator.new(link, options).call(@request, data)
|
102
103
|
end
|
103
104
|
end
|
@@ -2,8 +2,7 @@ require_relative "test_helper"
|
|
2
2
|
|
3
3
|
describe Committee::ResponseGenerator do
|
4
4
|
before do
|
5
|
-
@schema =
|
6
|
-
JsonSchema.parse!(JSON.parse(File.read("./test/data/schema.json")))
|
5
|
+
@schema = JsonSchema.parse!(hyper_schema_data)
|
7
6
|
@schema.expand_references!
|
8
7
|
# GET /apps/:id
|
9
8
|
@get_link = @link = @schema.properties["app"].links[2]
|
@@ -23,16 +22,26 @@ describe Committee::ResponseGenerator do
|
|
23
22
|
|
24
23
|
it "wraps list data in an array" do
|
25
24
|
@link = @list_link
|
25
|
+
|
26
|
+
@link.rel = nil
|
27
|
+
|
26
28
|
data = call
|
27
29
|
assert data.is_a?(Array)
|
28
30
|
end
|
29
31
|
|
30
|
-
it "wraps list data in an array" do
|
32
|
+
it "wraps list data tagged with rel 'instances' in an array" do
|
31
33
|
@link = @list_link
|
32
34
|
|
33
|
-
|
35
|
+
# forces the link to use `parent`
|
36
|
+
@link.target_schema = nil
|
34
37
|
|
35
38
|
data = call
|
39
|
+
|
40
|
+
# We're testing for legacy behavior here: even without a `targetSchema` as
|
41
|
+
# long as `rel` is set to `instances` we still wrap the the result in an
|
42
|
+
# array.
|
43
|
+
assert_equal "instances", @list_link.rel
|
44
|
+
|
36
45
|
assert data.is_a?(Array)
|
37
46
|
end
|
38
47
|
|
@@ -49,13 +58,48 @@ describe Committee::ResponseGenerator do
|
|
49
58
|
end
|
50
59
|
|
51
60
|
expected = <<-eos.gsub(/\n +/, "").strip
|
52
|
-
At "
|
61
|
+
At "get /apps/{(%23%2Fdefinitions%2Fapp%2Fdefinitions%2Fname)}"
|
62
|
+
"#/definitions/app/properties/maintenance": no "example" attribute and
|
53
63
|
"null" is not allowed; don't know how to generate property.
|
54
64
|
eos
|
55
65
|
assert_equal expected, e.message
|
56
66
|
end
|
57
67
|
|
68
|
+
it "generates basic types" do
|
69
|
+
link = Committee::Drivers::OpenAPI2::Link.new
|
70
|
+
link.target_schema = JsonSchema::Schema.new
|
71
|
+
|
72
|
+
link.target_schema.type = ["integer"]
|
73
|
+
assert_equal 0, Committee::ResponseGenerator.new.call(link)
|
74
|
+
|
75
|
+
link.target_schema.type = ["null"]
|
76
|
+
assert_equal nil, Committee::ResponseGenerator.new.call(link)
|
77
|
+
|
78
|
+
link.target_schema.type = ["string"]
|
79
|
+
assert_equal "", Committee::ResponseGenerator.new.call(link)
|
80
|
+
end
|
81
|
+
|
82
|
+
it "prefers an example to a built-in value" do
|
83
|
+
link = Committee::Drivers::OpenAPI2::Link.new
|
84
|
+
link.target_schema = JsonSchema::Schema.new
|
85
|
+
|
86
|
+
link.target_schema.data = { "example" => 123 }
|
87
|
+
link.target_schema.type = ["integer"]
|
88
|
+
|
89
|
+
assert_equal 123, Committee::ResponseGenerator.new.call(link)
|
90
|
+
end
|
91
|
+
|
92
|
+
it "prefers non-null types to null types" do
|
93
|
+
link = Committee::Drivers::OpenAPI2::Link.new
|
94
|
+
link.target_schema = JsonSchema::Schema.new
|
95
|
+
|
96
|
+
link.target_schema.type = ["null", "integer"]
|
97
|
+
assert_equal 0, Committee::ResponseGenerator.new.call(link)
|
98
|
+
end
|
99
|
+
|
58
100
|
def call
|
59
|
-
|
101
|
+
# hyper-schema link should be dropped into driver wrapper before it's used
|
102
|
+
link = Committee::Drivers::HyperSchema::Link.new(@link)
|
103
|
+
Committee::ResponseGenerator.new.call(link)
|
60
104
|
end
|
61
105
|
end
|
@@ -7,8 +7,7 @@ describe Committee::ResponseValidator do
|
|
7
7
|
"Content-Type" => "application/json"
|
8
8
|
}
|
9
9
|
@data = ValidApp.dup
|
10
|
-
@schema =
|
11
|
-
JsonSchema.parse!(JSON.parse(File.read("./test/data/schema.json")))
|
10
|
+
@schema = JsonSchema.parse!(hyper_schema_data)
|
12
11
|
@schema.expand_references!
|
13
12
|
# GET /apps/:id
|
14
13
|
@get_link = @link = @schema.properties["app"].links[2]
|
@@ -37,9 +36,33 @@ describe Committee::ResponseValidator do
|
|
37
36
|
call
|
38
37
|
end
|
39
38
|
|
40
|
-
it "
|
39
|
+
it "passes through a valid list response for for rel instances links" do
|
41
40
|
@link = @list_link
|
41
|
+
|
42
|
+
# forces the link to use `parent`
|
42
43
|
@link.target_schema = nil
|
44
|
+
|
45
|
+
# We're testing for legacy behavior here: even without a `targetSchema` as
|
46
|
+
# long as `rel` is set to `instances` we still wrap the the result in an
|
47
|
+
# array.
|
48
|
+
assert_equal "instances", @link.rel
|
49
|
+
|
50
|
+
@data = [@data]
|
51
|
+
@link = @list_link
|
52
|
+
call
|
53
|
+
end
|
54
|
+
|
55
|
+
it "detects an improperly formatted list response for rel instances link" do
|
56
|
+
@link = @list_link
|
57
|
+
|
58
|
+
# forces the link to use `parent`
|
59
|
+
@link.target_schema = nil
|
60
|
+
|
61
|
+
# We're testing for legacy behavior here: even without a `targetSchema` as
|
62
|
+
# long as `rel` is set to `instances` we still wrap the the result in an
|
63
|
+
# array.
|
64
|
+
assert_equal "instances", @link.rel
|
65
|
+
|
43
66
|
e = assert_raises(Committee::InvalidResponse) { call }
|
44
67
|
message = "List endpoints must return an array of objects."
|
45
68
|
assert_equal message, e.message
|
@@ -76,6 +99,8 @@ describe Committee::ResponseValidator do
|
|
76
99
|
private
|
77
100
|
|
78
101
|
def call
|
79
|
-
|
102
|
+
# hyper-schema link should be dropped into driver wrapper before it's used
|
103
|
+
link = Committee::Drivers::HyperSchema::Link.new(@link)
|
104
|
+
Committee::ResponseValidator.new(link).call(@status, @headers, @data)
|
80
105
|
end
|
81
106
|
end
|
data/test/router_test.rb
CHANGED
@@ -2,37 +2,64 @@ require_relative "test_helper"
|
|
2
2
|
|
3
3
|
describe Committee::Router do
|
4
4
|
it "builds routes without parameters" do
|
5
|
-
|
5
|
+
link, _ = hyper_schema_router.find_link("GET", "/apps")
|
6
|
+
refute_nil link
|
6
7
|
end
|
7
8
|
|
8
9
|
it "builds routes with parameters" do
|
9
|
-
|
10
|
+
link, _ = hyper_schema_router.find_link("GET", "/apps/123")
|
11
|
+
refute_nil link
|
10
12
|
end
|
11
13
|
|
12
14
|
it "doesn't match anything on a /" do
|
13
|
-
|
15
|
+
link, _ = hyper_schema_router.find_link("GET", "/")
|
16
|
+
assert_nil link
|
14
17
|
end
|
15
18
|
|
16
19
|
it "takes a prefix" do
|
17
20
|
# this is a sociopathic example
|
18
|
-
|
21
|
+
link, _ = hyper_schema_router(prefix: "/kpi").find_link("GET", "/kpi/apps/123")
|
22
|
+
refute_nil link
|
19
23
|
end
|
20
24
|
|
21
25
|
it "includes all paths without a prefix" do
|
22
|
-
|
23
|
-
|
26
|
+
link, _ = hyper_schema_router.includes?("/")
|
27
|
+
refute_nil link
|
28
|
+
|
29
|
+
link, _ = hyper_schema_router.includes?("/apps")
|
30
|
+
refute_nil link
|
24
31
|
end
|
25
32
|
|
26
33
|
it "only includes the prefix path with a prefix" do
|
27
|
-
|
28
|
-
|
29
|
-
|
34
|
+
link, _ = hyper_schema_router(prefix: "/kpi").includes?("/")
|
35
|
+
assert_nil link
|
36
|
+
|
37
|
+
link, _ = hyper_schema_router(prefix: "/kpi").includes?("/kpi")
|
38
|
+
refute_nil link
|
39
|
+
|
40
|
+
link, _ = hyper_schema_router(prefix: "/kpi").includes?("/kpi/apps")
|
41
|
+
refute_nil link
|
42
|
+
end
|
43
|
+
|
44
|
+
it "provides named parameters" do
|
45
|
+
link, param_matches = open_api_2_router.find_link("GET", "/api/pets/fido")
|
46
|
+
refute_nil link
|
47
|
+
assert_equal({ "id" => "fido" }, param_matches)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "doesn't provide named parameters where none are available" do
|
51
|
+
link, param_matches = open_api_2_router.find_link("GET", "/api/pets")
|
52
|
+
refute_nil link
|
53
|
+
assert_equal({}, param_matches)
|
54
|
+
end
|
55
|
+
|
56
|
+
def hyper_schema_router(options = {})
|
57
|
+
schema = Committee::Drivers::HyperSchema.new.parse(hyper_schema_data)
|
58
|
+
Committee::Router.new(schema, options)
|
30
59
|
end
|
31
60
|
|
32
|
-
def
|
33
|
-
|
34
|
-
schema = JsonSchema.parse!(data)
|
35
|
-
schema.expand_references!
|
61
|
+
def open_api_2_router(options = {})
|
62
|
+
schema = Committee::Drivers::OpenAPI2.new.parse(open_api_2_data)
|
36
63
|
Committee::Router.new(schema, options)
|
37
64
|
end
|
38
65
|
end
|
@@ -1,9 +1,8 @@
|
|
1
1
|
require_relative "test_helper"
|
2
2
|
|
3
|
-
describe Committee::
|
3
|
+
describe Committee::StringParamsCoercer do
|
4
4
|
before do
|
5
|
-
@schema =
|
6
|
-
JsonSchema.parse!(JSON.parse(File.read("./test/data/schema.json")))
|
5
|
+
@schema = JsonSchema.parse!(hyper_schema_data)
|
7
6
|
@schema.expand_references!
|
8
7
|
# GET /search/apps
|
9
8
|
@link = @link = @schema.properties["app"].links[5]
|
@@ -65,6 +64,6 @@ describe Committee::QueryParamsCoercer do
|
|
65
64
|
private
|
66
65
|
|
67
66
|
def call(data)
|
68
|
-
Committee::
|
67
|
+
Committee::StringParamsCoercer.new(data, @link.schema).call
|
69
68
|
end
|
70
69
|
end
|
data/test/test/methods_test.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require_relative "../test_helper"
|
2
2
|
|
3
|
-
describe Committee::
|
3
|
+
describe Committee::Test::Methods do
|
4
4
|
include Committee::Test::Methods
|
5
5
|
include Rack::Test::Methods
|
6
6
|
|
@@ -8,8 +8,16 @@ describe Committee::Middleware::Stub do
|
|
8
8
|
@app
|
9
9
|
end
|
10
10
|
|
11
|
-
def
|
12
|
-
|
11
|
+
def committee_schema
|
12
|
+
hyper_schema
|
13
|
+
end
|
14
|
+
|
15
|
+
before do
|
16
|
+
# This is a little icky, but the test methods will cache router and schema
|
17
|
+
# values between tests. This makes sense in real life, but is harmful for
|
18
|
+
# our purposes here in testing the module.
|
19
|
+
@committee_router = nil
|
20
|
+
@committee_schema = nil
|
13
21
|
end
|
14
22
|
|
15
23
|
describe "#assert_schema_content_type" do
|
@@ -35,9 +43,40 @@ describe Committee::Middleware::Stub do
|
|
35
43
|
assert_match /response header must be set to/i, e.message
|
36
44
|
end
|
37
45
|
|
38
|
-
it "
|
39
|
-
|
46
|
+
it "accepts schema string (legacy behavior)" do
|
47
|
+
mock(Committee).warn_deprecated.with_any_args
|
48
|
+
|
49
|
+
stub(self).committee_schema { nil }
|
50
|
+
stub(self).schema_contents { JSON.dump(hyper_schema_data) }
|
51
|
+
|
52
|
+
@app = new_rack_app(JSON.generate([ValidApp]))
|
53
|
+
get "/apps"
|
54
|
+
assert_schema_conform
|
55
|
+
end
|
56
|
+
|
57
|
+
it "accepts schema hash (legacy behavior)" do
|
40
58
|
mock(Committee).warn_deprecated.with_any_args
|
59
|
+
|
60
|
+
stub(self).committee_schema { nil }
|
61
|
+
stub(self).schema_contents { hyper_schema_data }
|
62
|
+
|
63
|
+
@app = new_rack_app(JSON.generate([ValidApp]))
|
64
|
+
get "/apps"
|
65
|
+
assert_schema_conform
|
66
|
+
end
|
67
|
+
|
68
|
+
it "accepts schema JsonSchema::Schema object (legacy behavior)" do
|
69
|
+
# Note we don't warn here because this is a recent deprecation and
|
70
|
+
# passing a schema object will not be a huge performance hit. We should
|
71
|
+
# probably start warning on the next version.
|
72
|
+
|
73
|
+
stub(self).committee_schema { nil }
|
74
|
+
stub(self).schema_contents do
|
75
|
+
schema = JsonSchema.parse!(hyper_schema_data)
|
76
|
+
schema.expand_references!
|
77
|
+
schema
|
78
|
+
end
|
79
|
+
|
41
80
|
@app = new_rack_app(JSON.generate([ValidApp]))
|
42
81
|
get "/apps"
|
43
82
|
assert_schema_conform
|
data/test/test_helper.rb
CHANGED
@@ -1,13 +1,71 @@
|
|
1
|
+
if RUBY_VERSION >= '2.0.0'
|
2
|
+
require 'simplecov'
|
3
|
+
|
4
|
+
SimpleCov.start do
|
5
|
+
# We do our utmost to test our executables by modularizing them into
|
6
|
+
# testable pieces, but testing them to completion is nearly impossible as
|
7
|
+
# far as I can tell, so include them in our tests but don't calculate
|
8
|
+
# coverage.
|
9
|
+
add_filter "/bin/"
|
10
|
+
|
11
|
+
add_filter "/test/"
|
12
|
+
|
13
|
+
# This library has a pretty modest number of lines, so let's try to stick
|
14
|
+
# to a 100% coverage target for a while and see what happens.
|
15
|
+
minimum_coverage 100
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
1
19
|
require "minitest"
|
2
20
|
require "minitest/spec"
|
3
21
|
require "minitest/autorun"
|
4
|
-
#require "pry-rescue/minitest"
|
5
22
|
require "rack/test"
|
6
23
|
require "rr"
|
7
24
|
|
8
25
|
require_relative "../lib/committee"
|
9
26
|
|
27
|
+
# The OpenAPI sample specification provided directly from the organization uses
|
28
|
+
# a couple custom "format" values for JSON schema, namely "int32" and "int64".
|
29
|
+
# Provide basic definitions for them here so that we don't error when trying to
|
30
|
+
# parse the sample.
|
31
|
+
JsonSchema.configure do |c|
|
32
|
+
c.register_format 'int32', ->(data) {}
|
33
|
+
c.register_format 'int64', ->(data) {}
|
34
|
+
end
|
35
|
+
|
36
|
+
# For our hyper-schema example.
|
10
37
|
ValidApp = {
|
11
38
|
"maintenance" => false,
|
12
39
|
"name" => "example",
|
13
40
|
}.freeze
|
41
|
+
|
42
|
+
# For our OpenAPI example.
|
43
|
+
ValidPet = {
|
44
|
+
"id" => 123,
|
45
|
+
"name" => "example",
|
46
|
+
"tag" => "tag-123",
|
47
|
+
}.freeze
|
48
|
+
|
49
|
+
def hyper_schema
|
50
|
+
@hyper_schema ||= begin
|
51
|
+
driver = Committee::Drivers::HyperSchema.new
|
52
|
+
driver.parse(hyper_schema_data)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def open_api_2_schema
|
57
|
+
@open_api_2_schema ||= begin
|
58
|
+
driver = Committee::Drivers::OpenAPI2.new
|
59
|
+
driver.parse(open_api_2_data)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Don't cache this because we'll often manipulate the created hash in tests.
|
64
|
+
def hyper_schema_data
|
65
|
+
JSON.parse(File.read("./test/data/hyperschema/paas.json"))
|
66
|
+
end
|
67
|
+
|
68
|
+
# Don't cache this because we'll often manipulate the created hash in tests.
|
69
|
+
def open_api_2_data
|
70
|
+
JSON.parse(File.read("./test/data/openapi2/petstore-expanded.json"))
|
71
|
+
end
|