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,49 +1,50 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'spec_helper'
|
3
4
|
|
4
5
|
describe Praxis::Mapper::SelectorGenerator do
|
5
6
|
let(:resource) { SimpleResource }
|
6
|
-
subject(:generator) {described_class.new }
|
7
|
+
subject(:generator) { described_class.new }
|
7
8
|
|
8
9
|
context '#add' do
|
9
10
|
let(:resource) { SimpleResource }
|
10
11
|
shared_examples 'a proper selector' do
|
11
12
|
it { expect(generator.add(resource, fields).selectors.dump).to be_deep_equal selectors }
|
12
13
|
end
|
13
|
-
|
14
|
+
|
14
15
|
context 'basic combos' do
|
15
16
|
context 'direct column fields' do
|
16
|
-
let(:fields) { {id: true, foobar: true} }
|
17
|
-
let(:selectors) do
|
17
|
+
let(:fields) { { id: true, foobar: true } }
|
18
|
+
let(:selectors) do
|
18
19
|
{
|
19
20
|
model: SimpleModel,
|
20
|
-
columns: [
|
21
|
-
}
|
21
|
+
columns: %i[id foobar]
|
22
|
+
}
|
22
23
|
end
|
23
24
|
it_behaves_like 'a proper selector'
|
24
25
|
end
|
25
26
|
|
26
27
|
context 'aliased column fields' do
|
27
|
-
let(:fields) { {id: true, name: true} }
|
28
|
+
let(:fields) { { id: true, name: true } }
|
28
29
|
let(:selectors) do
|
29
30
|
{
|
30
31
|
model: SimpleModel,
|
31
|
-
columns: [
|
32
|
+
columns: %i[id simple_name]
|
32
33
|
}
|
33
34
|
end
|
34
35
|
it_behaves_like 'a proper selector'
|
35
36
|
end
|
36
37
|
|
37
38
|
context 'pure associations without recursion' do
|
38
|
-
let(:fields) { {other_model: true} }
|
39
|
+
let(:fields) { { other_model: true } }
|
39
40
|
let(:selectors) do
|
40
41
|
{
|
41
42
|
model: SimpleModel,
|
42
43
|
columns: [:other_model_id], # FK of the other_model association
|
43
44
|
tracks: {
|
44
|
-
other_model: {
|
45
|
+
other_model: {
|
45
46
|
columns: [:id], # joining key for the association
|
46
|
-
model: OtherModel
|
47
|
+
model: OtherModel
|
47
48
|
}
|
48
49
|
}
|
49
50
|
}
|
@@ -52,15 +53,15 @@ describe Praxis::Mapper::SelectorGenerator do
|
|
52
53
|
end
|
53
54
|
|
54
55
|
context 'aliased associations without recursion' do
|
55
|
-
let(:fields) { {other_resource: true} }
|
56
|
+
let(:fields) { { other_resource: true } }
|
56
57
|
let(:selectors) do
|
57
58
|
{
|
58
59
|
model: SimpleModel,
|
59
60
|
columns: [:other_model_id], # FK of the other_model association
|
60
61
|
tracks: {
|
61
|
-
other_model: {
|
62
|
+
other_model: {
|
62
63
|
columns: [:id], # joining key for the association
|
63
|
-
model: OtherModel
|
64
|
+
model: OtherModel
|
64
65
|
}
|
65
66
|
}
|
66
67
|
}
|
@@ -68,15 +69,15 @@ describe Praxis::Mapper::SelectorGenerator do
|
|
68
69
|
it_behaves_like 'a proper selector'
|
69
70
|
end
|
70
71
|
context 'aliased associations without recursion (that map to columns and other associations)' do
|
71
|
-
let(:fields) { {aliased_method: true} }
|
72
|
+
let(:fields) { { aliased_method: true } }
|
72
73
|
let(:selectors) do
|
73
74
|
{
|
74
75
|
model: SimpleModel,
|
75
|
-
columns: [
|
76
|
+
columns: %i[column1 other_model_id], # other_model_id => because of the association
|
76
77
|
tracks: {
|
77
|
-
other_model: {
|
78
|
+
other_model: {
|
78
79
|
columns: [:id], # joining key for the association
|
79
|
-
model: OtherModel
|
80
|
+
model: OtherModel
|
80
81
|
}
|
81
82
|
}
|
82
83
|
}
|
@@ -85,13 +86,13 @@ describe Praxis::Mapper::SelectorGenerator do
|
|
85
86
|
end
|
86
87
|
|
87
88
|
context 'redefined associations that add some extra columns (would need both the underlying association AND the columns in place)' do
|
88
|
-
let(:fields) { {parent: true} }
|
89
|
+
let(:fields) { { parent: true } }
|
89
90
|
let(:selectors) do
|
90
91
|
{
|
91
92
|
model: SimpleModel,
|
92
|
-
columns: [
|
93
|
+
columns: %i[parent_id added_column],
|
93
94
|
tracks: {
|
94
|
-
parent: {
|
95
|
+
parent: {
|
95
96
|
columns: [:id],
|
96
97
|
model: ParentModel
|
97
98
|
}
|
@@ -102,29 +103,29 @@ describe Praxis::Mapper::SelectorGenerator do
|
|
102
103
|
end
|
103
104
|
|
104
105
|
context 'a simple property that requires all fields' do
|
105
|
-
let(:fields) { {everything: true} }
|
106
|
+
let(:fields) { { everything: true } }
|
106
107
|
let(:selectors) do
|
107
108
|
{
|
108
109
|
model: SimpleModel,
|
109
|
-
columns: [:*]
|
110
|
+
columns: [:*]
|
110
111
|
}
|
111
112
|
end
|
112
113
|
it_behaves_like 'a proper selector'
|
113
114
|
end
|
114
115
|
|
115
116
|
context 'a simple property that requires itself' do
|
116
|
-
let(:fields) { {circular_dep: true} }
|
117
|
+
let(:fields) { { circular_dep: true } }
|
117
118
|
let(:selectors) do
|
118
119
|
{
|
119
120
|
model: SimpleModel,
|
120
|
-
columns: [
|
121
|
+
columns: %i[circular_dep column1] # allows to "expand" the dependency into itself + others
|
121
122
|
}
|
122
123
|
end
|
123
124
|
it_behaves_like 'a proper selector'
|
124
125
|
end
|
125
126
|
|
126
127
|
context 'a simple property without dependencies' do
|
127
|
-
let(:fields) { {no_deps: true} }
|
128
|
+
let(:fields) { { no_deps: true } }
|
128
129
|
let(:selectors) do
|
129
130
|
{
|
130
131
|
model: SimpleModel
|
@@ -132,13 +133,12 @@ describe Praxis::Mapper::SelectorGenerator do
|
|
132
133
|
end
|
133
134
|
it_behaves_like 'a proper selector'
|
134
135
|
end
|
135
|
-
|
136
136
|
end
|
137
137
|
|
138
138
|
context 'nested tracking' do
|
139
139
|
context 'pure associations follow the nested fields' do
|
140
140
|
let(:fields) do
|
141
|
-
{
|
141
|
+
{
|
142
142
|
other_model: {
|
143
143
|
id: true
|
144
144
|
}
|
@@ -196,7 +196,7 @@ describe Praxis::Mapper::SelectorGenerator do
|
|
196
196
|
let(:selectors) do
|
197
197
|
{
|
198
198
|
model: SimpleModel,
|
199
|
-
columns: [
|
199
|
+
columns: %i[parent_id added_column],
|
200
200
|
tracks: {
|
201
201
|
parent: {
|
202
202
|
model: ParentModel,
|
@@ -225,7 +225,7 @@ describe Praxis::Mapper::SelectorGenerator do
|
|
225
225
|
tracks: {
|
226
226
|
other_model: {
|
227
227
|
model: OtherModel,
|
228
|
-
columns: [
|
228
|
+
columns: %i[id name]
|
229
229
|
}
|
230
230
|
}
|
231
231
|
}
|
@@ -242,7 +242,7 @@ describe Praxis::Mapper::SelectorGenerator do
|
|
242
242
|
tracks: {
|
243
243
|
other_model: {
|
244
244
|
model: OtherModel,
|
245
|
-
columns: [
|
245
|
+
columns: %i[id name]
|
246
246
|
}
|
247
247
|
}
|
248
248
|
}
|
@@ -251,13 +251,13 @@ describe Praxis::Mapper::SelectorGenerator do
|
|
251
251
|
end
|
252
252
|
|
253
253
|
context 'for a property that requires all fields from an association' do
|
254
|
-
let(:fields) { {everything_from_parent: true} }
|
254
|
+
let(:fields) { { everything_from_parent: true } }
|
255
255
|
let(:selectors) do
|
256
256
|
{
|
257
257
|
model: SimpleModel,
|
258
258
|
columns: [:parent_id],
|
259
259
|
tracks: {
|
260
|
-
parent: {
|
260
|
+
parent: {
|
261
261
|
model: ParentModel,
|
262
262
|
columns: [:*]
|
263
263
|
}
|
@@ -270,15 +270,15 @@ describe Praxis::Mapper::SelectorGenerator do
|
|
270
270
|
|
271
271
|
context 'required extra select fields due to associations' do
|
272
272
|
context 'many_to_one' do
|
273
|
-
let(:fields) { {other_model: true} }
|
273
|
+
let(:fields) { { other_model: true } }
|
274
274
|
let(:selectors) do
|
275
275
|
{
|
276
276
|
model: SimpleModel,
|
277
277
|
columns: [:other_model_id], # FK of the other_model association
|
278
278
|
tracks: {
|
279
|
-
other_model: {
|
279
|
+
other_model: {
|
280
280
|
columns: [:id],
|
281
|
-
model: OtherModel
|
281
|
+
model: OtherModel
|
282
282
|
}
|
283
283
|
}
|
284
284
|
}
|
@@ -287,39 +287,73 @@ describe Praxis::Mapper::SelectorGenerator do
|
|
287
287
|
end
|
288
288
|
context 'one_to_many' do
|
289
289
|
let(:resource) { ParentResource }
|
290
|
-
let(:fields) { {simple_children: true} }
|
290
|
+
let(:fields) { { simple_children: true } }
|
291
291
|
let(:selectors) do
|
292
292
|
{
|
293
293
|
model: ParentModel,
|
294
294
|
columns: [:id], # No FKs in the source model for one_to_many
|
295
295
|
tracks: {
|
296
|
-
simple_children: {
|
296
|
+
simple_children: {
|
297
297
|
columns: [:parent_id],
|
298
|
-
model: SimpleModel
|
298
|
+
model: SimpleModel
|
299
299
|
}
|
300
300
|
}
|
301
301
|
}
|
302
302
|
end
|
303
303
|
it_behaves_like 'a proper selector'
|
304
|
-
end
|
304
|
+
end
|
305
305
|
context 'many_to_many' do
|
306
306
|
let(:resource) { OtherResource }
|
307
|
-
let(:fields) { {simple_models: true} }
|
307
|
+
let(:fields) { { simple_models: true } }
|
308
308
|
let(:selectors) do
|
309
309
|
{
|
310
310
|
model: OtherModel,
|
311
|
-
columns: [:id], #join key in the source model for many_to_many (where the middle table points to)
|
311
|
+
columns: [:id], # join key in the source model for many_to_many (where the middle table points to)
|
312
312
|
tracks: {
|
313
|
-
simple_models: {
|
314
|
-
columns: [:id], #join key in the target model for many_to_many (where the middle table points to)
|
313
|
+
simple_models: {
|
314
|
+
columns: [:id], # join key in the target model for many_to_many (where the middle table points to)
|
315
315
|
model: SimpleModel
|
316
316
|
}
|
317
317
|
}
|
318
318
|
}
|
319
319
|
end
|
320
320
|
it_behaves_like 'a proper selector'
|
321
|
-
end
|
321
|
+
end
|
322
322
|
|
323
|
+
context 'that are several attriutes deep' do
|
324
|
+
let(:fields) { { deep_nested_deps: true } }
|
325
|
+
let(:selectors) do
|
326
|
+
{
|
327
|
+
model: SimpleModel,
|
328
|
+
columns: [:parent_id],
|
329
|
+
tracks: {
|
330
|
+
parent: {
|
331
|
+
model: ParentModel,
|
332
|
+
columns: [:id], # No FKs in the source model for one_to_many
|
333
|
+
tracks: {
|
334
|
+
simple_children: {
|
335
|
+
columns: %i[parent_id other_model_id],
|
336
|
+
model: SimpleModel,
|
337
|
+
tracks: {
|
338
|
+
other_model: {
|
339
|
+
model: OtherModel,
|
340
|
+
columns: %i[id parent_id],
|
341
|
+
tracks: {
|
342
|
+
parent: {
|
343
|
+
model: ParentModel,
|
344
|
+
columns: %i[id simple_name other_attribute]
|
345
|
+
}
|
346
|
+
}
|
347
|
+
}
|
348
|
+
}
|
349
|
+
}
|
350
|
+
}
|
351
|
+
}
|
352
|
+
}
|
353
|
+
}
|
354
|
+
end
|
355
|
+
it_behaves_like 'a proper selector'
|
356
|
+
end
|
323
357
|
end
|
324
358
|
end
|
325
359
|
end
|
@@ -1,4 +1,8 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# rubocop:disable Style/StringConcatenation
|
4
|
+
|
5
|
+
require 'spec_helper'
|
2
6
|
|
3
7
|
describe Praxis::MediaTypeIdentifier do
|
4
8
|
let(:example) { 'application/ice-cream+sundae; nuts="true"; fudge="true"' }
|
@@ -14,7 +18,7 @@ describe Praxis::MediaTypeIdentifier do
|
|
14
18
|
end
|
15
19
|
|
16
20
|
context 'of empty string values' do
|
17
|
-
let(:example) {
|
21
|
+
let(:example) { '' }
|
18
22
|
it 'returns nil' do
|
19
23
|
expect(subject).to be(nil)
|
20
24
|
end
|
@@ -47,8 +51,6 @@ describe Praxis::MediaTypeIdentifier do
|
|
47
51
|
# pending("need to stop using a regexp to do a context-free parser's job")
|
48
52
|
# expect(described_class.new(tricky_example).parameters['sauce']).to eq('yes; absolutely')
|
49
53
|
# end
|
50
|
-
|
51
|
-
|
52
54
|
end
|
53
55
|
|
54
56
|
context 'given a malformed type' do
|
@@ -164,7 +166,7 @@ describe Praxis::MediaTypeIdentifier do
|
|
164
166
|
|
165
167
|
let(:with_suffix) { 'application/vnd.widget+xml' }
|
166
168
|
let(:with_subtype) { 'text/xml' }
|
167
|
-
let(:with_both) { 'text/json+xml' } #nonsensical but valid!
|
169
|
+
let(:with_both) { 'text/json+xml' } # nonsensical but valid!
|
168
170
|
|
169
171
|
it 'uses the suffix' do
|
170
172
|
expect(subject.new(with_suffix).handler_name).to eq('xml')
|
@@ -192,15 +194,15 @@ describe Praxis::MediaTypeIdentifier do
|
|
192
194
|
|
193
195
|
it 'adds parameters' do
|
194
196
|
expect(simple_subject + 'nuts=true').to \
|
195
|
-
|
197
|
+
eq(described_class.new('application/vnd.icecream; nuts=true'))
|
196
198
|
|
197
199
|
expect(simple_subject + '; nuts=true').to \
|
198
|
-
|
200
|
+
eq(described_class.new('application/vnd.icecream; nuts=true'))
|
199
201
|
end
|
200
202
|
|
201
203
|
it 'adds suffix and parameters' do
|
202
204
|
expect(simple_subject + 'xml; nuts=true').to \
|
203
|
-
|
205
|
+
eq(described_class.new('application/vnd.icecream+xml; nuts=true'))
|
204
206
|
end
|
205
207
|
|
206
208
|
it 'replaces the suffix' do
|
@@ -210,7 +212,7 @@ describe Praxis::MediaTypeIdentifier do
|
|
210
212
|
|
211
213
|
it 'replaces existing parameters and adds new ones' do
|
212
214
|
expect(complex_subject + 'nuts=false; cherry=true').to \
|
213
|
-
|
215
|
+
eq(described_class.new('application/vnd.icecream+json; cherry=true; nuts=false'))
|
214
216
|
|
215
217
|
expect(complex_subject + '; nuts=false; cherry=true').to \
|
216
218
|
eq(described_class.new('application/vnd.icecream+json; cherry=true; nuts=false'))
|
@@ -235,4 +237,5 @@ describe Praxis::MediaTypeIdentifier do
|
|
235
237
|
end
|
236
238
|
end
|
237
239
|
end
|
238
|
-
end
|
240
|
+
end
|
241
|
+
# rubocop:enable Style/StringConcatenation
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
describe Praxis::MediaType do
|
@@ -5,19 +7,18 @@ describe Praxis::MediaType do
|
|
5
7
|
let(:manager_resource) { instance_double(Person, id: 101, name: /[:name:]/.gen, href: '/') }
|
6
8
|
let(:custodian_resource) { instance_double(Person, id: 102, name: /[:name:]/.gen, href: '/') }
|
7
9
|
let(:residents_summary_resource) do
|
8
|
-
instance_double(Person::CollectionSummary, href:
|
10
|
+
instance_double(Person::CollectionSummary, href: '/people', size: 2)
|
9
11
|
end
|
10
12
|
|
11
13
|
let(:resource) do
|
12
14
|
double('address',
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
)
|
15
|
+
id: 1,
|
16
|
+
name: 'Home',
|
17
|
+
owner: owner_resource,
|
18
|
+
manager: manager_resource,
|
19
|
+
custodian: custodian_resource,
|
20
|
+
residents_summary: residents_summary_resource,
|
21
|
+
fields: { id: true, name: true })
|
21
22
|
end
|
22
23
|
|
23
24
|
subject(:address) { Address.new(resource) }
|
@@ -28,7 +29,6 @@ describe Praxis::MediaType do
|
|
28
29
|
its(:owner) { should be_instance_of(Person) }
|
29
30
|
end
|
30
31
|
|
31
|
-
|
32
32
|
context 'accessor methods' do
|
33
33
|
subject(:address_klass) { address.class }
|
34
34
|
|
@@ -41,12 +41,12 @@ describe Praxis::MediaType do
|
|
41
41
|
its(:description) { should be_kind_of(String) }
|
42
42
|
end
|
43
43
|
|
44
|
-
context
|
44
|
+
context 'rendering' do
|
45
45
|
subject(:output) { address.render }
|
46
46
|
|
47
47
|
its([:id]) { should eq(address.id) }
|
48
48
|
its([:name]) { should eq(address.name) }
|
49
49
|
its([:owner]) { should eq(Person.dump(owner_resource)) }
|
50
|
-
its([:fields]) { should eq(address.fields.dump
|
50
|
+
its([:fields]) { should eq(address.fields.dump) }
|
51
51
|
end
|
52
52
|
end
|
@@ -1,73 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
describe Praxis::MiddlewareApp do
|
4
|
-
|
5
|
-
let(:
|
6
|
-
let(:
|
7
|
-
let(:instance){ middleware.new(target)}
|
6
|
+
let(:init_args) { { root: 'here' } }
|
7
|
+
let(:middleware) { Praxis::MiddlewareApp.for(**init_args) }
|
8
|
+
let(:instance) { middleware.new(target) }
|
8
9
|
|
9
10
|
context '.for' do
|
10
11
|
it 'does not initialize the Application instance yet' do
|
11
|
-
expect(
|
12
|
+
expect(Praxis::Application.instance).to_not receive(:setup)
|
12
13
|
middleware
|
13
14
|
end
|
14
15
|
it 'returns its class' do
|
15
|
-
expect(
|
16
|
+
expect(middleware).to be < Praxis::MiddlewareApp
|
16
17
|
end
|
17
18
|
end
|
18
19
|
|
19
20
|
context 'instantiated' do
|
20
|
-
subject{ instance }
|
21
|
-
let(:target_response){ [201,{}] }
|
22
|
-
let(:target){ double(
|
21
|
+
subject { instance }
|
22
|
+
let(:target_response) { [201, {}] }
|
23
|
+
let(:target) { double('target app', call: target_response) }
|
23
24
|
it 'saves the target app' do
|
24
25
|
expect(subject.target).to be(target)
|
25
26
|
end
|
26
27
|
it 'does not initialize the Application instance yet' do
|
27
|
-
expect(
|
28
|
+
expect(Praxis::Application.instance).to_not receive(:setup)
|
28
29
|
subject
|
29
30
|
end
|
30
|
-
|
31
|
+
|
31
32
|
context '.call' do
|
32
|
-
let(:env){ {} }
|
33
|
-
let(:praxis_response){ [200,{}] }
|
34
|
-
subject(:response){ instance.call(env) }
|
33
|
+
let(:env) { {} }
|
34
|
+
let(:praxis_response) { [200, {}] }
|
35
|
+
subject(:response) { instance.call(env) }
|
35
36
|
before do
|
36
37
|
# always invokes the praxis app
|
37
|
-
expect(
|
38
|
+
expect(Praxis::Application.instance).to receive(:call).with(env).once.and_return(praxis_response)
|
38
39
|
end
|
39
40
|
|
40
41
|
context 'when it has not been setup yet' do
|
41
42
|
it 'initializes the application singleton with the passed parameters' do
|
42
|
-
expect(
|
43
|
+
expect(Praxis::Application.instance).to receive(:setup).with(init_args).once
|
43
44
|
subject
|
44
45
|
end
|
45
46
|
end
|
46
47
|
context 'when it has already been setup' do
|
47
48
|
it 'does NOT call instance setup' do
|
48
49
|
middleware.setup
|
49
|
-
expect(
|
50
|
+
expect(Praxis::Application.instance).to_not receive(:setup)
|
50
51
|
subject
|
51
52
|
end
|
52
53
|
end
|
53
54
|
|
54
55
|
context 'properly handled (non-404 and 405) responses from praxis' do
|
55
56
|
it 'are returned straight through' do
|
56
|
-
expect(
|
57
|
+
expect(response).to be(praxis_response)
|
57
58
|
end
|
58
59
|
end
|
59
60
|
|
60
61
|
context '404/405 responses with X-Cascade = pass' do
|
61
|
-
let(:praxis_response){ [404, {'X-Cascade' => 'pass'}]}
|
62
|
+
let(:praxis_response) { [404, { 'X-Cascade' => 'pass' }] }
|
62
63
|
it 'are forwarded to the target app' do
|
63
|
-
expect(
|
64
|
+
expect(response).to be(target_response)
|
64
65
|
end
|
65
66
|
end
|
66
67
|
|
67
68
|
context '404/405 responses without X-Cascade = pass' do
|
68
|
-
let(:praxis_response){ [404, {}]}
|
69
|
+
let(:praxis_response) { [404, {}] }
|
69
70
|
it 'returned straight through' do
|
70
|
-
expect(
|
71
|
+
expect(response).to be(praxis_response)
|
71
72
|
end
|
72
73
|
end
|
73
74
|
end
|
@@ -1,7 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
describe Praxis::MultipartParser do
|
4
|
-
|
5
6
|
let(:form) do
|
6
7
|
form_data = MIME::Multipart::FormData.new
|
7
8
|
|
@@ -36,17 +37,16 @@ describe Praxis::MultipartParser do
|
|
36
37
|
form.add text, 'file', 'docker'
|
37
38
|
end
|
38
39
|
|
39
|
-
subject(:part) { parts.find { |p| p.name == 'file'} }
|
40
|
-
#subject(:part_body) { part.body }
|
41
|
-
|
40
|
+
subject(:part) { parts.find { |p| p.name == 'file' } }
|
41
|
+
# subject(:part_body) { part.body }
|
42
42
|
|
43
43
|
its(:payload) { should be_kind_of(Tempfile) }
|
44
|
-
its(:filename) { should eq(
|
45
|
-
its(:name) { should eq(
|
44
|
+
its(:filename) { should eq('docker') }
|
45
|
+
its(:name) { should eq('file') }
|
46
46
|
|
47
47
|
context 'headers' do
|
48
48
|
subject(:part_headers) { part.headers }
|
49
|
-
its(['Content-Type']) { should eq(
|
49
|
+
its(['Content-Type']) { should eq('text/plain') }
|
50
50
|
its(['Content-Disposition']) { should match(/filename=docker/) }
|
51
51
|
end
|
52
52
|
|
@@ -56,7 +56,5 @@ describe Praxis::MultipartParser do
|
|
56
56
|
part.payload.rewind
|
57
57
|
expect(part.payload.read).to eq('DOCKER_HOST=tcp://127.0.0.1:2375')
|
58
58
|
end
|
59
|
-
|
60
59
|
end
|
61
|
-
|
62
60
|
end
|
@@ -1,11 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
describe Praxis::Notifications do
|
4
|
-
|
5
6
|
let(:events) { [] }
|
6
7
|
|
7
8
|
before do
|
8
|
-
Praxis::Notifications.subscribe('render') do |
|
9
|
+
Praxis::Notifications.subscribe('render') do |_name, _start, _finish, _id, payload|
|
9
10
|
events << payload
|
10
11
|
end
|
11
12
|
|
@@ -17,7 +18,6 @@ describe Praxis::Notifications do
|
|
17
18
|
|
18
19
|
it 'works' do
|
19
20
|
expect(events).to have(2).items
|
20
|
-
expect(events).to match [{extra: :information}, {extra: :single}]
|
21
|
+
expect(events).to match [{ extra: :information }, { extra: :single }]
|
21
22
|
end
|
22
|
-
|
23
23
|
end
|
@@ -1,21 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
describe Praxis::PluginConcern do
|
4
|
-
|
5
6
|
it 'works' do
|
6
7
|
expect(Praxis::Request.instance_methods).to include(:user_abilities)
|
7
8
|
end
|
8
9
|
|
9
10
|
context 'ActionDefinition' do
|
10
11
|
subject(:action) { ApiResources::Instances.actions[:terminate] }
|
11
|
-
its(:required_abilities) { should match_array [
|
12
|
+
its(:required_abilities) { should match_array %i[terminate read] }
|
12
13
|
|
13
14
|
context '#describe' do
|
14
15
|
subject(:describe) { action.describe }
|
15
|
-
it { should have_key :required_abilities}
|
16
|
-
its([:required_abilities]) { should match_array action.required_abilities}
|
16
|
+
it { should have_key :required_abilities }
|
17
|
+
its([:required_abilities]) { should match_array action.required_abilities }
|
17
18
|
end
|
18
|
-
|
19
19
|
end
|
20
|
-
|
21
20
|
end
|