committee 3.0.0.alpha → 3.0.0.beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +5 -5
  2. data/lib/committee/drivers/hyper_schema.rb +8 -2
  3. data/lib/committee/drivers/open_api_2.rb +7 -2
  4. data/lib/committee/drivers/open_api_3.rb +9 -4
  5. data/lib/committee/drivers.rb +46 -0
  6. data/lib/committee/middleware/base.rb +9 -11
  7. data/lib/committee/middleware/response_validation.rb +8 -5
  8. data/lib/committee/request_unpacker.rb +4 -1
  9. data/lib/committee/{parameter_coercer.rb → schema_validator/hyper_schema/parameter_coercer.rb} +1 -2
  10. data/lib/committee/schema_validator/hyper_schema/request_validator.rb +1 -5
  11. data/lib/committee/schema_validator/hyper_schema/response_validator.rb +3 -9
  12. data/lib/committee/schema_validator/hyper_schema/router.rb +1 -1
  13. data/lib/committee/schema_validator/hyper_schema.rb +5 -4
  14. data/lib/committee/schema_validator/open_api_3/operation_wrapper.rb +46 -19
  15. data/lib/committee/schema_validator/open_api_3/request_validator.rb +14 -4
  16. data/lib/committee/schema_validator/open_api_3/response_validator.rb +9 -20
  17. data/lib/committee/schema_validator/open_api_3/router.rb +15 -4
  18. data/lib/committee/schema_validator/open_api_3.rb +14 -5
  19. data/lib/committee/schema_validator/option.rb +2 -5
  20. data/lib/committee/schema_validator/schema_validator.rb +15 -0
  21. data/lib/committee/test/methods.rb +3 -5
  22. data/lib/committee.rb +3 -1
  23. data/test/drivers/open_api_3_test.rb +2 -1
  24. data/test/drivers_test.rb +69 -0
  25. data/test/middleware/base_test.rb +20 -5
  26. data/test/middleware/request_validation_open_api_3_test.rb +136 -259
  27. data/test/middleware/request_validation_test.rb +18 -3
  28. data/test/middleware/response_validation_open_api_3_test.rb +83 -16
  29. data/test/middleware/response_validation_test.rb +19 -7
  30. data/test/middleware/stub_test.rb +1 -1
  31. data/test/{parameter_coercer_test.rb → schema_validator/hyper_schema/parameter_coercer_test.rb} +3 -3
  32. data/test/schema_validator/hyper_schema/router_test.rb +6 -0
  33. data/test/schema_validator/open_api_3/operation_wrapper_test.rb +29 -13
  34. data/test/schema_validator/open_api_3/request_validator_test.rb +31 -132
  35. data/test/schema_validator/open_api_3/response_validator_test.rb +19 -5
  36. data/test/test/methods_new_version_test.rb +19 -3
  37. data/test/test/methods_test.rb +15 -8
  38. data/test/test_helper.rb +15 -16
  39. metadata +8 -7
@@ -10,13 +10,13 @@ describe Committee::Middleware::ResponseValidation do
10
10
  end
11
11
 
12
12
  it "passes through a valid response" do
13
- @app = new_response_rack(JSON.generate(CHARACTERS_RESPONSE), {}, open_api_3: open_api_3_schema)
13
+ @app = new_response_rack(JSON.generate(CHARACTERS_RESPONSE), {}, schema: open_api_3_schema)
14
14
  get "/characters"
15
15
  assert_equal 200, last_response.status
16
16
  end
17
17
 
18
18
  it "passes through a invalid json" do
19
- @app = new_response_rack("not_json", {}, open_api_3: open_api_3_schema)
19
+ @app = new_response_rack("not_json", {}, schema: open_api_3_schema)
20
20
 
21
21
  get "/characters"
22
22
 
@@ -25,15 +25,15 @@ describe Committee::Middleware::ResponseValidation do
25
25
  end
26
26
 
27
27
  it "passes through not definition" do
