shamu 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +26 -0
- data/.gitignore +2 -1
- data/.rubocop.yml +89 -30
- data/.yardopts +4 -5
- data/Gemfile +24 -12
- data/Guardfile +5 -0
- data/LABELS.md +22 -0
- data/README.md +41 -0
- data/Rakefile +12 -0
- data/circle.yml +7 -3
- data/config.ru +7 -0
- data/lib/shamu/active_record.rb +7 -0
- data/lib/shamu/attributes/assignment.rb +114 -0
- data/lib/shamu/attributes/equality.rb +40 -0
- data/lib/shamu/attributes/fluid_assignment.rb +49 -0
- data/lib/shamu/attributes/validation.rb +74 -0
- data/lib/shamu/attributes.rb +255 -0
- data/lib/shamu/auditing/README.md +0 -0
- data/lib/shamu/auditing/audit_record.rb +32 -0
- data/lib/shamu/auditing/auditing_service.rb +32 -0
- data/lib/shamu/auditing/list_scope.rb +22 -0
- data/lib/shamu/auditing/logging_auditing_service.rb +16 -0
- data/lib/shamu/auditing/support.rb +75 -0
- data/lib/shamu/auditing/transaction.rb +58 -0
- data/lib/shamu/auditing.rb +12 -0
- data/lib/shamu/entities/README.md +1 -0
- data/lib/shamu/entities/active_record.rb +123 -0
- data/lib/shamu/entities/active_record_soft_destroy.rb +91 -0
- data/lib/shamu/entities/entity.rb +196 -0
- data/lib/shamu/entities/entity_path.rb +87 -0
- data/lib/shamu/entities/identity_cache.rb +64 -0
- data/lib/shamu/entities/list.rb +54 -0
- data/lib/shamu/entities/list_scope/dates.rb +57 -0
- data/lib/shamu/entities/list_scope/paging.rb +51 -0
- data/lib/shamu/entities/list_scope/scoped_paging.rb +65 -0
- data/lib/shamu/entities/list_scope/sorting.rb +76 -0
- data/lib/shamu/entities/list_scope.rb +105 -0
- data/lib/shamu/entities/null_entity.rb +88 -0
- data/lib/shamu/entities.rb +11 -0
- data/lib/shamu/error.rb +23 -5
- data/lib/shamu/events/README.md +0 -0
- data/lib/shamu/events/active_record/channel.rb +36 -0
- data/lib/shamu/events/active_record/message.rb +52 -0
- data/lib/shamu/events/active_record/migration.rb +49 -0
- data/lib/shamu/events/active_record/runner.rb +28 -0
- data/lib/shamu/events/active_record/service.rb +174 -0
- data/lib/shamu/events/active_record.rb +13 -0
- data/lib/shamu/events/channel_stats.rb +23 -0
- data/lib/shamu/events/error.rb +24 -0
- data/lib/shamu/events/events_service.rb +136 -0
- data/lib/shamu/events/in_memory/async_service.rb +48 -0
- data/lib/shamu/events/in_memory/service.rb +97 -0
- data/lib/shamu/events/in_memory.rb +10 -0
- data/lib/shamu/events/message.rb +38 -0
- data/lib/shamu/events/support.rb +60 -0
- data/lib/shamu/events.rb +12 -0
- data/lib/shamu/features/README.md +0 -0
- data/lib/shamu/features/conditions/condition.rb +39 -0
- data/lib/shamu/features/conditions/env.rb +37 -0
- data/lib/shamu/features/conditions/hosts.rb +25 -0
- data/lib/shamu/features/conditions/matching.rb +16 -0
- data/lib/shamu/features/conditions/not_matching.rb +16 -0
- data/lib/shamu/features/conditions/percentage.rb +44 -0
- data/lib/shamu/features/conditions/proc.rb +54 -0
- data/lib/shamu/features/conditions/roles.rb +23 -0
- data/lib/shamu/features/conditions/schedule_at.rb +27 -0
- data/lib/shamu/features/conditions.rb +18 -0
- data/lib/shamu/features/config_service.rb +10 -0
- data/lib/shamu/features/context.rb +80 -0
- data/lib/shamu/features/env_store.rb +88 -0
- data/lib/shamu/features/errors.rb +29 -0
- data/lib/shamu/features/features_service.rb +168 -0
- data/lib/shamu/features/list_scope.rb +30 -0
- data/lib/shamu/features/selector.rb +50 -0
- data/lib/shamu/features/support.rb +51 -0
- data/lib/shamu/features/toggle.rb +149 -0
- data/lib/shamu/features/toggle_codec.rb +69 -0
- data/lib/shamu/features.rb +16 -0
- data/lib/shamu/locale/en.yml +22 -2
- data/lib/shamu/logger.rb +13 -0
- data/lib/shamu/rack/README.md +0 -0
- data/lib/shamu/rack/cookies.rb +115 -0
- data/lib/shamu/rack/cookies_middleware.rb +26 -0
- data/lib/shamu/rack/query_params.rb +41 -0
- data/lib/shamu/rack/query_params_middleware.rb +24 -0
- data/lib/shamu/rack.rb +12 -0
- data/lib/shamu/rails/controller.rb +131 -0
- data/lib/shamu/rails/entity.rb +168 -0
- data/lib/shamu/rails/features.rb +13 -0
- data/lib/shamu/rails/railtie.rb +30 -0
- data/lib/shamu/rails.rb +10 -0
- data/lib/shamu/rspec/matchers.rb +44 -0
- data/lib/shamu/rspec.rb +1 -0
- data/lib/shamu/security/README.md +0 -0
- data/lib/shamu/security/active_record_policy.rb +106 -0
- data/lib/shamu/security/error.rb +65 -0
- data/lib/shamu/security/hashed_value.rb +71 -0
- data/lib/shamu/security/no_policy.rb +15 -0
- data/lib/shamu/security/policy.rb +289 -0
- data/lib/shamu/security/policy_refinement.rb +50 -0
- data/lib/shamu/security/policy_rule.rb +59 -0
- data/lib/shamu/security/principal.rb +72 -0
- data/lib/shamu/security/roles.rb +62 -0
- data/lib/shamu/security/roles_service.rb +30 -0
- data/lib/shamu/security/support.rb +83 -0
- data/lib/shamu/security.rb +43 -0
- data/lib/shamu/services/README.md +2 -0
- data/lib/shamu/services/active_record.rb +58 -0
- data/lib/shamu/services/active_record_crud.rb +378 -0
- data/lib/shamu/services/error.rb +24 -0
- data/lib/shamu/services/lazy_association.rb +31 -0
- data/lib/shamu/services/lazy_transform.rb +97 -0
- data/lib/shamu/services/request.rb +122 -0
- data/lib/shamu/services/request_support.rb +124 -0
- data/lib/shamu/services/result.rb +75 -0
- data/lib/shamu/services/service.rb +355 -0
- data/lib/shamu/services.rb +12 -0
- data/lib/shamu/sessions/README.md +2 -0
- data/lib/shamu/sessions/cookie_store.rb +79 -0
- data/lib/shamu/sessions/session_store.rb +42 -0
- data/lib/shamu/sessions.rb +8 -0
- data/lib/shamu/to_bool_extension.rb +57 -0
- data/lib/shamu/to_model_id_extension.rb +50 -0
- data/lib/shamu/version.rb +10 -4
- data/lib/shamu.rb +18 -6
- data/shamu.gemspec +21 -10
- data/spec/internal/README.md +4 -0
- data/spec/internal/config/database.yml +3 -0
- data/spec/internal/config/routes.rb +3 -0
- data/spec/internal/db/schema.rb +3 -0
- data/spec/internal/log/.gitignore +1 -0
- data/spec/internal/public/favicon.ico +0 -0
- data/spec/lib/shamu/active_record_support.rb +32 -0
- data/spec/lib/shamu/attributes/assignment_spec.rb +129 -0
- data/spec/lib/shamu/attributes/equality_spec.rb +63 -0
- data/spec/lib/shamu/attributes/fluid_assignment_spec.rb +31 -0
- data/spec/lib/shamu/attributes/validation_spec.rb +53 -0
- data/spec/lib/shamu/attributes_spec.rb +331 -0
- data/spec/lib/shamu/auditing/logging_auditing_service_spec.rb +18 -0
- data/spec/lib/shamu/auditing/support_spec.rb +41 -0
- data/spec/lib/shamu/entities/active_record_soft_destroy_spec.rb +82 -0
- data/spec/lib/shamu/entities/active_record_spec.rb +66 -0
- data/spec/lib/shamu/entities/entity_path_spec.rb +40 -0
- data/spec/lib/shamu/entities/entity_spec.rb +56 -0
- data/spec/lib/shamu/entities/identity_cache_spec.rb +69 -0
- data/spec/lib/shamu/entities/list_scope/dates_spec.rb +47 -0
- data/spec/lib/shamu/entities/list_scope/paging_spec.rb +41 -0
- data/spec/lib/shamu/entities/list_scope/scoped_paging_spec.rb +40 -0
- data/spec/lib/shamu/entities/list_scope/sorting_spec.rb +59 -0
- data/spec/lib/shamu/entities/list_scope_spec.rb +127 -0
- data/spec/lib/shamu/entities/list_spec.rb +60 -0
- data/spec/lib/shamu/entities/null_entity_spec.rb +94 -0
- data/spec/lib/shamu/events/active_record/migration_spec.rb +11 -0
- data/spec/lib/shamu/events/active_record/service_spec.rb +139 -0
- data/spec/lib/shamu/events/events_service_spec.rb +57 -0
- data/spec/lib/shamu/events/in_memory/async_service_spec.rb +37 -0
- data/spec/lib/shamu/events/in_memory/service_spec.rb +36 -0
- data/spec/lib/shamu/events/message_spec.rb +7 -0
- data/spec/lib/shamu/events/support_spec.rb +44 -0
- data/spec/lib/shamu/features/conditions/condition_spec.rb +8 -0
- data/spec/lib/shamu/features/conditions/env_spec.rb +29 -0
- data/spec/lib/shamu/features/conditions/hosts_spec.rb +21 -0
- data/spec/lib/shamu/features/conditions/matching_spec.rb +23 -0
- data/spec/lib/shamu/features/conditions/percentage_spec.rb +71 -0
- data/spec/lib/shamu/features/conditions/proc_spec.rb +28 -0
- data/spec/lib/shamu/features/env_store_spec.rb +48 -0
- data/spec/lib/shamu/features/features.yml +34 -0
- data/spec/lib/shamu/features/features_service_spec.rb +109 -0
- data/spec/lib/shamu/features/secondary.yml +5 -0
- data/spec/lib/shamu/features/selector_spec.rb +17 -0
- data/spec/lib/shamu/features/support_spec.rb +45 -0
- data/spec/lib/shamu/features/toggle_codec_spec.rb +28 -0
- data/spec/lib/shamu/features/toggle_spec.rb +42 -0
- data/spec/lib/shamu/rack/cookies_middleware_spec.rb +33 -0
- data/spec/lib/shamu/rack/cookies_spec.rb +43 -0
- data/spec/lib/shamu/rack/query_params_middleware_spec.rb +33 -0
- data/spec/lib/shamu/rack/query_params_spec.rb +23 -0
- data/spec/lib/shamu/rails/controller_spec.rb +74 -0
- data/spec/lib/shamu/rails/entity_spec.rb +150 -0
- data/spec/lib/shamu/rails/features.yml +13 -0
- data/spec/lib/shamu/rails/features_spec.rb +45 -0
- data/spec/lib/shamu/security/active_record_policy_spec.rb +38 -0
- data/spec/lib/shamu/security/hashed_value_spec.rb +41 -0
- data/spec/lib/shamu/security/policy_refinement_spec.rb +61 -0
- data/spec/lib/shamu/security/policy_rule_spec.rb +60 -0
- data/spec/lib/shamu/security/policy_spec.rb +158 -0
- data/spec/lib/shamu/security/roles_spec.rb +46 -0
- data/spec/lib/shamu/services/active_record_crud_spec.rb +460 -0
- data/spec/lib/shamu/services/active_record_spec.rb +92 -0
- data/spec/lib/shamu/services/lazy_association_spec.rb +31 -0
- data/spec/lib/shamu/services/lazy_transform_spec.rb +96 -0
- data/spec/lib/shamu/services/request_spec.rb +58 -0
- data/spec/lib/shamu/services/request_support_spec.rb +129 -0
- data/spec/lib/shamu/services/result_spec.rb +37 -0
- data/spec/lib/shamu/services/service_spec.rb +307 -0
- data/spec/lib/shamu/sessions/cookie_store_spec.rb +44 -0
- data/spec/lib/shamu/to_bool_extension_spec.rb +67 -0
- data/spec/lib/shamu/to_model_id_extension_spec.rb +54 -0
- data/spec/rails_helper.rb +13 -0
- data/spec/spec_helper.rb +17 -12
- data/spec/support/active_record.rb +17 -0
- data/spec/support/database.rb +14 -0
- data/spec/support/logger.rb +0 -0
- metadata +383 -9
- data/spec/lib/shamu_spec.rb +0 -5
- /data/{spec/internal/log/test.log → lib/shamu/attributes/README.md} +0 -0
@@ -0,0 +1,158 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Shamu::Security::Policy do
|
4
|
+
let( :principal ) { Shamu::Security::Principal.new }
|
5
|
+
let( :roles ) { [] }
|
6
|
+
let( :policy ) { klass.new principal: principal, roles: roles }
|
7
|
+
let( :klass ) do
|
8
|
+
Class.new( Shamu::Security::Policy ) do
|
9
|
+
role :super_user, inherits: :admin
|
10
|
+
role :admin, inherits: :user
|
11
|
+
role :user
|
12
|
+
|
13
|
+
public :in_role?, :add_rule, :rules, :permit, :deny, :when_elevated,
|
14
|
+
:alias_action, :expand_aliases
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "#authorize" do
|
19
|
+
it "raises when not permitted" do
|
20
|
+
allow( policy ).to receive( :permit? ).and_return false
|
21
|
+
|
22
|
+
expect do
|
23
|
+
policy.authorize! :read, :stuff
|
24
|
+
end.to raise_error Shamu::Security::AccessDeniedError
|
25
|
+
end
|
26
|
+
|
27
|
+
it "raises when maybe permitted" do
|
28
|
+
allow( policy ).to receive( :permit? ).and_return :maybe
|
29
|
+
|
30
|
+
expect do
|
31
|
+
policy.authorize! :read, :stuff
|
32
|
+
end.to raise_error Shamu::Security::AccessDeniedError
|
33
|
+
end
|
34
|
+
|
35
|
+
it "returns the authorized resource" do
|
36
|
+
allow( policy ).to receive( :permit? ).and_return :yes
|
37
|
+
resource = double
|
38
|
+
expect( policy.authorize!( :read, resource ) ).to be resource
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "#in_role?" do
|
43
|
+
it "is true for :user when principal is signed in" do
|
44
|
+
allow( policy.principal ).to receive( :user_id ).and_return 1
|
45
|
+
|
46
|
+
expect( policy.in_role?( :user ) ).to be_truthy
|
47
|
+
end
|
48
|
+
|
49
|
+
it "is false for :user when principal is anonymous" do
|
50
|
+
allow( policy.principal ).to receive( :user_id ).and_return nil
|
51
|
+
|
52
|
+
expect( policy.in_role?( :user ) ).to be_falsy
|
53
|
+
end
|
54
|
+
|
55
|
+
it "is true for an explicitly assigned role" do
|
56
|
+
roles << :admin
|
57
|
+
expect( policy.in_role?( :admin ) ).to be_truthy
|
58
|
+
end
|
59
|
+
|
60
|
+
it "is true for an implicitly assigned role" do
|
61
|
+
roles << :super_user
|
62
|
+
expect( policy.in_role?( :admin ) ).to be_truthy
|
63
|
+
end
|
64
|
+
|
65
|
+
it "is false for empty roles list" do
|
66
|
+
expect( policy.in_role? ).to be_falsy
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "#permit?" do
|
71
|
+
let( :rule ) { double Shamu::Security::PolicyRule }
|
72
|
+
let( :second_rule ) { double Shamu::Security::PolicyRule }
|
73
|
+
before( :each ) do
|
74
|
+
allow( policy ).to receive( :rules ).and_return [ rule, second_rule ]
|
75
|
+
|
76
|
+
[ rule, second_rule ].each do |r|
|
77
|
+
allow( r ).to receive( :match? ).and_return false
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
it "permits with matching rule" do
|
82
|
+
allow( rule ).to receive( :match? ).and_return true
|
83
|
+
allow( rule ).to receive( :result ).and_return :yes
|
84
|
+
|
85
|
+
expect( policy.permit?( :do, :stuff ) ).to be_truthy
|
86
|
+
end
|
87
|
+
|
88
|
+
it "denies if no matching rule" do
|
89
|
+
expect( policy.permit?( :do, :stuff ) ).to be_falsy
|
90
|
+
end
|
91
|
+
|
92
|
+
it "denies if expliclitly denied after permit" do
|
93
|
+
expect( rule ).to receive( :match? ).and_return true
|
94
|
+
expect( rule ).to receive( :result ).and_return false
|
95
|
+
|
96
|
+
allow( second_rule ).to receive( :match? ).and_return true
|
97
|
+
allow( second_rule ).to receive( :result ).and_return :yes
|
98
|
+
|
99
|
+
expect( policy.permit?( :do, :stuff ) ).to be_falsy
|
100
|
+
end
|
101
|
+
|
102
|
+
it "fails when testing an ActiveRecord resource" do
|
103
|
+
expect do
|
104
|
+
policy.permit? :check, Class.new( ActiveRecord::Base )
|
105
|
+
end.to raise_error Shamu::Security::NoActiveRecordPolicyChecksError
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe "#permit" do
|
110
|
+
it "adds a :maybe rule when defined within #when_elevated" do
|
111
|
+
allow( policy ).to receive( :permissions ) do
|
112
|
+
policy.when_elevated do
|
113
|
+
policy.permit :do, :stuff
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
expect( policy.rules.first.result ).to eq :maybe
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe "#add_rule" do
|
122
|
+
before( :each ) do
|
123
|
+
allow( policy ).to receive( :permissions )
|
124
|
+
end
|
125
|
+
|
126
|
+
it "expands action aliases" do
|
127
|
+
expect( policy ).to receive( :expand_aliases ).and_call_original
|
128
|
+
policy.add_rule [ :do ], :stuff, :yes
|
129
|
+
end
|
130
|
+
|
131
|
+
it "pushes rule to front" do
|
132
|
+
|
133
|
+
policy.add_rule [ :do ], :stuff, :one
|
134
|
+
policy.add_rule [ :do ], :stuff, :two
|
135
|
+
|
136
|
+
expect( policy.rules.first.result ).to eq :two
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe "#expand_aliases" do
|
141
|
+
before( :each ) do
|
142
|
+
policy.alias_action :show, :list, to: :read
|
143
|
+
policy.alias_action :index, to: :list
|
144
|
+
end
|
145
|
+
|
146
|
+
it "includes explicit actions" do
|
147
|
+
expect( policy.expand_aliases( [ :read ] ) ).to include :read
|
148
|
+
end
|
149
|
+
|
150
|
+
it "includes aliases" do
|
151
|
+
expect( policy.expand_aliases( [ :read ] ) ).to include :show
|
152
|
+
end
|
153
|
+
|
154
|
+
it "includes aliases of aliases" do
|
155
|
+
expect( policy.expand_aliases( [ :read ] ) ).to include :index
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Shamu::Security::Roles do
|
4
|
+
|
5
|
+
describe "#role" do
|
6
|
+
it "adds a role" do
|
7
|
+
klass = Class.new do
|
8
|
+
include Shamu::Security::Roles
|
9
|
+
|
10
|
+
role :admin
|
11
|
+
end
|
12
|
+
|
13
|
+
expect( klass.roles ).to have_key :admin
|
14
|
+
expect( klass.roles[:admin] ).to be_a Hash
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "#expand_roles" do
|
19
|
+
let( :klass ) do
|
20
|
+
Class.new do
|
21
|
+
include Shamu::Security::Roles
|
22
|
+
|
23
|
+
role :admin, inherits: :manager
|
24
|
+
role :manager, inherits: :user
|
25
|
+
role :user
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it "includes base roles" do
|
30
|
+
expect( klass.expand_roles( :user ) ).to include :user
|
31
|
+
end
|
32
|
+
|
33
|
+
it "excludes unknown roles" do
|
34
|
+
expect( klass.expand_roles( :magician ) ).to be_empty
|
35
|
+
end
|
36
|
+
|
37
|
+
it "includes inherited roles" do
|
38
|
+
expect( klass.expand_roles( :manager ) ).to include :user
|
39
|
+
end
|
40
|
+
|
41
|
+
it "includes inherited inherited roles" do
|
42
|
+
expect( klass.expand_roles( :admin ) ).to include :manager
|
43
|
+
expect( klass.expand_roles( :admin ) ).to include :user
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,460 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "shamu/active_record"
|
3
|
+
require_relative "../active_record_support"
|
4
|
+
|
5
|
+
module ActiveRecordCrudSpec
|
6
|
+
class FavoriteEntity < Shamu::Entities::Entity
|
7
|
+
model :record
|
8
|
+
attribute :id, on: :record
|
9
|
+
attribute :name, on: :record
|
10
|
+
attribute :label, on: :record
|
11
|
+
end
|
12
|
+
|
13
|
+
module Request
|
14
|
+
class Change < Shamu::Services::Request
|
15
|
+
attribute :name
|
16
|
+
attribute :label
|
17
|
+
end
|
18
|
+
|
19
|
+
class Create < Change
|
20
|
+
end
|
21
|
+
|
22
|
+
class Update < Change
|
23
|
+
attribute :id
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
class Service < Shamu::Services::Service
|
29
|
+
include Shamu::Services::ActiveRecordCrud
|
30
|
+
|
31
|
+
resource FavoriteEntity, ActiveRecordSpec::Favorite
|
32
|
+
create
|
33
|
+
change
|
34
|
+
finders
|
35
|
+
destroy
|
36
|
+
end
|
37
|
+
|
38
|
+
class FavoriteListScope < Shamu::Entities::ListScope
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
describe Shamu::Services::ActiveRecordCrud do
|
44
|
+
use_active_record
|
45
|
+
before( :all ) { Shamu::ToModelIdExtension.extend! }
|
46
|
+
|
47
|
+
let( :klass ) { ActiveRecordCrudSpec::Service }
|
48
|
+
let( :service ) { scorpion.new klass }
|
49
|
+
|
50
|
+
before( :each ) do
|
51
|
+
# Allow generic args to create the entity
|
52
|
+
allow( service ).to receive( :authorize! ).and_call_original
|
53
|
+
end
|
54
|
+
|
55
|
+
it "includes ActiveRecordService" do
|
56
|
+
expect( ActiveRecordCrudSpec::Service ).to include Shamu::Services::ActiveRecord
|
57
|
+
end
|
58
|
+
|
59
|
+
describe ".resource" do
|
60
|
+
it "defines an entity_class" do
|
61
|
+
expect( klass.entity_class ).to eq ActiveRecordCrudSpec::FavoriteEntity
|
62
|
+
end
|
63
|
+
|
64
|
+
it "defines a model_class" do
|
65
|
+
expect( klass.model_class ).to eq ActiveRecordSpec::Favorite
|
66
|
+
end
|
67
|
+
|
68
|
+
it "defines a build_entity method" do
|
69
|
+
expect( klass.new.respond_to?( :build_entity, true ) ).to be_truthy
|
70
|
+
end
|
71
|
+
|
72
|
+
Shamu::Services::ActiveRecordCrud::DSL_METHODS.each do |method|
|
73
|
+
it "defines standard DSL method `#{ method }` when passed via `:methods`" do
|
74
|
+
expect( klass ).to receive( method )
|
75
|
+
klass.resource( ActiveRecordCrudSpec::FavoriteEntity, ActiveRecordSpec::Favorite, methods: method )
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
it "takes a block defining #build_entity" do
|
80
|
+
expect do |b|
|
81
|
+
yield_klass = Class.new( klass ) do
|
82
|
+
resource( ActiveRecordCrudSpec::FavoriteEntity, ActiveRecordSpec::Favorite, &b )
|
83
|
+
end
|
84
|
+
|
85
|
+
scorpion.new( yield_klass ).create
|
86
|
+
end.to yield_control
|
87
|
+
end
|
88
|
+
|
89
|
+
context "when not used" do
|
90
|
+
let( :klass ) do
|
91
|
+
Class.new( Shamu::Services::Service ) do
|
92
|
+
include Shamu::Services::ActiveRecordCrud
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
it "raises helpful error on entity_class" do
|
97
|
+
expect do
|
98
|
+
klass.entity_class
|
99
|
+
end.to raise_error Shamu::Services::IncompleteSetupError
|
100
|
+
end
|
101
|
+
|
102
|
+
it "raises helpful error on model_class" do
|
103
|
+
expect do
|
104
|
+
klass.model_class
|
105
|
+
end.to raise_error Shamu::Services::IncompleteSetupError
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe ".create" do
|
111
|
+
let( :request ) { ActiveRecordCrudSpec::Request::Create.new( name: "Example", label: "Books" ) }
|
112
|
+
|
113
|
+
it "calls Model.new" do
|
114
|
+
expect( ActiveRecordSpec::Favorite ).to receive( :new ).and_call_original
|
115
|
+
|
116
|
+
service.create request
|
117
|
+
end
|
118
|
+
|
119
|
+
it "calls request.apply_to" do
|
120
|
+
expect( request ).to receive( :apply_to ).and_call_original
|
121
|
+
service.create request
|
122
|
+
end
|
123
|
+
|
124
|
+
it "calls apply_changes if present" do
|
125
|
+
expect( service ).to receive( :apply_changes )
|
126
|
+
.with(
|
127
|
+
request,
|
128
|
+
kind_of( ActiveRecord::Base )
|
129
|
+
)
|
130
|
+
service.create( request )
|
131
|
+
end
|
132
|
+
|
133
|
+
it "returns a Result" do
|
134
|
+
expect( service.create( request ) ).to be_a Shamu::Services::Result
|
135
|
+
end
|
136
|
+
|
137
|
+
it "applies request to entity" do
|
138
|
+
entity = service.create( request ).entity
|
139
|
+
|
140
|
+
expect( entity.name ).to eq "Example"
|
141
|
+
expect( entity.label ).to eq "Books"
|
142
|
+
end
|
143
|
+
|
144
|
+
it "yields if block given" do
|
145
|
+
expect do |b|
|
146
|
+
yield_klass = Class.new( klass ) do
|
147
|
+
create( &b )
|
148
|
+
end
|
149
|
+
|
150
|
+
scorpion.new( yield_klass ).create( request )
|
151
|
+
end.to yield_with_args(
|
152
|
+
request,
|
153
|
+
kind_of( ActiveRecord::Base )
|
154
|
+
)
|
155
|
+
end
|
156
|
+
|
157
|
+
it "does not call apply_changes if block given" do
|
158
|
+
yield_klass = Class.new( klass ) do
|
159
|
+
create { |_, _| }
|
160
|
+
end
|
161
|
+
|
162
|
+
service = scorpion.new( yield_klass )
|
163
|
+
expect( service ).not_to receive :apply_changes
|
164
|
+
service.create
|
165
|
+
end
|
166
|
+
|
167
|
+
it "calls #authorize!" do
|
168
|
+
expect( service ).to receive( :authorize! ).with(
|
169
|
+
:create,
|
170
|
+
ActiveRecordCrudSpec::FavoriteEntity,
|
171
|
+
kind_of( ActiveRecordCrudSpec::Request::Create )
|
172
|
+
)
|
173
|
+
|
174
|
+
service.create
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
describe ".change" do
|
179
|
+
let( :request ) { ActiveRecordCrudSpec::Request::Update.new( name: "Updated Example" ) }
|
180
|
+
let( :entity ) { service.create( name: "Example", label: "Books" ).entity }
|
181
|
+
|
182
|
+
it "calls Model.find" do
|
183
|
+
expect( ActiveRecordSpec::Favorite ).to receive( :find ).with( entity.id ).and_call_original
|
184
|
+
service.update entity.id, request
|
185
|
+
end
|
186
|
+
|
187
|
+
it "calls request.apply_to" do
|
188
|
+
expect( request ).to receive( :apply_to ).and_call_original
|
189
|
+
service.update entity, request
|
190
|
+
end
|
191
|
+
|
192
|
+
it "calls apply_changes if present" do
|
193
|
+
expect( service ).to receive( :apply_changes )
|
194
|
+
.with(
|
195
|
+
kind_of( Shamu::Services::Request ),
|
196
|
+
kind_of( ::ActiveRecord::Base )
|
197
|
+
)
|
198
|
+
service.create( request )
|
199
|
+
end
|
200
|
+
|
201
|
+
it "yields if block given" do
|
202
|
+
entity = service.create.entity
|
203
|
+
|
204
|
+
expect do |b|
|
205
|
+
yield_klass = Class.new( klass ) do
|
206
|
+
change( :update, &b )
|
207
|
+
end
|
208
|
+
|
209
|
+
scorpion.new( yield_klass ).update entity.id, request
|
210
|
+
end.to yield_with_args( request, kind_of( ::ActiveRecord::Base ) )
|
211
|
+
end
|
212
|
+
|
213
|
+
it "does not call apply_changes if block given" do
|
214
|
+
entity = service.create.entity
|
215
|
+
|
216
|
+
yield_klass = Class.new( klass ) do
|
217
|
+
change( :update ) { |_, _| }
|
218
|
+
end
|
219
|
+
|
220
|
+
service = scorpion.new( yield_klass )
|
221
|
+
expect( service ).not_to receive :apply_changes
|
222
|
+
service.update entity.id
|
223
|
+
end
|
224
|
+
|
225
|
+
it "calls #authorize!" do
|
226
|
+
expect( service ).to receive( :authorize! ).with(
|
227
|
+
:update,
|
228
|
+
kind_of( ActiveRecordCrudSpec::FavoriteEntity ),
|
229
|
+
kind_of( ActiveRecordCrudSpec::Request::Update )
|
230
|
+
)
|
231
|
+
|
232
|
+
service.update entity
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
describe ".apply_changes" do
|
237
|
+
it "defines an apply_changes method from the block" do
|
238
|
+
klass = Class.new( Shamu::Services::Service ) do
|
239
|
+
include Shamu::Services::ActiveRecordCrud
|
240
|
+
|
241
|
+
apply_changes do |record, request|
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
expect( klass.new.respond_to?( :apply_changes, true ) ).to be_truthy
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
describe ".finders" do
|
250
|
+
it "builds #lookup" do
|
251
|
+
expect( service ).to respond_to :lookup
|
252
|
+
end
|
253
|
+
|
254
|
+
it "builds #find" do
|
255
|
+
expect( service ).to respond_to :find
|
256
|
+
end
|
257
|
+
|
258
|
+
it "builds #list" do
|
259
|
+
expect( service ).to respond_to :list
|
260
|
+
end
|
261
|
+
|
262
|
+
context "filtered" do
|
263
|
+
let( :klass ) do
|
264
|
+
Class.new( Shamu::Services::Service ) do
|
265
|
+
include Shamu::Services::ActiveRecordCrud
|
266
|
+
resource ActiveRecordCrudSpec::FavoriteEntity, ActiveRecordSpec::Favorite
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
it "excludes unwanted methods" do
|
271
|
+
klass.finders except: :list
|
272
|
+
|
273
|
+
expect( klass.new ).to respond_to :find
|
274
|
+
expect( klass.new ).to respond_to :lookup
|
275
|
+
expect( klass.new ).not_to respond_to :list
|
276
|
+
end
|
277
|
+
|
278
|
+
it "includes only specific methods" do
|
279
|
+
klass.finders only: :list
|
280
|
+
|
281
|
+
expect( klass.new ).not_to respond_to :find
|
282
|
+
expect( klass.new ).not_to respond_to :lookup
|
283
|
+
expect( klass.new ).to respond_to :list
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
describe ".find" do
|
289
|
+
let( :entity ) { service.create( name: "Example", label: "Books" ).entity }
|
290
|
+
|
291
|
+
it "calls lookup if no block given" do
|
292
|
+
expect( service ).to receive( :lookup ).and_return( [entity] )
|
293
|
+
service.find( 1 )
|
294
|
+
end
|
295
|
+
|
296
|
+
it "yields to block if block given" do
|
297
|
+
find_klass = Class.new( klass )
|
298
|
+
expect do |b|
|
299
|
+
find_klass.find( &b )
|
300
|
+
scorpion.new( find_klass ).find( entity.id )
|
301
|
+
end.to yield_control
|
302
|
+
end
|
303
|
+
|
304
|
+
it "calls #authorize!" do
|
305
|
+
expect( service ).to receive( :authorize! ).with(
|
306
|
+
:read,
|
307
|
+
kind_of( ActiveRecordCrudSpec::FavoriteEntity )
|
308
|
+
)
|
309
|
+
|
310
|
+
service.find entity.id
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
describe ".lookup" do
|
315
|
+
let( :entity ) { service.create( name: "Example", label: "Books" ).entity }
|
316
|
+
|
317
|
+
it "uses cached_lookup" do
|
318
|
+
expect( service ).to receive( :cached_lookup ).and_call_original
|
319
|
+
service.lookup( entity.id )
|
320
|
+
end
|
321
|
+
|
322
|
+
it "uses entity_lookup_list" do
|
323
|
+
expect( service ).to receive( :entity_lookup_list ).and_call_original
|
324
|
+
service.lookup( entity.id )
|
325
|
+
end
|
326
|
+
|
327
|
+
it "returns a list of entities" do
|
328
|
+
list = service.lookup( entity.id )
|
329
|
+
expect( list ).to be_a Shamu::Entities::List
|
330
|
+
expect( list.size ).to eq 1
|
331
|
+
expect( list.first ).to eq entity
|
332
|
+
end
|
333
|
+
|
334
|
+
it "returns NullEntitys for missing ids" do
|
335
|
+
list = service.lookup( entity.id + 1 )
|
336
|
+
expect( list.first ).to be_a Shamu::Entities::NullEntity
|
337
|
+
end
|
338
|
+
|
339
|
+
it "yields to block if given?" do
|
340
|
+
expect do |b|
|
341
|
+
yield_klass = Class.new( klass ) do
|
342
|
+
lookup( &b )
|
343
|
+
end
|
344
|
+
|
345
|
+
scorpion.new( yield_klass ).lookup entity.id
|
346
|
+
end.to yield_control
|
347
|
+
end
|
348
|
+
|
349
|
+
it "calls #authorize!" do
|
350
|
+
expect( service ).to receive( :authorize! ).with(
|
351
|
+
:read,
|
352
|
+
kind_of( ActiveRecordCrudSpec::FavoriteEntity )
|
353
|
+
)
|
354
|
+
|
355
|
+
service.lookup entity.id
|
356
|
+
end
|
357
|
+
|
358
|
+
it "calls #authorize_relation" do
|
359
|
+
expect( service ).to receive( :authorize_relation ).with(
|
360
|
+
:read,
|
361
|
+
kind_of( ActiveRecord::Relation )
|
362
|
+
)
|
363
|
+
|
364
|
+
service.lookup entity.id
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
describe ".list" do
|
369
|
+
let!( :entity ) { service.create( name: "Example", label: "Books" ).entity }
|
370
|
+
|
371
|
+
it "returns all the entities" do
|
372
|
+
list = service.list
|
373
|
+
expect( list ).to be_a Shamu::Entities::List
|
374
|
+
expect( list.size ).to eq 1
|
375
|
+
expect( list.first ).to eq entity
|
376
|
+
end
|
377
|
+
|
378
|
+
it "yields if block given" do
|
379
|
+
expect do |b|
|
380
|
+
yield_klass = Class.new( klass ) do
|
381
|
+
list( &b )
|
382
|
+
end
|
383
|
+
|
384
|
+
scorpion.new( yield_klass ).list
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
it "calls #authorize! for each entity" do
|
389
|
+
expect( service ).to receive( :authorize! ).with(
|
390
|
+
:read,
|
391
|
+
kind_of( ActiveRecordCrudSpec::FavoriteEntity )
|
392
|
+
)
|
393
|
+
|
394
|
+
service.list.to_a
|
395
|
+
end
|
396
|
+
|
397
|
+
it "calls #authorize! to list" do
|
398
|
+
expect( service ).to receive( :authorize! ).with(
|
399
|
+
:list,
|
400
|
+
ActiveRecordCrudSpec::FavoriteEntity,
|
401
|
+
kind_of( ActiveRecordCrudSpec::FavoriteListScope )
|
402
|
+
)
|
403
|
+
|
404
|
+
service.list
|
405
|
+
end
|
406
|
+
|
407
|
+
it "calls #authorize_relation" do
|
408
|
+
expect( service ).to receive( :authorize_relation ).with(
|
409
|
+
:read,
|
410
|
+
kind_of( ActiveRecord::Relation ),
|
411
|
+
kind_of( ActiveRecordCrudSpec::FavoriteListScope )
|
412
|
+
)
|
413
|
+
|
414
|
+
service.list
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
describe ".destroy" do
|
419
|
+
let!( :entity ) { service.create( name: "Example", label: "Books" ).entity }
|
420
|
+
|
421
|
+
it "destroys the record" do
|
422
|
+
expect do
|
423
|
+
service.destroy entity
|
424
|
+
end.to change( ActiveRecordSpec::Favorite, :count ).by( -1 )
|
425
|
+
end
|
426
|
+
|
427
|
+
it "calls #authorize!" do
|
428
|
+
expect( service ).to receive( :authorize! ).with(
|
429
|
+
:destroy,
|
430
|
+
kind_of( ActiveRecordCrudSpec::FavoriteEntity )
|
431
|
+
)
|
432
|
+
|
433
|
+
service.destroy entity.id
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
437
|
+
describe ".build_entity" do
|
438
|
+
let!( :entity ) { service.create( name: "Example", label: "Books" ).entity }
|
439
|
+
let( :entity_class ) do
|
440
|
+
Class.new( Shamu::Entities::Entity ) do
|
441
|
+
attribute :id
|
442
|
+
end
|
443
|
+
end
|
444
|
+
let( :klass ) do
|
445
|
+
ec = entity_class
|
446
|
+
Class.new( super() ) do
|
447
|
+
build_entity do |record, _ = nil|
|
448
|
+
scorpion.fetch ec, { record: record }, {}
|
449
|
+
end
|
450
|
+
public :build_entity
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
454
|
+
it "builds an entity from the model record defined by .resource" do
|
455
|
+
entity = service.build_entity( ActiveRecordSpec::Favorite.first )
|
456
|
+
expect( entity ).to be_a entity_class
|
457
|
+
end
|
458
|
+
|
459
|
+
end
|
460
|
+
end
|