audited 5.0.0 → 5.8.0

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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/Appraisals +40 -17
  3. data/CHANGELOG.md +143 -0
  4. data/README.md +49 -15
  5. data/Rakefile +1 -3
  6. data/audited.gemspec +38 -0
  7. data/lib/audited/audit.rb +8 -4
  8. data/lib/audited/auditor.rb +124 -38
  9. data/lib/audited/version.rb +1 -1
  10. data/lib/audited.rb +19 -10
  11. data/lib/generators/audited/migration.rb +10 -2
  12. metadata +39 -56
  13. data/.gitignore +0 -17
  14. data/.standard.yml +0 -5
  15. data/.travis.yml +0 -67
  16. data/.yardopts +0 -3
  17. data/gemfiles/rails50.gemfile +0 -10
  18. data/gemfiles/rails51.gemfile +0 -10
  19. data/gemfiles/rails52.gemfile +0 -10
  20. data/gemfiles/rails60.gemfile +0 -10
  21. data/gemfiles/rails61.gemfile +0 -10
  22. data/spec/audited/audit_spec.rb +0 -357
  23. data/spec/audited/auditor_spec.rb +0 -1097
  24. data/spec/audited/rspec_matchers_spec.rb +0 -69
  25. data/spec/audited/sweeper_spec.rb +0 -133
  26. data/spec/audited_spec.rb +0 -18
  27. data/spec/audited_spec_helpers.rb +0 -32
  28. data/spec/rails_app/app/assets/config/manifest.js +0 -2
  29. data/spec/rails_app/config/application.rb +0 -13
  30. data/spec/rails_app/config/database.yml +0 -25
  31. data/spec/rails_app/config/environment.rb +0 -5
  32. data/spec/rails_app/config/environments/test.rb +0 -47
  33. data/spec/rails_app/config/initializers/backtrace_silencers.rb +0 -7
  34. data/spec/rails_app/config/initializers/inflections.rb +0 -2
  35. data/spec/rails_app/config/initializers/secret_token.rb +0 -3
  36. data/spec/rails_app/config/routes.rb +0 -3
  37. data/spec/spec_helper.rb +0 -24
  38. data/spec/support/active_record/models.rb +0 -151
  39. data/spec/support/active_record/postgres/1_change_audited_changes_type_to_json.rb +0 -11
  40. data/spec/support/active_record/postgres/2_change_audited_changes_type_to_jsonb.rb +0 -11
  41. data/spec/support/active_record/schema.rb +0 -90
  42. data/test/db/version_1.rb +0 -17
  43. data/test/db/version_2.rb +0 -18
  44. data/test/db/version_3.rb +0 -18
  45. data/test/db/version_4.rb +0 -19
  46. data/test/db/version_5.rb +0 -17
  47. data/test/db/version_6.rb +0 -19
  48. data/test/install_generator_test.rb +0 -62
  49. data/test/test_helper.rb +0 -18
  50. data/test/upgrade_generator_test.rb +0 -97