28
- @app = new_response_rack(JSON.generate(CHARACTERS_RESPONSE), {}, open_api_3: open_api_3_schema)
28
+ @app = new_response_rack(JSON.generate(CHARACTERS_RESPONSE), {}, schema: open_api_3_schema)
29
29
  get "/no_data"
30
30
  assert_equal 200, last_response.status
31
31
  end
32
32
 
33
33
  it "detects a response invalid due to schema" do
34
- @app = new_response_rack("[]", {}, open_api_3: open_api_3_schema)
34
+ @app = new_response_rack("[]", {}, schema: open_api_3_schema, raise: true)
35
35
 
36
- e = assert_raises(Committee::InvalidRequest) { # TODO: change invalid request
36
+ e = assert_raises(Committee::InvalidResponse) {
37
37
  get "/characters"
38
38
  }
39
39
 
@@ -41,44 +41,111 @@ describe Committee::Middleware::ResponseValidation do
41
41
  end
42
42
 
43
43
  it "passes through a 204 (no content) response" do
44
- @app = new_response_rack("", {}, {open_api_3: open_api_3_schema}, {status: 204})
44
+ @app = new_response_rack("", {}, {schema: open_api_3_schema}, {status: 204})
45
45
  post "/validate"
46
46
  assert_equal 204, last_response.status
47
47
  end
48
48
 
49
49
  it "passes through a valid response with prefix" do
50
- @app = new_response_rack(JSON.generate(CHARACTERS_RESPONSE), {}, open_api_3: open_api_3_schema, prefix: "/v1")
50
+ @app = new_response_rack(JSON.generate(CHARACTERS_RESPONSE), {}, schema: open_api_3_schema, prefix: "/v1")
51
51
  get "/v1/characters"
52
52
  assert_equal 200, last_response.status
53
53
  end
54
54
 
55
55
  it "passes through a invalid json with prefix" do
56
- @app = new_response_rack("not_json", {}, open_api_3: open_api_3_schema, prefix: "/v1")
56
+ @app = new_response_rack("not_json", {}, schema: open_api_3_schema, prefix: "/v1")
57
57
 
58
58
  get "/v1/characters"
59
59
 
60
- # TODO: support prefix
61
- assert_equal 200, last_response.status
62
- # assert_equal 500, last_response.status
63
- # assert_equal "{\"id\":\"invalid_response\",\"message\":\"Response wasn't valid JSON.\"}", last_response.body
60
+ assert_equal 500, last_response.status
61
+ assert_equal "{\"id\":\"invalid_response\",\"message\":\"Response wasn't valid JSON.\"}", last_response.body
64
62
  end
65
63
 
66
64
  it "rescues JSON errors" do
67
- @app = new_response_rack("_42", {}, open_api_3: open_api_3_schema, raise: true)
65
+ @app = new_response_rack("_42", {}, schema: open_api_3_schema, raise: true)
68
66
  assert_raises(Committee::InvalidResponse) do
69
67
  get "/characters"
70
68
  end
71
69
  end
72
70
 
73
71
  it "not parameter requset" do
74
- @app = new_response_rack({integer: '1'}.to_json, {}, open_api_3: open_api_3_schema)
72
+ @app = new_response_rack({integer: '1'}.to_json, {}, schema: open_api_3_schema, raise: true)
75
73
 
76
- # TODO: error change
77
- assert_raises(Committee::InvalidRequest) do
74
+ assert_raises(Committee::InvalidResponse) do
78
75
  patch "/validate_no_parameter", {no_schema: 'no'}
79
76
  end
80
77
  end
81
78
 
79
+ it "optionally validates non-2xx blank responses" do
80
+ @app = new_response_rack("", {}, schema: open_api_3_schema, validate_success_only: false)
81
+ get "/characters"
82
+ assert_equal 200, last_response.status
83
+ end
84
+
85
+ it "optionally validates non-2xx invalid responses with invalid json" do
86
+ @app = new_response_rack("{_}", {}, schema: open_api_3_schema, validate_success_only: false)
87
+ get "/characters"
88
+ assert_equal 500, last_response.status
89
+ assert_match(/valid JSON/i, last_response.body)
90
+ end
91
+
92
+ describe 'check header' do
93
+ it 'valid type header' do
94
+ @app = new_response_rack({}.to_json, {'x-limit' => 1}, schema: open_api_3_schema, raise: true)
95
+
96
+ get "/header"
97
+
98
+ assert_equal 200, last_response.status
99
+ end
100
+
101
+ it 'invalid type header' do
102
+ @app = new_response_rack({}.to_json, {'x-limit' => '1'}, schema: open_api_3_schema, raise: true)
103
+
104
+ assert_raises(Committee::InvalidResponse) do
105
+ get "/header"
106
+ end
107
+ end
108
+
109
+ it 'invalid type but not check' do
110
+ @app = new_response_rack({}.to_json, {'x-limit' => '1'}, schema: open_api_3_schema, raise: true, check_header: false)
111
+
112
+ get "/header"
113
+
114
+ assert_equal 200, last_response.status
115
+ end
116
+ end
117
+
118
+ describe 'validate error option' do
119
+ it "detects an invalid response status code" do
120
+ @app = new_response_rack({ integer: '1' }.to_json,
121
+ {},
122
+ app_status: 400,
123
+ schema: open_api_3_schema,
124
+ raise: true,
125
+ validate_success_only: false)
126
+
127
+
128
+ e = assert_raises(Committee::InvalidResponse) do
129
+ get "/characters"
130
+ end
131
+ assert_match(/1 class is String/i, e.message)
132
+ end
133
+
134
+ it "detects an invalid response status code with validate_success_only=true" do
135
+ @app = new_response_rack({ string_1: :honoka }.to_json,
136
+ {},
137
+ app_status: 400,
138
+ schema: open_api_3_schema,
139
+ raise: true,
140
+ validate_success_only: true)
141
+
142
+
143
+ get "/characters"
144
+
145
+ assert_equal 400, last_response.status
146
+ end
147
+ end
148
+
82
149
  private
83
150
 
84
151
  def new_response_rack(response, headers = {}, options = {}, rack_options = {})
@@ -15,8 +15,8 @@ describe Committee::Middleware::ResponseValidation do
15
15
 
16
16
  it "doesn't call error_handler when response is valid" do
17
17
  called = false
18
- pr = ->(e) { called = true }
19
- @app = new_rack_app(JSON.generate([ValidApp]), {}, schema: hyper_schema)
18
+ pr = ->(_e) { called = true }
19
+ @app = new_rack_app(JSON.generate([ValidApp]), {}, schema: hyper_schema, error_handler: pr)
20
20
  get "/apps"
21
21
  assert !called, "error_handler is called"
22
22
  end
@@ -29,7 +29,7 @@ describe Committee::Middleware::ResponseValidation do
29
29
  end
30
30
 
31
31
  it "detects a response invalid due to not being JSON" do
32
- @app = new_rack_app("", {}, schema: hyper_schema)
32
+ @app = new_rack_app("{_}", {}, schema: hyper_schema)
33
33
  get "/apps"
34
34
  assert_equal 500, last_response.status
35
35
  assert_match(/valid JSON/i, last_response.body)
@@ -42,9 +42,14 @@ describe Committee::Middleware::ResponseValidation do
42
42
  end
43
43
 
44
44
  it "optionally validates non-2xx invalid responses" do
45
- @app = new_rack_app("", {}, app_status: 404, validate_errors: true,
46
- schema: hyper_schema)
45
+ @app = new_rack_app("", {}, app_status: 404, validate_success_only: false, schema: hyper_schema)
46
+ get "/apps"
47
+ assert_equal 500, last_response.status
48
+ assert_match(/Invalid response/i, last_response.body)
49
+ end
47
50
 
51
+ it "optionally validates non-2xx invalid responses with invalid json" do
52
+ @app = new_rack_app("{_}", {}, app_status: 404, validate_success_only: false, schema: hyper_schema)
48
53
  get "/apps"
49
54
  assert_equal 500, last_response.status
50
55
  assert_match(/valid JSON/i, last_response.body)
@@ -56,8 +61,15 @@ describe Committee::Middleware::ResponseValidation do
56
61
  assert_equal 204, last_response.status
57
62
  end
58
63
 
64
+ it "skip validation when 4xx" do
65
+ @app = new_rack_app("[{x:y}]", {}, schema: hyper_schema, validate_success_only: true, app_status: 400)
66
+ get "/apps"
67
+ assert_equal 400, last_response.status
68
+ assert_match("[{x:y}]", last_response.body)
69
+ end
70
+
59
71
  it "rescues JSON errors" do
60
- @app = new_rack_app("[{x:y}]", {}, schema: hyper_schema)
72
+ @app = new_rack_app("[{x:y}]", {}, schema: hyper_schema, validate_success_only: false)
61
73
  get "/apps"
62
74
  assert_equal 500, last_response.status
63
75
  assert_match(/valid json/i, last_response.body)
@@ -103,7 +115,7 @@ describe Committee::Middleware::ResponseValidation do
103
115
  end
104
116
 
105
117
  it "detects an invalid response for OpenAPI" do
106
- @app = new_rack_app("", {}, schema: open_api_2_schema)
118
+ @app = new_rack_app("{_}", {}, schema: open_api_2_schema)
107
119
  get "/api/pets"
108
120
  assert_equal 500, last_response.status
109
121
  assert_match(/valid JSON/i, last_response.body)
@@ -98,7 +98,7 @@ describe Committee::Middleware::Stub do
98
98
 
99
99
  it "caches the response if called multiple times" do
100
100
  cache = {}
101
- @app = new_rack_app(cache: cache, open_api_3: open_api_3_schema)
101
+ @app = new_rack_app(cache: cache, schema: open_api_3_schema)
102
102
 
103
103
  assert_raises(Committee::NotSupportOpenAPI3) do
104
104
  get "/characters"
@@ -1,8 +1,8 @@
1
- require_relative "test_helper"
1
+ require_relative "../../test_helper"
2
2
 
3
3
  require "stringio"
4
4
 
5
- describe Committee::ParameterCoercer do
5
+ describe Committee::SchemaValidator::HyperSchema::ParameterCoercer do
6
6
  before do
7
7
  @schema = JsonSchema.parse!(hyper_schema_data)
8
8
  @schema.expand_references!
@@ -106,6 +106,6 @@ describe Committee::ParameterCoercer do
106
106
 
107
107
  def call(params, options={})
108
108
  link = Committee::Drivers::HyperSchema::Link.new(@link)
109
- Committee::ParameterCoercer.new(params, link.schema, options).call!
109
+ Committee::SchemaValidator::HyperSchema::ParameterCoercer.new(params, link.schema, options).call!
110
110
  end
111
111
  end
@@ -60,6 +60,12 @@ describe Committee::SchemaValidator::HyperSchema::Router do
60
60
  assert_equal '/api/pets/dog', link.href
61
61
  end
62
62
 
63
+ it "fewer match not support in HyperSchema" do
64
+ link, _ = hyper_schema_router.find_link("GET", "/apps/abc")
65
+ refute_nil link
66
+ assert_equal '/apps/{(%23%2Fdefinitions%2Fapp%2Fdefinitions%2Fname)}', link.href
67
+ end
68
+
63
69
  def hyper_schema_router(options = {})
64
70
  schema = Committee::Drivers::HyperSchema.new.parse(hyper_schema_data)
65
71
  validator_option = Committee::SchemaValidator::Option.new(options, schema, :hyper_schema)
@@ -14,6 +14,8 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
14
14
  open_api_3_schema.operation_object(@path, @method)
15
15
  end
16
16
 
17
+ HEADER = { 'Content-Type' => 'application/json' }
18
+
17
19
  SCHEMA_PROPERTIES_PAIR = [
18
20
  ['string', 'str'],
19
21
  ['integer', 1],
@@ -23,7 +25,7 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
23
25
  ]
24
26
 
25
27
  it 'correct data' do
26
- operation_object.validate_request_params(SCHEMA_PROPERTIES_PAIR.to_h, @validator_option)
28
+ operation_object.validate_request_params(SCHEMA_PROPERTIES_PAIR.to_h, HEADER, @validator_option)
27
29
  assert true
28
30
  end
29
31
 
@@ -37,6 +39,7 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
37
39
  "number_1" => nil
38
40
  }
