praxis 2.0.pre.17 → 2.0.pre.21
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +54 -0
- data/.simplecov +3 -1
- data/.travis.yml +2 -1
- data/CHANGELOG.md +19 -0
- data/CONTRIBUTING.md +2 -79
- data/Gemfile +5 -1
- data/Guardfile +6 -4
- data/LICENSE +0 -2
- data/MAINTAINERS.md +1 -0
- data/README.md +15 -22
- data/Rakefile +4 -2
- data/bin/praxis +55 -58
- data/lib/praxis/action_definition/headers_dsl_compiler.rb +5 -6
- data/lib/praxis/action_definition.rb +65 -95
- data/lib/praxis/api_definition.rb +21 -29
- data/lib/praxis/api_general_info.rb +55 -66
- data/lib/praxis/application.rb +15 -32
- data/lib/praxis/blueprint.rb +80 -73
- data/lib/praxis/bootloader.rb +24 -33
- data/lib/praxis/bootloader_stages/environment.rb +5 -10
- data/lib/praxis/bootloader_stages/file_loader.rb +3 -6
- data/lib/praxis/bootloader_stages/plugin_config_load.rb +4 -6
- data/lib/praxis/bootloader_stages/plugin_config_prepare.rb +2 -2
- data/lib/praxis/bootloader_stages/plugin_loader.rb +3 -7
- data/lib/praxis/bootloader_stages/plugin_setup.rb +3 -3
- data/lib/praxis/bootloader_stages/routing.rb +5 -8
- data/lib/praxis/bootloader_stages/subgroup_loader.rb +2 -10
- data/lib/praxis/bootloader_stages/warn_unloaded_files.rb +15 -19
- data/lib/praxis/callbacks.rb +12 -11
- data/lib/praxis/collection.rb +11 -14
- data/lib/praxis/config.rb +17 -28
- data/lib/praxis/config_hash.rb +2 -1
- data/lib/praxis/controller.rb +7 -6
- data/lib/praxis/dispatcher.rb +34 -42
- data/lib/praxis/docs/open_api/info_object.rb +11 -8
- data/lib/praxis/docs/open_api/media_type_object.rb +18 -17
- data/lib/praxis/docs/open_api/operation_object.rb +7 -4
- data/lib/praxis/docs/open_api/parameter_object.rb +17 -14
- data/lib/praxis/docs/open_api/paths_object.rb +11 -9
- data/lib/praxis/docs/open_api/request_body_object.rb +14 -13
- data/lib/praxis/docs/open_api/response_object.rb +24 -18
- data/lib/praxis/docs/open_api/responses_object.rb +3 -1
- data/lib/praxis/docs/open_api/schema_object.rb +61 -29
- data/lib/praxis/docs/open_api/server_object.rb +5 -2
- data/lib/praxis/docs/open_api/tag_object.rb +9 -6
- data/lib/praxis/docs/open_api_generator.rb +114 -150
- data/lib/praxis/endpoint_definition.rb +60 -77
- data/lib/praxis/error_handler.rb +2 -2
- data/lib/praxis/exception.rb +2 -0
- data/lib/praxis/exceptions/config.rb +3 -1
- data/lib/praxis/exceptions/config_load.rb +2 -0
- data/lib/praxis/exceptions/config_validation.rb +3 -1
- data/lib/praxis/exceptions/invalid_configuration.rb +3 -1
- data/lib/praxis/exceptions/invalid_response.rb +3 -1
- data/lib/praxis/exceptions/invalid_trait.rb +3 -1
- data/lib/praxis/exceptions/stage_not_found.rb +3 -1
- data/lib/praxis/exceptions/validation.rb +4 -3
- data/lib/praxis/extensions/attribute_filtering/active_record_filter_query_builder.rb +163 -149
- data/lib/praxis/extensions/attribute_filtering/active_record_patches/5x.rb +18 -13
- data/lib/praxis/extensions/attribute_filtering/active_record_patches/6_0.rb +13 -9
- data/lib/praxis/extensions/attribute_filtering/active_record_patches/6_1_plus.rb +14 -11
- data/lib/praxis/extensions/attribute_filtering/active_record_patches.rb +12 -9
- data/lib/praxis/extensions/attribute_filtering/filter_tree_node.rb +8 -5
- data/lib/praxis/extensions/attribute_filtering/filtering_params.rb +89 -65
- data/lib/praxis/extensions/attribute_filtering/filters_parser.rb +68 -62
- data/lib/praxis/extensions/attribute_filtering.rb +3 -1
- data/lib/praxis/extensions/field_expansion.rb +6 -4
- data/lib/praxis/extensions/field_selection/active_record_query_selector.rb +10 -8
- data/lib/praxis/extensions/field_selection/field_selector.rb +91 -92
- data/lib/praxis/extensions/field_selection/sequel_query_selector.rb +12 -12
- data/lib/praxis/extensions/field_selection.rb +3 -1
- data/lib/praxis/extensions/pagination/active_record_pagination_handler.rb +6 -4
- data/lib/praxis/extensions/pagination/header_generator.rb +16 -11
- data/lib/praxis/extensions/pagination/ordering_params.rb +29 -28
- data/lib/praxis/extensions/pagination/pagination_handler.rb +44 -42
- data/lib/praxis/extensions/pagination/pagination_params.rb +29 -48
- data/lib/praxis/extensions/pagination/sequel_pagination_handler.rb +8 -7
- data/lib/praxis/extensions/pagination.rb +10 -15
- data/lib/praxis/extensions/rails_compat/request_methods.rb +3 -4
- data/lib/praxis/extensions/rails_compat.rb +2 -0
- data/lib/praxis/extensions/rendering.rb +12 -12
- data/lib/praxis/field_expander.rb +8 -9
- data/lib/praxis/file_group.rb +8 -12
- data/lib/praxis/finalizable.rb +1 -0
- data/lib/praxis/handlers/json.rb +5 -2
- data/lib/praxis/handlers/plain.rb +2 -1
- data/lib/praxis/handlers/www_form.rb +6 -3
- data/lib/praxis/handlers/{xml-sample.rb → xml_sample.rb} +26 -22
- data/lib/praxis/mapper/active_model_compat.rb +13 -10
- data/lib/praxis/mapper/resource.rb +196 -181
- data/lib/praxis/mapper/selector_generator.rb +106 -112
- data/lib/praxis/mapper/sequel_compat.rb +70 -67
- data/lib/praxis/media_type.rb +2 -2
- data/lib/praxis/media_type_identifier.rb +26 -22
- data/lib/praxis/middleware_app.rb +18 -15
- data/lib/praxis/multipart/parser.rb +46 -51
- data/lib/praxis/multipart/part.rb +78 -110
- data/lib/praxis/notifications.rb +2 -4
- data/lib/praxis/plugin.rb +11 -18
- data/lib/praxis/plugin_concern.rb +12 -15
- data/lib/praxis/plugins/mapper_plugin.rb +15 -13
- data/lib/praxis/plugins/pagination_plugin.rb +8 -6
- data/lib/praxis/plugins/rails_plugin.rb +33 -28
- data/lib/praxis/renderer.rb +11 -15
- data/lib/praxis/request.rb +48 -44
- data/lib/praxis/request_stages/action.rb +4 -6
- data/lib/praxis/request_stages/load_request.rb +2 -4
- data/lib/praxis/request_stages/request_stage.rb +19 -23
- data/lib/praxis/request_stages/response.rb +4 -6
- data/lib/praxis/request_stages/validate.rb +3 -5
- data/lib/praxis/request_stages/validate_params_and_headers.rb +15 -22
- data/lib/praxis/request_stages/validate_payload.rb +25 -28
- data/lib/praxis/request_superclassing.rb +3 -3
- data/lib/praxis/resource_definition.rb +1 -0
- data/lib/praxis/response.rb +24 -26
- data/lib/praxis/response_definition.rb +77 -122
- data/lib/praxis/response_template.rb +11 -15
- data/lib/praxis/responses/http.rb +23 -44
- data/lib/praxis/responses/internal_server_error.rb +18 -21
- data/lib/praxis/responses/multipart_ok.rb +4 -9
- data/lib/praxis/responses/validation_error.rb +8 -15
- data/lib/praxis/route.rb +8 -10
- data/lib/praxis/router/rack.rb +13 -7
- data/lib/praxis/router/simple.rb +10 -5
- data/lib/praxis/router.rb +27 -34
- data/lib/praxis/routing_config.rb +52 -29
- data/lib/praxis/simple_media_type.rb +5 -8
- data/lib/praxis/stage.rb +17 -25
- data/lib/praxis/tasks/api_docs.rb +17 -16
- data/lib/praxis/tasks/console.rb +3 -1
- data/lib/praxis/tasks/environment.rb +2 -0
- data/lib/praxis/tasks/routes.rb +26 -24
- data/lib/praxis/tasks.rb +3 -1
- data/lib/praxis/trait.rb +37 -46
- data/lib/praxis/types/fuzzy_hash.rb +13 -14
- data/lib/praxis/types/media_type_common.rb +11 -10
- data/lib/praxis/types/multipart_array/part_definition.rb +14 -17
- data/lib/praxis/types/multipart_array.rb +100 -115
- data/lib/praxis/validation_handler.rb +5 -3
- data/lib/praxis/version.rb +3 -1
- data/lib/praxis.rb +4 -5
- data/praxis.gemspec +22 -21
- data/spec/functional_spec.rb +44 -56
- data/spec/praxis/action_definition_spec.rb +39 -48
- data/spec/praxis/api_definition_spec.rb +45 -47
- data/spec/praxis/api_general_info_spec.rb +28 -29
- data/spec/praxis/application_spec.rb +18 -14
- data/spec/praxis/blueprint_spec.rb +33 -34
- data/spec/praxis/bootloader_spec.rb +32 -30
- data/spec/praxis/callbacks_spec.rb +37 -37
- data/spec/praxis/collection_spec.rb +18 -25
- data/spec/praxis/config_hash_spec.rb +5 -4
- data/spec/praxis/config_spec.rb +27 -26
- data/spec/praxis/controller_spec.rb +8 -9
- data/spec/praxis/endpoint_definition_spec.rb +25 -32
- data/spec/praxis/extensions/attribute_filtering/active_record_filter_query_builder_spec.rb +171 -114
- data/spec/praxis/extensions/attribute_filtering/filter_tree_node_spec.rb +22 -21
- data/spec/praxis/extensions/attribute_filtering/filtering_params_spec.rb +112 -60
- data/spec/praxis/extensions/attribute_filtering/filters_parser_spec.rb +37 -38
- data/spec/praxis/extensions/field_expansion_spec.rb +8 -10
- data/spec/praxis/extensions/field_selection/active_record_query_selector_spec.rb +14 -13
- data/spec/praxis/extensions/field_selection/field_selector_spec.rb +9 -16
- data/spec/praxis/extensions/field_selection/sequel_query_selector_spec.rb +50 -49
- data/spec/praxis/extensions/pagination/active_record_pagination_handler_spec.rb +32 -31
- data/spec/praxis/extensions/rendering_spec.rb +9 -9
- data/spec/praxis/extensions/support/spec_resources_active_model.rb +32 -49
- data/spec/praxis/extensions/support/spec_resources_sequel.rb +48 -48
- data/spec/praxis/field_expander_spec.rb +6 -5
- data/spec/praxis/file_group_spec.rb +3 -1
- data/spec/praxis/handlers/json_spec.rb +6 -5
- data/spec/praxis/mapper/resource_spec.rb +39 -29
- data/spec/praxis/mapper/selector_generator_spec.rb +80 -46
- data/spec/praxis/media_type_identifier_spec.rb +13 -10
- data/spec/praxis/media_type_spec.rb +12 -12
- data/spec/praxis/middleware_app_spec.rb +23 -22
- data/spec/praxis/multipart/parser_spec.rb +7 -9
- data/spec/praxis/notifications_spec.rb +4 -4
- data/spec/praxis/plugin_concern_spec.rb +5 -6
- data/spec/praxis/renderer_spec.rb +10 -9
- data/spec/praxis/request_spec.rb +38 -41
- data/spec/praxis/request_stages/action_spec.rb +14 -15
- data/spec/praxis/request_stages/request_stage_spec.rb +30 -41
- data/spec/praxis/request_stages/validate_spec.rb +3 -1
- data/spec/praxis/response_definition_spec.rb +79 -92
- data/spec/praxis/response_spec.rb +35 -40
- data/spec/praxis/responses/internal_server_error_spec.rb +6 -9
- data/spec/praxis/responses/validation_error_spec.rb +17 -18
- data/spec/praxis/route_spec.rb +4 -7
- data/spec/praxis/router_spec.rb +69 -79
- data/spec/praxis/routing_config_spec.rb +15 -14
- data/spec/praxis/stage_spec.rb +56 -53
- data/spec/praxis/trait_spec.rb +17 -17
- data/spec/praxis/types/fuzzy_hash_spec.rb +11 -9
- data/spec/praxis/types/multipart_array/part_definition_spec.rb +3 -2
- data/spec/praxis/types/multipart_array_spec.rb +33 -48
- data/spec/spec_app/app/concerns/authenticated.rb +5 -5
- data/spec/spec_app/app/concerns/basic_api.rb +3 -1
- data/spec/spec_app/app/concerns/log_wrapper.rb +5 -3
- data/spec/spec_app/app/controllers/base_class.rb +6 -5
- data/spec/spec_app/app/controllers/instances.rb +31 -34
- data/spec/spec_app/app/controllers/volumes.rb +6 -6
- data/spec/spec_app/app/responses/multipart.rb +1 -2
- data/spec/spec_app/app/responses/other_response.rb +2 -2
- data/spec/spec_app/config/environment.rb +19 -6
- data/spec/spec_app/config.ru +4 -3
- data/spec/spec_app/design/api.rb +13 -15
- data/spec/spec_app/design/media_types/instance.rb +6 -6
- data/spec/spec_app/design/media_types/volume.rb +2 -1
- data/spec/spec_app/design/media_types/volume_snapshot.rb +2 -1
- data/spec/spec_app/design/resources/instances.rb +11 -17
- data/spec/spec_app/design/resources/volume_snapshots.rb +4 -5
- data/spec/spec_app/design/resources/volumes.rb +4 -5
- data/spec/spec_helper.rb +11 -13
- data/spec/support/be_deep_equal_matcher.rb +5 -0
- data/spec/support/spec_authorization_plugin.rb +7 -12
- data/spec/support/spec_blueprints.rb +5 -4
- data/spec/support/spec_complex_authentication_plugin.rb +17 -34
- data/spec/support/spec_endpoint_definitions.rb +2 -3
- data/spec/support/spec_media_types.rb +28 -35
- data/spec/support/spec_resources.rb +22 -16
- data/spec/support/spec_simple_authentication_plugin.rb +5 -9
- data/tasks/loader.thor +4 -2
- data/tasks/thor/app.rb +7 -5
- data/tasks/thor/example.rb +23 -22
- data/tasks/thor/model.rb +7 -7
- data/tasks/thor/scaffold.rb +23 -23
- data/tasks/thor/templates/generator/example_app/app/v1/resources/user.rb +0 -8
- data/tasks/thor/templates/generator/scaffold/implementation/resources/item.rb +1 -2
- metadata +72 -84
- data/MAINTAINERS +0 -2
- data/TODO.md +0 -25
- data/spec/praxis/api_resource_spec.rb +0 -0
- data/spec/praxis/dispatcher_spec.rb +0 -0
- data/spec/spec_app/app/responses/bulk_response.rb +0 -0
@@ -1,15 +1,17 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
2
4
|
|
3
5
|
describe Praxis::ResponseDefinition do
|
4
6
|
subject(:response_definition) { Praxis::ResponseDefinition.new(name, &block) }
|
5
7
|
let(:name) { 'response_name' }
|
6
8
|
|
7
9
|
let(:block) do
|
8
|
-
|
10
|
+
proc do
|
9
11
|
status 200
|
10
12
|
description 'test description'
|
11
|
-
header(
|
12
|
-
header(
|
13
|
+
header('X-Header', 'value', description: 'Very nais header')
|
14
|
+
header('Content-Type', 'application/some-type')
|
13
15
|
end
|
14
16
|
end
|
15
17
|
|
@@ -17,11 +19,10 @@ describe Praxis::ResponseDefinition do
|
|
17
19
|
its(:description) { should == 'test description' }
|
18
20
|
its(:parts) { should be(nil) }
|
19
21
|
let(:response_status) { 200 }
|
20
|
-
let(:response_content_type) {
|
21
|
-
let(:response_headers) { {
|
22
|
-
|
23
|
-
let(:response) { instance_double("Praxis::Response", status: response_status , headers: response_headers, content_type: response_content_type ) }
|
22
|
+
let(:response_content_type) { 'application/some-type' }
|
23
|
+
let(:response_headers) { { 'X-Header' => 'value', 'Content-Type' => response_content_type, 'Location' => '/somewhere/over/the/rainbow' } }
|
24
24
|
|
25
|
+
let(:response) { instance_double('Praxis::Response', status: response_status, headers: response_headers, content_type: response_content_type) }
|
25
26
|
|
26
27
|
context '#media_type' do
|
27
28
|
it 'accepts a MediaType object and returns the media_type that was set' do
|
@@ -42,11 +43,11 @@ describe Praxis::ResponseDefinition do
|
|
42
43
|
end
|
43
44
|
|
44
45
|
it 'should return an error when media_type is not a String or a MediaType' do
|
45
|
-
expect{ response_definition.media_type Object.new }.to raise_error(Praxis::Exceptions::InvalidConfiguration)
|
46
|
+
expect { response_definition.media_type Object.new }.to raise_error(Praxis::Exceptions::InvalidConfiguration)
|
46
47
|
end
|
47
48
|
|
48
49
|
it 'should return an error when media_type is a Symbol other than :controller_defined' do
|
49
|
-
expect{ response_definition.media_type :symbol }.to raise_error(Praxis::Exceptions::InvalidConfiguration)
|
50
|
+
expect { response_definition.media_type :symbol }.to raise_error(Praxis::Exceptions::InvalidConfiguration)
|
50
51
|
end
|
51
52
|
end
|
52
53
|
|
@@ -73,7 +74,7 @@ describe Praxis::ResponseDefinition do
|
|
73
74
|
end
|
74
75
|
|
75
76
|
# TODO: Complete/correct the "example" generation when it is done in the ResponseDefinition class
|
76
|
-
#context 'with media_type set to a MediaType' do
|
77
|
+
# context 'with media_type set to a MediaType' do
|
77
78
|
# let(:media_type) { Person }
|
78
79
|
#
|
79
80
|
# let(:expected_context) { "Person-#{name}" }
|
@@ -87,17 +88,17 @@ describe Praxis::ResponseDefinition do
|
|
87
88
|
# it 'is rendered in the describe output' do
|
88
89
|
# expect(response_definition.describe[:example]).to eq(example.render)
|
89
90
|
# end
|
90
|
-
#end
|
91
|
+
# end
|
91
92
|
end
|
92
93
|
|
93
94
|
context '#location' do
|
94
95
|
it 'accepts a String' do
|
95
|
-
response_definition.location
|
96
|
-
expect(response_definition.location).to eq(
|
96
|
+
response_definition.location 'string_location'
|
97
|
+
expect(response_definition.location).to eq('string_location')
|
97
98
|
end
|
98
99
|
|
99
100
|
it 'accepts a Regex' do
|
100
|
-
response_definition.location
|
101
|
+
response_definition.location(/regex_location/)
|
101
102
|
expect(response_definition.location).to eq(/regex_location/)
|
102
103
|
end
|
103
104
|
|
@@ -114,31 +115,30 @@ describe Praxis::ResponseDefinition do
|
|
114
115
|
|
115
116
|
subject(:parts) { response_definition.parts }
|
116
117
|
|
117
|
-
it{ should be_kind_of(Praxis::ResponseDefinition) }
|
118
|
-
its('media_type.identifier'){ should == 'application/special' }
|
119
|
-
its(:name){ should be(:ok) }
|
120
|
-
its(:status){ should be(
|
121
|
-
|
118
|
+
it { should be_kind_of(Praxis::ResponseDefinition) }
|
119
|
+
its('media_type.identifier') { should == 'application/special' }
|
120
|
+
its(:name) { should be(:ok) }
|
121
|
+
its(:status) { should be(200) }
|
122
122
|
end
|
123
123
|
context 'without a :like argument, and without a block' do
|
124
124
|
it 'complains' do
|
125
|
-
expect
|
125
|
+
expect do
|
126
126
|
response_definition.parts media_type: 'application/special'
|
127
|
-
|
127
|
+
end.to raise_error(ArgumentError, /needs a :like argument or a block/)
|
128
128
|
end
|
129
129
|
end
|
130
130
|
context 'with a :like argument, and a block' do
|
131
131
|
it 'complains' do
|
132
|
-
expect
|
132
|
+
expect do
|
133
133
|
response_definition.parts like: :something, media_type: 'application/special' do
|
134
134
|
end
|
135
|
-
|
135
|
+
end.to raise_error(ArgumentError, /does not allow :like and a block simultaneously/)
|
136
136
|
end
|
137
137
|
end
|
138
138
|
|
139
139
|
context 'with a proc' do
|
140
140
|
let(:the_proc) do
|
141
|
-
|
141
|
+
proc do
|
142
142
|
status 201
|
143
143
|
media_type 'from_proc'
|
144
144
|
end
|
@@ -150,10 +150,9 @@ describe Praxis::ResponseDefinition do
|
|
150
150
|
|
151
151
|
subject(:parts) { response_definition.parts }
|
152
152
|
|
153
|
-
it{ should be_kind_of(Praxis::ResponseDefinition) }
|
154
|
-
its('media_type.identifier'){ should == 'from_proc' }
|
155
|
-
its(:status){ should be(
|
156
|
-
|
153
|
+
it { should be_kind_of(Praxis::ResponseDefinition) }
|
154
|
+
its('media_type.identifier') { should == 'from_proc' }
|
155
|
+
its(:status) { should be(201) }
|
157
156
|
end
|
158
157
|
|
159
158
|
context 'with a block' do
|
@@ -166,10 +165,9 @@ describe Praxis::ResponseDefinition do
|
|
166
165
|
|
167
166
|
subject(:parts) { response_definition.parts }
|
168
167
|
|
169
|
-
it{ should be_kind_of(Praxis::ResponseDefinition) }
|
170
|
-
its('media_type.identifier'){ should == 'from_proc' }
|
171
|
-
its(:status){ should be(
|
172
|
-
|
168
|
+
it { should be_kind_of(Praxis::ResponseDefinition) }
|
169
|
+
its('media_type.identifier') { should == 'from_proc' }
|
170
|
+
its(:status) { should be(201) }
|
173
171
|
end
|
174
172
|
end
|
175
173
|
# context '#multipart' do
|
@@ -217,8 +215,7 @@ describe Praxis::ResponseDefinition do
|
|
217
215
|
|
218
216
|
context '#validate' do
|
219
217
|
context 'functional test' do
|
220
|
-
|
221
|
-
it "calls all the validation sub-functions" do
|
218
|
+
it 'calls all the validation sub-functions' do
|
222
219
|
expect(response_definition).to receive(:validate_status!).once
|
223
220
|
expect(response_definition).to receive(:validate_headers!).once
|
224
221
|
expect(response_definition).to receive(:validate_content_type!).once
|
@@ -227,68 +224,64 @@ describe Praxis::ResponseDefinition do
|
|
227
224
|
end
|
228
225
|
|
229
226
|
describe 'custom validate_xxx! methods' do
|
230
|
-
|
231
|
-
describe "#validate_status!" do
|
227
|
+
describe '#validate_status!' do
|
232
228
|
context 'that is completely valid' do
|
233
229
|
it 'should succeed' do
|
234
|
-
expect
|
230
|
+
expect do
|
235
231
|
response_definition.validate_status!(response)
|
236
|
-
|
232
|
+
end.to_not raise_error
|
237
233
|
end
|
238
234
|
end
|
239
235
|
|
240
|
-
|
241
236
|
context 'with internal error' do
|
242
237
|
let(:response_status) { 500 }
|
243
238
|
it 'should raise an error that later gets swallowed' do
|
244
|
-
expect
|
239
|
+
expect do
|
245
240
|
response_definition.validate_status!(response)
|
246
|
-
|
241
|
+
end.to raise_error(Praxis::Exceptions::Validation)
|
247
242
|
end
|
248
243
|
end
|
249
|
-
|
250
244
|
end
|
251
245
|
|
252
|
-
describe
|
246
|
+
describe '#validate_headers!' do
|
253
247
|
context 'when there are missing headers' do
|
254
248
|
it 'should raise error' do
|
255
249
|
response_definition.header('X-Unknown', 'test')
|
256
|
-
expect
|
250
|
+
expect do
|
257
251
|
response_definition.validate_headers!(response)
|
258
|
-
|
252
|
+
end.to raise_error(Praxis::Exceptions::Validation)
|
259
253
|
end
|
260
254
|
end
|
261
255
|
context 'when headers with same names are returned' do
|
262
256
|
it 'a simply required header should not raise error just by being there' do
|
263
257
|
response_definition.header('X-Header', nil)
|
264
|
-
expect
|
258
|
+
expect do
|
265
259
|
response_definition.validate_headers!(response)
|
266
|
-
|
260
|
+
end.to_not raise_error
|
267
261
|
end
|
268
262
|
it 'an exact string header should not raise error if it fully matches' do
|
269
263
|
response_definition.header('X-Header', 'value')
|
270
|
-
expect
|
264
|
+
expect do
|
271
265
|
response_definition.validate_headers!(response)
|
272
|
-
|
266
|
+
end.to_not raise_error
|
273
267
|
end
|
274
268
|
it 'a regexp header should not raise error if it matches the regexp' do
|
275
269
|
response_definition.header('X-Header', /value/)
|
276
|
-
expect
|
270
|
+
expect do
|
277
271
|
response_definition.validate_headers!(response)
|
278
|
-
|
272
|
+
end.to_not raise_error
|
279
273
|
end
|
280
274
|
it 'a regexp header should raise error if it does not match the regexp' do
|
281
275
|
response_definition.header('X-Header', /anotherthing/)
|
282
|
-
expect
|
276
|
+
expect do
|
283
277
|
response_definition.validate_headers!(response)
|
284
|
-
|
278
|
+
end.to raise_error(Praxis::Exceptions::Validation)
|
285
279
|
end
|
286
280
|
end
|
287
281
|
end
|
288
282
|
|
289
|
-
describe
|
290
|
-
|
291
|
-
let(:response_headers) { {'Content-Type' => content_type } }
|
283
|
+
describe '#validate_content_type!' do
|
284
|
+
let(:response_headers) { { 'Content-Type' => content_type } }
|
292
285
|
let(:content_type) { 'application/none' }
|
293
286
|
|
294
287
|
let(:media_type) do
|
@@ -299,9 +292,9 @@ describe Praxis::ResponseDefinition do
|
|
299
292
|
|
300
293
|
context 'for definition without media_type defined' do
|
301
294
|
it 'should not check that it matches the content type' do
|
302
|
-
expect
|
295
|
+
expect do
|
303
296
|
response_definition.validate_content_type!(response)
|
304
|
-
|
297
|
+
end.to_not raise_error
|
305
298
|
end
|
306
299
|
end
|
307
300
|
|
@@ -312,60 +305,58 @@ describe Praxis::ResponseDefinition do
|
|
312
305
|
let(:response_content_type) { content_type }
|
313
306
|
|
314
307
|
it 'validates successfully' do
|
315
|
-
expect
|
308
|
+
expect do
|
316
309
|
response_definition.validate_content_type!(response)
|
317
|
-
|
310
|
+
end.to_not raise_error
|
318
311
|
end
|
319
312
|
end
|
320
313
|
|
321
314
|
context 'when content type includes a parameter' do
|
322
315
|
let(:response_content_type) { "#{content_type}; collection=true" }
|
323
316
|
it 'validates successfully' do
|
324
|
-
expect
|
317
|
+
expect do
|
325
318
|
response_definition.validate_content_type!(response)
|
326
|
-
|
319
|
+
end.to_not raise_error
|
327
320
|
end
|
328
321
|
end
|
329
322
|
|
330
323
|
context 'when content type does not match' do
|
331
|
-
let(:response_content_type) {
|
324
|
+
let(:response_content_type) { 'application/will_never_match' }
|
332
325
|
|
333
326
|
it 'should raise error telling you so' do
|
334
|
-
expect
|
327
|
+
expect do
|
335
328
|
response_definition.validate_content_type!(response)
|
336
|
-
|
329
|
+
end.to raise_error(Praxis::Exceptions::Validation)
|
337
330
|
end
|
338
331
|
end
|
339
332
|
|
340
333
|
context 'when content type is not set' do
|
341
334
|
let(:response_headers) { {} }
|
342
335
|
it 'should still raise an error' do
|
343
|
-
expect
|
336
|
+
expect do
|
344
337
|
response_definition.validate_content_type!(response)
|
345
|
-
|
338
|
+
end.to raise_error(Praxis::Exceptions::Validation)
|
346
339
|
end
|
347
340
|
end
|
348
341
|
end
|
349
342
|
end
|
350
343
|
end
|
351
|
-
|
352
344
|
end
|
353
345
|
|
354
|
-
|
355
346
|
context 'with invalid definitions' do
|
356
347
|
it 'raises an error if status code is not part of the definition' do
|
357
348
|
expect do
|
358
349
|
Praxis::ResponseDefinition.new('response name') do
|
359
|
-
description
|
350
|
+
description 'testing'
|
360
351
|
end
|
361
352
|
end.to raise_error(Praxis::Exceptions::InvalidConfiguration)
|
362
353
|
end
|
363
354
|
end
|
364
355
|
|
365
356
|
context '.describe' do
|
366
|
-
let(:description) {
|
357
|
+
let(:description) { 'A description' }
|
367
358
|
let(:location) { %r{/my/url/} }
|
368
|
-
let(:headers) { {'Header1' => 'Value1'} }
|
359
|
+
let(:headers) { { 'Header1' => 'Value1' } }
|
369
360
|
let(:parts) { nil }
|
370
361
|
let(:parts_block) { nil }
|
371
362
|
|
@@ -380,7 +371,7 @@ describe Praxis::ResponseDefinition do
|
|
380
371
|
response.description(description) if description
|
381
372
|
response.location(location) if location
|
382
373
|
if parts || parts_block
|
383
|
-
parts ? response.parts(nil, **parts, &parts_block) : response.parts(nil, &parts_block)
|
374
|
+
parts ? response.parts(nil, **parts, &parts_block) : response.parts(nil, &parts_block)
|
384
375
|
end
|
385
376
|
|
386
377
|
headers&.each do |(name, value)|
|
@@ -403,7 +394,6 @@ describe Praxis::ResponseDefinition do
|
|
403
394
|
it 'properly encodes the example bodies' do
|
404
395
|
expect(JSON.parse(examples['json'][:body])).to be_kind_of(Hash)
|
405
396
|
end
|
406
|
-
|
407
397
|
end
|
408
398
|
|
409
399
|
context 'which does not have a identifier' do
|
@@ -416,51 +406,48 @@ describe Praxis::ResponseDefinition do
|
|
416
406
|
expect(subject['json'][:content_type]).to eq('application/json')
|
417
407
|
end
|
418
408
|
end
|
419
|
-
|
420
|
-
|
421
409
|
end
|
422
410
|
|
423
|
-
|
424
411
|
context 'for a definition without parts' do
|
425
|
-
it{ should be_kind_of(::Hash) }
|
426
|
-
its([:description]){ should be(description) }
|
427
|
-
its([:location]){ should == {value: location.inspect
|
412
|
+
it { should be_kind_of(::Hash) }
|
413
|
+
its([:description]) { should be(description) }
|
414
|
+
its([:location]) { should == { value: location.inspect, type: :regexp } }
|
428
415
|
|
429
416
|
it 'should have a header defined with value and type keys' do
|
430
|
-
expect(
|
431
|
-
expect(
|
432
|
-
expect(
|
417
|
+
expect(output[:headers]).to have(2).keys
|
418
|
+
expect(output[:headers]['Header1']).to eq({ value: 'Value1', type: :string })
|
419
|
+
expect(output[:headers]['Location']).to eq({ value: '/\\/my\\/url\\//', type: :regexp })
|
433
420
|
end
|
434
421
|
end
|
435
422
|
|
436
423
|
context 'for a definition with (homogeneous) parts' do
|
437
|
-
subject(:described_parts){ output[:parts_like] }
|
424
|
+
subject(:described_parts) { output[:parts_like] }
|
438
425
|
context 'using :like' do
|
439
|
-
let(:parts) { {like: :ok, media_type: 'foobar'} }
|
426
|
+
let(:parts) { { like: :ok, media_type: 'foobar' } }
|
440
427
|
|
441
428
|
it 'should contain a parts_like key with a hash' do
|
442
|
-
expect(
|
429
|
+
expect(output).to have_key(:parts_like)
|
443
430
|
end
|
444
431
|
|
445
|
-
it{ should be_kind_of(::Hash) }
|
432
|
+
it { should be_kind_of(::Hash) }
|
446
433
|
it 'has the right type info' do
|
447
434
|
expect(subject[:payload][:type]).to match(id: 'Praxis-SimpleMediaType', name: 'Praxis::SimpleMediaType', family: 'string', identifier: 'foobar')
|
448
435
|
end
|
449
|
-
its([:status]){ should == 200 }
|
436
|
+
its([:status]) { should == 200 }
|
450
437
|
end
|
451
438
|
context 'using a full response definition block' do
|
452
439
|
let(:parts_block) do
|
453
|
-
|
440
|
+
proc do
|
454
441
|
status 234
|
455
442
|
media_type 'custom_media'
|
456
443
|
end
|
457
444
|
end
|
458
445
|
|
459
446
|
it 'should contain a parts_like key with a hash' do
|
460
|
-
expect(
|
447
|
+
expect(output).to have_key(:parts_like)
|
461
448
|
end
|
462
449
|
|
463
|
-
it{ should be_kind_of(::Hash) }
|
450
|
+
it { should be_kind_of(::Hash) }
|
464
451
|
it 'has the right type info' do
|
465
452
|
expect(subject[:payload][:type]).to match(id: 'Praxis-SimpleMediaType', name: 'Praxis::SimpleMediaType', family: 'string', identifier: 'custom_media')
|
466
453
|
end
|
@@ -1,11 +1,12 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'spec_helper'
|
3
4
|
|
4
5
|
describe Praxis::Response do
|
5
6
|
let(:spec_status) { 200 }
|
6
7
|
let(:spec_location) { /resources/ }
|
7
8
|
let(:spec_headers) { { 'X-Header' => 'Foobar' } }
|
8
|
-
let(:spec_mime_type) {
|
9
|
+
let(:spec_mime_type) { 'application/vnd.resource' }
|
9
10
|
|
10
11
|
let(:application_vnd_resource_media_type) do
|
11
12
|
Class.new(Praxis::MediaType) do
|
@@ -18,33 +19,33 @@ describe Praxis::Response do
|
|
18
19
|
let(:response_spec) do
|
19
20
|
instance_double(
|
20
21
|
Praxis::ResponseDefinition,
|
21
|
-
:
|
22
|
-
:
|
23
|
-
:
|
24
|
-
:
|
25
|
-
:
|
22
|
+
status: spec_status,
|
23
|
+
location: spec_location,
|
24
|
+
headers: spec_headers,
|
25
|
+
media_type: spec_media_type,
|
26
|
+
name: :ok
|
26
27
|
)
|
27
28
|
end
|
28
29
|
|
29
30
|
let(:action) do
|
30
31
|
instance_double(
|
31
32
|
Praxis::ActionDefinition,
|
32
|
-
:
|
33
|
+
endpoint_definition: config_class
|
33
34
|
)
|
34
35
|
end
|
35
36
|
|
36
37
|
let(:response_status) { 200 }
|
37
|
-
let(:response_headers)
|
38
|
+
let(:response_headers) do
|
38
39
|
{ 'Content-Type' => 'application/vnd.resource+json;type=collection',
|
39
|
-
'X-Header'
|
40
|
-
'Location'
|
41
|
-
|
40
|
+
'X-Header' => 'Foobar',
|
41
|
+
'Location' => '/api/resources/123' }
|
42
|
+
end
|
42
43
|
|
43
44
|
let(:config_media_type) { nil }
|
44
45
|
let(:config_class) do
|
45
46
|
instance_double(
|
46
47
|
Praxis::ResponseDefinition,
|
47
|
-
:
|
48
|
+
media_type: config_media_type
|
48
49
|
)
|
49
50
|
end
|
50
51
|
|
@@ -52,7 +53,7 @@ describe Praxis::Response do
|
|
52
53
|
|
53
54
|
describe '#validate' do
|
54
55
|
before do
|
55
|
-
allow(action).to receive(:responses).and_return({response_spec.name => response_spec })
|
56
|
+
allow(action).to receive(:responses).and_return({ response_spec.name => response_spec })
|
56
57
|
end
|
57
58
|
context 'response spec is not defined' do
|
58
59
|
before :each do
|
@@ -60,26 +61,29 @@ describe Praxis::Response do
|
|
60
61
|
end
|
61
62
|
|
62
63
|
it 'should raise an error' do
|
63
|
-
|
64
|
-
|
65
|
-
|
64
|
+
resp = nil
|
65
|
+
expect do
|
66
|
+
resp = response.validate(action)
|
67
|
+
end.to_not raise_error
|
68
|
+
|
69
|
+
expect(resp.status).to eq(500)
|
70
|
+
expect(resp.body[:name]).to eq('ValidationError')
|
71
|
+
expect(resp.body[:summary]).to eq('Error validating response')
|
72
|
+
expect(resp.body[:errors]).to include(/response definition with that name can be found/)
|
66
73
|
end
|
67
74
|
end
|
68
75
|
|
69
76
|
context 'with an existing response spec in the action' do
|
70
|
-
|
71
77
|
it 'should use the spec to validate the response' do
|
72
78
|
expect(response_spec).to receive(:validate).and_return(nil)
|
73
79
|
|
74
80
|
response.validate(action)
|
75
81
|
end
|
76
82
|
end
|
77
|
-
|
78
|
-
|
79
83
|
end
|
80
84
|
|
81
85
|
describe '#encode!' do
|
82
|
-
let(:response_body_structured_data) { [{
|
86
|
+
let(:response_body_structured_data) { [{ 'moo' => 'bah' }] }
|
83
87
|
let(:response_body_entity) { '[{"moo": "bah"}]' }
|
84
88
|
|
85
89
|
context 'given a String body' do
|
@@ -96,31 +100,28 @@ describe Praxis::Response do
|
|
96
100
|
|
97
101
|
it 'encodes using a suitable handler' do
|
98
102
|
response.encode!
|
99
|
-
expect(JSON.
|
103
|
+
expect(JSON.parse(response.body)).to eq(response_body_structured_data)
|
100
104
|
end
|
101
105
|
end
|
102
106
|
|
103
107
|
context 'when no Content-Type is defined' do
|
104
108
|
before { response.body = response_body_structured_data }
|
105
109
|
|
106
|
-
let(:response_headers)
|
107
|
-
{ 'X-Header'
|
108
|
-
'Location'
|
109
|
-
|
110
|
+
let(:response_headers) do
|
111
|
+
{ 'X-Header' => 'Foobar',
|
112
|
+
'Location' => '/api/resources/123' }
|
113
|
+
end
|
110
114
|
it 'still defaults to the default handler' do
|
111
115
|
response.encode!
|
112
|
-
expect(JSON.
|
116
|
+
expect(JSON.parse(response.body)).to eq(response_body_structured_data)
|
113
117
|
end
|
114
118
|
end
|
115
|
-
|
116
|
-
|
117
119
|
end
|
118
120
|
|
119
121
|
context 'multipart responses' do
|
120
|
-
let(:part) { Praxis::MultipartPart.new('not so ok', {'Status' => 400,
|
122
|
+
let(:part) { Praxis::MultipartPart.new('not so ok', { 'Status' => 400, 'Location' => 'somewhere' }) }
|
121
123
|
|
122
124
|
context '#add_part' do
|
123
|
-
|
124
125
|
context 'without a name' do
|
125
126
|
before do
|
126
127
|
response.add_part(part)
|
@@ -140,18 +141,16 @@ describe Praxis::Response do
|
|
140
141
|
context 'with a name' do
|
141
142
|
let(:part_name) { 'a-part' }
|
142
143
|
before do
|
143
|
-
response.add_part(
|
144
|
+
response.add_part(part, part_name)
|
144
145
|
end
|
145
146
|
|
146
147
|
it 'adds the part' do
|
147
148
|
expect(response.parts[part_name]).to be(part)
|
148
149
|
end
|
149
150
|
end
|
150
|
-
|
151
151
|
end
|
152
152
|
|
153
153
|
context '#finish for a multipart response' do
|
154
|
-
|
155
154
|
before do
|
156
155
|
response.add_part(part)
|
157
156
|
response.body = 'a preamble'
|
@@ -172,7 +171,7 @@ describe Praxis::Response do
|
|
172
171
|
end
|
173
172
|
|
174
173
|
it 'sets the headers' do
|
175
|
-
expect(response.headers['Content-Type']).to match(/
|
174
|
+
expect(response.headers['Content-Type']).to match(%r{multipart/form-data})
|
176
175
|
expect(response.headers['Location']).to eq('/api/resources/123')
|
177
176
|
end
|
178
177
|
|
@@ -180,7 +179,7 @@ describe Praxis::Response do
|
|
180
179
|
parser = Praxis::MultipartParser.new(response.headers, response.body)
|
181
180
|
preamble, parts = parser.parse
|
182
181
|
|
183
|
-
expect(preamble).to eq(
|
182
|
+
expect(preamble).to eq('a preamble')
|
184
183
|
expect(parts).to have(1).item
|
185
184
|
|
186
185
|
part_response = parts.first
|
@@ -189,9 +188,5 @@ describe Praxis::Response do
|
|
189
188
|
expect(part_response.body).to eq('not so ok')
|
190
189
|
end
|
191
190
|
end
|
192
|
-
|
193
191
|
end
|
194
|
-
|
195
|
-
|
196
|
-
|
197
192
|
end
|
@@ -1,8 +1,8 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'spec_helper'
|
3
4
|
|
4
5
|
describe Praxis::Responses::InternalServerError do
|
5
|
-
|
6
6
|
context 'a basic response' do
|
7
7
|
subject(:response) { Praxis::Responses::InternalServerError.new }
|
8
8
|
it 'always sets the json content type' do
|
@@ -15,12 +15,11 @@ describe Praxis::Responses::InternalServerError do
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
|
19
18
|
context '.format!' do
|
20
19
|
let(:error) { double('error', message: 'error message', backtrace: [1, 2], cause: cause) }
|
21
20
|
|
22
21
|
let(:show_exceptions) { true }
|
23
|
-
let(:config) { double(
|
22
|
+
let(:config) { double('config', show_exceptions: show_exceptions) }
|
24
23
|
|
25
24
|
before do
|
26
25
|
allow(Praxis::Application.instance.config).to receive(:praxis).and_return(config)
|
@@ -30,18 +29,17 @@ describe Praxis::Responses::InternalServerError do
|
|
30
29
|
end
|
31
30
|
|
32
31
|
context 'with show_exceptions true' do
|
33
|
-
|
34
32
|
context 'without a cause' do
|
35
33
|
let(:cause) { nil }
|
36
34
|
it 'it fills message and backtrace' do
|
37
|
-
expect(response.body).to eq({name: error.class.name, message: error.message, backtrace: error.backtrace})
|
35
|
+
expect(response.body).to eq({ name: error.class.name, message: error.message, backtrace: error.backtrace })
|
38
36
|
end
|
39
37
|
end
|
40
38
|
|
41
39
|
context 'with a cause' do
|
42
40
|
let(:cause) { Exception.new('cause message') }
|
43
41
|
it 'it fills message, backtrace and cause' do
|
44
|
-
expect(response.body.keys).to eq([
|
42
|
+
expect(response.body.keys).to eq(%i[name message backtrace cause])
|
45
43
|
expect(response.body[:name]).to eq(error.class.name)
|
46
44
|
expect(response.body[:message]).to eq(error.message)
|
47
45
|
expect(response.body[:backtrace]).to eq(error.backtrace)
|
@@ -55,11 +53,10 @@ describe Praxis::Responses::InternalServerError do
|
|
55
53
|
expect(response.body).to be_nil
|
56
54
|
response.format!
|
57
55
|
end
|
58
|
-
|
59
56
|
end
|
60
57
|
|
61
58
|
context 'its response template' do
|
62
|
-
let(:template){ Praxis::ApiDefinition.instance.responses[:internal_server_error] }
|
59
|
+
let(:template) { Praxis::ApiDefinition.instance.responses[:internal_server_error] }
|
63
60
|
it 'is registered with the ApiDefinition' do
|
64
61
|
expect(template).to be_kind_of(Praxis::ResponseTemplate)
|
65
62
|
end
|