praxis 2.0.pre.17 → 2.0.pre.21
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 +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,4 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
require_relative '../spec_helper'
|
|
3
4
|
|
|
4
5
|
describe Praxis::Renderer do
|
|
@@ -30,7 +31,7 @@ describe Praxis::Renderer do
|
|
|
30
31
|
address: {
|
|
31
32
|
state: true,
|
|
32
33
|
street: true,
|
|
33
|
-
resident:
|
|
34
|
+
resident: { name: true }
|
|
34
35
|
},
|
|
35
36
|
prior_addresses: { name: true },
|
|
36
37
|
work_address: true,
|
|
@@ -45,15 +46,15 @@ describe Praxis::Renderer do
|
|
|
45
46
|
subject(:output) { renderer.render(person, fields) }
|
|
46
47
|
|
|
47
48
|
it 'renders existing attributes' do
|
|
48
|
-
expect(output.keys).to match_array([
|
|
49
|
+
expect(output.keys).to match_array(%i[name full_name alive address prior_addresses metadata aliases])
|
|
49
50
|
|
|
50
51
|
expect(output[:name]).to eq person.name
|
|
51
52
|
expect(output[:full_name]).to eq(first: person.full_name.first, last: person.full_name.last)
|
|
52
53
|
expect(output[:alive]).to be false
|
|
53
54
|
|
|
54
55
|
expect(output[:address]).to eq(state: person.address.state,
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
street: person.address.street,
|
|
57
|
+
resident: { name: person.address.resident.name })
|
|
57
58
|
|
|
58
59
|
expected_prior_addresses = prior_addresses.collect { |addr| { name: addr.name } }
|
|
59
60
|
expect(output[:prior_addresses]).to match_array(expected_prior_addresses)
|
|
@@ -118,18 +119,18 @@ describe Praxis::Renderer do
|
|
|
118
119
|
|
|
119
120
|
context 'rendering stuff that breaks badly' do
|
|
120
121
|
it 'does not break badly' do
|
|
121
|
-
expect{renderer.render(person, {tags: true})}.to_not raise_error
|
|
122
|
+
expect { renderer.render(person, { tags: true }) }.to_not raise_error
|
|
122
123
|
end
|
|
123
124
|
end
|
|
124
125
|
|
|
125
126
|
context 'caching rendered objects' do
|
|
126
|
-
let(:fields) { {full_name: true} }
|
|
127
|
+
let(:fields) { { full_name: true } }
|
|
127
128
|
it 'caches and returns identical results for the same field objects' do
|
|
128
129
|
expect(person).to receive(:full_name).once.and_call_original
|
|
129
130
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
expect(
|
|
131
|
+
render1 = renderer.render(person, fields)
|
|
132
|
+
render2 = renderer.render(person, fields)
|
|
133
|
+
expect(render1).to be(render2)
|
|
133
134
|
end
|
|
134
135
|
end
|
|
135
136
|
|
data/spec/praxis/request_spec.rb
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'spec_helper'
|
|
2
4
|
|
|
3
5
|
describe Praxis::Request do
|
|
4
|
-
let(:path) { '/instances/1?junk=foo&api_version=1.0' }
|
|
6
|
+
let(:path) { '/instances/1?junk=foo&api_version=1.0' }
|
|
5
7
|
let(:rack_input) { StringIO.new('{"something": "given"}') }
|
|
6
|
-
let(:env_content_type){ 'application/json' }
|
|
8
|
+
let(:env_content_type) { 'application/json' }
|
|
7
9
|
let(:env) do
|
|
8
10
|
env = Rack::MockRequest.env_for(path)
|
|
9
11
|
env['rack.input'] = rack_input
|
|
@@ -17,9 +19,9 @@ describe Praxis::Request do
|
|
|
17
19
|
|
|
18
20
|
let(:context) do
|
|
19
21
|
{
|
|
20
|
-
params: [Attributor::
|
|
21
|
-
headers: [Attributor::
|
|
22
|
-
payload: [Attributor::
|
|
22
|
+
params: [Attributor::ROOT_PREFIX, 'params'],
|
|
23
|
+
headers: [Attributor::ROOT_PREFIX, 'headers'],
|
|
24
|
+
payload: [Attributor::ROOT_PREFIX, 'payload']
|
|
23
25
|
}.freeze
|
|
24
26
|
end
|
|
25
27
|
|
|
@@ -29,9 +31,9 @@ describe Praxis::Request do
|
|
|
29
31
|
request
|
|
30
32
|
end
|
|
31
33
|
|
|
32
|
-
its(:verb) { should eq(
|
|
34
|
+
its(:verb) { should eq('GET') }
|
|
33
35
|
its(:path) { should eq('/instances/1') }
|
|
34
|
-
its(:raw_params) { should eq({'junk' => 'foo'}) }
|
|
36
|
+
its(:raw_params) { should eq({ 'junk' => 'foo' }) }
|
|
35
37
|
its(:version) { should eq('1.0') }
|
|
36
38
|
|
|
37
39
|
context 'path versioning' do
|
|
@@ -42,26 +44,24 @@ describe Praxis::Request do
|
|
|
42
44
|
allow(
|
|
43
45
|
Praxis::ApiDefinition.instance.info
|
|
44
46
|
).to receive(:base_path).and_return('/api/v:api_version')
|
|
45
|
-
|
|
46
47
|
end
|
|
47
48
|
|
|
48
49
|
let(:path) { '/api/v2.0/instances/1' }
|
|
49
50
|
|
|
50
|
-
|
|
51
51
|
its(:version) { should eq '2.0' }
|
|
52
|
-
#its('class.path_version_prefix'){ should eq("/v") }
|
|
53
|
-
#its(:path_version_matcher){ should be_kind_of(Regexp) }
|
|
54
|
-
#it 'uses a "/v*" default matcher with a "version" named capture' do
|
|
52
|
+
# its('class.path_version_prefix'){ should eq("/v") }
|
|
53
|
+
# its(:path_version_matcher){ should be_kind_of(Regexp) }
|
|
54
|
+
# it 'uses a "/v*" default matcher with a "version" named capture' do
|
|
55
55
|
# match = subject.path_version_matcher.match("/v5.5/something")
|
|
56
56
|
# expect(match).to_not be(nil)
|
|
57
57
|
# expect(match['version']).to eq("5.5")
|
|
58
|
-
#end
|
|
58
|
+
# end
|
|
59
59
|
end
|
|
60
60
|
|
|
61
61
|
context 'loading api version' do
|
|
62
|
-
#let(:request) { Praxis::Request.new(env) }
|
|
63
|
-
subject(:version){ request.version }
|
|
64
|
-
let(:versioning_scheme){ Praxis::Request::VERSION_USING_DEFAULTS }
|
|
62
|
+
# let(:request) { Praxis::Request.new(env) }
|
|
63
|
+
subject(:version) { request.version }
|
|
64
|
+
let(:versioning_scheme) { Praxis::Request::VERSION_USING_DEFAULTS }
|
|
65
65
|
before do
|
|
66
66
|
allow(
|
|
67
67
|
Praxis::Application.instance
|
|
@@ -69,18 +69,18 @@ describe Praxis::Request do
|
|
|
69
69
|
end
|
|
70
70
|
|
|
71
71
|
context 'using X-Api-Header' do
|
|
72
|
-
let(:env){ {'HTTP_X_API_VERSION' =>
|
|
73
|
-
let(:versioning_scheme){ :header }
|
|
72
|
+
let(:env) { { 'HTTP_X_API_VERSION' => '5.0', 'PATH_INFO' => '/something' } }
|
|
73
|
+
let(:versioning_scheme) { :header }
|
|
74
74
|
it { should eq('5.0') }
|
|
75
75
|
end
|
|
76
76
|
context 'using query param' do
|
|
77
77
|
let(:env) { Rack::MockRequest.env_for('/instances/1?junk=foo&api_version=5.0') }
|
|
78
|
-
let(:versioning_scheme){ :params }
|
|
78
|
+
let(:versioning_scheme) { :params }
|
|
79
79
|
it { should eq('5.0') }
|
|
80
80
|
end
|
|
81
81
|
context 'using path (with the default pattern matcher)' do
|
|
82
|
-
let(:env){ Rack::MockRequest.env_for('/v5.0/instances/1?junk=foo') }
|
|
83
|
-
let(:versioning_scheme){ :path }
|
|
82
|
+
let(:env) { Rack::MockRequest.env_for('/v5.0/instances/1?junk=foo') }
|
|
83
|
+
let(:versioning_scheme) { :path }
|
|
84
84
|
|
|
85
85
|
before do
|
|
86
86
|
allow(
|
|
@@ -92,21 +92,21 @@ describe Praxis::Request do
|
|
|
92
92
|
|
|
93
93
|
context 'using a method that it is not allowed in the definition' do
|
|
94
94
|
context 'allowing query param but passing it through a header' do
|
|
95
|
-
let(:env){ {'HTTP_X_API_VERSION' =>
|
|
96
|
-
let(:versioning_scheme){ :params }
|
|
95
|
+
let(:env) { { 'HTTP_X_API_VERSION' => '5.0', 'PATH_INFO' => '/something' } }
|
|
96
|
+
let(:versioning_scheme) { :params }
|
|
97
97
|
it { should eq('n/a') }
|
|
98
98
|
end
|
|
99
99
|
context 'allowing header but passing it through param' do
|
|
100
100
|
let(:env) { Rack::MockRequest.env_for('/instances/1?junk=foo&api_version=5.0') }
|
|
101
|
-
let(:versioning_scheme){ :header }
|
|
101
|
+
let(:versioning_scheme) { :header }
|
|
102
102
|
it { should eq('n/a') }
|
|
103
103
|
end
|
|
104
104
|
end
|
|
105
105
|
|
|
106
106
|
context 'using defaults' do
|
|
107
|
-
subject(:version){ request.version }
|
|
107
|
+
subject(:version) { request.version }
|
|
108
108
|
context 'would succeed if passed through the header' do
|
|
109
|
-
let(:env){ {'HTTP_X_API_VERSION' =>
|
|
109
|
+
let(:env) { { 'HTTP_X_API_VERSION' => '5.0', 'PATH_INFO' => '/something' } }
|
|
110
110
|
it { should eq('5.0') }
|
|
111
111
|
end
|
|
112
112
|
context 'would succeed if passed through params' do
|
|
@@ -126,9 +126,9 @@ describe Praxis::Request do
|
|
|
126
126
|
form_data
|
|
127
127
|
end
|
|
128
128
|
|
|
129
|
-
let(:rack_input)
|
|
129
|
+
let(:rack_input) do
|
|
130
130
|
StringIO.new(form.body.to_s)
|
|
131
|
-
|
|
131
|
+
end
|
|
132
132
|
|
|
133
133
|
let(:env) do
|
|
134
134
|
env = Rack::MockRequest.env_for('/instances/1?junk=foo&api_version=1.0')
|
|
@@ -138,21 +138,18 @@ describe Praxis::Request do
|
|
|
138
138
|
env
|
|
139
139
|
end
|
|
140
140
|
|
|
141
|
-
#its(:multipart?) { should be(true) }
|
|
141
|
+
# its(:multipart?) { should be(true) }
|
|
142
142
|
|
|
143
143
|
it 'works' do
|
|
144
|
-
#p request #.body
|
|
145
|
-
#p request #.parts
|
|
144
|
+
# p request #.body
|
|
145
|
+
# p request #.parts
|
|
146
146
|
end
|
|
147
|
-
|
|
148
|
-
|
|
149
147
|
end
|
|
150
148
|
|
|
151
149
|
context '#load_headers' do
|
|
152
|
-
|
|
153
150
|
it 'is done preserving the original case' do
|
|
154
151
|
request.load_headers(context[:headers])
|
|
155
|
-
expect(request.headers).to eq({
|
|
152
|
+
expect(request.headers).to eq({ 'Authorization' => 'Secret' })
|
|
156
153
|
end
|
|
157
154
|
|
|
158
155
|
it 'performs it using the memoized rack keys from the action (Hacky but...performance is important)' do
|
|
@@ -161,7 +158,7 @@ describe Praxis::Request do
|
|
|
161
158
|
end
|
|
162
159
|
end
|
|
163
160
|
|
|
164
|
-
context
|
|
161
|
+
context 'performs request validation' do
|
|
165
162
|
before(:each) do
|
|
166
163
|
request.load_headers(context[:headers])
|
|
167
164
|
request.load_params(context[:params])
|
|
@@ -205,17 +202,17 @@ describe Praxis::Request do
|
|
|
205
202
|
end
|
|
206
203
|
|
|
207
204
|
context '#load_payload' do
|
|
208
|
-
let(:load_context){ context[:payload] }
|
|
209
|
-
let(:parsed_result){ double(
|
|
205
|
+
let(:load_context) { context[:payload] }
|
|
206
|
+
let(:parsed_result) { double('parsed') }
|
|
210
207
|
|
|
211
208
|
after do
|
|
212
|
-
expect(request.action.payload).to receive(:load).with(parsed_result, load_context, content_type: request.content_type.to_s
|
|
213
|
-
request.load_payload(
|
|
209
|
+
expect(request.action.payload).to receive(:load).with(parsed_result, load_context, content_type: request.content_type.to_s)
|
|
210
|
+
request.load_payload(load_context)
|
|
214
211
|
end
|
|
215
212
|
|
|
216
213
|
context 'that is json encoded' do
|
|
217
214
|
let(:rack_input) { StringIO.new('{"one":1,"sub_hash":{"first":"hello"}}') }
|
|
218
|
-
let(:env_content_type){ 'application/json' }
|
|
215
|
+
let(:env_content_type) { 'application/json' }
|
|
219
216
|
let(:parsed_result) { Praxis::Handlers::JSON.new.parse(request.raw_payload) }
|
|
220
217
|
|
|
221
218
|
it 'decodes using the JSON handler' do end
|
|
@@ -1,17 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'spec_helper'
|
|
2
4
|
|
|
3
5
|
describe Praxis::RequestStages::Action do
|
|
4
|
-
|
|
5
6
|
let(:controller) do
|
|
6
7
|
Class.new do
|
|
7
8
|
include Praxis::Controller
|
|
8
9
|
end.new(request)
|
|
9
10
|
end
|
|
10
11
|
|
|
11
|
-
let(:action) { double(
|
|
12
|
-
let(:response){ Praxis::Responses::Ok.new }
|
|
13
|
-
let(:app){ double(
|
|
14
|
-
let(:action_stage){ Praxis::RequestStages::Action.new(action.name,app) }
|
|
12
|
+
let(:action) { double('action', name: 'foo') }
|
|
13
|
+
let(:response) { Praxis::Responses::Ok.new }
|
|
14
|
+
let(:app) { double('App', controller: controller, action: action, request: request) }
|
|
15
|
+
let(:action_stage) { Praxis::RequestStages::Action.new(action.name, app) }
|
|
15
16
|
|
|
16
17
|
let(:request) do
|
|
17
18
|
env = Rack::MockRequest.env_for('/instances/1?cloud_id=1&api_version=1.0')
|
|
@@ -23,19 +24,17 @@ describe Praxis::RequestStages::Action do
|
|
|
23
24
|
request
|
|
24
25
|
end
|
|
25
26
|
|
|
26
|
-
|
|
27
27
|
context '.execute' do
|
|
28
28
|
before do
|
|
29
29
|
expect(controller).to receive(action_stage.name) do |args|
|
|
30
30
|
if args
|
|
31
31
|
expect(args).to eq({})
|
|
32
32
|
else
|
|
33
|
-
|
|
33
|
+
expect(args).to eq(nil)
|
|
34
34
|
end
|
|
35
35
|
end.and_return(controller_response)
|
|
36
|
-
|
|
37
36
|
end
|
|
38
|
-
let(:controller_response){ controller.response }
|
|
37
|
+
let(:controller_response) { controller.response }
|
|
39
38
|
|
|
40
39
|
it 'always call the right controller method' do
|
|
41
40
|
action_stage.execute
|
|
@@ -47,28 +46,28 @@ describe Praxis::RequestStages::Action do
|
|
|
47
46
|
end
|
|
48
47
|
|
|
49
48
|
it 'sends the right ActiveSupport::Notification' do
|
|
50
|
-
expect(ActiveSupport::Notifications).to receive(:instrument).with('praxis.request_stage.execute', {controller: an_instance_of(controller.class)}).and_call_original
|
|
49
|
+
expect(ActiveSupport::Notifications).to receive(:instrument).with('praxis.request_stage.execute', { controller: an_instance_of(controller.class) }).and_call_original
|
|
51
50
|
action_stage.execute
|
|
52
51
|
end
|
|
53
52
|
|
|
54
53
|
context 'if the controller method returns a string' do
|
|
55
|
-
let(:controller_response){
|
|
54
|
+
let(:controller_response) { 'this is the body' }
|
|
56
55
|
it 'sets the response body with it (and save the request too)' do
|
|
57
56
|
action_stage.execute
|
|
58
|
-
expect(controller.response.body).to eq(
|
|
57
|
+
expect(controller.response.body).to eq('this is the body')
|
|
59
58
|
end
|
|
60
59
|
end
|
|
61
60
|
context 'if the controller method returns a response object' do
|
|
62
|
-
let(:controller_response){ Praxis::Responses::Created.new }
|
|
61
|
+
let(:controller_response) { Praxis::Responses::Created.new }
|
|
63
62
|
it 'set that response in the controller' do
|
|
64
63
|
action_stage.execute
|
|
65
64
|
expect(controller.response).to eq(controller_response)
|
|
66
65
|
end
|
|
67
66
|
end
|
|
68
67
|
context 'if the controller method returns neither a string or a response' do
|
|
69
|
-
let(:controller_response){ nil }
|
|
68
|
+
let(:controller_response) { nil }
|
|
70
69
|
it 'an error is raised ' do
|
|
71
|
-
expect{ action_stage.execute }.to raise_error(/Only Response objects or Strings allowed/)
|
|
70
|
+
expect { action_stage.execute }.to raise_error(/Only Response objects or Strings allowed/)
|
|
72
71
|
end
|
|
73
72
|
end
|
|
74
73
|
end
|
|
@@ -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
|