39
41
  },
42
+ HEADER,
40
43
  @validator_option)
41
44
 
42
45
  assert true
@@ -44,7 +47,7 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
44
47
 
45
48
  it 'invalid params' do
46
49
  e = assert_raises(Committee::InvalidRequest) {
47
- operation_object.validate_request_params({"string" => 1}, @validator_option)
50
+ operation_object.validate_request_params({"string" => 1}, HEADER, @validator_option)
48
51
  }
49
52
 
50
53
  # FIXME: when ruby 2.3 dropped, fix because ruby 2.3 return Fixnum, ruby 2.4 or later return Integer
@@ -53,10 +56,10 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
53
56
 
54
57
  it 'support put method' do
55
58
  @method = "put"
56
- operation_object.validate_request_params({"string" => "str"}, @validator_option)
59
+ operation_object.validate_request_params({"string" => "str"}, HEADER, @validator_option)
57
60
 
58
61
  e = assert_raises(Committee::InvalidRequest) {
59
- operation_object.validate_request_params({"string" => 1}, @validator_option)
62
+ operation_object.validate_request_params({"string" => 1}, HEADER, @validator_option)
60
63
  }
61
64
 
62
65
  # FIXME: when ruby 2.3 dropped, fix because ruby 2.3 return Fixnum, ruby 2.4 or later return Integer
