praxis 0.21 → 2.0.pre.3
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/.travis.yml +8 -15
- data/CHANGELOG.md +328 -299
- data/CONTRIBUTING.md +4 -4
- data/README.md +11 -9
- data/lib/api_browser/app/js/directives/attribute_table.js +2 -1
- data/lib/api_browser/app/js/directives/conditional_requirements.js +13 -0
- data/lib/api_browser/app/js/directives/type_placeholder.js +10 -1
- data/lib/api_browser/app/js/factories/normalize_attributes.js +4 -2
- data/lib/api_browser/app/js/factories/template_for.js +5 -2
- data/lib/api_browser/app/js/filters/has_requirement.js +14 -0
- data/lib/api_browser/app/js/filters/tag_requirement.js +13 -0
- data/lib/api_browser/app/sass/praxis.scss +11 -0
- data/lib/api_browser/app/views/action.html +2 -2
- data/lib/api_browser/app/views/directives/attribute_description/member_options.html +2 -2
- data/lib/api_browser/app/views/directives/attribute_table.html +1 -1
- data/lib/api_browser/app/views/type.html +1 -1
- data/lib/api_browser/app/views/type/details.html +2 -2
- data/lib/api_browser/app/views/types/embedded/array.html +2 -0
- data/lib/api_browser/app/views/types/embedded/default.html +3 -1
- data/lib/api_browser/app/views/types/embedded/requirements.html +6 -0
- data/lib/api_browser/app/views/types/embedded/single_req.html +9 -0
- data/lib/api_browser/app/views/types/embedded/struct.html +14 -2
- data/lib/api_browser/app/views/types/standalone/array.html +1 -1
- data/lib/api_browser/app/views/types/standalone/struct.html +2 -1
- data/lib/api_browser/package.json +1 -1
- data/lib/praxis.rb +9 -3
- data/lib/praxis/action_definition.rb +1 -1
- data/lib/praxis/action_definition/headers_dsl_compiler.rb +1 -1
- data/lib/praxis/application.rb +1 -9
- data/lib/praxis/bootloader.rb +1 -4
- data/lib/praxis/config.rb +1 -1
- data/lib/praxis/dispatcher.rb +10 -6
- data/lib/praxis/docs/generator.rb +2 -1
- data/lib/praxis/extensions/attribute_filtering/active_record_filter_query_builder.rb +180 -0
- data/lib/praxis/extensions/attribute_filtering/filtering_params.rb +273 -0
- data/lib/praxis/extensions/attribute_filtering/sequel_filter_query_builder.rb +125 -0
- data/lib/praxis/extensions/field_selection.rb +1 -9
- data/lib/praxis/extensions/field_selection/active_record_query_selector.rb +51 -0
- data/lib/praxis/extensions/field_selection/sequel_query_selector.rb +61 -0
- data/lib/praxis/extensions/rails_compat.rb +2 -0
- data/lib/praxis/extensions/rails_compat/request_methods.rb +19 -0
- data/lib/praxis/handlers/xml.rb +1 -1
- data/lib/praxis/mapper/active_model_compat.rb +98 -0
- data/lib/praxis/mapper/resource.rb +242 -0
- data/lib/praxis/mapper/selector_generator.rb +149 -0
- data/lib/praxis/mapper/sequel_compat.rb +76 -0
- data/lib/praxis/media_type_identifier.rb +2 -1
- data/lib/praxis/middleware_app.rb +20 -2
- data/lib/praxis/multipart/parser.rb +14 -2
- data/lib/praxis/notifications.rb +1 -1
- data/lib/praxis/plugins/mapper_plugin.rb +64 -0
- data/lib/praxis/plugins/rails_plugin.rb +104 -0
- data/lib/praxis/request.rb +7 -1
- data/lib/praxis/request_superclassing.rb +11 -0
- data/lib/praxis/resource_definition.rb +5 -5
- data/lib/praxis/response.rb +1 -1
- data/lib/praxis/route.rb +1 -1
- data/lib/praxis/routing_config.rb +1 -1
- data/lib/praxis/trait.rb +1 -1
- data/lib/praxis/types/media_type_common.rb +2 -2
- data/lib/praxis/types/multipart.rb +1 -1
- data/lib/praxis/types/multipart_array.rb +2 -2
- data/lib/praxis/types/multipart_array/part_definition.rb +1 -1
- data/lib/praxis/version.rb +1 -1
- data/praxis.gemspec +14 -13
- data/spec/functional_spec.rb +4 -7
- data/spec/praxis/action_definition_spec.rb +1 -1
- data/spec/praxis/application_spec.rb +1 -1
- data/spec/praxis/collection_spec.rb +3 -2
- data/spec/praxis/config_spec.rb +2 -2
- data/spec/praxis/extensions/field_selection/active_record_query_selector_spec.rb +106 -0
- data/spec/praxis/extensions/field_selection/sequel_query_selector_spec.rb +147 -0
- data/spec/praxis/extensions/field_selection/support/spec_resources_active_model.rb +130 -0
- data/spec/praxis/extensions/field_selection/support/spec_resources_sequel.rb +106 -0
- data/spec/praxis/handlers/xml_spec.rb +2 -2
- data/spec/praxis/mapper/resource_spec.rb +169 -0
- data/spec/praxis/mapper/selector_generator_spec.rb +293 -0
- data/spec/praxis/media_type_spec.rb +0 -10
- data/spec/praxis/middleware_app_spec.rb +29 -9
- data/spec/praxis/request_stages/action_spec.rb +8 -1
- data/spec/praxis/response_definition_spec.rb +7 -4
- data/spec/praxis/response_spec.rb +1 -1
- data/spec/praxis/responses/internal_server_error_spec.rb +2 -2
- data/spec/praxis/responses/validation_error_spec.rb +2 -2
- data/spec/praxis/router_spec.rb +1 -1
- data/spec/spec_app/app/controllers/instances.rb +1 -1
- data/spec/spec_app/config/environment.rb +3 -21
- data/spec/spec_helper.rb +11 -15
- data/spec/support/be_deep_equal_matcher.rb +39 -0
- data/spec/support/spec_resources.rb +124 -0
- data/tasks/thor/templates/generator/empty_app/Gemfile +3 -3
- metadata +102 -77
- data/.ruby-version +0 -1
- data/lib/praxis/extensions/mapper_selectors.rb +0 -16
- data/lib/praxis/media_type_collection.rb +0 -127
- data/lib/praxis/plugins/praxis_mapper_plugin.rb +0 -246
- data/lib/praxis/stats.rb +0 -113
- data/spec/praxis/media_type_collection_spec.rb +0 -157
- data/spec/praxis/plugins/praxis_mapper_plugin_spec.rb +0 -142
- data/spec/praxis/stats_spec.rb +0 -9
- data/spec/spec_app/app/models/person.rb +0 -3
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
require "spec_helper"
|
|
2
|
-
|
|
3
|
-
describe Praxis::MediaTypeCollection do
|
|
4
|
-
|
|
5
|
-
subject!(:media_type_collection) do
|
|
6
|
-
silence_warnings do
|
|
7
|
-
klass = Class.new(Praxis::MediaTypeCollection) do
|
|
8
|
-
member_type VolumeSnapshot
|
|
9
|
-
description 'A container for a collection of Volumes'
|
|
10
|
-
display_name 'Volumes Collection'
|
|
11
|
-
|
|
12
|
-
attributes do
|
|
13
|
-
attribute :name, String, regexp: /snapshots-(\w+)/
|
|
14
|
-
attribute :size, Integer
|
|
15
|
-
attribute :href, String
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
view :link do
|
|
19
|
-
attribute :name
|
|
20
|
-
attribute :size
|
|
21
|
-
attribute :href
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
member_view :default, using: :default
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
klass.finalize!
|
|
28
|
-
klass
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
context '.member_type' do
|
|
33
|
-
its(:member_type){ should be(VolumeSnapshot) }
|
|
34
|
-
its(:member_attribute){ should be_kind_of(Attributor::Attribute) }
|
|
35
|
-
its('member_attribute.type'){ should be(VolumeSnapshot) }
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
context '.load' do
|
|
39
|
-
context 'with a hash' do
|
|
40
|
-
let(:snapshots_data) { {name: 'snapshots', href: '/bob/snapshots' } }
|
|
41
|
-
subject(:snapshots) { media_type_collection.load(snapshots_data) }
|
|
42
|
-
|
|
43
|
-
its(:name) { should eq(snapshots_data[:name]) }
|
|
44
|
-
its(:href) { should eq(snapshots_data[:href]) }
|
|
45
|
-
|
|
46
|
-
it 'has no members set' do
|
|
47
|
-
expect(snapshots.to_a).to eq([])
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
context 'loading an array' do
|
|
53
|
-
let(:snapshots_data) do
|
|
54
|
-
[{id: 1, name: 'snapshot-1'},
|
|
55
|
-
{id: 2, name: 'snapshot-2'}]
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
let(:snapshots) { media_type_collection.load(snapshots_data) }
|
|
59
|
-
subject(:members) { snapshots.to_a }
|
|
60
|
-
|
|
61
|
-
it 'sets the collection members' do
|
|
62
|
-
expect(members).to have(2).items
|
|
63
|
-
|
|
64
|
-
expect(members[0].id).to eq(1)
|
|
65
|
-
expect(members[0].name).to eq('snapshot-1')
|
|
66
|
-
expect(members[1].id).to eq(2)
|
|
67
|
-
expect(members[1].name).to eq('snapshot-2')
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
it 'has no attributes set' do
|
|
71
|
-
expect(snapshots.name).to be(nil)
|
|
72
|
-
expect(snapshots.size).to be(nil)
|
|
73
|
-
expect(snapshots.href).to be(nil)
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
context '#render' do
|
|
80
|
-
context 'for standard views' do
|
|
81
|
-
let(:snapshots_data) { {name: 'snapshots', href: '/bob/snapshots' } }
|
|
82
|
-
let(:snapshots) { media_type_collection.load(snapshots_data) }
|
|
83
|
-
subject(:output) { snapshots.render(view: :link) }
|
|
84
|
-
|
|
85
|
-
its([:name]) { should eq(snapshots.name)}
|
|
86
|
-
its([:size]) { should eq(snapshots.size)}
|
|
87
|
-
its([:href]) { should eq(snapshots.href)}
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
context 'for members' do
|
|
91
|
-
let(:snapshots_data) do
|
|
92
|
-
[{id: 1, name: 'snapshot-1'},
|
|
93
|
-
{id: 2, name: 'snapshot-2'}]
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
let(:snapshots) { media_type_collection.load(snapshots_data) }
|
|
97
|
-
|
|
98
|
-
subject(:output) { media_type_collection.dump(snapshots, view: :default) }
|
|
99
|
-
|
|
100
|
-
it { should eq(snapshots.collect(&:render)) }
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
context '#validate' do
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
context 'with a hash' do
|
|
109
|
-
let(:snapshots_data) { {name: 'snapshots-1', href: '/bob/snapshots' } }
|
|
110
|
-
subject(:snapshots) { media_type_collection.load(snapshots_data) }
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
it 'validates' do
|
|
114
|
-
expect(snapshots.validate).to be_empty
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
context 'with invalid attributes' do
|
|
118
|
-
let(:snapshots_data) { {name: 'notsnapshots', href: '/bob/snapshots' } }
|
|
119
|
-
it 'returns the error' do
|
|
120
|
-
expect(snapshots.validate).to have(1).item
|
|
121
|
-
expect(snapshots.validate[0]).to match(/value \(notsnapshots\) does not match regexp/)
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
context 'for an array' do
|
|
127
|
-
let(:snapshots_data) do
|
|
128
|
-
[{id: 1, name: 'snapshot-1'},
|
|
129
|
-
{id: 2, name: 'snapshot-2'}]
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
subject(:snapshots) { media_type_collection.load(snapshots_data) }
|
|
133
|
-
|
|
134
|
-
it 'validates' do
|
|
135
|
-
expect(snapshots.validate).to be_empty
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
context 'with invalid members' do
|
|
139
|
-
let(:snapshots_data) do
|
|
140
|
-
[{id: 1, name: 'invalid-1'},
|
|
141
|
-
{id: 2, name: 'snapshot-2'}]
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
it 'returns the error' do
|
|
145
|
-
expect(snapshots.validate).to have(1).item
|
|
146
|
-
expect(snapshots.validate[0]).to match(/value \(invalid-1\) does not match regexp/)
|
|
147
|
-
end
|
|
148
|
-
end
|
|
149
|
-
end
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
context '#describe' do
|
|
153
|
-
subject(:described) { media_type_collection.describe }
|
|
154
|
-
its([:description]){ should be(media_type_collection.description)}
|
|
155
|
-
its([:display_name]){ should be(media_type_collection.display_name)}
|
|
156
|
-
end
|
|
157
|
-
end
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
describe Praxis::Plugins::PraxisMapperPlugin do
|
|
4
|
-
|
|
5
|
-
subject(:plugin) { Praxis::Plugins::PraxisMapperPlugin::Plugin.instance }
|
|
6
|
-
let(:config) { plugin.config }
|
|
7
|
-
context 'Plugin' do
|
|
8
|
-
context 'configuration' do
|
|
9
|
-
subject { config }
|
|
10
|
-
its(:log_stats) { should eq 'detailed' }
|
|
11
|
-
its(:stats_log_level) { should eq :info }
|
|
12
|
-
its(:repositories) { should have_key("default") }
|
|
13
|
-
|
|
14
|
-
context 'default repository' do
|
|
15
|
-
subject(:default) { config.repositories['default'] }
|
|
16
|
-
its(['type']) { should eq 'sequel' }
|
|
17
|
-
it 'has the right connection settings' do
|
|
18
|
-
if RUBY_PLATFORM !~ /java/
|
|
19
|
-
expect(subject['connection_settings'].dump).to eq( 'adapter' => 'sqlite','database' => ':memory:' )
|
|
20
|
-
else
|
|
21
|
-
expect(subject['connection_settings'].dump).to eq( 'adapter' => 'jdbc', 'uri' => 'jdbc:sqlite::memory:' )
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
context 'Request' do
|
|
32
|
-
|
|
33
|
-
it 'should have identity_map accessors' do
|
|
34
|
-
expect(Praxis::Plugins::PraxisMapperPlugin::Request.instance_methods).to include(:identity_map,:identity_map=)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
it 'should have silence_mapper_stats accessors' do
|
|
38
|
-
expect(Praxis::Plugins::PraxisMapperPlugin::Request.instance_methods)
|
|
39
|
-
.to include(:silence_mapper_stats,:silence_mapper_stats=)
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
context 'functional test' do
|
|
43
|
-
|
|
44
|
-
def app
|
|
45
|
-
Praxis::Application.instance
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
let(:session) { double("session", valid?: true)}
|
|
49
|
-
|
|
50
|
-
around(:each) do |example|
|
|
51
|
-
orig_level = Praxis::Application.instance.logger.level
|
|
52
|
-
Praxis::Application.instance.logger.level = 2
|
|
53
|
-
example.run
|
|
54
|
-
Praxis::Application.instance.logger.level = orig_level
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
context 'with no identity_map set in the request' do
|
|
58
|
-
it 'does not log stats' do
|
|
59
|
-
expect(Praxis::Plugins::PraxisMapperPlugin::Statistics).to_not receive(:log)
|
|
60
|
-
the_body = StringIO.new("{}") # This is a funny, GET request expecting a body
|
|
61
|
-
get '/api/clouds/1/instances/2?api_version=1.0', nil, 'rack.input' => the_body,'CONTENT_TYPE' => "application/json", 'global_session' => session
|
|
62
|
-
|
|
63
|
-
expect(last_response.status).to eq(200)
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
context 'with an identity_map set in the request' do
|
|
67
|
-
it 'logs stats' do
|
|
68
|
-
expect(Praxis::Plugins::PraxisMapperPlugin::Statistics).to receive(:log).
|
|
69
|
-
with(kind_of(Praxis::Request),kind_of(Praxis::Mapper::IdentityMap), 'detailed').
|
|
70
|
-
and_call_original
|
|
71
|
-
the_body = StringIO.new("{}") # This is a funny, GET request expecting a body
|
|
72
|
-
get '/api/clouds/1/instances/2?create_identity_map=true&api_version=1.0', nil, 'rack.input' => the_body,'CONTENT_TYPE' => "application/json", 'global_session' => session
|
|
73
|
-
|
|
74
|
-
expect(last_response.status).to eq(200)
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
context 'Statistics' do
|
|
81
|
-
context '.log' do
|
|
82
|
-
let(:queries){ { some: :queries } }
|
|
83
|
-
let(:identity_map) { double('identity_map', queries: queries) }
|
|
84
|
-
let(:log_stats){ 'detailed' }
|
|
85
|
-
let(:request){ double('request', silence_mapper_stats: false ) }
|
|
86
|
-
|
|
87
|
-
after do
|
|
88
|
-
Praxis::Plugins::PraxisMapperPlugin::Statistics.log(request, identity_map, log_stats)
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
context 'when the request silences mapper stats' do
|
|
92
|
-
let(:request){ double('request', silence_mapper_stats: true ) }
|
|
93
|
-
it 'should not log anything' do
|
|
94
|
-
expect(Praxis::Plugins::PraxisMapperPlugin::Statistics).to_not receive(:to_logger)
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
context 'without the request silencing mapper stats' do
|
|
99
|
-
context 'when log_stats = detailed' do
|
|
100
|
-
it 'should call the detailed method' do
|
|
101
|
-
expect(Praxis::Plugins::PraxisMapperPlugin::Statistics).to receive(:detailed).with(identity_map)
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
context 'when log_stats = short' do
|
|
106
|
-
let(:log_stats){ 'short' }
|
|
107
|
-
it 'should call the short method' do
|
|
108
|
-
expect(Praxis::Plugins::PraxisMapperPlugin::Statistics).to receive(:short).with(identity_map)
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
context 'when log_stats = skip' do
|
|
113
|
-
let(:log_stats){ 'skip' }
|
|
114
|
-
|
|
115
|
-
it 'should not log anything' do
|
|
116
|
-
expect(Praxis::Plugins::PraxisMapperPlugin::Statistics).to_not receive(:to_logger)
|
|
117
|
-
end
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
context 'when there is no identity map' do
|
|
121
|
-
let(:identity_map) { nil }
|
|
122
|
-
it 'should not log anything' do
|
|
123
|
-
expect(Praxis::Plugins::PraxisMapperPlugin::Statistics).to_not receive(:to_logger)
|
|
124
|
-
end
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
context 'when no queries are logged in the identity map' do
|
|
128
|
-
let(:queries){ {} }
|
|
129
|
-
it 'should log a special message' do
|
|
130
|
-
expect(Praxis::Plugins::PraxisMapperPlugin::Statistics).to receive(:to_logger)
|
|
131
|
-
.with("No database interactions observed.")
|
|
132
|
-
end
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
end
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
it 'has specs for testing the detailed log output'
|
|
139
|
-
it 'has specs for testing the short log output'
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
end
|
data/spec/praxis/stats_spec.rb
DELETED