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.
- checksums.yaml +5 -5
- data/lib/committee/drivers/hyper_schema.rb +8 -2
- data/lib/committee/drivers/open_api_2.rb +7 -2
- data/lib/committee/drivers/open_api_3.rb +9 -4
- data/lib/committee/drivers.rb +46 -0
- data/lib/committee/middleware/base.rb +9 -11
- data/lib/committee/middleware/response_validation.rb +8 -5
- data/lib/committee/request_unpacker.rb +4 -1
- data/lib/committee/{parameter_coercer.rb → schema_validator/hyper_schema/parameter_coercer.rb} +1 -2
- data/lib/committee/schema_validator/hyper_schema/request_validator.rb +1 -5
- data/lib/committee/schema_validator/hyper_schema/response_validator.rb +3 -9
- data/lib/committee/schema_validator/hyper_schema/router.rb +1 -1
- data/lib/committee/schema_validator/hyper_schema.rb +5 -4
- data/lib/committee/schema_validator/open_api_3/operation_wrapper.rb +46 -19
- data/lib/committee/schema_validator/open_api_3/request_validator.rb +14 -4
- data/lib/committee/schema_validator/open_api_3/response_validator.rb +9 -20
- data/lib/committee/schema_validator/open_api_3/router.rb +15 -4
- data/lib/committee/schema_validator/open_api_3.rb +14 -5
- data/lib/committee/schema_validator/option.rb +2 -5
- data/lib/committee/schema_validator/schema_validator.rb +15 -0
- data/lib/committee/test/methods.rb +3 -5
- data/lib/committee.rb +3 -1
- data/test/drivers/open_api_3_test.rb +2 -1
- data/test/drivers_test.rb +69 -0
- data/test/middleware/base_test.rb +20 -5
- data/test/middleware/request_validation_open_api_3_test.rb +136 -259
- data/test/middleware/request_validation_test.rb +18 -3
- data/test/middleware/response_validation_open_api_3_test.rb +83 -16
- data/test/middleware/response_validation_test.rb +19 -7
- data/test/middleware/stub_test.rb +1 -1
- data/test/{parameter_coercer_test.rb → schema_validator/hyper_schema/parameter_coercer_test.rb} +3 -3
- data/test/schema_validator/hyper_schema/router_test.rb +6 -0
- data/test/schema_validator/open_api_3/operation_wrapper_test.rb +29 -13
- data/test/schema_validator/open_api_3/request_validator_test.rb +31 -132
- data/test/schema_validator/open_api_3/response_validator_test.rb +19 -5
- data/test/test/methods_new_version_test.rb +19 -3
- data/test/test/methods_test.rb +15 -8
- data/test/test_helper.rb +15 -16
- 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), {},
|
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", {},
|
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), {},
|
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("[]", {},
|
34
|
+
@app = new_response_rack("[]", {}, schema: open_api_3_schema, raise: true)
|
35
35
|
|
36
|
-
e = assert_raises(Committee::
|
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("", {}, {
|
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), {},
|
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", {},
|
56
|
+
@app = new_response_rack("not_json", {}, schema: open_api_3_schema, prefix: "/v1")
|
57
57
|
|
58
58
|
get "/v1/characters"
|
59
59
|
|
60
|
-
|
61
|
-
assert_equal
|
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", {},
|
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, {},
|
72
|
+
@app = new_response_rack({integer: '1'}.to_json, {}, schema: open_api_3_schema, raise: true)
|
75
73
|
|
76
|
-
|
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 = ->(
|
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,
|
46
|
-
|
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,
|
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"
|
data/test/{parameter_coercer_test.rb → schema_validator/hyper_schema/parameter_coercer_test.rb}
RENAMED
@@ -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(
|
88
|
-
|
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(
|
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 '
|
9
|
-
|
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
|
-
|
22
|
-
@
|
23
|
-
call({})
|
7
|
+
def app
|
8
|
+
@app
|
24
9
|
end
|
25
10
|
|
26
|
-
it "
|
27
|
-
|
28
|
-
|
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
|
-
|
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 "
|
34
|
-
@
|
35
|
-
|
36
|
-
|
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
|
-
|
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 "
|
46
|
-
|
47
|
-
|
48
|
-
|
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
|
-
|
55
|
-
|
56
|
-
assert_equal
|
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
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
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
|
-
|
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
|
-
|
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.
|
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
|
-
[
|
79
|
+
[status, headers, [response]]
|
64
80
|
}
|
65
81
|
}
|
66
82
|
end
|