@@ -65,17 +68,17 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
65
68
 
66
69
  it 'support patch method' do
67
70
  @method = "patch"
68
- operation_object.validate_request_params({"integer" => 1}, @validator_option)
71
+ operation_object.validate_request_params({"integer" => 1}, HEADER, @validator_option)
69
72
 
70
73
  e = assert_raises(Committee::InvalidRequest) {
71
- operation_object.validate_request_params({"integer" => "str"}, @validator_option)
74
+ operation_object.validate_request_params({"integer" => "str"}, HEADER, @validator_option)
72
75
  }
73
76
 
74
77
  assert e.message.start_with?("str class is String but it's not valid")
75
78
  end
76
79
 
77
80
  it 'unknown param' do
78
- operation_object.validate_request_params({"unknown" => 1}, @validator_option)
81
+ operation_object.validate_request_params({"unknown" => 1}, HEADER, @validator_option)
79
82
  end
80
83
 
81
84
  describe 'support get method' do
@@ -84,15 +87,24 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
84
87
  end
85
88
 
86
89
  it 'correct' do
87
- operation_object.validate_request_params({"query_string" => "query", "query_integer_list" => [1, 2]}, @validator_option)
88
- operation_object.validate_request_params({"query_string" => "query", "query_integer_list" => [1, 2], "optional_integer" => 1}, @validator_option)
90
+ operation_object.validate_request_params(
91
+ {"query_string" => "query", "query_integer_list" => [1, 2]},
92
+ HEADER,
93
+ @validator_option
94
+ )
95
+
96
+ operation_object.validate_request_params(
97
+ {"query_string" => "query", "query_integer_list" => [1, 2], "optional_integer" => 1},
98
+ HEADER,
99
+ @validator_option
100
+ )
89
101
 
