audited 5.0.2 → 5.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/Appraisals +15 -2
  3. data/CHANGELOG.md +105 -1
  4. data/README.md +29 -11
  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 +81 -28
  9. data/lib/audited/version.rb +1 -1
  10. data/lib/audited.rb +18 -9
  11. data/lib/generators/audited/migration.rb +10 -2
  12. metadata +39 -57
  13. data/.github/workflows/ci.yml +0 -115
  14. data/.gitignore +0 -17
  15. data/.standard.yml +0 -5
  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/gemfiles/rails70.gemfile +0 -10
  23. data/spec/audited/audit_spec.rb +0 -357
  24. data/spec/audited/auditor_spec.rb +0 -1097
  25. data/spec/audited/rspec_matchers_spec.rb +0 -69
  26. data/spec/audited/sweeper_spec.rb +0 -133
  27. data/spec/audited_spec.rb +0 -18
  28. data/spec/audited_spec_helpers.rb +0 -32
  29. data/spec/rails_app/app/assets/config/manifest.js +0 -2
  30. data/spec/rails_app/config/application.rb +0 -13
  31. data/spec/rails_app/config/database.yml +0 -26
  32. data/spec/rails_app/config/environment.rb +0 -5
  33. data/spec/rails_app/config/environments/test.rb +0 -47
  34. data/spec/rails_app/config/initializers/backtrace_silencers.rb +0 -7
  35. data/spec/rails_app/config/initializers/inflections.rb +0 -2
  36. data/spec/rails_app/config/initializers/secret_token.rb +0 -3
  37. data/spec/rails_app/config/routes.rb +0 -3
  38. data/spec/spec_helper.rb +0 -24
  39. data/spec/support/active_record/models.rb +0 -151
  40. data/spec/support/active_record/postgres/1_change_audited_changes_type_to_json.rb +0 -11
  41. data/spec/support/active_record/postgres/2_change_audited_changes_type_to_jsonb.rb +0 -11
  42. data/spec/support/active_record/schema.rb +0 -90
  43. data/test/db/version_1.rb +0 -17
  44. data/test/db/version_2.rb +0 -18
  45. data/test/db/version_3.rb +0 -18
  46. data/test/db/version_4.rb +0 -19
  47. data/test/db/version_5.rb +0 -17
  48. data/test/db/version_6.rb +0 -19
  49. data/test/install_generator_test.rb +0 -62
  50. data/test/test_helper.rb +0 -18
  51. 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