@@ -1,1097 +0,0 @@
1
- require "spec_helper"
2
-
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
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
67
- describe "configuration" do
68
- it "should include instance methods" do
69
- expect(Models::ActiveRecord::User.new).to be_a_kind_of(Audited::Auditor::AuditedInstanceMethods)
70
- end
71
-
72
- it "should include class methods" do
73
- expect(Models::ActiveRecord::User).to be_a_kind_of(Audited::Auditor::AuditedClassMethods)
74
- end
75
-
76
- ["created_at", "updated_at", "created_on", "updated_on", "lock_version", "id", "password"].each do |column|
77
- it "should not audit #{column}" do
78
- expect(Models::ActiveRecord::User.non_audited_columns).to include(column)
79
- end
80
- end
81
-
82
- context "should be configurable which conditions are audited" do
83
- subject { ConditionalCompany.new.send(:auditing_enabled) }
84
-
85
- context "when condition method is private" do
86
- subject { ConditionalPrivateCompany.new.send(:auditing_enabled) }
87
-
88
- it { is_expected.to be_truthy }
89
- end
90
-
91
- context "when passing a method name" do
92
- context "when conditions are true" do
93
- before { allow_any_instance_of(ConditionalCompany).to receive(:public?).and_return(true) }
94
- it { is_expected.to be_truthy }
95
- end
96
-
97
- context "when conditions are false" do
98
- before { allow_any_instance_of(ConditionalCompany).to receive(:public?).and_return(false) }
99
- it { is_expected.to be_falsey }
100
- end
101
- end
102
-
103
- context "when passing a Proc" do
104
- context "when conditions are true" do
105
- subject { InclusiveCompany.new.send(:auditing_enabled) }
106
-
107
- it { is_expected.to be_truthy }
108
- end
109
-
110
- context "when conditions are false" do
111
- subject { ExclusiveCompany.new.send(:auditing_enabled) }
112
- it { is_expected.to be_falsey }
113
- end
114
- end
115
- end
116
-
117
- context "should be configurable which conditions aren't audited" do
118
- context "when using a method name" do
119
- subject { ExclusionaryCompany.new.send(:auditing_enabled) }
120
-
121
- context "when conditions are true" do
122
- before { allow_any_instance_of(ExclusionaryCompany).to receive(:non_profit?).and_return(true) }
123
- it { is_expected.to be_falsey }
124
- end
125
-
126
- context "when conditions are false" do
127
- before { allow_any_instance_of(ExclusionaryCompany).to receive(:non_profit?).and_return(false) }
128
- it { is_expected.to be_truthy }
129
- end
130
- end
131
-
132
- context "when using a proc" do
133
- context "when conditions are true" do
134
- subject { ExclusionaryCompany2.new.send(:auditing_enabled) }
135
- it { is_expected.to be_falsey }
136
- end
137
-
138
- context "when conditions are false" do
139
- subject { InclusiveCompany2.new.send(:auditing_enabled) }
140
- it { is_expected.to be_truthy }
141
- end
142
- end
143
- end
144
-
145
- it "should be configurable which attributes are not audited via ignored_attributes" do
146
- Audited.ignored_attributes = ["delta", "top_secret", "created_at"]
147
-
148
- expect(Secret.non_audited_columns).to include("delta", "top_secret", "created_at")
149
- end
150
-
151
- it "should be configurable which attributes are not audited via non_audited_columns=" do
152
- expect(Secret2.non_audited_columns).to include("delta", "top_secret", "created_at")
153
- end
154
-
155
- it "should not save non-audited columns" do
156
- previous = Models::ActiveRecord::User.non_audited_columns
157
- begin
158
- Models::ActiveRecord::User.non_audited_columns += [:favourite_device]
159
-
160
- expect(create_user.audits.first.audited_changes.keys.any? { |col| ["favourite_device", "created_at", "updated_at", "password"].include?(col) }).to eq(false)
161
- ensure
162
- Models::ActiveRecord::User.non_audited_columns = previous
163
- end
164
- end
165
-
166
- it "should not save other columns than specified in 'only' option" do
167
- user = Models::ActiveRecord::UserOnlyPassword.create
168
- user.instance_eval do
169
- def non_column_attr
170
- @non_column_attr
171
- end
172
-
173
- def non_column_attr=(val)
174
- attribute_will_change!("non_column_attr")
175
- @non_column_attr = val
176
- end
177
- end
178
-
179
- user.password = "password"
180
- user.non_column_attr = "some value"
181
- user.save!
182
- expect(user.audits.last.audited_changes.keys).to eq(%w[password])
183
- end
184
-
185
- it "should save attributes not specified in 'except' option" do
186
- user = Models::ActiveRecord::User.create
187
- user.instance_eval do
188
- def non_column_attr
189
- @non_column_attr
190
- end
191
-
192
- def non_column_attr=(val)
193
- attribute_will_change!("non_column_attr")
194
- @non_column_attr = val
195
- end
196
- end
197
-
198
- user.password = "password"
199
- user.non_column_attr = "some value"
200
- user.save!
201
- expect(user.audits.last.audited_changes.keys).to eq(%w[non_column_attr])
202
- end
203
-
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"
238
- describe "'json' and 'jsonb' audited_changes column type" do
239
- let(:migrations_path) { SPEC_ROOT.join("support/active_record/postgres") }
240
-
241
- after do
242
- run_migrations(:down, migrations_path)
243
- end
244
-
245
- it "should work if column type is 'json'" do
246
- run_migrations(:up, migrations_path, 1)
247
- Audited::Audit.reset_column_information
248
- expect(Audited::Audit.columns_hash["audited_changes"].sql_type).to eq("json")
249
-
250
- user = Models::ActiveRecord::User.create
251
- user.name = "new name"
252
- user.save!
253
- expect(user.audits.last.audited_changes).to eq({"name" => [nil, "new name"]})
254
- end
255
-
256
- it "should work if column type is 'jsonb'" do
257
- run_migrations(:up, migrations_path, 2)
258
- Audited::Audit.reset_column_information
259
- expect(Audited::Audit.columns_hash["audited_changes"].sql_type).to eq("jsonb")
260
-
261
- user = Models::ActiveRecord::User.create
262
- user.name = "new name"
263
- user.save!
264
- expect(user.audits.last.audited_changes).to eq({"name" => [nil, "new name"]})
265
- end
266
- end
267
- end
268
- end
269
-
270
- describe :new do
271
- it "should allow mass assignment of all unprotected attributes" do
272
- yesterday = 1.day.ago
273
-
274
- u = Models::ActiveRecord::NoAttributeProtectionUser.new(name: "name",
275
- username: "username",
276
- password: "password",
277
- activated: true,
278
- suspended_at: yesterday,
279
- logins: 2)
280
-
281
- expect(u.name).to eq("name")
282
- expect(u.username).to eq("username")
283
- expect(u.password).to eq("password")
284
- expect(u.activated).to eq(true)
285
- expect(u.suspended_at.to_i).to eq(yesterday.to_i)
286
- expect(u.logins).to eq(2)
287
- end
288
- end
289
-
290
- describe "on create" do
291
- let(:user) { create_user status: :reliable, audit_comment: "Create" }
292
-
293
- it "should change the audit count" do
294
- expect {
295
- user
296
- }.to change(Audited::Audit, :count).by(1)
297
- end
298
-
299
- it "should create associated audit" do
300
- expect(user.audits.count).to eq(1)
301
- end
302
-
303
- it "should set the action to create" do
304
- expect(user.audits.first.action).to eq("create")
305
- expect(Audited::Audit.creates.order(:id).last).to eq(user.audits.first)
306
- expect(user.audits.creates.count).to eq(1)
307
- expect(user.audits.updates.count).to eq(0)
308
- expect(user.audits.destroys.count).to eq(0)
309
- end
310
-
311
- it "should store all the audited attributes" do
312
- expect(user.audits.first.audited_changes).to eq(user.audited_attributes)
313
- end
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
-
328
- it "should store comment" do
329
- expect(user.audits.first.comment).to eq("Create")
330
- end
331
-
332
- it "should not audit an attribute which is excepted if specified on create or destroy" do
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)
335
- end
336
-
337
- it "should not save an audit if only specified on update/destroy" do
338
- expect {
339
- Models::ActiveRecord::OnUpdateDestroy.create!(name: "Bart")
340
- }.to_not change(Audited::Audit, :count)
341
- end
342
- end
343
-
344
- describe "on update" do
345
- before do
346
- @user = create_user(name: "Brandon", status: :active, audit_comment: "Update")
347
- end
348
-
349
- it "should save an audit" do
350
- expect {
351
- @user.update_attribute(:name, "Someone")
352
- }.to change(Audited::Audit, :count).by(1)
353
- expect {
354
- @user.update_attribute(:name, "Someone else")
355
- }.to change(Audited::Audit, :count).by(1)
356
- end
357
-
358
- it "should set the action to 'update'" do
359
- @user.update! name: "Changed"
360
- expect(@user.audits.last.action).to eq("update")
361
- expect(Audited::Audit.updates.order(:id).last).to eq(@user.audits.last)
362
- expect(@user.audits.updates.last).to eq(@user.audits.last)
363
- end
364
-
365
- it "should store the changed attributes" do
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])
373
- end
374
-
375
- it "should store audit comment" do
376
- expect(@user.audits.last.comment).to eq("Update")
377
- end
378
-
379
- it "should not save an audit if only specified on create/destroy" do
380
- on_create_destroy = Models::ActiveRecord::OnCreateDestroy.create(name: "Bart")
381
- expect {
382
- on_create_destroy.update! name: "Changed"
383
- }.to_not change(Audited::Audit, :count)
384
- end
385
-
386
- it "should not save an audit if the value doesn't change after type casting" do
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)
391
- end
392
-
393
- describe "with no dirty changes" do
394
- it "does not create an audit if the record is not changed" do
395
- expect {
396
- @user.save!
397
- }.to_not change(Audited::Audit, :count)
398
- end
399
-
400
- it "creates an audit when an audit comment is present" do
401
- expect {
402
- @user.audit_comment = "Comment"
403
- @user.save!
404
- }.to change(Audited::Audit, :count)
405
- end
406
- end
407
- end
408
-
409
- describe "on destroy" do
410
- before do
411
- @user = create_user(status: :active)
412
- end
413
-
414
- it "should save an audit" do
415
- expect {
416
- @user.destroy
417
- }.to change(Audited::Audit, :count)
418
-
419
- expect(@user.audits.size).to eq(2)
420
- end
421
-
422
- it "should set the action to 'destroy'" do
423
- @user.destroy
424
-
425
- expect(@user.audits.last.action).to eq("destroy")
426
- expect(Audited::Audit.destroys.order(:id).last).to eq(@user.audits.last)
427
- expect(@user.audits.destroys.last).to eq(@user.audits.last)
428
- end
429
-
430
- it "should store all of the audited attributes" do
431
- @user.destroy
432
-
433
- expect(@user.audits.last.audited_changes).to eq(@user.audited_attributes)
434
- end
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
-
441
- it "should be able to reconstruct a destroyed record without history" do
442
- @user.audits.delete_all
443
- @user.destroy
444
-
445
- revision = @user.audits.first.revision
446
- expect(revision.name).to eq(@user.name)
447
- end
448
-
449
- it "should not save an audit if only specified on create/update" do
450
- on_create_update = Models::ActiveRecord::OnCreateUpdate.create!(name: "Bart")
451
-
452
- expect {
453
- on_create_update.destroy
454
- }.to_not change(Audited::Audit, :count)
455
- end
456
-
457
- it "should audit dependent destructions" do
458
- owner = Models::ActiveRecord::Owner.create!
459
- company = owner.companies.create!
460
-
461
- expect {
462
- owner.destroy
463
- }.to change(Audited::Audit, :count)
464
-
465
- expect(company.audits.map { |a| a.action }).to eq(["create", "destroy"])
466
- end
467
- end
468
-
469
- describe "on destroy with unsaved object" do
470
- let(:user) { Models::ActiveRecord::User.new }
471
-
472
- it "should not audit on 'destroy'" do
473
- expect {
474
- user.destroy
475
- }.to_not raise_error
476
-
477
- expect(user.audits).to be_empty
478
- end
479
- end
480
-
481
- describe "associated with" do
482
- let(:owner) { Models::ActiveRecord::Owner.create(name: "Models::ActiveRecord::Owner") }
483
- let(:owned_company) { Models::ActiveRecord::OwnedCompany.create!(name: "The auditors", owner: owner) }
484
-
485
- it "should record the associated object on create" do
486
- expect(owned_company.audits.first.associated).to eq(owner)
487
- end
488
-
489
- it "should store the associated object on update" do
490
- owned_company.update_attribute(:name, "The Auditors")
491
- expect(owned_company.audits.last.associated).to eq(owner)
492
- end
493
-
494
- it "should store the associated object on destroy" do
495
- owned_company.destroy
496
- expect(owned_company.audits.last.associated).to eq(owner)
497
- end
498
- end
499
-
500
- describe "has associated audits" do
501
- let!(:owner) { Models::ActiveRecord::Owner.create!(name: "Models::ActiveRecord::Owner") }
502
- let!(:owned_company) { Models::ActiveRecord::OwnedCompany.create!(name: "The auditors", owner: owner) }
503
-
504
- it "should list the associated audits" do
505
- expect(owner.associated_audits.length).to eq(1)
506
- expect(owner.associated_audits.first.auditable).to eq(owned_company)
507
- end
508
- end
509
-
510
- describe "max_audits" do
511
- it "should respect global setting" do
512
- stub_global_max_audits(10) do
513
- expect(Models::ActiveRecord::User.audited_options[:max_audits]).to eq(10)
514
- end
515
- end
516
-
517
- it "should respect per model setting" do
518
- stub_global_max_audits(10) do
519
- expect(Models::ActiveRecord::MaxAuditsUser.audited_options[:max_audits]).to eq(5)
520
- end
521
- end
522
-
523
- it "should delete old audits when keeped amount exceeded" do
524
- stub_global_max_audits(2) do
525
- user = create_versions(2)
526
- user.update(name: "John")
527
- expect(user.audits.pluck(:version)).to eq([2, 3])
528
- end
529
- end
530
-
531
- it "should not delete old audits when keeped amount not exceeded" do
532
- stub_global_max_audits(3) do
533
- user = create_versions(2)
534
- user.update(name: "John")
535
- expect(user.audits.pluck(:version)).to eq([1, 2, 3])
536
- end
537
- end
538
-
539
- it "should delete old extra audits after introducing limit" do
540
- stub_global_max_audits(nil) do
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)
545
-
546
- Audited.max_audits = 3
547
- Models::ActiveRecord::User.send(:normalize_audited_options)
548
- user.update!(favourite_device: "Android Phone")
549
- audits = user.audits
550
-
551
- expect(audits.count).to eq(3)
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"]})
555
- end
556
- end
557
-
558
- it "should add comment line for combined audit" do
559
- stub_global_max_audits(2) do
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")
563
- expect(user.audits.first.comment).to match(/First audit comment.+is the result of multiple/m)
564
- end
565
- end
566
-
567
- def stub_global_max_audits(max_audits)
568
- previous_max_audits = Audited.max_audits
569
- previous_user_audited_options = Models::ActiveRecord::User.audited_options.dup
570
- begin
571
- Audited.max_audits = max_audits
572
- Models::ActiveRecord::User.send(:normalize_audited_options) # reloads audited_options
573
- yield
574
- ensure
575
- Audited.max_audits = previous_max_audits
576
- Models::ActiveRecord::User.audited_options = previous_user_audited_options
577
- end
578
- end
579
- end
580
-
581
- describe "revisions" do
582
- let(:user) { create_versions }
583
-
584
- it "should return an Array of Users" do
585
- expect(user.revisions).to be_a_kind_of(Array)
586
- user.revisions.each { |version| expect(version).to be_a_kind_of Models::ActiveRecord::User }
587
- end
588
-
589
- it "should have one revision for a new record" do
590
- expect(create_user.revisions.size).to eq(1)
591
- end
592
-
593
- it "should have one revision for each audit" do
594
- expect(user.audits.size).to eql(user.revisions.size)
595
- end
596
-
597
- it "should set the attributes for each revision" do
598
- u = Models::ActiveRecord::User.create(name: "Brandon", username: "brandon")
599
- u.update! name: "Foobar"
600
- u.update! name: "Awesome", username: "keepers"
601
-
602
- expect(u.revisions.size).to eql(3)
603
-
604
- expect(u.revisions[0].name).to eql("Brandon")
605
- expect(u.revisions[0].username).to eql("brandon")
606
-
607
- expect(u.revisions[1].name).to eql("Foobar")
608
- expect(u.revisions[1].username).to eql("brandon")
609
-
610
- expect(u.revisions[2].name).to eql("Awesome")
611
- expect(u.revisions[2].username).to eql("keepers")
612
- end
613
-
614
- it "access to only recent revisions" do
615
- u = Models::ActiveRecord::User.create(name: "Brandon", username: "brandon")
616
- u.update! name: "Foobar"
617
- u.update! name: "Awesome", username: "keepers"
618
-
619
- expect(u.revisions(2).size).to eq(2)
620
-
621
- expect(u.revisions(2)[0].name).to eq("Foobar")
622
- expect(u.revisions(2)[0].username).to eq("brandon")
623
-
624
- expect(u.revisions(2)[1].name).to eq("Awesome")
625
- expect(u.revisions(2)[1].username).to eq("keepers")
626
- end
627
-
628
- it "should be empty if no audits exist" do
629
- user.audits.delete_all
630
- expect(user.revisions).to be_empty
631
- end
632
-
633
- it "should ignore attributes that have been deleted" do
634
- user.audits.last.update! audited_changes: {old_attribute: "old value"}
635
- expect { user.revisions }.to_not raise_error
636
- end
637
- end
638
-
639
- describe "revisions" do
640
- let(:user) { create_versions(5) }
641
-
642
- it "should maintain identity" do
643
- expect(user.revision(1)).to eq(user)
644
- end
645
-
646
- it "should find the given revision" do
647
- revision = user.revision(3)
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")
651
- end
652
-
653
- it "should find the previous revision with :previous" do
654
- revision = user.revision(:previous)
655
- expect(revision.audit_version).to eq(4)
656
- # expect(revision).to eq(user.revision(4))
657
- expect(revision.attributes).to eq(user.revision(4).attributes)
658
- end
659
-
660
- it "should be able to get the previous revision repeatedly" do
661
- previous = user.revision(:previous)
662
- expect(previous.audit_version).to eq(4)
663
- expect(previous.revision(:previous).audit_version).to eq(3)
664
- end
665
-
666
- it "should be able to set protected attributes" do
667
- u = Models::ActiveRecord::User.create(name: "Brandon")
668
- u.update_attribute :logins, 1
669
- u.update_attribute :logins, 2
670
-
671
- expect(u.revision(3).logins).to eq(2)
672
- expect(u.revision(2).logins).to eq(1)
673
- expect(u.revision(1).logins).to eq(0)
674
- end
675
-
676
- it "should set attributes directly" do
677
- u = Models::ActiveRecord::User.create(name: "<Joe>")
678
- expect(u.revision(1).name).to eq("&lt;Joe&gt;")
679
- end
680
-
681
- it "should set the attributes for each revision" do
682
- u = Models::ActiveRecord::User.create(name: "Brandon", username: "brandon")
683
- u.update! name: "Foobar"
684
- u.update! name: "Awesome", username: "keepers"
685
-
686
- expect(u.revision(3).name).to eq("Awesome")
687
- expect(u.revision(3).username).to eq("keepers")
688
-
689
- expect(u.revision(2).name).to eq("Foobar")
690
- expect(u.revision(2).username).to eq("brandon")
691
-
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
704
- end
705
-
706
- it "should be able to get time for first revision" do
707
- suspended_at = Time.zone.now
708
- u = Models::ActiveRecord::User.create(suspended_at: suspended_at)
709
- expect(u.revision(1).suspended_at.to_s).to eq(suspended_at.to_s)
710
- end
711
-
712
- it "should not raise an error when no previous audits exist" do
713
- user.audits.destroy_all
714
- expect { user.revision(:previous) }.to_not raise_error
715
- end
716
-
717
- it "should mark revision's attributes as changed" do
718
- expect(user.revision(1).name_changed?).to eq(true)
719
- end
720
-
721
- it "should record new audit when saving revision" do
722
- expect {
723
- user.revision(1).save!
724
- }.to change(user.audits, :count).by(1)
725
- end
726
-
727
- it "should re-insert destroyed records" do
728
- user.destroy
729
- expect {
730
- user.revision(1).save!
731
- }.to change(Models::ActiveRecord::User, :count).by(1)
732
- end
733
-
734
- it "should return nil for values greater than the number of revisions" do
735
- expect(user.revision(user.revisions.count + 1)).to be_nil
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
745
- end
746
-
747
- describe "revision_at" do
748
- let(:user) { create_user }
749
-
750
- it "should find the latest revision before the given time" do
751
- audit = user.audits.first
752
- audit.created_at = 1.hour.ago
753
- audit.save!
754
- user.update! name: "updated"
755
- expect(user.revision_at(2.minutes.ago).audit_version).to eq(1)
756
- end
757
-
758
- it "should be nil if given a time before audits" do
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])
800
- end
801
- end
802
-
803
- describe "without auditing" do
804
- it "should not save an audit when calling #save_without_auditing" do
805
- expect {
806
- u = Models::ActiveRecord::User.new(name: "Brandon")
807
- expect(u.save_without_auditing).to eq(true)
808
- }.to_not change(Audited::Audit, :count)
809
- end
810
-
811
- it "should not save an audit inside of the #without_auditing block" do
812
- expect {
813
- Models::ActiveRecord::User.without_auditing { Models::ActiveRecord::User.create!(name: "Brandon") }
814
- }.to_not change(Audited::Audit, :count)
815
- end
816
-
817
- it "should reset auditing status even it raises an exception" do
818
- begin
819
- Models::ActiveRecord::User.without_auditing { raise }
820
- rescue
821
- nil
822
- end
823
- expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
824
- end
825
-
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
889
- begin
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
905
- expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
906
-
907
- Models::ActiveRecord::User.create!(name: "Shaggy")
908
- sleep 1
909
- expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
910
- end
911
- expect(Models::ActiveRecord::User.auditing_enabled).to eq(false)
912
- Models::ActiveRecord::User.enable_auditing
913
- end
914
-
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
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)
928
- end
929
- end
930
-
931
- describe "comment required" do
932
- describe "on create" do
933
- it "should not validate when audit_comment is not supplied when initialized" do
934
- expect(Models::ActiveRecord::CommentRequiredUser.new(name: "Foo")).not_to be_valid
935
- end
936
-
937
- it "should not validate when audit_comment is not supplied trying to create" do
938
- expect(Models::ActiveRecord::CommentRequiredUser.create(name: "Foo")).not_to be_valid
939
- end
940
-
941
- it "should validate when audit_comment is supplied" do
942
- expect(Models::ActiveRecord::CommentRequiredUser.create(name: "Foo", audit_comment: "Create")).to be_valid
943
- end
944
-
945
- it "should validate when audit_comment is not supplied, and creating is not being audited" do
946
- expect(Models::ActiveRecord::OnUpdateCommentRequiredUser.create(name: "Foo")).to be_valid
947
- expect(Models::ActiveRecord::OnDestroyCommentRequiredUser.create(name: "Foo")).to be_valid
948
- end
949
-
950
- it "should validate when audit_comment is not supplied, and auditing is disabled" do
951
- Models::ActiveRecord::CommentRequiredUser.disable_auditing
952
- expect(Models::ActiveRecord::CommentRequiredUser.create(name: "Foo")).to be_valid
953
- Models::ActiveRecord::CommentRequiredUser.enable_auditing
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
959
- end
960
-
961
- describe "on update" do
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 }
965
-
966
- it "should not validate when audit_comment is not supplied" do
967
- expect(user.update(name: "Test")).to eq(false)
968
- end
969
-
970
- it "should validate when audit_comment is not supplied, and updating is not being audited" do
971
- expect(on_create_user.update(name: "Test")).to eq(true)
972
- expect(on_destroy_user.update(name: "Test")).to eq(true)
973
- end
974
-
975
- it "should validate when audit_comment is supplied" do
976
- expect(user.update(name: "Test", audit_comment: "Update")).to eq(true)
977
- end
978
-
979
- it "should validate when audit_comment is not supplied, and auditing is disabled" do
980
- Models::ActiveRecord::CommentRequiredUser.disable_auditing
981
- expect(user.update(name: "Test")).to eq(true)
982
- Models::ActiveRecord::CommentRequiredUser.enable_auditing
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
988
- end
989
-
990
- describe "on destroy" do
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 }
994
-
995
- it "should not validate when audit_comment is not supplied" do
996
- expect(user.destroy).to eq(false)
997
- end
998
-
999
- it "should validate when audit_comment is supplied" do
1000
- user.audit_comment = "Destroy"
1001
- expect(user.destroy).to eq(user)
1002
- end
1003
-
1004
- it "should validate when audit_comment is not supplied, and destroying is not being audited" do
1005
- expect(on_create_user.destroy).to eq(on_create_user)
1006
- expect(on_update_user.destroy).to eq(on_update_user)
1007
- end
1008
-
1009
- it "should validate when audit_comment is not supplied, and auditing is disabled" do
1010
- Models::ActiveRecord::CommentRequiredUser.disable_auditing
1011
- expect(user.destroy).to eq(user)
1012
- Models::ActiveRecord::CommentRequiredUser.enable_auditing
1013
- end
1014
- end
1015
- end
1016
-
1017
- describe "no update with comment only" do
1018
- let(:user) { Models::ActiveRecord::NoUpdateWithCommentOnlyUser.create }
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
1024
- end
1025
-
1026
- describe "attr_protected and attr_accessible" do
1027
- it "should not raise error when attr_accessible is set and protected is false" do
1028
- expect {
1029
- Models::ActiveRecord::AccessibleAfterDeclarationUser.new(name: "No fail!")
1030
- }.to_not raise_error
1031
- end
1032
-
1033
- it "should not rause an error when attr_accessible is declared before audited" do
1034
- expect {
1035
- Models::ActiveRecord::AccessibleAfterDeclarationUser.new(name: "No fail!")
1036
- }.to_not raise_error
1037
- end
1038
- end
1039
-
1040
- describe "audit_as" do
1041
- let(:user) { Models::ActiveRecord::User.create name: "Testing" }
1042
-
1043
- it "should record user objects" do
1044
- Models::ActiveRecord::Company.audit_as(user) do
1045
- company = Models::ActiveRecord::Company.create name: "The auditors"
1046
- company.update! name: "The Auditors"
1047
-
1048
- company.audits.each do |audit|
1049
- expect(audit.user).to eq(user)
1050
- end
1051
- end
1052
- end
1053
-
1054
- it "should record usernames" do
1055
- Models::ActiveRecord::Company.audit_as(user.name) do
1056
- company = Models::ActiveRecord::Company.create name: "The auditors"
1057
- company.update! name: "The Auditors"
1058
-
1059
- company.audits.each do |audit|
1060
- expect(audit.user).to eq(user.name)
1061
- end
1062
- end
1063
- end
1064
- end
1065
-
1066
- describe "after_audit" do
1067
- let(:user) { Models::ActiveRecord::UserWithAfterAudit.new }
1068
-
1069
- it "should invoke after_audit callback on create" do
1070
- expect(user.bogus_attr).to be_nil
1071
- expect(user.save).to eq(true)
1072
- expect(user.bogus_attr).to eq("do something")
1073
- end
1074
- end
1075
-
1076
- describe "around_audit" do
1077
- let(:user) { Models::ActiveRecord::UserWithAfterAudit.new }
1078
-
1079
- it "should invoke around_audit callback on create" do
1080
- expect(user.around_attr).to be_nil
1081
- expect(user.save).to eq(true)
1082
- expect(user.around_attr).to eq(user.audits.last)
1083
- end
1084
- end
1085
-
1086
- describe "STI auditing" do
1087
- it "should correctly disable auditing when using STI" do
1088
- company = Models::ActiveRecord::Company::STICompany.create name: "The auditors"
1089
- expect(company.type).to eq("Models::ActiveRecord::Company::STICompany")
1090
- expect {
1091
- Models::ActiveRecord::Company.auditing_enabled = false
1092
- company.update! name: "STI auditors"
1093
- Models::ActiveRecord::Company.auditing_enabled = true
1094
- }.to_not change(Audited::Audit, :count)
1095
- end
1096
- end
1097
- end