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
@@ -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
|