90
102
  assert true
91
103
  end
92
104
 
93
105
  it 'not exist required' do
94
106
  e = assert_raises(Committee::InvalidRequest) {
95
- operation_object.validate_request_params({"query_integer_list" => [1, 2]}, @validator_option)
107
+ operation_object.validate_request_params({"query_integer_list" => [1, 2]}, HEADER, @validator_option)
96
108
  }
97
109
 
98
110
  assert e.message.start_with?("required parameters query_string not exist in")
@@ -100,7 +112,11 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
100
112
 
101
113
  it 'invalid type' do
102
114
  e = assert_raises(Committee::InvalidRequest) {
103
- operation_object.validate_request_params({"query_string" => 1, "query_integer_list" => [1, 2], "optional_integer" => 1}, @validator_option)
115
+ operation_object.validate_request_params(
116
+ {"query_string" => 1, "query_integer_list" => [1, 2], "optional_integer" => 1},
117
+ HEADER,
118
+ @validator_option
119
+ )
104
120
  }
105
121
 
106
122
  # FIXME: when ruby 2.3 dropped, fix because ruby 2.3 return Fixnum, ruby 2.4 or later return Integer
@@ -115,14 +131,14 @@ describe Committee::SchemaValidator::OpenAPI3::OperationWrapper do
115
131
  end
