committee 0.4.2 → 0.4.3
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.
- data/lib/committee/errors.rb +9 -0
- data/lib/committee/param_validator.rb +16 -66
- data/lib/committee/response_validator.rb +16 -49
- data/lib/committee/test/methods.rb +36 -0
- data/lib/committee/validation.rb +81 -0
- data/lib/committee.rb +3 -0
- data/test/param_validator_test.rb +48 -22
- data/test/response_validator_test.rb +55 -5
- data/test/test/methods_test.rb +69 -0
- data/test/test_helper.rb +12 -0
- metadata +5 -2
data/lib/committee/errors.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
module Committee
|
2
2
|
class ParamValidator
|
3
|
+
include Validation
|
4
|
+
|
3
5
|
def initialize(params, schema, link_schema)
|
4
6
|
@params = params
|
5
7
|
@schema = schema
|
@@ -31,79 +33,27 @@ module Committee
|
|
31
33
|
try_match(key, @params[key], definitions)
|
32
34
|
else
|
33
35
|
# only assume one possible array definition for now
|
34
|
-
|
36
|
+
definitions = find_definitions(value["items"]["$ref"])
|
37
|
+
array_definition = definitions[0]
|
35
38
|
@params[key].each do |item|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
39
|
+
# separate logic for a complex object that includes properties
|
40
|
+
if array_definition.key?("properties")
|
41
|
+
array_definition["properties"].each do |array_key, array_value|
|
42
|
+
return unless item.key?(array_key)
|
43
|
+
|
44
|
+
# @todo: this should really be recursive; only one array level is
|
45
|
+
# supported for now
|
46
|
+
item_definitions = find_definitions(array_value["$ref"])
|
47
|
+
try_match(array_key, item[array_key], item_definitions)
|
48
|
+
end
|
49
|
+
else
|
50
|
+
try_match(key, item, definitions)
|
43
51
|
end
|
44
52
|
end
|
45
53
|
end
|
46
54
|
end
|
47
55
|
end
|
48
56
|
|
49
|
-
def check_format(format, value, key)
|
50
|
-
case format
|
51
|
-
when "date-time"
|
52
|
-
value =~ /^(\d{4})-(\d{2})-(\d{2})T(\d{2})\:(\d{2})\:(\d{2})(Z|[+-](\d{2})\:(\d{2}))$/
|
53
|
-
when "email"
|
54
|
-
value =~ /^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$/i
|
55
|
-
when "uuid"
|
56
|
-
value =~ /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/
|
57
|
-
else
|
58
|
-
true
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def check_format!(format, value, key)
|
63
|
-
unless check_format(format, value, key)
|
64
|
-
raise InvalidParams,
|
65
|
-
%{Invalid format for key "#{key}": expected "#{value}" to be "#{format}".}
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def check_pattern(pattern, value, key)
|
70
|
-
!pattern || value =~ pattern
|
71
|
-
end
|
72
|
-
|
73
|
-
def check_pattern!(pattern, value, key)
|
74
|
-
unless check_pattern(pattern, value, key)
|
75
|
-
raise InvalidParams,
|
76
|
-
%{Invalid pattern for key "#{key}": expected #{value} to match "#{pattern}".}
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def check_type(allowed_types, value, key)
|
81
|
-
types = case value
|
82
|
-
when NilClass
|
83
|
-
["null"]
|
84
|
-
when TrueClass, FalseClass
|
85
|
-
["boolean"]
|
86
|
-
when Bignum, Fixnum
|
87
|
-
["integer", "number"]
|
88
|
-
when Float
|
89
|
-
["number"]
|
90
|
-
when Hash
|
91
|
-
["object"]
|
92
|
-
when String
|
93
|
-
["string"]
|
94
|
-
else
|
95
|
-
["unknown"]
|
96
|
-
end
|
97
|
-
!(allowed_types & types).empty?
|
98
|
-
end
|
99
|
-
|
100
|
-
def check_type!(types, value, key)
|
101
|
-
unless check_type(types, value, key)
|
102
|
-
raise InvalidParams,
|
103
|
-
%{Invalid type for key "#{key}": expected #{value} to be #{types}.}
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
57
|
def detect_extra!
|
108
58
|
extra = @params.keys - all_keys
|
109
59
|
if extra.count > 0
|
@@ -1,6 +1,9 @@
|
|
1
1
|
module Committee
|
2
2
|
class ResponseValidator
|
3
|
+
include Validation
|
4
|
+
|
3
5
|
def initialize(data, schema, link_schema, type_schema)
|
6
|
+
|
4
7
|
@data = data
|
5
8
|
@schema = schema
|
6
9
|
@link_schema = link_schema
|
@@ -8,7 +11,7 @@ module Committee
|
|
8
11
|
end
|
9
12
|
|
10
13
|
def call
|
11
|
-
data = if @link_schema["
|
14
|
+
data = if @link_schema["rel"] == "instances"
|
12
15
|
if !@data.is_a?(Array)
|
13
16
|
raise InvalidResponse, "List endpoints must return an array of objects."
|
14
17
|
end
|
@@ -45,6 +48,16 @@ module Committee
|
|
45
48
|
schema["properties"].each do |key, value|
|
46
49
|
if value["properties"]
|
47
50
|
check_data!(value, data[key], path + [key])
|
51
|
+
elsif value["type"] == ["array"]
|
52
|
+
definition = @schema.find(value["items"]["$ref"])
|
53
|
+
data[key].each do |datum|
|
54
|
+
check_type!(definition["type"], datum, path + [key])
|
55
|
+
unless definition["type"].include?("null") && datum.nil?
|
56
|
+
check_format!(definition["format"], datum, path + [key])
|
57
|
+
check_pattern!(definition["pattern"], datum, path + [key])
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
48
61
|
else
|
49
62
|
definition = @schema.find(value["$ref"])
|
50
63
|
check_type!(definition["type"], data[key], path + [key])
|
@@ -56,54 +69,6 @@ module Committee
|
|
56
69
|
end
|
57
70
|
end
|
58
71
|
|
59
|
-
def check_format!(format, value, path)
|
60
|
-
return if !format
|
61
|
-
valid = case format
|
62
|
-
when "date-time"
|
63
|
-
value =~ /^(\d{4})-(\d{2})-(\d{2})T(\d{2})\:(\d{2})\:(\d{2})(Z|[+-](\d{2})\:(\d{2}))$/
|
64
|
-
when "email"
|
65
|
-
value =~ /^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$/i
|
66
|
-
when "uuid"
|
67
|
-
value =~ /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/
|
68
|
-
else
|
69
|
-
true
|
70
|
-
end
|
71
|
-
unless valid
|
72
|
-
raise InvalidResponse,
|
73
|
-
%{Invalid format at "#{path.join(":")}": expected "#{value}" to be "#{format}".}
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def check_pattern!(pattern, value, path)
|
78
|
-
if pattern && !(value =~ pattern)
|
79
|
-
raise InvalidResponse,
|
80
|
-
%{Invalid pattern at "#{path.join(":")}": expected #{value} to match "#{pattern}".}
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def check_type!(allowed_types, value, path)
|
85
|
-
types = case value
|
86
|
-
when NilClass
|
87
|
-
["null"]
|
88
|
-
when TrueClass, FalseClass
|
89
|
-
["boolean"]
|
90
|
-
when Bignum, Fixnum
|
91
|
-
["integer", "number"]
|
92
|
-
when Float
|
93
|
-
["number"]
|
94
|
-
when Hash
|
95
|
-
["object"]
|
96
|
-
when String
|
97
|
-
["string"]
|
98
|
-
else
|
99
|
-
["unknown"]
|
100
|
-
end
|
101
|
-
if (allowed_types & types).empty?
|
102
|
-
raise InvalidResponse,
|
103
|
-
%{Invalid type at "#{path.join(":")}": expected #{value} to be #{allowed_types} (was: #{types}).}
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
72
|
private
|
108
73
|
|
109
74
|
def build_data_keys(data)
|
@@ -123,6 +88,8 @@ module Committee
|
|
123
88
|
@type_schema["properties"].each do |key, info|
|
124
89
|
data = if info["properties"]
|
125
90
|
info
|
91
|
+
elsif info["type"] == ["array"]
|
92
|
+
@schema.find(info["items"]["$ref"])
|
126
93
|
elsif info["$ref"]
|
127
94
|
@schema.find(info["$ref"])
|
128
95
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Committee::Test
|
2
|
+
module Methods
|
3
|
+
def assert_schema_conform
|
4
|
+
assert_schema_content_type
|
5
|
+
|
6
|
+
@schema ||= Committee::Schema.new(File.read(schema_path))
|
7
|
+
@router ||= Committee::Router.new(@schema)
|
8
|
+
|
9
|
+
link_schema, type_schema = @router.routes_request?(last_request)
|
10
|
+
|
11
|
+
unless link_schema
|
12
|
+
response = "`#{last_request.request_method} #{last_request.path_info}` undefined in schema."
|
13
|
+
raise Committee::InvalidResponse.new(response)
|
14
|
+
end
|
15
|
+
|
16
|
+
data = MultiJson.decode(last_response.body)
|
17
|
+
Committee::ResponseValidator.new(
|
18
|
+
data,
|
19
|
+
@schema,
|
20
|
+
link_schema,
|
21
|
+
type_schema
|
22
|
+
).call
|
23
|
+
end
|
24
|
+
|
25
|
+
def assert_schema_content_type
|
26
|
+
unless last_response.headers["Content-Type"] =~ %r{application/json}
|
27
|
+
raise Committee::InvalidResponse,
|
28
|
+
%{"Content-Type" response header must be set to "application/json".}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def schema_path
|
33
|
+
raise "Please override #schema_path."
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Committee
|
2
|
+
module Validation
|
3
|
+
def check_format!(format, value, identifier)
|
4
|
+
return if !format
|
5
|
+
return if check_format(format, value, identifier)
|
6
|
+
|
7
|
+
description = case identifier
|
8
|
+
when String
|
9
|
+
%{Invalid format for key "#{identifier}": expected "#{value}" to be "#{format}".}
|
10
|
+
when Array
|
11
|
+
%{Invalid format at "#{identifier.join(":")}": expected "#{value}" to be "#{format}".}
|
12
|
+
end
|
13
|
+
|
14
|
+
raise InvalidFormat, description
|
15
|
+
end
|
16
|
+
|
17
|
+
def check_format(format, value, identifier)
|
18
|
+
case format
|
19
|
+
when "date-time"
|
20
|
+
value =~ /^(\d{4})-(\d{2})-(\d{2})T(\d{2})\:(\d{2})\:(\d{2})(\.\d{1,})?(Z|[+-](\d{2})\:(\d{2}))$/
|
21
|
+
when "email"
|
22
|
+
value =~ /^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$/i
|
23
|
+
when "uuid"
|
24
|
+
value =~ /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/
|
25
|
+
else
|
26
|
+
true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def check_type!(allowed_types, value, identifier)
|
31
|
+
return if check_type(allowed_types, value, identifier)
|
32
|
+
|
33
|
+
description = case identifier
|
34
|
+
when String
|
35
|
+
%{Invalid type for key "#{identifier}": expected #{value} to be #{allowed_types}.}
|
36
|
+
when Array
|
37
|
+
%{Invalid type at "#{identifier.join(":")}": expected #{value} to be #{allowed_types}.}
|
38
|
+
end
|
39
|
+
|
40
|
+
raise InvalidType, description
|
41
|
+
end
|
42
|
+
|
43
|
+
def check_type(allowed_types, value, identifier)
|
44
|
+
types = case value
|
45
|
+
when NilClass
|
46
|
+
["null"]
|
47
|
+
when TrueClass, FalseClass
|
48
|
+
["boolean"]
|
49
|
+
when Bignum, Fixnum
|
50
|
+
["integer", "number"]
|
51
|
+
when Float
|
52
|
+
["number"]
|
53
|
+
when Hash
|
54
|
+
["object"]
|
55
|
+
when String
|
56
|
+
["string"]
|
57
|
+
else
|
58
|
+
["unknown"]
|
59
|
+
end
|
60
|
+
|
61
|
+
!(allowed_types & types).empty?
|
62
|
+
end
|
63
|
+
|
64
|
+
def check_pattern!(pattern, value, identifier)
|
65
|
+
return if check_pattern(pattern, value, identifier)
|
66
|
+
|
67
|
+
description = case identifier
|
68
|
+
when String
|
69
|
+
%{Invalid pattern for key "#{identifier}": expected #{value} to match "#{pattern}".}
|
70
|
+
when Array
|
71
|
+
%{Invalid pattern at "#{identifier.join(":")}": expected #{value} to match "#{pattern}".}
|
72
|
+
end
|
73
|
+
|
74
|
+
raise InvalidPattern, description
|
75
|
+
end
|
76
|
+
|
77
|
+
def check_pattern(pattern, value, identifier)
|
78
|
+
!pattern || value =~ pattern
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/lib/committee.rb
CHANGED
@@ -2,6 +2,7 @@ require "multi_json"
|
|
2
2
|
require "rack"
|
3
3
|
|
4
4
|
require_relative "committee/errors"
|
5
|
+
require_relative "committee/validation"
|
5
6
|
require_relative "committee/param_validator"
|
6
7
|
require_relative "committee/request_unpacker"
|
7
8
|
require_relative "committee/response_generator"
|
@@ -13,3 +14,5 @@ require_relative "committee/middleware/base"
|
|
13
14
|
require_relative "committee/middleware/request_validation"
|
14
15
|
require_relative "committee/middleware/response_validation"
|
15
16
|
require_relative "committee/middleware/stub"
|
17
|
+
|
18
|
+
require_relative "committee/test/methods"
|
@@ -41,7 +41,7 @@ describe Committee::ParamValidator do
|
|
41
41
|
"app" => "heroku-api",
|
42
42
|
"recipient" => 123,
|
43
43
|
}
|
44
|
-
e = assert_raises(Committee::
|
44
|
+
e = assert_raises(Committee::InvalidType) do
|
45
45
|
Committee::ParamValidator.new(params, @schema, @link_schema).call
|
46
46
|
end
|
47
47
|
message = %{Invalid type for key "recipient": expected 123 to be ["string"].}
|
@@ -53,7 +53,7 @@ describe Committee::ParamValidator do
|
|
53
53
|
"app" => "heroku-api",
|
54
54
|
"recipient" => "not-email",
|
55
55
|
}
|
56
|
-
e = assert_raises(Committee::
|
56
|
+
e = assert_raises(Committee::InvalidFormat) do
|
57
57
|
Committee::ParamValidator.new(params, @schema, @link_schema).call
|
58
58
|
end
|
59
59
|
message = %{Invalid format for key "recipient": expected "not-email" to be "email".}
|
@@ -65,35 +65,61 @@ describe Committee::ParamValidator do
|
|
65
65
|
"name" => "%@!"
|
66
66
|
}
|
67
67
|
link_schema = @schema["app"]["links"][0]
|
68
|
-
e = assert_raises(Committee::
|
68
|
+
e = assert_raises(Committee::InvalidPattern) do
|
69
69
|
Committee::ParamValidator.new(params, @schema, link_schema).call
|
70
70
|
end
|
71
71
|
message = %{Invalid pattern for key "name": expected %@! to match "(?-mix:^[a-z][a-z0-9-]{3,30}$)".}
|
72
72
|
assert_equal message, e.message
|
73
73
|
end
|
74
74
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
75
|
+
describe "complex arrays" do
|
76
|
+
it "passes an array parameter" do
|
77
|
+
params = {
|
78
|
+
"updates" => [
|
79
|
+
{ "name" => "bamboo", "state" => "private" },
|
80
|
+
{ "name" => "cedar", "state" => "public" },
|
81
|
+
]
|
82
|
+
}
|
83
|
+
link_schema = @schema["stack"]["links"][2]
|
84
|
+
Committee::ParamValidator.new(params, @schema, link_schema).call
|
85
|
+
end
|
86
|
+
|
87
|
+
it "detects an array item with a parameter of the wrong type" do
|
88
|
+
params = {
|
89
|
+
"updates" => [
|
90
|
+
{ "name" => "bamboo", "state" => 123 },
|
91
|
+
]
|
92
|
+
}
|
93
|
+
link_schema = @schema["stack"]["links"][2]
|
94
|
+
e = assert_raises(Committee::InvalidType) do
|
95
|
+
Committee::ParamValidator.new(params, @schema, link_schema).call
|
96
|
+
end
|
97
|
+
message = %{Invalid type for key "state": expected 123 to be ["string"].}
|
98
|
+
assert_equal message, e.message
|
99
|
+
end
|
84
100
|
end
|
85
101
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
e = assert_raises(Committee::InvalidParams) do
|
102
|
+
describe "simple arrays" do
|
103
|
+
it "passes an array parameter" do
|
104
|
+
params = {
|
105
|
+
"password" => "1234",
|
106
|
+
"flags" => [ "vip", "customer" ]
|
107
|
+
}
|
108
|
+
link_schema = @schema["account"]["links"][1]
|
94
109
|
Committee::ParamValidator.new(params, @schema, link_schema).call
|
95
110
|
end
|
96
|
-
|
97
|
-
|
111
|
+
|
112
|
+
it "detects an array item with a parameter of the wrong type" do
|
113
|
+
params = {
|
114
|
+
"password" => "1234",
|
115
|
+
"flags" => [ "vip", "customer", 999 ]
|
116
|
+
}
|
117
|
+
link_schema = @schema["account"]["links"][1]
|
118
|
+
e = assert_raises(Committee::InvalidType) do
|
119
|
+
Committee::ParamValidator.new(params, @schema, link_schema).call
|
120
|
+
end
|
121
|
+
message = %{Invalid type for key "flags": expected 999 to be ["string"].}
|
122
|
+
assert_equal message, e.message
|
123
|
+
end
|
98
124
|
end
|
99
125
|
end
|
@@ -6,6 +6,7 @@ describe Committee::ResponseValidator do
|
|
6
6
|
@schema = Committee::Schema.new(File.read("./test/data/schema.json"))
|
7
7
|
# GET /apps/:id
|
8
8
|
@link_schema = @schema["app"]["links"][2]
|
9
|
+
@type_schema = @schema["app"]
|
9
10
|
end
|
10
11
|
|
11
12
|
it "passes through a valid response" do
|
@@ -19,6 +20,12 @@ describe Committee::ResponseValidator do
|
|
19
20
|
call
|
20
21
|
end
|
21
22
|
|
23
|
+
it "passes through a valid list response with non-default title" do
|
24
|
+
@data = [@data]
|
25
|
+
@link_schema = @schema["app"]["links"][4]
|
26
|
+
call
|
27
|
+
end
|
28
|
+
|
22
29
|
it "detects an improperly formatted list response" do
|
23
30
|
# GET /apps
|
24
31
|
@link_schema = @schema["app"]["links"][3]
|
@@ -43,25 +50,68 @@ describe Committee::ResponseValidator do
|
|
43
50
|
|
44
51
|
it "detects mismatched types" do
|
45
52
|
@data.merge!("maintenance" => "not-bool")
|
46
|
-
e = assert_raises(Committee::
|
47
|
-
message = %{Invalid type at "maintenance": expected not-bool to be ["boolean"]
|
53
|
+
e = assert_raises(Committee::InvalidType) { call }
|
54
|
+
message = %{Invalid type at "maintenance": expected not-bool to be ["boolean"].}
|
48
55
|
assert_equal message, e.message
|
49
56
|
end
|
50
57
|
|
51
58
|
it "detects bad formats" do
|
52
59
|
@data.merge!("id" => "123")
|
53
|
-
e = assert_raises(Committee::
|
60
|
+
e = assert_raises(Committee::InvalidFormat) { call }
|
54
61
|
message = %{Invalid format at "id": expected "123" to be "uuid".}
|
55
62
|
assert_equal message, e.message
|
56
63
|
end
|
57
64
|
|
58
65
|
it "detects bad patterns" do
|
59
66
|
@data.merge!("name" => "%@!")
|
60
|
-
e = assert_raises(Committee::
|
67
|
+
e = assert_raises(Committee::InvalidPattern) { call }
|
61
68
|
message = %{Invalid pattern at "name": expected %@! to match "(?-mix:^[a-z][a-z0-9-]{3,30}$)".}
|
62
69
|
assert_equal message, e.message
|
63
70
|
end
|
64
71
|
|
72
|
+
it "accepts date-time format without milliseconds" do
|
73
|
+
validator = Committee::ResponseValidator.new(
|
74
|
+
@data,
|
75
|
+
@schema,
|
76
|
+
@link_schema,
|
77
|
+
@schema["app"])
|
78
|
+
|
79
|
+
value = "2014-03-10T00:00:00Z"
|
80
|
+
assert_nil validator.check_format!("date-time", value, ["example"])
|
81
|
+
end
|
82
|
+
|
83
|
+
it "accepts date-time format with milliseconds" do
|
84
|
+
validator = Committee::ResponseValidator.new(
|
85
|
+
@data,
|
86
|
+
@schema,
|
87
|
+
@link_schema,
|
88
|
+
@schema["app"])
|
89
|
+
|
90
|
+
value = "2014-03-10T00:00:00.123Z"
|
91
|
+
assert_nil validator.check_format!("date-time", value, ["example"])
|
92
|
+
end
|
93
|
+
|
94
|
+
it "accepts a simple array" do
|
95
|
+
@data = ValidAccount.dup
|
96
|
+
@data["flags"] = @data["flags"].dup
|
97
|
+
@link_schema = @schema["account"]["links"][1]
|
98
|
+
@type_schema = @schema["account"]
|
99
|
+
|
100
|
+
call
|
101
|
+
end
|
102
|
+
|
103
|
+
it "detects a simple array with an item of the wrong type" do
|
104
|
+
@data = ValidAccount.dup
|
105
|
+
@data["flags"] = @data["flags"].dup
|
106
|
+
@data["flags"] << false
|
107
|
+
@link_schema = @schema["account"]["links"][1]
|
108
|
+
@type_schema = @schema["account"]
|
109
|
+
|
110
|
+
e = assert_raises(Committee::InvalidType) { call }
|
111
|
+
message = %{Invalid type at "flags": expected false to be ["string"].}
|
112
|
+
assert_equal message, e.message
|
113
|
+
end
|
114
|
+
|
65
115
|
private
|
66
116
|
|
67
117
|
def call
|
@@ -69,7 +119,7 @@ describe Committee::ResponseValidator do
|
|
69
119
|
@data,
|
70
120
|
@schema,
|
71
121
|
@link_schema,
|
72
|
-
@
|
122
|
+
@type_schema
|
73
123
|
).call
|
74
124
|
end
|
75
125
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require_relative "../test_helper"
|
2
|
+
|
3
|
+
describe Committee::Middleware::Stub do
|
4
|
+
include Committee::Test::Methods
|
5
|
+
include Rack::Test::Methods
|
6
|
+
|
7
|
+
def app
|
8
|
+
@app
|
9
|
+
end
|
10
|
+
|
11
|
+
def schema_path
|
12
|
+
"./test/data/schema.json"
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#assert_schema_content_type" do
|
16
|
+
it "passes through a valid response" do
|
17
|
+
@app = new_rack_app(MultiJson.encode([ValidApp]))
|
18
|
+
get "/apps"
|
19
|
+
assert_schema_content_type
|
20
|
+
end
|
21
|
+
|
22
|
+
it "detects an invalid response Content-Type" do
|
23
|
+
@app = new_rack_app(MultiJson.encode([ValidApp]), {})
|
24
|
+
get "/apps"
|
25
|
+
e = assert_raises(Committee::InvalidResponse) do
|
26
|
+
assert_schema_content_type
|
27
|
+
end
|
28
|
+
assert_match /response header must be set to/i, e.message
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#assert_schema_conform" do
|
33
|
+
it "passes through a valid response" do
|
34
|
+
@app = new_rack_app(MultiJson.encode([ValidApp]))
|
35
|
+
get "/apps"
|
36
|
+
assert_schema_conform
|
37
|
+
end
|
38
|
+
|
39
|
+
it "detects an invalid response Content-Type" do
|
40
|
+
@app = new_rack_app(MultiJson.encode([ValidApp]), {})
|
41
|
+
get "/apps"
|
42
|
+
e = assert_raises(Committee::InvalidResponse) do
|
43
|
+
assert_schema_conform
|
44
|
+
end
|
45
|
+
assert_match /response header must be set to/i, e.message
|
46
|
+
end
|
47
|
+
|
48
|
+
it "detects missing keys in response" do
|
49
|
+
data = ValidApp.dup
|
50
|
+
data.delete("name")
|
51
|
+
@app = new_rack_app(MultiJson.encode([data]))
|
52
|
+
get "/apps"
|
53
|
+
e = assert_raises(Committee::InvalidResponse) do
|
54
|
+
assert_schema_conform
|
55
|
+
end
|
56
|
+
assert_match /missing keys/i, e.message
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def new_rack_app(response, headers={ "Content-Type" => "application/json" })
|
63
|
+
Rack::Builder.new {
|
64
|
+
run lambda { |_|
|
65
|
+
[200, headers, [response]]
|
66
|
+
}
|
67
|
+
}
|
68
|
+
end
|
69
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -34,3 +34,15 @@ ValidApp = {
|
|
34
34
|
"updated_at" => "2012-01-01T12:00:00Z",
|
35
35
|
"web_url" => "http://example.herokuapp.com"
|
36
36
|
}.freeze
|
37
|
+
|
38
|
+
ValidAccount = {
|
39
|
+
"allow_tracking" => true,
|
40
|
+
"beta" => true,
|
41
|
+
"created_at" => "2012-01-01T12:00:00Z",
|
42
|
+
"email" => "username@example.com",
|
43
|
+
"id" => "01234567-89ab-cdef-0123-456789abcdef",
|
44
|
+
"last_login" => "2012-01-01T12:00:00Z",
|
45
|
+
"updated_at" => "2012-01-01T12:00:00Z",
|
46
|
+
"verified" => true,
|
47
|
+
"flags" => ["foo", "bar"]
|
48
|
+
}.freeze
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: committee
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2014-
|
13
|
+
date: 2014-04-20 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: multi_json
|
@@ -112,6 +112,8 @@ files:
|
|
112
112
|
- lib/committee/response_validator.rb
|
113
113
|
- lib/committee/router.rb
|
114
114
|
- lib/committee/schema.rb
|
115
|
+
- lib/committee/test/methods.rb
|
116
|
+
- lib/committee/validation.rb
|
115
117
|
- lib/committee.rb
|
116
118
|
- test/middleware/request_validation_test.rb
|
117
119
|
- test/middleware/response_validation_test.rb
|
@@ -122,6 +124,7 @@ files:
|
|
122
124
|
- test/response_validator_test.rb
|
123
125
|
- test/router_test.rb
|
124
126
|
- test/schema_test.rb
|
127
|
+
- test/test/methods_test.rb
|
125
128
|
- test/test_helper.rb
|
126
129
|
- bin/committee-stub
|
127
130
|
homepage: https://github.com/heroku/rack-committee
|