committee 3.0.0.alpha → 3.0.0.beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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
|