praxis 2.0.pre.18 → 2.0.pre.19
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 +6 -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 +64 -94
- 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 +64 -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 +10 -13
- 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 +6 -3
- 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 +16 -16
- data/lib/praxis/docs/open_api/server_object.rb +5 -2
- data/lib/praxis/docs/open_api/tag_object.rb +6 -3
- data/lib/praxis/docs/open_api_generator.rb +92 -95
- 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 +171 -180
- 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 +46 -47
- 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 -16
- data/lib/praxis/request_stages/validate_payload.rb +25 -27
- data/lib/praxis/request_superclassing.rb +3 -3
- data/lib/praxis/resource_definition.rb +1 -0
- data/lib/praxis/response.rb +13 -25
- 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 +15 -15
- 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 +88 -112
- 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 +40 -52
- data/spec/praxis/action_definition_spec.rb +36 -46
- 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 +27 -30
- data/spec/praxis/mapper/selector_generator_spec.rb +50 -50
- 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 +28 -39
- 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 -18
- 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 +5 -5
- 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 +9 -15
- 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 +2 -1
- 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 +20 -18
- 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,7 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
describe Praxis::RequestStages::RequestStage do
|
4
|
-
|
5
6
|
let(:controller_class) do
|
6
7
|
Class.new do
|
7
8
|
include Praxis::Controller
|
@@ -11,15 +12,14 @@ describe Praxis::RequestStages::RequestStage do
|
|
11
12
|
let(:stage_class) { Class.new(Praxis::RequestStages::RequestStage) }
|
12
13
|
|
13
14
|
let(:request) { Praxis::Request.new({}) }
|
14
|
-
let(:controller){ controller_class.new(request) }
|
15
|
+
let(:controller) { controller_class.new(request) }
|
15
16
|
|
17
|
+
let(:action) { instance_double('Praxis::ActionDefinition') }
|
18
|
+
let(:context) { double('context', controller: controller, action: action) }
|
16
19
|
|
17
|
-
let(:
|
18
|
-
let(:
|
19
|
-
|
20
|
-
let(:substage_1) { instance_double('Praxis::RequestStage') }
|
21
|
-
let(:substage_2) { instance_double('Praxis::RequestStage') }
|
22
|
-
let(:substage_3) { instance_double('Praxis::RequestStage') }
|
20
|
+
let(:substage1) { instance_double('Praxis::RequestStage') }
|
21
|
+
let(:substage2) { instance_double('Praxis::RequestStage') }
|
22
|
+
let(:substage3) { instance_double('Praxis::RequestStage') }
|
23
23
|
|
24
24
|
let(:before_callbacks) { double('before_callbacks') }
|
25
25
|
let(:after_callbacks) { double('after_callbacks') }
|
@@ -28,19 +28,18 @@ describe Praxis::RequestStages::RequestStage do
|
|
28
28
|
|
29
29
|
subject(:stage) { stage_class.new(:action, context) }
|
30
30
|
|
31
|
-
|
32
31
|
before do
|
33
32
|
# clear any pre-existing callbacks that may have been added by plugins
|
34
|
-
controller_class.before_callbacks =
|
35
|
-
controller_class.after_callbacks =
|
33
|
+
controller_class.before_callbacks = ({})
|
34
|
+
controller_class.after_callbacks = ({})
|
36
35
|
end
|
37
36
|
|
38
37
|
context 'for an abstract stage' do
|
39
38
|
subject(:stage) { Praxis::RequestStages::RequestStage.new(:action, context) }
|
40
39
|
it 'raises NotImplementedError for undefined #execute' do
|
41
|
-
expect
|
40
|
+
expect do
|
42
41
|
stage.execute
|
43
|
-
|
42
|
+
end.to raise_error(NotImplementedError, /Subclass must implement Stage#execute/)
|
44
43
|
end
|
45
44
|
end
|
46
45
|
|
@@ -57,16 +56,16 @@ describe Praxis::RequestStages::RequestStage do
|
|
57
56
|
end
|
58
57
|
end
|
59
58
|
|
60
|
-
context
|
59
|
+
context '#execute' do
|
61
60
|
before do
|
62
|
-
stage.stages.push(
|
61
|
+
stage.stages.push(substage1, substage2, substage3)
|
63
62
|
end
|
64
63
|
|
65
64
|
context 'when all stages succeed' do
|
66
|
-
it
|
67
|
-
expect(
|
68
|
-
expect(
|
69
|
-
expect(
|
65
|
+
it 'runs them all and returns nil' do
|
66
|
+
expect(substage1).to receive(:run).once
|
67
|
+
expect(substage2).to receive(:run).once
|
68
|
+
expect(substage3).to receive(:run).once
|
70
69
|
expect(stage.execute).to be(nil)
|
71
70
|
end
|
72
71
|
end
|
@@ -74,12 +73,12 @@ describe Praxis::RequestStages::RequestStage do
|
|
74
73
|
context 'when one stage returns a Response' do
|
75
74
|
let(:response) { Praxis::Responses::Ok.new }
|
76
75
|
before do
|
77
|
-
expect(
|
78
|
-
expect(
|
76
|
+
expect(substage1).to receive(:run).once
|
77
|
+
expect(substage2).to receive(:run).once.and_return(response)
|
79
78
|
end
|
80
79
|
|
81
|
-
it
|
82
|
-
expect(
|
80
|
+
it 'runs no further stages after that' do
|
81
|
+
expect(substage3).to_not receive(:run)
|
83
82
|
stage.execute
|
84
83
|
end
|
85
84
|
|
@@ -88,12 +87,10 @@ describe Praxis::RequestStages::RequestStage do
|
|
88
87
|
|
89
88
|
expect(controller.response).to be(response)
|
90
89
|
end
|
91
|
-
|
92
90
|
end
|
93
91
|
end
|
94
92
|
|
95
|
-
context
|
96
|
-
|
93
|
+
context '#run' do
|
97
94
|
let(:before_callbacks) { double('before_callbacks') }
|
98
95
|
let(:after_callbacks) { double('after_callbacks') }
|
99
96
|
|
@@ -113,14 +110,13 @@ describe Praxis::RequestStages::RequestStage do
|
|
113
110
|
allow(controller_class).to receive(:after_callbacks).once.and_return(controller_after_callbacks)
|
114
111
|
end
|
115
112
|
|
116
|
-
it
|
113
|
+
it 'sets up and executes callbacks' do
|
117
114
|
expect(stage).to receive(:execute)
|
118
115
|
expect(stage).to receive(:execute_callbacks).once.with(before_callbacks)
|
119
116
|
expect(stage).to receive(:execute_callbacks).once.with(after_callbacks)
|
120
117
|
expect(stage).to receive(:execute_controller_callbacks).once.with(controller_before_callbacks)
|
121
118
|
expect(stage).to receive(:execute_controller_callbacks).once.with(controller_after_callbacks)
|
122
119
|
end
|
123
|
-
|
124
120
|
end
|
125
121
|
|
126
122
|
context 'when the before execute_controller_callbacks return a Response' do
|
@@ -131,7 +127,6 @@ describe Praxis::RequestStages::RequestStage do
|
|
131
127
|
expect(stage).to receive(:execute_controller_callbacks).once.and_return(response)
|
132
128
|
end
|
133
129
|
|
134
|
-
|
135
130
|
it 'does not call "execute"' do
|
136
131
|
expect(stage).to_not receive(:execute)
|
137
132
|
end
|
@@ -140,22 +135,20 @@ describe Praxis::RequestStages::RequestStage do
|
|
140
135
|
expect(stage).to_not receive(:after_callbacks)
|
141
136
|
expect(controller_class).to_not receive(:after_callbacks)
|
142
137
|
end
|
143
|
-
|
144
138
|
end
|
145
139
|
|
146
140
|
context 'with substages' do
|
147
141
|
before do
|
148
|
-
stage.stages.push(
|
142
|
+
stage.stages.push(substage1, substage2, substage3)
|
149
143
|
end
|
150
144
|
|
151
|
-
|
152
145
|
context 'when one returns a Response' do
|
153
146
|
let(:response) { Praxis::Responses::Unauthorized.new }
|
154
147
|
|
155
148
|
before do
|
156
|
-
expect(
|
157
|
-
expect(
|
158
|
-
expect(
|
149
|
+
expect(substage1).to receive(:run).once
|
150
|
+
expect(substage2).to receive(:run).once.and_return(response)
|
151
|
+
expect(substage3).to_not receive(:run)
|
159
152
|
end
|
160
153
|
|
161
154
|
it 'runs no after callbacks (including from the controller) ' do
|
@@ -165,14 +158,10 @@ describe Praxis::RequestStages::RequestStage do
|
|
165
158
|
|
166
159
|
it 'assigns controller.response' do
|
167
160
|
# twice, because we do it once in #execute, and again in #run...
|
168
|
-
expect(controller).to receive(:response=)
|
169
|
-
with(response).twice.and_call_original
|
161
|
+
expect(controller).to receive(:response=)
|
162
|
+
.with(response).twice.and_call_original
|
170
163
|
end
|
171
|
-
|
172
164
|
end
|
173
165
|
end
|
174
166
|
end
|
175
|
-
|
176
|
-
|
177
|
-
|
178
167
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
describe Praxis::RequestStages::Validate do
|
@@ -19,7 +21,7 @@ describe Praxis::RequestStages::Validate do
|
|
19
21
|
|
20
22
|
let(:request) do
|
21
23
|
r = Praxis::Request.new(env)
|
22
|
-
r.route_params = {id: 1}
|
24
|
+
r.route_params = { id: 1 }
|
23
25
|
r.action = action
|
24
26
|
r
|
25
27
|
end
|
@@ -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
|