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.
@@ -2,6 +2,15 @@ module Committee
2
2
  class BadRequest < StandardError
3
3
  end
4
4
 
5
+ class InvalidPattern < StandardError
6
+ end
7
+
8
+ class InvalidFormat < StandardError
9
+ end
10
+
11
+ class InvalidType < StandardError
12
+ end
13
+
5
14
  class InvalidParams < StandardError
6
15
  end
7
16
 
@@ -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
- array_definition = find_definitions(value["items"]["$ref"])[0]
36
+ definitions = find_definitions(value["items"]["$ref"])
37
+ array_definition = definitions[0]
35
38
  @params[key].each do |item|
36
- array_definition["properties"].each do |array_key, array_value|
37
- return unless item.key?(array_key)
38
-
39
- # @todo: this should really be recursive; only one array level is
40
- # supported for now
41
- definitions = find_definitions(array_value["$ref"])
42
- try_match(array_key, item[array_key], definitions)
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["title"] == "List"
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::InvalidParams) do
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::InvalidParams) do
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::InvalidParams) do
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
- it "passes an array parameter" do
76
- params = {
77
- "updates" => [
78
- { "name" => "bamboo", "state" => "private" },
79
- { "name" => "cedar", "state" => "public" },
80
- ]
81
- }
82
- link_schema = @schema["stack"]["links"][2]
83
- Committee::ParamValidator.new(params, @schema, link_schema).call
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
- it "detects an array item with a parameter of the wrong type" do
87
- params = {
88
- "updates" => [
89
- { "name" => "bamboo", "state" => 123 },
90
- ]
91
- }
92
- link_schema = @schema["stack"]["links"][2]
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
- message = %{Invalid type for key "state": expected 123 to be ["string"].}
97
- assert_equal message, e.message
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::InvalidResponse) { call }
47
- message = %{Invalid type at "maintenance": expected not-bool to be ["boolean"] (was: ["string"]).}
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::InvalidResponse) { call }
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::InvalidResponse) { call }
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
- @schema["app"]
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.2
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-02-06 00:00:00.000000000 Z
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