116
132
 
117
133
  it 'correct' do
118
- operation_object.validate_request_params({"limit" => "1"}, @validator_option)
134
+ operation_object.validate_request_params({"limit" => "1"}, HEADER, @validator_option)
119
135
 
120
136
  assert true
121
137
  end
122
138
 
123
139
  it 'invalid type' do
124
140
  e = assert_raises(Committee::InvalidRequest) {
125
- operation_object.validate_request_params({"limit" => "a"}, @validator_option)
141
+ operation_object.validate_request_params({"limit" => "a"}, HEADER, @validator_option)
126
142
  }
127
143
 
128
144
  assert e.message.start_with?("a class is String but")
@@ -1,151 +1,50 @@
1
1
  require_relative "../../test_helper"
2
2
 
3
- require "stringio"
4
-
5
- # TODO: fix
6
-
7
3
  describe Committee::SchemaValidator::OpenAPI3::RequestValidator do
8
- describe 'open_api_3' do
9
- before do
10
- @schema = JsonSchema.parse!(hyper_schema_data)
11
- @schema.expand_references!
12
- # POST /apps/:id
13
- @link = @schema.properties["app"].links[0]
14
- @request = Rack::Request.new({
15
- "CONTENT_TYPE" => "application/json",
16
- "rack.input" => StringIO.new("{}"),
17
- "REQUEST_METHOD" => "POST"
18
- })
19
- end
4
+ describe 'OpenAPI3' do
5
+ include Rack::Test::Methods
20
6
 
21
- it "passes through a valid request with Content-Type options" do
22
- @headers = { "Content-Type" => "application/json; charset=utf-8" }
23
- call({})
7
+ def app
8
+ @app
24
9
  end
25
10
 
