audited 4.7.0 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of audited might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/.gitignore +0 -1
- data/.standard.yml +5 -0
- data/.travis.yml +35 -26
- data/Appraisals +27 -18
- data/CHANGELOG.md +106 -2
- data/Gemfile +1 -1
- data/README.md +88 -19
- data/Rakefile +6 -6
- data/gemfiles/rails50.gemfile +3 -0
- data/gemfiles/rails51.gemfile +3 -0
- data/gemfiles/rails52.gemfile +4 -2
- data/gemfiles/rails60.gemfile +10 -0
- data/gemfiles/rails61.gemfile +10 -0
- data/lib/audited-rspec.rb +3 -1
- data/lib/audited.rb +26 -8
- data/lib/audited/audit.rb +48 -43
- data/lib/audited/auditor.rb +135 -56
- data/lib/audited/railtie.rb +16 -0
- data/lib/audited/rspec_matchers.rb +5 -3
- data/lib/audited/sweeper.rb +3 -10
- data/lib/audited/version.rb +3 -1
- data/lib/generators/audited/install_generator.rb +9 -7
- data/lib/generators/audited/migration.rb +2 -0
- data/lib/generators/audited/migration_helper.rb +3 -1
- data/lib/generators/audited/templates/add_association_to_audits.rb +2 -0
- data/lib/generators/audited/templates/add_comment_to_audits.rb +2 -0
- data/lib/generators/audited/templates/add_remote_address_to_audits.rb +2 -0
- data/lib/generators/audited/templates/add_request_uuid_to_audits.rb +2 -0
- data/lib/generators/audited/templates/add_version_to_auditable_index.rb +23 -0
- data/lib/generators/audited/templates/install.rb +3 -1
- data/lib/generators/audited/templates/rename_association_to_associated.rb +2 -0
- data/lib/generators/audited/templates/rename_changes_to_audited_changes.rb +2 -0
- data/lib/generators/audited/templates/rename_parent_to_association.rb +2 -0
- data/lib/generators/audited/templates/revert_polymorphic_indexes_order.rb +2 -0
- data/lib/generators/audited/upgrade_generator.rb +20 -14
- data/spec/audited/audit_spec.rb +151 -62
- data/spec/audited/auditor_spec.rb +456 -239
- data/spec/audited/sweeper_spec.rb +29 -20
- data/spec/audited_spec.rb +18 -0
- data/spec/audited_spec_helpers.rb +7 -7
- data/spec/rails_app/app/assets/config/manifest.js +2 -0
- data/spec/rails_app/config/application.rb +7 -2
- data/spec/rails_app/config/database.yml +1 -0
- data/spec/rails_app/config/environment.rb +1 -1
- data/spec/rails_app/config/environments/test.rb +5 -5
- data/spec/rails_app/config/initializers/secret_token.rb +2 -2
- data/spec/spec_helper.rb +15 -13
- data/spec/support/active_record/models.rb +37 -11
- data/spec/support/active_record/postgres/1_change_audited_changes_type_to_json.rb +1 -2
- data/spec/support/active_record/postgres/2_change_audited_changes_type_to_jsonb.rb +1 -2
- data/spec/support/active_record/schema.rb +28 -20
- data/test/db/version_1.rb +2 -2
- data/test/db/version_2.rb +2 -2
- data/test/db/version_3.rb +2 -3
- data/test/db/version_4.rb +2 -3
- data/test/db/version_5.rb +0 -1
- data/test/db/version_6.rb +2 -0
- data/test/install_generator_test.rb +18 -19
- data/test/test_helper.rb +6 -7
- data/test/upgrade_generator_test.rb +22 -17
- metadata +64 -29
- data/gemfiles/rails40.gemfile +0 -9
- data/gemfiles/rails41.gemfile +0 -8
- data/gemfiles/rails42.gemfile +0 -8
- data/spec/rails_app/config/environments/development.rb +0 -21
- data/spec/rails_app/config/environments/production.rb +0 -35
@@ -1,17 +1,79 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
|
3
|
+
SingleCov.covered! uncovered: 9 # not testing proxy_respond_to? hack / 2 methods / deprecation of `version`
|
4
|
+
|
5
|
+
class ConditionalPrivateCompany < ::ActiveRecord::Base
|
6
|
+
self.table_name = "companies"
|
7
|
+
|
8
|
+
audited if: :foo?
|
9
|
+
|
10
|
+
private def foo?
|
11
|
+
true
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class ConditionalCompany < ::ActiveRecord::Base
|
16
|
+
self.table_name = "companies"
|
17
|
+
|
18
|
+
audited if: :public?
|
19
|
+
|
20
|
+
def public?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class ExclusiveCompany < ::ActiveRecord::Base
|
25
|
+
self.table_name = "companies"
|
26
|
+
audited if: proc { false }
|
27
|
+
end
|
28
|
+
|
29
|
+
class ExclusionaryCompany < ::ActiveRecord::Base
|
30
|
+
self.table_name = "companies"
|
31
|
+
|
32
|
+
audited unless: :non_profit?
|
33
|
+
|
34
|
+
def non_profit?
|
35
|
+
end
|
36
|
+
end
|
4
37
|
|
38
|
+
class ExclusionaryCompany2 < ::ActiveRecord::Base
|
39
|
+
self.table_name = "companies"
|
40
|
+
audited unless: proc { |c| c.exclusive? }
|
41
|
+
|
42
|
+
def exclusive?
|
43
|
+
true
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class InclusiveCompany < ::ActiveRecord::Base
|
48
|
+
self.table_name = "companies"
|
49
|
+
audited if: proc { true }
|
50
|
+
end
|
51
|
+
|
52
|
+
class InclusiveCompany2 < ::ActiveRecord::Base
|
53
|
+
self.table_name = "companies"
|
54
|
+
audited unless: proc { false }
|
55
|
+
end
|
56
|
+
|
57
|
+
class Secret < ::ActiveRecord::Base
|
58
|
+
audited
|
59
|
+
end
|
60
|
+
|
61
|
+
class Secret2 < ::ActiveRecord::Base
|
62
|
+
audited
|
63
|
+
self.non_audited_columns = ["delta", "top_secret", "created_at"]
|
64
|
+
end
|
65
|
+
|
66
|
+
describe Audited::Auditor do
|
5
67
|
describe "configuration" do
|
6
68
|
it "should include instance methods" do
|
7
|
-
expect(Models::ActiveRecord::User.new).to be_a_kind_of(
|
69
|
+
expect(Models::ActiveRecord::User.new).to be_a_kind_of(Audited::Auditor::AuditedInstanceMethods)
|
8
70
|
end
|
9
71
|
|
10
72
|
it "should include class methods" do
|
11
|
-
expect(Models::ActiveRecord::User).to be_a_kind_of(
|
73
|
+
expect(Models::ActiveRecord::User).to be_a_kind_of(Audited::Auditor::AuditedClassMethods)
|
12
74
|
end
|
13
75
|
|
14
|
-
[
|
76
|
+
["created_at", "updated_at", "created_on", "updated_on", "lock_version", "id", "password"].each do |column|
|
15
77
|
it "should not audit #{column}" do
|
16
78
|
expect(Models::ActiveRecord::User.non_audited_columns).to include(column)
|
17
79
|
end
|
@@ -20,49 +82,32 @@ describe Audited::Auditor do
|
|
20
82
|
context "should be configurable which conditions are audited" do
|
21
83
|
subject { ConditionalCompany.new.send(:auditing_enabled) }
|
22
84
|
|
23
|
-
context "when
|
24
|
-
|
25
|
-
class ConditionalCompany < ::ActiveRecord::Base
|
26
|
-
self.table_name = 'companies'
|
27
|
-
|
28
|
-
audited if: :public?
|
85
|
+
context "when condition method is private" do
|
86
|
+
subject { ConditionalPrivateCompany.new.send(:auditing_enabled) }
|
29
87
|
|
30
|
-
|
31
|
-
|
32
|
-
end
|
88
|
+
it { is_expected.to be_truthy }
|
89
|
+
end
|
33
90
|
|
91
|
+
context "when passing a method name" do
|
34
92
|
context "when conditions are true" do
|
35
93
|
before { allow_any_instance_of(ConditionalCompany).to receive(:public?).and_return(true) }
|
36
|
-
it
|
94
|
+
it { is_expected.to be_truthy }
|
37
95
|
end
|
38
96
|
|
39
97
|
context "when conditions are false" do
|
40
98
|
before { allow_any_instance_of(ConditionalCompany).to receive(:public?).and_return(false) }
|
41
|
-
it
|
99
|
+
it { is_expected.to be_falsey }
|
42
100
|
end
|
43
101
|
end
|
44
102
|
|
45
103
|
context "when passing a Proc" do
|
46
104
|
context "when conditions are true" do
|
47
|
-
before do
|
48
|
-
class InclusiveCompany < ::ActiveRecord::Base
|
49
|
-
self.table_name = 'companies'
|
50
|
-
audited if: Proc.new { true }
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
105
|
subject { InclusiveCompany.new.send(:auditing_enabled) }
|
55
106
|
|
56
107
|
it { is_expected.to be_truthy }
|
57
108
|
end
|
58
109
|
|
59
110
|
context "when conditions are false" do
|
60
|
-
before do
|
61
|
-
class ExclusiveCompany < ::ActiveRecord::Base
|
62
|
-
self.table_name = 'companies'
|
63
|
-
audited if: Proc.new { false }
|
64
|
-
end
|
65
|
-
end
|
66
111
|
subject { ExclusiveCompany.new.send(:auditing_enabled) }
|
67
112
|
it { is_expected.to be_falsey }
|
68
113
|
end
|
@@ -71,76 +116,40 @@ describe Audited::Auditor do
|
|
71
116
|
|
72
117
|
context "should be configurable which conditions aren't audited" do
|
73
118
|
context "when using a method name" do
|
74
|
-
before do
|
75
|
-
class ExclusionaryCompany < ::ActiveRecord::Base
|
76
|
-
self.table_name = 'companies'
|
77
|
-
|
78
|
-
audited unless: :non_profit?
|
79
|
-
|
80
|
-
def non_profit?; end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
119
|
subject { ExclusionaryCompany.new.send(:auditing_enabled) }
|
85
120
|
|
86
121
|
context "when conditions are true" do
|
87
122
|
before { allow_any_instance_of(ExclusionaryCompany).to receive(:non_profit?).and_return(true) }
|
88
|
-
it
|
123
|
+
it { is_expected.to be_falsey }
|
89
124
|
end
|
90
125
|
|
91
126
|
context "when conditions are false" do
|
92
127
|
before { allow_any_instance_of(ExclusionaryCompany).to receive(:non_profit?).and_return(false) }
|
93
|
-
it
|
128
|
+
it { is_expected.to be_truthy }
|
94
129
|
end
|
95
130
|
end
|
96
131
|
|
97
132
|
context "when using a proc" do
|
98
133
|
context "when conditions are true" do
|
99
|
-
|
100
|
-
|
101
|
-
self.table_name = 'companies'
|
102
|
-
audited unless: Proc.new { |c| c.exclusive? }
|
103
|
-
|
104
|
-
def exclusive?
|
105
|
-
true
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
subject { ExclusionaryCompany.new.send(:auditing_enabled) }
|
111
|
-
it { is_expected.to be_falsey }
|
134
|
+
subject { ExclusionaryCompany2.new.send(:auditing_enabled) }
|
135
|
+
it { is_expected.to be_falsey }
|
112
136
|
end
|
113
137
|
|
114
138
|
context "when conditions are false" do
|
115
|
-
|
116
|
-
|
117
|
-
self.table_name = 'companies'
|
118
|
-
audited unless: Proc.new { false }
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
subject { InclusiveCompany.new.send(:auditing_enabled) }
|
123
|
-
it { is_expected.to be_truthy }
|
139
|
+
subject { InclusiveCompany2.new.send(:auditing_enabled) }
|
140
|
+
it { is_expected.to be_truthy }
|
124
141
|
end
|
125
142
|
end
|
126
143
|
end
|
127
144
|
|
128
145
|
it "should be configurable which attributes are not audited via ignored_attributes" do
|
129
|
-
Audited.ignored_attributes = [
|
130
|
-
class Secret < ::ActiveRecord::Base
|
131
|
-
audited
|
132
|
-
end
|
146
|
+
Audited.ignored_attributes = ["delta", "top_secret", "created_at"]
|
133
147
|
|
134
|
-
expect(Secret.non_audited_columns).to include(
|
148
|
+
expect(Secret.non_audited_columns).to include("delta", "top_secret", "created_at")
|
135
149
|
end
|
136
150
|
|
137
151
|
it "should be configurable which attributes are not audited via non_audited_columns=" do
|
138
|
-
|
139
|
-
audited
|
140
|
-
self.non_audited_columns = ['delta', 'top_secret', 'created_at']
|
141
|
-
end
|
142
|
-
|
143
|
-
expect(Secret2.non_audited_columns).to include('delta', 'top_secret', 'created_at')
|
152
|
+
expect(Secret2.non_audited_columns).to include("delta", "top_secret", "created_at")
|
144
153
|
end
|
145
154
|
|
146
155
|
it "should not save non-audited columns" do
|
@@ -148,7 +157,7 @@ describe Audited::Auditor do
|
|
148
157
|
begin
|
149
158
|
Models::ActiveRecord::User.non_audited_columns += [:favourite_device]
|
150
159
|
|
151
|
-
expect(create_user.audits.first.audited_changes.keys.any? { |col| [
|
160
|
+
expect(create_user.audits.first.audited_changes.keys.any? { |col| ["favourite_device", "created_at", "updated_at", "password"].include?(col) }).to eq(false)
|
152
161
|
ensure
|
153
162
|
Models::ActiveRecord::User.non_audited_columns = previous
|
154
163
|
end
|
@@ -170,7 +179,7 @@ describe Audited::Auditor do
|
|
170
179
|
user.password = "password"
|
171
180
|
user.non_column_attr = "some value"
|
172
181
|
user.save!
|
173
|
-
expect(user.audits.last.audited_changes.keys).to eq(%w
|
182
|
+
expect(user.audits.last.audited_changes.keys).to eq(%w[password])
|
174
183
|
end
|
175
184
|
|
176
185
|
it "should save attributes not specified in 'except' option" do
|
@@ -189,10 +198,43 @@ describe Audited::Auditor do
|
|
189
198
|
user.password = "password"
|
190
199
|
user.non_column_attr = "some value"
|
191
200
|
user.save!
|
192
|
-
expect(user.audits.last.audited_changes.keys).to eq(%w
|
201
|
+
expect(user.audits.last.audited_changes.keys).to eq(%w[non_column_attr])
|
193
202
|
end
|
194
203
|
|
195
|
-
|
204
|
+
it "should redact columns specified in 'redacted' option" do
|
205
|
+
redacted = Audited::Auditor::AuditedInstanceMethods::REDACTED
|
206
|
+
user = Models::ActiveRecord::UserRedactedPassword.create(password: "password")
|
207
|
+
user.save!
|
208
|
+
expect(user.audits.last.audited_changes["password"]).to eq(redacted)
|
209
|
+
user.password = "new_password"
|
210
|
+
user.save!
|
211
|
+
expect(user.audits.last.audited_changes["password"]).to eq([redacted, redacted])
|
212
|
+
end
|
213
|
+
|
214
|
+
it "should redact columns specified in 'redacted' option when there are multiple specified" do
|
215
|
+
redacted = Audited::Auditor::AuditedInstanceMethods::REDACTED
|
216
|
+
user =
|
217
|
+
Models::ActiveRecord::UserMultipleRedactedAttributes.create(
|
218
|
+
password: "password",
|
219
|
+
ssn: 123456789
|
220
|
+
)
|
221
|
+
user.save!
|
222
|
+
expect(user.audits.last.audited_changes["password"]).to eq(redacted)
|
223
|
+
expect(user.audits.last.audited_changes["ssn"]).to eq(redacted)
|
224
|
+
user.password = "new_password"
|
225
|
+
user.ssn = 987654321
|
226
|
+
user.save!
|
227
|
+
expect(user.audits.last.audited_changes["password"]).to eq([redacted, redacted])
|
228
|
+
expect(user.audits.last.audited_changes["ssn"]).to eq([redacted, redacted])
|
229
|
+
end
|
230
|
+
|
231
|
+
it "should redact columns in 'redacted' column with custom option" do
|
232
|
+
user = Models::ActiveRecord::UserRedactedPasswordCustomRedaction.create(password: "password")
|
233
|
+
user.save!
|
234
|
+
expect(user.audits.last.audited_changes["password"]).to eq(["My", "Custom", "Value", 7])
|
235
|
+
end
|
236
|
+
|
237
|
+
if ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
|
196
238
|
describe "'json' and 'jsonb' audited_changes column type" do
|
197
239
|
let(:migrations_path) { SPEC_ROOT.join("support/active_record/postgres") }
|
198
240
|
|
@@ -229,16 +271,16 @@ describe Audited::Auditor do
|
|
229
271
|
it "should allow mass assignment of all unprotected attributes" do
|
230
272
|
yesterday = 1.day.ago
|
231
273
|
|
232
|
-
u = Models::ActiveRecord::NoAttributeProtectionUser.new(name:
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
274
|
+
u = Models::ActiveRecord::NoAttributeProtectionUser.new(name: "name",
|
275
|
+
username: "username",
|
276
|
+
password: "password",
|
277
|
+
activated: true,
|
278
|
+
suspended_at: yesterday,
|
279
|
+
logins: 2)
|
238
280
|
|
239
|
-
expect(u.name).to eq(
|
240
|
-
expect(u.username).to eq(
|
241
|
-
expect(u.password).to eq(
|
281
|
+
expect(u.name).to eq("name")
|
282
|
+
expect(u.username).to eq("username")
|
283
|
+
expect(u.password).to eq("password")
|
242
284
|
expect(u.activated).to eq(true)
|
243
285
|
expect(u.suspended_at.to_i).to eq(yesterday.to_i)
|
244
286
|
expect(u.logins).to eq(2)
|
@@ -246,12 +288,12 @@ describe Audited::Auditor do
|
|
246
288
|
end
|
247
289
|
|
248
290
|
describe "on create" do
|
249
|
-
let(
|
291
|
+
let(:user) { create_user status: :reliable, audit_comment: "Create" }
|
250
292
|
|
251
293
|
it "should change the audit count" do
|
252
294
|
expect {
|
253
295
|
user
|
254
|
-
}.to change(
|
296
|
+
}.to change(Audited::Audit, :count).by(1)
|
255
297
|
end
|
256
298
|
|
257
299
|
it "should create associated audit" do
|
@@ -259,7 +301,7 @@ describe Audited::Auditor do
|
|
259
301
|
end
|
260
302
|
|
261
303
|
it "should set the action to create" do
|
262
|
-
expect(user.audits.first.action).to eq(
|
304
|
+
expect(user.audits.first.action).to eq("create")
|
263
305
|
expect(Audited::Audit.creates.order(:id).last).to eq(user.audits.first)
|
264
306
|
expect(user.audits.creates.count).to eq(1)
|
265
307
|
expect(user.audits.updates.count).to eq(0)
|
@@ -270,91 +312,109 @@ describe Audited::Auditor do
|
|
270
312
|
expect(user.audits.first.audited_changes).to eq(user.audited_attributes)
|
271
313
|
end
|
272
314
|
|
315
|
+
it "should store enum value" do
|
316
|
+
expect(user.audits.first.audited_changes["status"]).to eq(1)
|
317
|
+
end
|
318
|
+
|
319
|
+
context "when store_synthesized_enums is set to true" do
|
320
|
+
before { Audited.store_synthesized_enums = true }
|
321
|
+
after { Audited.store_synthesized_enums = false }
|
322
|
+
|
323
|
+
it "should store enum value as Rails synthesized value" do
|
324
|
+
expect(user.audits.first.audited_changes["status"]).to eq("reliable")
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
273
328
|
it "should store comment" do
|
274
|
-
expect(user.audits.first.comment).to eq(
|
329
|
+
expect(user.audits.first.comment).to eq("Create")
|
275
330
|
end
|
276
331
|
|
277
332
|
it "should not audit an attribute which is excepted if specified on create or destroy" do
|
278
|
-
on_create_destroy_except_name = Models::ActiveRecord::OnCreateDestroyExceptName.create(name:
|
279
|
-
expect(on_create_destroy_except_name.audits.first.audited_changes.keys.any?{|col| [
|
333
|
+
on_create_destroy_except_name = Models::ActiveRecord::OnCreateDestroyExceptName.create(name: "Bart")
|
334
|
+
expect(on_create_destroy_except_name.audits.first.audited_changes.keys.any? { |col| ["name"].include? col }).to eq(false)
|
280
335
|
end
|
281
336
|
|
282
337
|
it "should not save an audit if only specified on update/destroy" do
|
283
338
|
expect {
|
284
|
-
Models::ActiveRecord::OnUpdateDestroy.create!(
|
285
|
-
}.to_not change(
|
339
|
+
Models::ActiveRecord::OnUpdateDestroy.create!(name: "Bart")
|
340
|
+
}.to_not change(Audited::Audit, :count)
|
286
341
|
end
|
287
342
|
end
|
288
343
|
|
289
344
|
describe "on update" do
|
290
345
|
before do
|
291
|
-
@user = create_user(
|
346
|
+
@user = create_user(name: "Brandon", status: :active, audit_comment: "Update")
|
292
347
|
end
|
293
348
|
|
294
349
|
it "should save an audit" do
|
295
350
|
expect {
|
296
351
|
@user.update_attribute(:name, "Someone")
|
297
|
-
}.to change(
|
352
|
+
}.to change(Audited::Audit, :count).by(1)
|
298
353
|
expect {
|
299
354
|
@user.update_attribute(:name, "Someone else")
|
300
|
-
}.to change(
|
355
|
+
}.to change(Audited::Audit, :count).by(1)
|
301
356
|
end
|
302
357
|
|
303
358
|
it "should set the action to 'update'" do
|
304
|
-
@user.
|
305
|
-
expect(@user.audits.last.action).to eq(
|
359
|
+
@user.update! name: "Changed"
|
360
|
+
expect(@user.audits.last.action).to eq("update")
|
306
361
|
expect(Audited::Audit.updates.order(:id).last).to eq(@user.audits.last)
|
307
362
|
expect(@user.audits.updates.last).to eq(@user.audits.last)
|
308
363
|
end
|
309
364
|
|
310
365
|
it "should store the changed attributes" do
|
311
|
-
@user.
|
312
|
-
expect(@user.audits.last.audited_changes).to eq({
|
366
|
+
@user.update! name: "Changed"
|
367
|
+
expect(@user.audits.last.audited_changes).to eq({"name" => ["Brandon", "Changed"]})
|
368
|
+
end
|
369
|
+
|
370
|
+
it "should store changed enum values" do
|
371
|
+
@user.update! status: 1
|
372
|
+
expect(@user.audits.last.audited_changes["status"]).to eq([0, 1])
|
313
373
|
end
|
314
374
|
|
315
375
|
it "should store audit comment" do
|
316
|
-
expect(@user.audits.last.comment).to eq(
|
376
|
+
expect(@user.audits.last.comment).to eq("Update")
|
317
377
|
end
|
318
378
|
|
319
379
|
it "should not save an audit if only specified on create/destroy" do
|
320
|
-
on_create_destroy = Models::ActiveRecord::OnCreateDestroy.create(
|
380
|
+
on_create_destroy = Models::ActiveRecord::OnCreateDestroy.create(name: "Bart")
|
321
381
|
expect {
|
322
|
-
on_create_destroy.
|
323
|
-
}.to_not change(
|
382
|
+
on_create_destroy.update! name: "Changed"
|
383
|
+
}.to_not change(Audited::Audit, :count)
|
324
384
|
end
|
325
385
|
|
326
386
|
it "should not save an audit if the value doesn't change after type casting" do
|
327
|
-
@user.
|
328
|
-
expect { @user.update_attribute :logins,
|
329
|
-
expect { @user.update_attribute :activated, 1 }.to_not change(
|
330
|
-
expect { @user.update_attribute :activated,
|
387
|
+
@user.update! logins: 0, activated: true
|
388
|
+
expect { @user.update_attribute :logins, "0" }.to_not change(Audited::Audit, :count)
|
389
|
+
expect { @user.update_attribute :activated, 1 }.to_not change(Audited::Audit, :count)
|
390
|
+
expect { @user.update_attribute :activated, "1" }.to_not change(Audited::Audit, :count)
|
331
391
|
end
|
332
392
|
|
333
393
|
describe "with no dirty changes" do
|
334
394
|
it "does not create an audit if the record is not changed" do
|
335
395
|
expect {
|
336
396
|
@user.save!
|
337
|
-
}.to_not change(
|
397
|
+
}.to_not change(Audited::Audit, :count)
|
338
398
|
end
|
339
399
|
|
340
400
|
it "creates an audit when an audit comment is present" do
|
341
401
|
expect {
|
342
402
|
@user.audit_comment = "Comment"
|
343
403
|
@user.save!
|
344
|
-
}.to change(
|
404
|
+
}.to change(Audited::Audit, :count)
|
345
405
|
end
|
346
406
|
end
|
347
407
|
end
|
348
408
|
|
349
409
|
describe "on destroy" do
|
350
410
|
before do
|
351
|
-
@user = create_user
|
411
|
+
@user = create_user(status: :active)
|
352
412
|
end
|
353
413
|
|
354
414
|
it "should save an audit" do
|
355
415
|
expect {
|
356
416
|
@user.destroy
|
357
|
-
}.to change(
|
417
|
+
}.to change(Audited::Audit, :count)
|
358
418
|
|
359
419
|
expect(@user.audits.size).to eq(2)
|
360
420
|
end
|
@@ -362,7 +422,7 @@ describe Audited::Auditor do
|
|
362
422
|
it "should set the action to 'destroy'" do
|
363
423
|
@user.destroy
|
364
424
|
|
365
|
-
expect(@user.audits.last.action).to eq(
|
425
|
+
expect(@user.audits.last.action).to eq("destroy")
|
366
426
|
expect(Audited::Audit.destroys.order(:id).last).to eq(@user.audits.last)
|
367
427
|
expect(@user.audits.destroys.last).to eq(@user.audits.last)
|
368
428
|
end
|
@@ -373,6 +433,11 @@ describe Audited::Auditor do
|
|
373
433
|
expect(@user.audits.last.audited_changes).to eq(@user.audited_attributes)
|
374
434
|
end
|
375
435
|
|
436
|
+
it "should store enum value" do
|
437
|
+
@user.destroy
|
438
|
+
expect(@user.audits.last.audited_changes["status"]).to eq(0)
|
439
|
+
end
|
440
|
+
|
376
441
|
it "should be able to reconstruct a destroyed record without history" do
|
377
442
|
@user.audits.delete_all
|
378
443
|
@user.destroy
|
@@ -382,11 +447,11 @@ describe Audited::Auditor do
|
|
382
447
|
end
|
383
448
|
|
384
449
|
it "should not save an audit if only specified on create/update" do
|
385
|
-
on_create_update = Models::ActiveRecord::OnCreateUpdate.create!(
|
450
|
+
on_create_update = Models::ActiveRecord::OnCreateUpdate.create!(name: "Bart")
|
386
451
|
|
387
452
|
expect {
|
388
453
|
on_create_update.destroy
|
389
|
-
}.to_not change(
|
454
|
+
}.to_not change(Audited::Audit, :count)
|
390
455
|
end
|
391
456
|
|
392
457
|
it "should audit dependent destructions" do
|
@@ -395,9 +460,9 @@ describe Audited::Auditor do
|
|
395
460
|
|
396
461
|
expect {
|
397
462
|
owner.destroy
|
398
|
-
}.to change(
|
463
|
+
}.to change(Audited::Audit, :count)
|
399
464
|
|
400
|
-
expect(company.audits.map { |a| a.action }).to eq([
|
465
|
+
expect(company.audits.map { |a| a.action }).to eq(["create", "destroy"])
|
401
466
|
end
|
402
467
|
end
|
403
468
|
|
@@ -409,20 +474,20 @@ describe Audited::Auditor do
|
|
409
474
|
user.destroy
|
410
475
|
}.to_not raise_error
|
411
476
|
|
412
|
-
expect(
|
477
|
+
expect(user.audits).to be_empty
|
413
478
|
end
|
414
479
|
end
|
415
480
|
|
416
481
|
describe "associated with" do
|
417
|
-
let(:owner) { Models::ActiveRecord::Owner.create(name:
|
418
|
-
let(:owned_company) { Models::ActiveRecord::OwnedCompany.create!(name:
|
482
|
+
let(:owner) { Models::ActiveRecord::Owner.create(name: "Models::ActiveRecord::Owner") }
|
483
|
+
let(:owned_company) { Models::ActiveRecord::OwnedCompany.create!(name: "The auditors", owner: owner) }
|
419
484
|
|
420
485
|
it "should record the associated object on create" do
|
421
486
|
expect(owned_company.audits.first.associated).to eq(owner)
|
422
487
|
end
|
423
488
|
|
424
489
|
it "should store the associated object on update" do
|
425
|
-
owned_company.update_attribute(:name,
|
490
|
+
owned_company.update_attribute(:name, "The Auditors")
|
426
491
|
expect(owned_company.audits.last.associated).to eq(owner)
|
427
492
|
end
|
428
493
|
|
@@ -433,8 +498,8 @@ describe Audited::Auditor do
|
|
433
498
|
end
|
434
499
|
|
435
500
|
describe "has associated audits" do
|
436
|
-
let!(:owner) { Models::ActiveRecord::Owner.create!(name:
|
437
|
-
let!(:owned_company) { Models::ActiveRecord::OwnedCompany.create!(name:
|
501
|
+
let!(:owner) { Models::ActiveRecord::Owner.create!(name: "Models::ActiveRecord::Owner") }
|
502
|
+
let!(:owned_company) { Models::ActiveRecord::OwnedCompany.create!(name: "The auditors", owner: owner) }
|
438
503
|
|
439
504
|
it "should list the associated audits" do
|
440
505
|
expect(owner.associated_audits.length).to eq(1)
|
@@ -458,7 +523,7 @@ describe Audited::Auditor do
|
|
458
523
|
it "should delete old audits when keeped amount exceeded" do
|
459
524
|
stub_global_max_audits(2) do
|
460
525
|
user = create_versions(2)
|
461
|
-
user.update(name:
|
526
|
+
user.update(name: "John")
|
462
527
|
expect(user.audits.pluck(:version)).to eq([2, 3])
|
463
528
|
end
|
464
529
|
end
|
@@ -466,35 +531,35 @@ describe Audited::Auditor do
|
|
466
531
|
it "should not delete old audits when keeped amount not exceeded" do
|
467
532
|
stub_global_max_audits(3) do
|
468
533
|
user = create_versions(2)
|
469
|
-
user.update(name:
|
534
|
+
user.update(name: "John")
|
470
535
|
expect(user.audits.pluck(:version)).to eq([1, 2, 3])
|
471
536
|
end
|
472
537
|
end
|
473
538
|
|
474
539
|
it "should delete old extra audits after introducing limit" do
|
475
540
|
stub_global_max_audits(nil) do
|
476
|
-
user = Models::ActiveRecord::User.create!(name:
|
477
|
-
user.
|
478
|
-
user.
|
479
|
-
user.
|
541
|
+
user = Models::ActiveRecord::User.create!(name: "Brandon", username: "brandon")
|
542
|
+
user.update!(name: "Foobar")
|
543
|
+
user.update!(name: "Awesome", username: "keepers")
|
544
|
+
user.update!(activated: true)
|
480
545
|
|
481
546
|
Audited.max_audits = 3
|
482
547
|
Models::ActiveRecord::User.send(:normalize_audited_options)
|
483
|
-
user.
|
548
|
+
user.update!(favourite_device: "Android Phone")
|
484
549
|
audits = user.audits
|
485
550
|
|
486
551
|
expect(audits.count).to eq(3)
|
487
|
-
expect(audits[0].audited_changes).to include({
|
488
|
-
expect(audits[1].audited_changes).to eq({
|
489
|
-
expect(audits[2].audited_changes).to eq({
|
552
|
+
expect(audits[0].audited_changes).to include({"name" => ["Foobar", "Awesome"], "username" => ["brandon", "keepers"]})
|
553
|
+
expect(audits[1].audited_changes).to eq({"activated" => [nil, true]})
|
554
|
+
expect(audits[2].audited_changes).to eq({"favourite_device" => [nil, "Android Phone"]})
|
490
555
|
end
|
491
556
|
end
|
492
557
|
|
493
558
|
it "should add comment line for combined audit" do
|
494
559
|
stub_global_max_audits(2) do
|
495
|
-
user = Models::ActiveRecord::User.create!(name:
|
496
|
-
user.update(name:
|
497
|
-
user.update(name:
|
560
|
+
user = Models::ActiveRecord::User.create!(name: "Foobar 1")
|
561
|
+
user.update(name: "Foobar 2", audit_comment: "First audit comment")
|
562
|
+
user.update(name: "Foobar 3", audit_comment: "Second audit comment")
|
498
563
|
expect(user.audits.first.comment).to match(/First audit comment.+is the result of multiple/m)
|
499
564
|
end
|
500
565
|
end
|
@@ -514,10 +579,10 @@ describe Audited::Auditor do
|
|
514
579
|
end
|
515
580
|
|
516
581
|
describe "revisions" do
|
517
|
-
let(
|
582
|
+
let(:user) { create_versions }
|
518
583
|
|
519
584
|
it "should return an Array of Users" do
|
520
|
-
expect(user.revisions).to be_a_kind_of(
|
585
|
+
expect(user.revisions).to be_a_kind_of(Array)
|
521
586
|
user.revisions.each { |version| expect(version).to be_a_kind_of Models::ActiveRecord::User }
|
522
587
|
end
|
523
588
|
|
@@ -526,38 +591,38 @@ describe Audited::Auditor do
|
|
526
591
|
end
|
527
592
|
|
528
593
|
it "should have one revision for each audit" do
|
529
|
-
expect(user.audits.size).to eql(
|
594
|
+
expect(user.audits.size).to eql(user.revisions.size)
|
530
595
|
end
|
531
596
|
|
532
597
|
it "should set the attributes for each revision" do
|
533
|
-
u = Models::ActiveRecord::User.create(name:
|
534
|
-
u.
|
535
|
-
u.
|
598
|
+
u = Models::ActiveRecord::User.create(name: "Brandon", username: "brandon")
|
599
|
+
u.update! name: "Foobar"
|
600
|
+
u.update! name: "Awesome", username: "keepers"
|
536
601
|
|
537
602
|
expect(u.revisions.size).to eql(3)
|
538
603
|
|
539
|
-
expect(u.revisions[0].name).to eql(
|
540
|
-
expect(u.revisions[0].username).to eql(
|
604
|
+
expect(u.revisions[0].name).to eql("Brandon")
|
605
|
+
expect(u.revisions[0].username).to eql("brandon")
|
541
606
|
|
542
|
-
expect(u.revisions[1].name).to eql(
|
543
|
-
expect(u.revisions[1].username).to eql(
|
607
|
+
expect(u.revisions[1].name).to eql("Foobar")
|
608
|
+
expect(u.revisions[1].username).to eql("brandon")
|
544
609
|
|
545
|
-
expect(u.revisions[2].name).to eql(
|
546
|
-
expect(u.revisions[2].username).to eql(
|
610
|
+
expect(u.revisions[2].name).to eql("Awesome")
|
611
|
+
expect(u.revisions[2].username).to eql("keepers")
|
547
612
|
end
|
548
613
|
|
549
614
|
it "access to only recent revisions" do
|
550
|
-
u = Models::ActiveRecord::User.create(name:
|
551
|
-
u.
|
552
|
-
u.
|
615
|
+
u = Models::ActiveRecord::User.create(name: "Brandon", username: "brandon")
|
616
|
+
u.update! name: "Foobar"
|
617
|
+
u.update! name: "Awesome", username: "keepers"
|
553
618
|
|
554
619
|
expect(u.revisions(2).size).to eq(2)
|
555
620
|
|
556
|
-
expect(u.revisions(2)[0].name).to eq(
|
557
|
-
expect(u.revisions(2)[0].username).to eq(
|
621
|
+
expect(u.revisions(2)[0].name).to eq("Foobar")
|
622
|
+
expect(u.revisions(2)[0].username).to eq("brandon")
|
558
623
|
|
559
|
-
expect(u.revisions(2)[1].name).to eq(
|
560
|
-
expect(u.revisions(2)[1].username).to eq(
|
624
|
+
expect(u.revisions(2)[1].name).to eq("Awesome")
|
625
|
+
expect(u.revisions(2)[1].username).to eq("keepers")
|
561
626
|
end
|
562
627
|
|
563
628
|
it "should be empty if no audits exist" do
|
@@ -566,13 +631,13 @@ describe Audited::Auditor do
|
|
566
631
|
end
|
567
632
|
|
568
633
|
it "should ignore attributes that have been deleted" do
|
569
|
-
user.audits.last.
|
634
|
+
user.audits.last.update! audited_changes: {old_attribute: "old value"}
|
570
635
|
expect { user.revisions }.to_not raise_error
|
571
636
|
end
|
572
637
|
end
|
573
638
|
|
574
639
|
describe "revisions" do
|
575
|
-
let(
|
640
|
+
let(:user) { create_versions(5) }
|
576
641
|
|
577
642
|
it "should maintain identity" do
|
578
643
|
expect(user.revision(1)).to eq(user)
|
@@ -580,26 +645,26 @@ describe Audited::Auditor do
|
|
580
645
|
|
581
646
|
it "should find the given revision" do
|
582
647
|
revision = user.revision(3)
|
583
|
-
expect(revision).to be_a_kind_of(
|
584
|
-
expect(revision.
|
585
|
-
expect(revision.name).to eq(
|
648
|
+
expect(revision).to be_a_kind_of(Models::ActiveRecord::User)
|
649
|
+
expect(revision.audit_version).to eq(3)
|
650
|
+
expect(revision.name).to eq("Foobar 3")
|
586
651
|
end
|
587
652
|
|
588
653
|
it "should find the previous revision with :previous" do
|
589
654
|
revision = user.revision(:previous)
|
590
|
-
expect(revision.
|
591
|
-
#expect(revision).to eq(user.revision(4))
|
655
|
+
expect(revision.audit_version).to eq(4)
|
656
|
+
# expect(revision).to eq(user.revision(4))
|
592
657
|
expect(revision.attributes).to eq(user.revision(4).attributes)
|
593
658
|
end
|
594
659
|
|
595
660
|
it "should be able to get the previous revision repeatedly" do
|
596
661
|
previous = user.revision(:previous)
|
597
|
-
expect(previous.
|
598
|
-
expect(previous.revision(:previous).
|
662
|
+
expect(previous.audit_version).to eq(4)
|
663
|
+
expect(previous.revision(:previous).audit_version).to eq(3)
|
599
664
|
end
|
600
665
|
|
601
666
|
it "should be able to set protected attributes" do
|
602
|
-
u = Models::ActiveRecord::User.create(name:
|
667
|
+
u = Models::ActiveRecord::User.create(name: "Brandon")
|
603
668
|
u.update_attribute :logins, 1
|
604
669
|
u.update_attribute :logins, 2
|
605
670
|
|
@@ -609,23 +674,33 @@ describe Audited::Auditor do
|
|
609
674
|
end
|
610
675
|
|
611
676
|
it "should set attributes directly" do
|
612
|
-
u = Models::ActiveRecord::User.create(name:
|
613
|
-
expect(u.revision(1).name).to eq(
|
677
|
+
u = Models::ActiveRecord::User.create(name: "<Joe>")
|
678
|
+
expect(u.revision(1).name).to eq("<Joe>")
|
614
679
|
end
|
615
680
|
|
616
681
|
it "should set the attributes for each revision" do
|
617
|
-
u = Models::ActiveRecord::User.create(name:
|
618
|
-
u.
|
619
|
-
u.
|
682
|
+
u = Models::ActiveRecord::User.create(name: "Brandon", username: "brandon")
|
683
|
+
u.update! name: "Foobar"
|
684
|
+
u.update! name: "Awesome", username: "keepers"
|
620
685
|
|
621
|
-
expect(u.revision(3).name).to eq(
|
622
|
-
expect(u.revision(3).username).to eq(
|
686
|
+
expect(u.revision(3).name).to eq("Awesome")
|
687
|
+
expect(u.revision(3).username).to eq("keepers")
|
623
688
|
|
624
|
-
expect(u.revision(2).name).to eq(
|
625
|
-
expect(u.revision(2).username).to eq(
|
689
|
+
expect(u.revision(2).name).to eq("Foobar")
|
690
|
+
expect(u.revision(2).username).to eq("brandon")
|
626
691
|
|
627
|
-
expect(u.revision(1).name).to eq(
|
628
|
-
expect(u.revision(1).username).to eq(
|
692
|
+
expect(u.revision(1).name).to eq("Brandon")
|
693
|
+
expect(u.revision(1).username).to eq("brandon")
|
694
|
+
end
|
695
|
+
|
696
|
+
it "should correctly restore revision with enum" do
|
697
|
+
u = Models::ActiveRecord::User.create(status: :active)
|
698
|
+
u.update_attribute(:status, :reliable)
|
699
|
+
u.update_attribute(:status, :banned)
|
700
|
+
|
701
|
+
expect(u.revision(3)).to be_banned
|
702
|
+
expect(u.revision(2)).to be_reliable
|
703
|
+
expect(u.revision(1)).to be_active
|
629
704
|
end
|
630
705
|
|
631
706
|
it "should be able to get time for first revision" do
|
@@ -646,141 +721,276 @@ describe Audited::Auditor do
|
|
646
721
|
it "should record new audit when saving revision" do
|
647
722
|
expect {
|
648
723
|
user.revision(1).save!
|
649
|
-
}.to change(
|
724
|
+
}.to change(user.audits, :count).by(1)
|
650
725
|
end
|
651
726
|
|
652
727
|
it "should re-insert destroyed records" do
|
653
728
|
user.destroy
|
654
729
|
expect {
|
655
730
|
user.revision(1).save!
|
656
|
-
}.to change(
|
731
|
+
}.to change(Models::ActiveRecord::User, :count).by(1)
|
657
732
|
end
|
658
733
|
|
659
734
|
it "should return nil for values greater than the number of revisions" do
|
660
735
|
expect(user.revision(user.revisions.count + 1)).to be_nil
|
661
736
|
end
|
737
|
+
|
738
|
+
it "should work with array attributes" do
|
739
|
+
u = Models::ActiveRecord::User.create!(phone_numbers: ["+1 800-444-4444"])
|
740
|
+
u.update!(phone_numbers: ["+1 804-222-1111", "+1 317 222-2222"])
|
741
|
+
|
742
|
+
expect(u.revision(0).phone_numbers).to eq(["+1 804-222-1111", "+1 317 222-2222"])
|
743
|
+
expect(u.revision(1).phone_numbers).to eq(["+1 800-444-4444"])
|
744
|
+
end
|
662
745
|
end
|
663
746
|
|
664
747
|
describe "revision_at" do
|
665
|
-
let(
|
748
|
+
let(:user) { create_user }
|
666
749
|
|
667
750
|
it "should find the latest revision before the given time" do
|
668
751
|
audit = user.audits.first
|
669
752
|
audit.created_at = 1.hour.ago
|
670
753
|
audit.save!
|
671
|
-
user.
|
672
|
-
expect(user.revision_at(
|
754
|
+
user.update! name: "updated"
|
755
|
+
expect(user.revision_at(2.minutes.ago).audit_version).to eq(1)
|
673
756
|
end
|
674
757
|
|
675
758
|
it "should be nil if given a time before audits" do
|
676
|
-
expect(user.revision_at(
|
759
|
+
expect(user.revision_at(1.week.ago)).to be_nil
|
760
|
+
end
|
761
|
+
end
|
762
|
+
|
763
|
+
describe "own_and_associated_audits" do
|
764
|
+
it "should return audits for self and associated audits" do
|
765
|
+
owner = Models::ActiveRecord::Owner.create!
|
766
|
+
company = owner.companies.create!
|
767
|
+
company.update!(name: "Collective Idea")
|
768
|
+
|
769
|
+
other_owner = Models::ActiveRecord::Owner.create!
|
770
|
+
other_owner.companies.create!
|
771
|
+
|
772
|
+
expect(owner.own_and_associated_audits).to match_array(owner.audits + company.audits)
|
773
|
+
end
|
774
|
+
|
775
|
+
it "should return audits for STI classes" do
|
776
|
+
# Where parent is STI
|
777
|
+
sti_company = Models::ActiveRecord::Company::STICompany.create!
|
778
|
+
sti_company.update!(name: "Collective Idea")
|
779
|
+
expect(sti_company.own_and_associated_audits).to match_array(sti_company.audits)
|
780
|
+
|
781
|
+
# Where associated is STI
|
782
|
+
owner = Models::ActiveRecord::Owner.create!
|
783
|
+
company = owner.companies.create! type: "Models::ActiveRecord::OwnedCompany::STICompany"
|
784
|
+
company.update!(name: "Collective Idea")
|
785
|
+
expect(owner.own_and_associated_audits).to match_array(owner.audits + company.audits)
|
786
|
+
end
|
787
|
+
|
788
|
+
it "should order audits by creation time" do
|
789
|
+
owner = Models::ActiveRecord::Owner.create!
|
790
|
+
first_audit = owner.audits.first
|
791
|
+
first_audit.update_column(:created_at, 1.year.ago)
|
792
|
+
|
793
|
+
company = owner.companies.create!
|
794
|
+
second_audit = company.audits.first
|
795
|
+
second_audit.update_column(:created_at, 1.month.ago)
|
796
|
+
|
797
|
+
company.update!(name: "Collective Idea")
|
798
|
+
third_audit = company.audits.last
|
799
|
+
expect(owner.own_and_associated_audits.to_a).to eq([third_audit, second_audit, first_audit])
|
677
800
|
end
|
678
801
|
end
|
679
802
|
|
680
803
|
describe "without auditing" do
|
681
804
|
it "should not save an audit when calling #save_without_auditing" do
|
682
805
|
expect {
|
683
|
-
u = Models::ActiveRecord::User.new(name:
|
806
|
+
u = Models::ActiveRecord::User.new(name: "Brandon")
|
684
807
|
expect(u.save_without_auditing).to eq(true)
|
685
|
-
}.to_not change(
|
808
|
+
}.to_not change(Audited::Audit, :count)
|
686
809
|
end
|
687
810
|
|
688
811
|
it "should not save an audit inside of the #without_auditing block" do
|
689
812
|
expect {
|
690
|
-
Models::ActiveRecord::User.without_auditing { Models::ActiveRecord::User.create!(
|
691
|
-
}.to_not change(
|
813
|
+
Models::ActiveRecord::User.without_auditing { Models::ActiveRecord::User.create!(name: "Brandon") }
|
814
|
+
}.to_not change(Audited::Audit, :count)
|
692
815
|
end
|
693
816
|
|
694
817
|
it "should reset auditing status even it raises an exception" do
|
695
|
-
|
818
|
+
begin
|
819
|
+
Models::ActiveRecord::User.without_auditing { raise }
|
820
|
+
rescue
|
821
|
+
nil
|
822
|
+
end
|
696
823
|
expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
|
697
824
|
end
|
698
825
|
|
699
826
|
it "should be thread safe using a #without_auditing block" do
|
827
|
+
skip if Models::ActiveRecord::User.connection.class.name.include?("SQLite")
|
828
|
+
|
829
|
+
t1 = Thread.new do
|
830
|
+
expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
|
831
|
+
Models::ActiveRecord::User.without_auditing do
|
832
|
+
expect(Models::ActiveRecord::User.auditing_enabled).to eq(false)
|
833
|
+
Models::ActiveRecord::User.create!(name: "Bart")
|
834
|
+
sleep 1
|
835
|
+
expect(Models::ActiveRecord::User.auditing_enabled).to eq(false)
|
836
|
+
end
|
837
|
+
expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
|
838
|
+
end
|
839
|
+
|
840
|
+
t2 = Thread.new do
|
841
|
+
sleep 0.5
|
842
|
+
expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
|
843
|
+
Models::ActiveRecord::User.create!(name: "Lisa")
|
844
|
+
end
|
845
|
+
t1.join
|
846
|
+
t2.join
|
847
|
+
|
848
|
+
expect(Models::ActiveRecord::User.find_by_name("Bart").audits.count).to eq(0)
|
849
|
+
expect(Models::ActiveRecord::User.find_by_name("Lisa").audits.count).to eq(1)
|
850
|
+
end
|
851
|
+
|
852
|
+
it "should not save an audit when auditing is globally disabled" do
|
853
|
+
expect(Audited.auditing_enabled).to eq(true)
|
854
|
+
Audited.auditing_enabled = false
|
855
|
+
expect(Models::ActiveRecord::User.auditing_enabled).to eq(false)
|
856
|
+
|
857
|
+
user = create_user
|
858
|
+
expect(user.audits.count).to eq(0)
|
859
|
+
|
860
|
+
Audited.auditing_enabled = true
|
861
|
+
expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
|
862
|
+
|
863
|
+
user.update!(name: "Test")
|
864
|
+
expect(user.audits.count).to eq(1)
|
865
|
+
Models::ActiveRecord::User.enable_auditing
|
866
|
+
end
|
867
|
+
end
|
868
|
+
|
869
|
+
describe "with auditing" do
|
870
|
+
it "should save an audit when calling #save_with_auditing" do
|
871
|
+
expect {
|
872
|
+
u = Models::ActiveRecord::User.new(name: "Brandon")
|
873
|
+
Models::ActiveRecord::User.auditing_enabled = false
|
874
|
+
expect(u.save_with_auditing).to eq(true)
|
875
|
+
Models::ActiveRecord::User.auditing_enabled = true
|
876
|
+
}.to change(Audited::Audit, :count).by(1)
|
877
|
+
end
|
878
|
+
|
879
|
+
it "should save an audit inside of the #with_auditing block" do
|
880
|
+
expect {
|
881
|
+
Models::ActiveRecord::User.auditing_enabled = false
|
882
|
+
Models::ActiveRecord::User.with_auditing { Models::ActiveRecord::User.create!(name: "Brandon") }
|
883
|
+
Models::ActiveRecord::User.auditing_enabled = true
|
884
|
+
}.to change(Audited::Audit, :count).by(1)
|
885
|
+
end
|
886
|
+
|
887
|
+
it "should reset auditing status even it raises an exception" do
|
888
|
+
Models::ActiveRecord::User.disable_auditing
|
700
889
|
begin
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
890
|
+
Models::ActiveRecord::User.with_auditing { raise }
|
891
|
+
rescue
|
892
|
+
nil
|
893
|
+
end
|
894
|
+
expect(Models::ActiveRecord::User.auditing_enabled).to eq(false)
|
895
|
+
Models::ActiveRecord::User.enable_auditing
|
896
|
+
end
|
897
|
+
|
898
|
+
it "should be thread safe using a #with_auditing block" do
|
899
|
+
skip if Models::ActiveRecord::User.connection.class.name.include?("SQLite")
|
900
|
+
|
901
|
+
t1 = Thread.new do
|
902
|
+
Models::ActiveRecord::User.disable_auditing
|
903
|
+
expect(Models::ActiveRecord::User.auditing_enabled).to eq(false)
|
904
|
+
Models::ActiveRecord::User.with_auditing do
|
709
905
|
expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
|
710
|
-
end
|
711
906
|
|
712
|
-
|
713
|
-
sleep
|
907
|
+
Models::ActiveRecord::User.create!(name: "Shaggy")
|
908
|
+
sleep 1
|
714
909
|
expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
|
715
|
-
Models::ActiveRecord::User.create!( name: 'Lisa' )
|
716
910
|
end
|
717
|
-
|
718
|
-
|
911
|
+
expect(Models::ActiveRecord::User.auditing_enabled).to eq(false)
|
912
|
+
Models::ActiveRecord::User.enable_auditing
|
913
|
+
end
|
719
914
|
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
915
|
+
t2 = Thread.new do
|
916
|
+
sleep 0.5
|
917
|
+
Models::ActiveRecord::User.disable_auditing
|
918
|
+
expect(Models::ActiveRecord::User.auditing_enabled).to eq(false)
|
919
|
+
Models::ActiveRecord::User.create!(name: "Scooby")
|
920
|
+
Models::ActiveRecord::User.enable_auditing
|
724
921
|
end
|
922
|
+
t1.join
|
923
|
+
t2.join
|
924
|
+
|
925
|
+
Models::ActiveRecord::User.enable_auditing
|
926
|
+
expect(Models::ActiveRecord::User.find_by_name("Shaggy").audits.count).to eq(1)
|
927
|
+
expect(Models::ActiveRecord::User.find_by_name("Scooby").audits.count).to eq(0)
|
725
928
|
end
|
726
929
|
end
|
727
930
|
|
728
931
|
describe "comment required" do
|
729
|
-
|
730
932
|
describe "on create" do
|
731
933
|
it "should not validate when audit_comment is not supplied when initialized" do
|
732
|
-
expect(Models::ActiveRecord::CommentRequiredUser.new(name:
|
934
|
+
expect(Models::ActiveRecord::CommentRequiredUser.new(name: "Foo")).not_to be_valid
|
733
935
|
end
|
734
936
|
|
735
937
|
it "should not validate when audit_comment is not supplied trying to create" do
|
736
|
-
expect(Models::ActiveRecord::CommentRequiredUser.create(name:
|
938
|
+
expect(Models::ActiveRecord::CommentRequiredUser.create(name: "Foo")).not_to be_valid
|
737
939
|
end
|
738
940
|
|
739
941
|
it "should validate when audit_comment is supplied" do
|
740
|
-
expect(Models::ActiveRecord::CommentRequiredUser.create(name:
|
942
|
+
expect(Models::ActiveRecord::CommentRequiredUser.create(name: "Foo", audit_comment: "Create")).to be_valid
|
741
943
|
end
|
742
944
|
|
743
945
|
it "should validate when audit_comment is not supplied, and creating is not being audited" do
|
744
|
-
expect(Models::ActiveRecord::OnUpdateCommentRequiredUser.create(name:
|
745
|
-
expect(Models::ActiveRecord::OnDestroyCommentRequiredUser.create(name:
|
946
|
+
expect(Models::ActiveRecord::OnUpdateCommentRequiredUser.create(name: "Foo")).to be_valid
|
947
|
+
expect(Models::ActiveRecord::OnDestroyCommentRequiredUser.create(name: "Foo")).to be_valid
|
746
948
|
end
|
747
949
|
|
748
950
|
it "should validate when audit_comment is not supplied, and auditing is disabled" do
|
749
951
|
Models::ActiveRecord::CommentRequiredUser.disable_auditing
|
750
|
-
expect(Models::ActiveRecord::CommentRequiredUser.create(name:
|
952
|
+
expect(Models::ActiveRecord::CommentRequiredUser.create(name: "Foo")).to be_valid
|
751
953
|
Models::ActiveRecord::CommentRequiredUser.enable_auditing
|
752
954
|
end
|
955
|
+
|
956
|
+
it "should validate when audit_comment is not supplied, and only excluded attributes changed" do
|
957
|
+
expect(Models::ActiveRecord::CommentRequiredUser.new(password: "Foo")).to be_valid
|
958
|
+
end
|
753
959
|
end
|
754
960
|
|
755
961
|
describe "on update" do
|
756
|
-
let(
|
757
|
-
let(
|
758
|
-
let(
|
962
|
+
let(:user) { Models::ActiveRecord::CommentRequiredUser.create!(audit_comment: "Create") }
|
963
|
+
let(:on_create_user) { Models::ActiveRecord::OnDestroyCommentRequiredUser.create }
|
964
|
+
let(:on_destroy_user) { Models::ActiveRecord::OnDestroyCommentRequiredUser.create }
|
759
965
|
|
760
966
|
it "should not validate when audit_comment is not supplied" do
|
761
|
-
expect(user.
|
967
|
+
expect(user.update(name: "Test")).to eq(false)
|
762
968
|
end
|
763
969
|
|
764
970
|
it "should validate when audit_comment is not supplied, and updating is not being audited" do
|
765
|
-
expect(on_create_user.
|
766
|
-
expect(on_destroy_user.
|
971
|
+
expect(on_create_user.update(name: "Test")).to eq(true)
|
972
|
+
expect(on_destroy_user.update(name: "Test")).to eq(true)
|
767
973
|
end
|
768
974
|
|
769
975
|
it "should validate when audit_comment is supplied" do
|
770
|
-
expect(user.
|
976
|
+
expect(user.update(name: "Test", audit_comment: "Update")).to eq(true)
|
771
977
|
end
|
772
978
|
|
773
979
|
it "should validate when audit_comment is not supplied, and auditing is disabled" do
|
774
980
|
Models::ActiveRecord::CommentRequiredUser.disable_auditing
|
775
|
-
expect(user.
|
981
|
+
expect(user.update(name: "Test")).to eq(true)
|
776
982
|
Models::ActiveRecord::CommentRequiredUser.enable_auditing
|
777
983
|
end
|
984
|
+
|
985
|
+
it "should validate when audit_comment is not supplied, and only excluded attributes changed" do
|
986
|
+
expect(user.update(password: "Test")).to eq(true)
|
987
|
+
end
|
778
988
|
end
|
779
989
|
|
780
990
|
describe "on destroy" do
|
781
|
-
let(
|
782
|
-
let(
|
783
|
-
let(
|
991
|
+
let(:user) { Models::ActiveRecord::CommentRequiredUser.create!(audit_comment: "Create") }
|
992
|
+
let(:on_create_user) { Models::ActiveRecord::OnCreateCommentRequiredUser.create!(audit_comment: "Create") }
|
993
|
+
let(:on_update_user) { Models::ActiveRecord::OnUpdateCommentRequiredUser.create }
|
784
994
|
|
785
995
|
it "should not validate when audit_comment is not supplied" do
|
786
996
|
expect(user.destroy).to eq(false)
|
@@ -802,31 +1012,38 @@ describe Audited::Auditor do
|
|
802
1012
|
Models::ActiveRecord::CommentRequiredUser.enable_auditing
|
803
1013
|
end
|
804
1014
|
end
|
1015
|
+
end
|
1016
|
+
|
1017
|
+
describe "no update with comment only" do
|
1018
|
+
let(:user) { Models::ActiveRecord::NoUpdateWithCommentOnlyUser.create }
|
805
1019
|
|
1020
|
+
it "does not create an audit when only an audit_comment is present" do
|
1021
|
+
user.audit_comment = "Comment"
|
1022
|
+
expect { user.save! }.to_not change(Audited::Audit, :count)
|
1023
|
+
end
|
806
1024
|
end
|
807
1025
|
|
808
1026
|
describe "attr_protected and attr_accessible" do
|
809
|
-
|
810
1027
|
it "should not raise error when attr_accessible is set and protected is false" do
|
811
1028
|
expect {
|
812
|
-
Models::ActiveRecord::AccessibleAfterDeclarationUser.new(name:
|
1029
|
+
Models::ActiveRecord::AccessibleAfterDeclarationUser.new(name: "No fail!")
|
813
1030
|
}.to_not raise_error
|
814
1031
|
end
|
815
1032
|
|
816
1033
|
it "should not rause an error when attr_accessible is declared before audited" do
|
817
1034
|
expect {
|
818
|
-
Models::ActiveRecord::AccessibleAfterDeclarationUser.new(name:
|
1035
|
+
Models::ActiveRecord::AccessibleAfterDeclarationUser.new(name: "No fail!")
|
819
1036
|
}.to_not raise_error
|
820
1037
|
end
|
821
1038
|
end
|
822
1039
|
|
823
1040
|
describe "audit_as" do
|
824
|
-
let(
|
1041
|
+
let(:user) { Models::ActiveRecord::User.create name: "Testing" }
|
825
1042
|
|
826
1043
|
it "should record user objects" do
|
827
|
-
Models::ActiveRecord::Company.audit_as(
|
828
|
-
company = Models::ActiveRecord::Company.create name:
|
829
|
-
company.
|
1044
|
+
Models::ActiveRecord::Company.audit_as(user) do
|
1045
|
+
company = Models::ActiveRecord::Company.create name: "The auditors"
|
1046
|
+
company.update! name: "The Auditors"
|
830
1047
|
|
831
1048
|
company.audits.each do |audit|
|
832
1049
|
expect(audit.user).to eq(user)
|
@@ -835,9 +1052,9 @@ describe Audited::Auditor do
|
|
835
1052
|
end
|
836
1053
|
|
837
1054
|
it "should record usernames" do
|
838
|
-
Models::ActiveRecord::Company.audit_as(
|
839
|
-
company = Models::ActiveRecord::Company.create name:
|
840
|
-
company.
|
1055
|
+
Models::ActiveRecord::Company.audit_as(user.name) do
|
1056
|
+
company = Models::ActiveRecord::Company.create name: "The auditors"
|
1057
|
+
company.update! name: "The Auditors"
|
841
1058
|
|
842
1059
|
company.audits.each do |audit|
|
843
1060
|
expect(audit.user).to eq(user.name)
|
@@ -847,7 +1064,7 @@ describe Audited::Auditor do
|
|
847
1064
|
end
|
848
1065
|
|
849
1066
|
describe "after_audit" do
|
850
|
-
let(
|
1067
|
+
let(:user) { Models::ActiveRecord::UserWithAfterAudit.new }
|
851
1068
|
|
852
1069
|
it "should invoke after_audit callback on create" do
|
853
1070
|
expect(user.bogus_attr).to be_nil
|
@@ -857,7 +1074,7 @@ describe Audited::Auditor do
|
|
857
1074
|
end
|
858
1075
|
|
859
1076
|
describe "around_audit" do
|
860
|
-
let(
|
1077
|
+
let(:user) { Models::ActiveRecord::UserWithAfterAudit.new }
|
861
1078
|
|
862
1079
|
it "should invoke around_audit callback on create" do
|
863
1080
|
expect(user.around_attr).to be_nil
|
@@ -868,13 +1085,13 @@ describe Audited::Auditor do
|
|
868
1085
|
|
869
1086
|
describe "STI auditing" do
|
870
1087
|
it "should correctly disable auditing when using STI" do
|
871
|
-
company = Models::ActiveRecord::Company::STICompany.create name:
|
1088
|
+
company = Models::ActiveRecord::Company::STICompany.create name: "The auditors"
|
872
1089
|
expect(company.type).to eq("Models::ActiveRecord::Company::STICompany")
|
873
1090
|
expect {
|
874
1091
|
Models::ActiveRecord::Company.auditing_enabled = false
|
875
|
-
company.
|
1092
|
+
company.update! name: "STI auditors"
|
876
1093
|
Models::ActiveRecord::Company.auditing_enabled = true
|
877
|
-
}.to_not change(
|
1094
|
+
}.to_not change(Audited::Audit, :count)
|
878
1095
|
end
|
879
1096
|
end
|
880
1097
|
end
|