26
- it "passes through a valid request" do
27
- data = {
28
- "name" => "heroku-api",
11
+ it "optionally content_type check" do
12
+ @app = new_rack_app(check_content_type: true, schema: open_api_3_schema)
13
+ params = {
14
+ "string_post_1" => "cloudnasium"
29
15
  }
30
- call(data)
16
+ header "Content-Type", "text/html"
17
+ post "/characters", JSON.generate(params)
18
+ assert_equal 400, last_response.status
31
19
  end
32
20
 
33
- it "passes through a valid request with Content-Type options" do
34
- @request =
35
- Rack::Request.new({
36
- "CONTENT_TYPE" => "application/json; charset=utf-8",
37
- "rack.input" => StringIO.new("{}"),
38
- })
39
- data = {
40
- "name" => "heroku-api",
21
+ it "optionally skip content_type check" do
22
+ @app = new_rack_app(check_content_type: false, schema: open_api_3_schema)
23
+ params = {
24
+ "string_post_1" => "cloudnasium"
41
25
  }
42
- call(data)
26
+ header "Content-Type", "text/html"
27
+ post "/characters", JSON.generate(params)
28
+ assert_equal 200, last_response.status
43
29
  end
44
30
 
45
- it "detects an invalid request Content-Type" do
46
- e = assert_raises(Committee::InvalidRequest) {
47
- @request =
48
- Rack::Request.new({
49
- "CONTENT_TYPE" => "application/x-www-form-urlencoded",
50
- "rack.input" => StringIO.new("{}"),
51
- })
52
- call({})
31
+ it "if not exist requsetBody definition, skip content_type check" do
32
+ @app = new_rack_app(check_content_type: true, schema: open_api_3_schema)
33
+ params = {
34
+ "string_post_1" => "cloudnasium"
53
35
  }
54
- message =
55
- %{"Content-Type" request header must be set to "application/json".}
56
- assert_equal message, e.message
57
- end
58
-
59
- it "allows skipping content_type check" do
60
- @request =
61
- Rack::Request.new({
62
- "CONTENT_TYPE" => "application/x-www-form-urlencoded",
63
- "rack.input" => StringIO.new("{}"),
64
- })
65
- call({}, {}, check_content_type: false)
66
- end
67
-
68
- it "detects an missing parameter in GET requests" do
69
- # GET /apps/search?query=...
70
- @link = @schema.properties["app"].links[5]
71
- @request = Rack::Request.new({})
72
- e = assert_raises(Committee::InvalidRequest) do
73
- call({})
74
- end
75
- message =
76
- %{Invalid request.\n\n#: failed schema #/definitions/app/links/5/schema: "query" wasn't supplied.}
77
- assert_equal message, e.message
78
- end
79
-
80
- it "allows an invalid Content-Type with an empty body" do
81
- @request =
82
- Rack::Request.new({
83
- "CONTENT_TYPE" => "application/x-www-form-urlencoded",
84
- "rack.input" => StringIO.new(""),
85
- })
86
- call({})
87
- end
88
-
89
- it "detects a parameter of the wrong pattern" do
90
- data = {
91
- "name" => "%@!"
92
- }
93
- e = assert_raises(Committee::InvalidRequest) do
94
- call(data)
95
- end
96
- message = %{Invalid request.\n\n#/name: failed schema #/definitions/app/links/0/schema/properties/name: %@! does not match /^[a-z][a-z0-9-]{3,30}$/.}
97
- assert_equal message, e.message
98
- end
99
-
100
- private
101
-
102
- def call(data, headers={}, options={})
103
- # hyper-schema link should be dropped into driver wrapper before it's used
104
- link = Committee::Drivers::HyperSchema::Link.new(@link)
105
- Committee::SchemaValidator::HyperSchema::RequestValidator.new(link, options).call(@request, data, headers)
36
+ header "Content-Type", "application/json"
37
+ patch "/validate_no_parameter", JSON.generate(params)
38
+ assert_equal 200, last_response.status
106
39
  end
107
- end
108
40
 
109
- describe 'OpenAPI 2' do
110
- before do
111
- @schema = open_api_2_schema
112
- @link = @schema.routes['GET'][0][1]
113
- @request = Rack::Request.new({
114
- "CONTENT_TYPE" => "application/json",
115
- "rack.input" => StringIO.new("{}"),
116
- "REQUEST_METHOD" => "POST"
117
- })
118
- end
119
-
120
-
121
- it "passes through a valid request" do
122
- headers = {
123
- "AUTH-TOKEN" => "xxx"
41
+ def new_rack_app(options = {})
42
+ Rack::Builder.new {
43
+ use Committee::Middleware::RequestValidation, options
44
+ run lambda { |_|
45
+ [200, {}, []]
46
+ }
124
47
  }
125
- call({}, headers)
126
- end
127
-
128
- it "detects an missing header parameter in GET requests" do
129
- @link = @schema.routes['GET'][0][1]
130
- @request = Rack::Request.new({})
131
- e = assert_raises(Committee::InvalidRequest) do
132
- call({}, {})
133
- end
134
- message = %{Invalid request.\n\n#: failed schema : "AUTH-TOKEN" wasn't supplied.}
135
- assert_equal message, e.message
136
- end
137
-
138
- it "allows skipping header schema check" do
139
- @link = @schema.routes['GET'][0][1]
140
- @request = Rack::Request.new({})
141
- call({}, {}, { check_header: false })
142
- end
143
-
144
- private
145
-
146
- def call(data, headers={}, options={})
147
- # hyper-schema link should be dropped into driver wrapper before it's used
148
- Committee::SchemaValidator::HyperSchema::RequestValidator.new(@link, options).call(@request, data, headers)
149
48
  end
150
49
  end
151
50
  end
@@ -22,18 +22,30 @@ describe Committee::SchemaValidator::OpenAPI3::ResponseValidator do
22
22
  call_response_validator
23
23
  end
24
24
 
25
- # TODO: raise error option
26
- it "passes through a valid response with no registered Content-Type" do
25
+ it "passes through a valid response with no registered Content-Type with strict = false" do
27
26
  @headers = { "Content-Type" => "application/xml" }
28
27
  call_response_validator
29
28
  end
30
29
 
31
- # TODO: raise error option
30
+ it "passes through a valid response with no registered Content-Type with strict = true" do
31
+ @headers = { "Content-Type" => "application/xml" }
32
+ assert_raises(Committee::InvalidResponse) {
33
+ call_response_validator(true)
34
+ }
35
+ end
36
+
32
37
  it "passes through a valid response with no Content-Type" do
33
38
  @headers = {}
34
39
  call_response_validator
35
40
  end
36
41
 
42
+ it "passes through a valid response with no Content-Type with strict option" do
43
+ @headers = {}
44
+ assert_raises(Committee::InvalidResponse) {
45
+ call_response_validator(true)
46
+ }
47
+ end
48
+
37
49
  it "passes through a valid list response" do
38
50
  @path = '/validate_response_array'
39
51
  @method = 'get'
@@ -48,8 +60,10 @@ describe Committee::SchemaValidator::OpenAPI3::ResponseValidator do
48
60
 
49
61
  private
50
62
 
51
- def call_response_validator
63
+ def call_response_validator(strict = false)
52
64
  @operation_object = open_api_3_schema.operation_object(@path, @method)
53
- Committee::SchemaValidator::OpenAPI3::ResponseValidator.new(@operation_object, @validator_option).call(@status, @headers, @data)
65
+ Committee::SchemaValidator::OpenAPI3::ResponseValidator.
66
+ new(@operation_object, @validator_option).
67
+ call(@status, @headers, @data, strict)
54
68
  end
55
69
  end
@@ -46,7 +46,23 @@ describe Committee::Test::Methods do
46
46
  end
47
47
 
48
48
  it "detects an invalid response Content-Type" do
49
- @app = new_rack_app(JSON.generate([ValidApp]), {})
49
+ @app = new_rack_app(JSON.generate([ValidApp]), 200, {})
50
+ get "/apps"
51
+ e = assert_raises(Committee::InvalidResponse) do
52
+ assert_schema_conform
53
+ end
54
+ assert_match(/response header must be set to/i, e.message)
55
+ end
56
+
57
+ it "detects an invalid response Content-Type but ignore because it's not success status code" do
58
+ @committee_options.merge!(validate_success_only: true)
59
+ @app = new_rack_app(JSON.generate([ValidApp]), 400, {})
60
+ get "/apps"
61
+ assert_schema_conform
62
+ end
63
+
64
+ it "detects an invalid response Content-Type and check all status code" do
65
+ @app = new_rack_app(JSON.generate([ValidApp]), 400, {})
50
66
  get "/apps"
51
67
  e = assert_raises(Committee::InvalidResponse) do
52
68
  assert_schema_conform
@@ -57,10 +73,10 @@ describe Committee::Test::Methods do
57
73
 
58
74
  private
59
75
 
60
- def new_rack_app(response, headers={ "Content-Type" => "application/json" })
76
+ def new_rack_app(response, status=200, headers={ "Content-Type" => "application/json" })
61
77
  Rack::Builder.new {
62
78
  run lambda { |_|
63
- [200, headers, [response]]
79
+ [status, headers, [response]]
64
80
  }
65
81
  }
66
82
  end