audited-hp 4.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.travis.yml +32 -0
  4. data/.yardopts +3 -0
  5. data/Appraisals +22 -0
  6. data/CHANGELOG +153 -0
  7. data/Gemfile +3 -0
  8. data/LICENSE +19 -0
  9. data/README.md +299 -0
  10. data/Rakefile +18 -0
  11. data/gemfiles/rails40.gemfile +9 -0
  12. data/gemfiles/rails41.gemfile +8 -0
  13. data/gemfiles/rails42.gemfile +8 -0
  14. data/gemfiles/rails50.gemfile +8 -0
  15. data/lib/audited-rspec.rb +4 -0
  16. data/lib/audited.rb +29 -0
  17. data/lib/audited/audit.rb +149 -0
  18. data/lib/audited/auditor.rb +309 -0
  19. data/lib/audited/rspec_matchers.rb +177 -0
  20. data/lib/audited/sweeper.rb +60 -0
  21. data/lib/audited/version.rb +3 -0
  22. data/lib/generators/audited/install_generator.rb +20 -0
  23. data/lib/generators/audited/migration.rb +15 -0
  24. data/lib/generators/audited/templates/add_association_to_audits.rb +11 -0
  25. data/lib/generators/audited/templates/add_comment_to_audits.rb +9 -0
  26. data/lib/generators/audited/templates/add_remote_address_to_audits.rb +10 -0
  27. data/lib/generators/audited/templates/add_request_uuid_to_audits.rb +10 -0
  28. data/lib/generators/audited/templates/install.rb +30 -0
  29. data/lib/generators/audited/templates/rename_association_to_associated.rb +23 -0
  30. data/lib/generators/audited/templates/rename_changes_to_audited_changes.rb +9 -0
  31. data/lib/generators/audited/templates/rename_parent_to_association.rb +11 -0
  32. data/lib/generators/audited/upgrade_generator.rb +57 -0
  33. data/spec/audited/audit_spec.rb +199 -0
  34. data/spec/audited/auditor_spec.rb +607 -0
  35. data/spec/audited/sweeper_spec.rb +106 -0
  36. data/spec/audited_spec_helpers.rb +20 -0
  37. data/spec/rails_app/config/application.rb +8 -0
  38. data/spec/rails_app/config/database.yml +24 -0
  39. data/spec/rails_app/config/environment.rb +5 -0
  40. data/spec/rails_app/config/environments/development.rb +21 -0
  41. data/spec/rails_app/config/environments/production.rb +35 -0
  42. data/spec/rails_app/config/environments/test.rb +47 -0
  43. data/spec/rails_app/config/initializers/backtrace_silencers.rb +7 -0
  44. data/spec/rails_app/config/initializers/inflections.rb +2 -0
  45. data/spec/rails_app/config/initializers/secret_token.rb +3 -0
  46. data/spec/rails_app/config/routes.rb +3 -0
  47. data/spec/spec_helper.rb +21 -0
  48. data/spec/support/active_record/models.rb +99 -0
  49. data/spec/support/active_record/schema.rb +81 -0
  50. data/test/db/version_1.rb +17 -0
  51. data/test/db/version_2.rb +18 -0
  52. data/test/db/version_3.rb +19 -0
  53. data/test/db/version_4.rb +20 -0
  54. data/test/db/version_5.rb +18 -0
  55. data/test/db/version_6.rb +17 -0
  56. data/test/install_generator_test.rb +17 -0
  57. data/test/test_helper.rb +19 -0
  58. data/test/upgrade_generator_test.rb +77 -0
  59. metadata +229 -0
@@ -0,0 +1,199 @@
1
+ require "spec_helper"
2
+
3
+ describe Audited::Audit do
4
+ let(:user) { Models::ActiveRecord::User.new name: "Testing" }
5
+
6
+ describe "user=" do
7
+
8
+ it "should be able to set the user to a model object" do
9
+ subject.user = user
10
+ expect(subject.user).to eq(user)
11
+ end
12
+
13
+ it "should be able to set the user to nil" do
14
+ subject.user_id = 1
15
+ subject.user_type = 'Models::ActiveRecord::User'
16
+ subject.username = 'joe'
17
+
18
+ subject.user = nil
19
+
20
+ expect(subject.user).to be_nil
21
+ expect(subject.user_id).to be_nil
22
+ expect(subject.user_type).to be_nil
23
+ expect(subject.username).to be_nil
24
+ end
25
+
26
+ it "should be able to set the user to a string" do
27
+ subject.user = 'test'
28
+ expect(subject.user).to eq('test')
29
+ end
30
+
31
+ it "should clear model when setting to a string" do
32
+ subject.user = user
33
+ subject.user = 'testing'
34
+ expect(subject.user_id).to be_nil
35
+ expect(subject.user_type).to be_nil
36
+ end
37
+
38
+ it "should clear the username when setting to a model" do
39
+ subject.username = 'test'
40
+ subject.user = user
41
+ expect(subject.username).to be_nil
42
+ end
43
+
44
+ end
45
+
46
+ describe "revision" do
47
+
48
+ it "should recreate attributes" do
49
+ user = Models::ActiveRecord::User.create name: "1"
50
+ 5.times {|i| user.update_attribute :name, (i + 2).to_s }
51
+
52
+ user.audits.each do |audit|
53
+ expect(audit.revision.name).to eq(audit.version.to_s)
54
+ end
55
+ end
56
+
57
+ it "should set protected attributes" do
58
+ u = Models::ActiveRecord::User.create(name: "Brandon")
59
+ u.update_attribute :logins, 1
60
+ u.update_attribute :logins, 2
61
+
62
+ expect(u.audits[2].revision.logins).to eq(2)
63
+ expect(u.audits[1].revision.logins).to eq(1)
64
+ expect(u.audits[0].revision.logins).to eq(0)
65
+ end
66
+
67
+ it "should bypass attribute assignment wrappers" do
68
+ u = Models::ActiveRecord::User.create(name: "<Joe>")
69
+ expect(u.audits.first.revision.name).to eq("&lt;Joe&gt;")
70
+ end
71
+
72
+ it "should work for deleted records" do
73
+ user = Models::ActiveRecord::User.create name: "1"
74
+ user.destroy
75
+ revision = user.audits.last.revision
76
+ expect(revision.name).to eq(user.name)
77
+ expect(revision).to be_a_new_record
78
+ end
79
+ end
80
+
81
+ it "should set the version number on create" do
82
+ user = Models::ActiveRecord::User.create! name: "Set Version Number"
83
+ expect(user.audits.first.version).to eq(1)
84
+ user.update_attribute :name, "Set to 2"
85
+ expect(user.audits.reload.first.version).to eq(1)
86
+ expect(user.audits.reload.last.version).to eq(2)
87
+ user.destroy
88
+ expect(Audited::Audit.where(auditable_type: "Models::ActiveRecord::User", auditable_id: user.id).last.version).to eq(3)
89
+ end
90
+
91
+ it "should set the request uuid on create" do
92
+ user = Models::ActiveRecord::User.create! name: "Set Request UUID"
93
+ expect(user.audits.reload.first.request_uuid).not_to be_blank
94
+ end
95
+
96
+ describe "reconstruct_attributes" do
97
+ it "should work with the old way of storing just the new value" do
98
+ audits = Audited::Audit.reconstruct_attributes([Audited::Audit.new(audited_changes: {"attribute" => "value"})])
99
+ expect(audits["attribute"]).to eq("value")
100
+ end
101
+ end
102
+
103
+ describe "audited_classes" do
104
+ class Models::ActiveRecord::CustomUser < ::ActiveRecord::Base
105
+ end
106
+ class Models::ActiveRecord::CustomUserSubclass < Models::ActiveRecord::CustomUser
107
+ audited
108
+ end
109
+
110
+ it "should include audited classes" do
111
+ expect(Audited::Audit.audited_classes).to include(Models::ActiveRecord::User)
112
+ end
113
+
114
+ it "should include subclasses" do
115
+ expect(Audited::Audit.audited_classes).to include(Models::ActiveRecord::CustomUserSubclass)
116
+ end
117
+ end
118
+
119
+ describe "new_attributes" do
120
+ it "should return a hash of the new values" do
121
+ new_attributes = Audited::Audit.new(audited_changes: {a: [1, 2], b: [3, 4]}).new_attributes
122
+ expect(new_attributes).to eq({"a" => 2, "b" => 4})
123
+ end
124
+ end
125
+
126
+ describe "old_attributes" do
127
+ it "should return a hash of the old values" do
128
+ old_attributes = Audited::Audit.new(audited_changes: {a: [1, 2], b: [3, 4]}).old_attributes
129
+ expect(old_attributes).to eq({"a" => 1, "b" => 3})
130
+ end
131
+ end
132
+
133
+ describe "as_user" do
134
+ it "should record user objects" do
135
+ Audited::Audit.as_user(user) do
136
+ company = Models::ActiveRecord::Company.create name: "The auditors"
137
+ company.name = "The Auditors, Inc"
138
+ company.save
139
+
140
+ company.audits.each do |audit|
141
+ expect(audit.user).to eq(user)
142
+ end
143
+ end
144
+ end
145
+
146
+ it "should record usernames" do
147
+ Audited::Audit.as_user(user.name) do
148
+ company = Models::ActiveRecord::Company.create name: "The auditors"
149
+ company.name = "The Auditors, Inc"
150
+ company.save
151
+
152
+ company.audits.each do |audit|
153
+ expect(audit.username).to eq(user.name)
154
+ end
155
+ end
156
+ end
157
+
158
+ it "should be thread safe" do
159
+ begin
160
+ expect(user.save).to eq(true)
161
+
162
+ t1 = Thread.new do
163
+ Audited::Audit.as_user(user) do
164
+ sleep 1
165
+ expect(Models::ActiveRecord::Company.create(name: "The Auditors, Inc").audits.first.user).to eq(user)
166
+ end
167
+ end
168
+
169
+ t2 = Thread.new do
170
+ Audited::Audit.as_user(user.name) do
171
+ expect(Models::ActiveRecord::Company.create(name: "The Competing Auditors, LLC").audits.first.username).to eq(user.name)
172
+ sleep 0.5
173
+ end
174
+ end
175
+
176
+ t1.join
177
+ t2.join
178
+ end
179
+ end if ActiveRecord::Base.connection.adapter_name != 'SQLite'
180
+
181
+ it "should return the value from the yield block" do
182
+ result = Audited::Audit.as_user('foo') do
183
+ 42
184
+ end
185
+ expect(result).to eq(42)
186
+ end
187
+
188
+ it "should reset audited_user when the yield block raises an exception" do
189
+ expect {
190
+ Audited::Audit.as_user('foo') do
191
+ raise StandardError.new('expected')
192
+ end
193
+ }.to raise_exception('expected')
194
+ expect(Thread.current[:audited_user]).to be_nil
195
+ end
196
+
197
+ end
198
+
199
+ end
@@ -0,0 +1,607 @@
1
+ require "spec_helper"
2
+
3
+ describe Audited::Auditor do
4
+
5
+ describe "configuration" do
6
+ it "should include instance methods" do
7
+ expect(Models::ActiveRecord::User.new).to be_a_kind_of( Audited::Auditor::AuditedInstanceMethods)
8
+ end
9
+
10
+ it "should include class methods" do
11
+ expect(Models::ActiveRecord::User).to be_a_kind_of( Audited::Auditor::AuditedClassMethods )
12
+ end
13
+
14
+ ['created_at', 'updated_at', 'created_on', 'updated_on', 'lock_version', 'id', 'password'].each do |column|
15
+ it "should not audit #{column}" do
16
+ expect(Models::ActiveRecord::User.non_audited_columns).to include(column)
17
+ end
18
+ end
19
+
20
+ it "should be configurable which attributes are not audited" do
21
+ Audited.ignored_attributes = ['delta', 'top_secret', 'created_at']
22
+ class Secret < ::ActiveRecord::Base
23
+ audited
24
+ end
25
+
26
+ expect(Secret.non_audited_columns).to include('delta', 'top_secret', 'created_at')
27
+ end
28
+
29
+ it "should not save non-audited columns" do
30
+ expect(create_user.audits.first.audited_changes.keys.any? { |col| ['created_at', 'updated_at', 'password'].include?( col ) }).to eq(false)
31
+ end
32
+
33
+ it "should not save other columns than specified in 'only' option" do
34
+ user = Models::ActiveRecord::UserOnlyPassword.create
35
+ user.instance_eval do
36
+ def non_column_attr
37
+ @non_column_attr
38
+ end
39
+
40
+ def non_column_attr=(val)
41
+ attribute_will_change!("non_column_attr")
42
+ @non_column_attr = val
43
+ end
44
+ end
45
+
46
+ user.password = "password"
47
+ user.non_column_attr = "some value"
48
+ user.save!
49
+ expect(user.audits.last.audited_changes.keys).to eq(%w{password})
50
+ end
51
+ end
52
+
53
+ describe :new do
54
+ it "should allow mass assignment of all unprotected attributes" do
55
+ yesterday = 1.day.ago
56
+
57
+ u = Models::ActiveRecord::NoAttributeProtectionUser.new(name: 'name',
58
+ username: 'username',
59
+ password: 'password',
60
+ activated: true,
61
+ suspended_at: yesterday,
62
+ logins: 2)
63
+
64
+ expect(u.name).to eq('name')
65
+ expect(u.username).to eq('username')
66
+ expect(u.password).to eq('password')
67
+ expect(u.activated).to eq(true)
68
+ expect(u.suspended_at.to_i).to eq(yesterday.to_i)
69
+ expect(u.logins).to eq(2)
70
+ end
71
+ end
72
+
73
+ describe "on create" do
74
+ let( :user ) { create_user audit_comment: "Create" }
75
+
76
+ it "should change the audit count" do
77
+ expect {
78
+ user
79
+ }.to change( Audited::Audit, :count ).by(1)
80
+ end
81
+
82
+ it "should create associated audit" do
83
+ expect(user.audits.count).to eq(1)
84
+ end
85
+
86
+ it "should set the action to create" do
87
+ expect(user.audits.first.action).to eq('create')
88
+ expect(Audited::Audit.creates.order(:id).last).to eq(user.audits.first)
89
+ expect(user.audits.creates.count).to eq(1)
90
+ expect(user.audits.updates.count).to eq(0)
91
+ expect(user.audits.destroys.count).to eq(0)
92
+ end
93
+
94
+ it "should store all the audited attributes" do
95
+ expect(user.audits.first.audited_changes).to eq(user.audited_attributes)
96
+ end
97
+
98
+ it "should store comment" do
99
+ expect(user.audits.first.comment).to eq('Create')
100
+ end
101
+
102
+ it "should not audit an attribute which is excepted if specified on create or destroy" do
103
+ on_create_destroy_except_name = Models::ActiveRecord::OnCreateDestroyExceptName.create(name: 'Bart')
104
+ expect(on_create_destroy_except_name.audits.first.audited_changes.keys.any?{|col| ['name'].include? col}).to eq(false)
105
+ end
106
+
107
+ it "should not save an audit if only specified on update/destroy" do
108
+ expect {
109
+ Models::ActiveRecord::OnUpdateDestroy.create!( name: 'Bart' )
110
+ }.to_not change( Audited::Audit, :count )
111
+ end
112
+ end
113
+
114
+ describe "on update" do
115
+ before do
116
+ @user = create_user( name: 'Brandon', audit_comment: 'Update' )
117
+ end
118
+
119
+ it "should save an audit" do
120
+ expect {
121
+ @user.update_attribute(:name, "Someone")
122
+ }.to change( Audited::Audit, :count ).by(1)
123
+ expect {
124
+ @user.update_attribute(:name, "Someone else")
125
+ }.to change( Audited::Audit, :count ).by(1)
126
+ end
127
+
128
+ it "should set the action to 'update'" do
129
+ @user.update_attributes name: 'Changed'
130
+ expect(@user.audits.last.action).to eq('update')
131
+ expect(Audited::Audit.updates.order(:id).last).to eq(@user.audits.last)
132
+ expect(@user.audits.updates.last).to eq(@user.audits.last)
133
+ end
134
+
135
+ it "should store the changed attributes" do
136
+ @user.update_attributes name: 'Changed'
137
+ expect(@user.audits.last.audited_changes).to eq({ 'name' => ['Brandon', 'Changed'] })
138
+ end
139
+
140
+ it "should store audit comment" do
141
+ expect(@user.audits.last.comment).to eq('Update')
142
+ end
143
+
144
+ it "should not save an audit if only specified on create/destroy" do
145
+ on_create_destroy = Models::ActiveRecord::OnCreateDestroy.create( name: 'Bart' )
146
+ expect {
147
+ on_create_destroy.update_attributes name: 'Changed'
148
+ }.to_not change( Audited::Audit, :count )
149
+ end
150
+
151
+ it "should not save an audit if the value doesn't change after type casting" do
152
+ @user.update_attributes! logins: 0, activated: true
153
+ expect { @user.update_attribute :logins, '0' }.to_not change( Audited::Audit, :count )
154
+ expect { @user.update_attribute :activated, 1 }.to_not change( Audited::Audit, :count )
155
+ expect { @user.update_attribute :activated, '1' }.to_not change( Audited::Audit, :count )
156
+ end
157
+
158
+ describe "with no dirty changes" do
159
+ it "does not create an audit if the record is not changed" do
160
+ expect {
161
+ @user.save!
162
+ }.to_not change( Audited::Audit, :count )
163
+ end
164
+
165
+ it "creates an audit when an audit comment is present" do
166
+ expect {
167
+ @user.audit_comment = "Comment"
168
+ @user.save!
169
+ }.to change( Audited::Audit, :count )
170
+ end
171
+ end
172
+ end
173
+
174
+ describe "on destroy" do
175
+ before do
176
+ @user = create_user
177
+ end
178
+
179
+ it "should save an audit" do
180
+ expect {
181
+ @user.destroy
182
+ }.to change( Audited::Audit, :count )
183
+
184
+ expect(@user.audits.size).to eq(2)
185
+ end
186
+
187
+ it "should set the action to 'destroy'" do
188
+ @user.destroy
189
+
190
+ expect(@user.audits.last.action).to eq('destroy')
191
+ expect(Audited::Audit.destroys.order(:id).last).to eq(@user.audits.last)
192
+ expect(@user.audits.destroys.last).to eq(@user.audits.last)
193
+ end
194
+
195
+ it "should store all of the audited attributes" do
196
+ @user.destroy
197
+
198
+ expect(@user.audits.last.audited_changes).to eq(@user.audited_attributes)
199
+ end
200
+
201
+ it "should be able to reconstruct a destroyed record without history" do
202
+ @user.audits.delete_all
203
+ @user.destroy
204
+
205
+ revision = @user.audits.first.revision
206
+ expect(revision.name).to eq(@user.name)
207
+ end
208
+
209
+ it "should not save an audit if only specified on create/update" do
210
+ on_create_update = Models::ActiveRecord::OnCreateUpdate.create!( name: 'Bart' )
211
+
212
+ expect {
213
+ on_create_update.destroy
214
+ }.to_not change( Audited::Audit, :count )
215
+ end
216
+
217
+ it "should audit dependent destructions" do
218
+ owner = Models::ActiveRecord::Owner.create!
219
+ company = owner.companies.create!
220
+
221
+ expect {
222
+ owner.destroy
223
+ }.to change( Audited::Audit, :count )
224
+
225
+ expect(company.audits.map { |a| a.action }).to eq(['create', 'destroy'])
226
+ end
227
+ end
228
+
229
+ describe "on destroy with unsaved object" do
230
+ let(:user) { Models::ActiveRecord::User.new }
231
+
232
+ it "should not audit on 'destroy'" do
233
+ expect {
234
+ user.destroy
235
+ }.to_not raise_error
236
+
237
+ expect( user.audits ).to be_empty
238
+ end
239
+ end
240
+
241
+ describe "associated with" do
242
+ let(:owner) { Models::ActiveRecord::Owner.create(name: 'Models::ActiveRecord::Owner') }
243
+ let(:owned_company) { Models::ActiveRecord::OwnedCompany.create!(name: 'The auditors', owner: owner) }
244
+
245
+ it "should record the associated object on create" do
246
+ expect(owned_company.audits.first.associated).to eq(owner)
247
+ end
248
+
249
+ it "should store the associated object on update" do
250
+ owned_company.update_attribute(:name, 'The Auditors')
251
+ expect(owned_company.audits.last.associated).to eq(owner)
252
+ end
253
+
254
+ it "should store the associated object on destroy" do
255
+ owned_company.destroy
256
+ expect(owned_company.audits.last.associated).to eq(owner)
257
+ end
258
+ end
259
+
260
+ describe "has associated audits" do
261
+ let!(:owner) { Models::ActiveRecord::Owner.create!(name: 'Models::ActiveRecord::Owner') }
262
+ let!(:owned_company) { Models::ActiveRecord::OwnedCompany.create!(name: 'The auditors', owner: owner) }
263
+
264
+ it "should list the associated audits" do
265
+ expect(owner.associated_audits.length).to eq(1)
266
+ expect(owner.associated_audits.first.auditable).to eq(owned_company)
267
+ end
268
+ end
269
+
270
+ describe "revisions" do
271
+ let( :user ) { create_versions }
272
+
273
+ it "should return an Array of Users" do
274
+ expect(user.revisions).to be_a_kind_of( Array )
275
+ user.revisions.each { |version| expect(version).to be_a_kind_of Models::ActiveRecord::User }
276
+ end
277
+
278
+ it "should have one revision for a new record" do
279
+ expect(create_user.revisions.size).to eq(1)
280
+ end
281
+
282
+ it "should have one revision for each audit" do
283
+ expect(user.audits.size).to eql( user.revisions.size )
284
+ end
285
+
286
+ it "should set the attributes for each revision" do
287
+ u = Models::ActiveRecord::User.create(name: 'Brandon', username: 'brandon')
288
+ u.update_attributes name: 'Foobar'
289
+ u.update_attributes name: 'Awesome', username: 'keepers'
290
+
291
+ expect(u.revisions.size).to eql(3)
292
+
293
+ expect(u.revisions[0].name).to eql('Brandon')
294
+ expect(u.revisions[0].username).to eql('brandon')
295
+
296
+ expect(u.revisions[1].name).to eql('Foobar')
297
+ expect(u.revisions[1].username).to eql('brandon')
298
+
299
+ expect(u.revisions[2].name).to eql('Awesome')
300
+ expect(u.revisions[2].username).to eql('keepers')
301
+ end
302
+
303
+ it "access to only recent revisions" do
304
+ u = Models::ActiveRecord::User.create(name: 'Brandon', username: 'brandon')
305
+ u.update_attributes name: 'Foobar'
306
+ u.update_attributes name: 'Awesome', username: 'keepers'
307
+
308
+ expect(u.revisions(2).size).to eq(2)
309
+
310
+ expect(u.revisions(2)[0].name).to eq('Foobar')
311
+ expect(u.revisions(2)[0].username).to eq('brandon')
312
+
313
+ expect(u.revisions(2)[1].name).to eq('Awesome')
314
+ expect(u.revisions(2)[1].username).to eq('keepers')
315
+ end
316
+
317
+ it "should be empty if no audits exist" do
318
+ user.audits.delete_all
319
+ expect(user.revisions).to be_empty
320
+ end
321
+
322
+ it "should ignore attributes that have been deleted" do
323
+ user.audits.last.update_attributes audited_changes: {old_attribute: 'old value'}
324
+ expect { user.revisions }.to_not raise_error
325
+ end
326
+ end
327
+
328
+ describe "revisions" do
329
+ let( :user ) { create_versions(5) }
330
+
331
+ it "should maintain identity" do
332
+ expect(user.revision(1)).to eq(user)
333
+ end
334
+
335
+ it "should find the given revision" do
336
+ revision = user.revision(3)
337
+ expect(revision).to be_a_kind_of( Models::ActiveRecord::User )
338
+ expect(revision.version).to eq(3)
339
+ expect(revision.name).to eq('Foobar 3')
340
+ end
341
+
342
+ it "should find the previous revision with :previous" do
343
+ revision = user.revision(:previous)
344
+ expect(revision.version).to eq(4)
345
+ #expect(revision).to eq(user.revision(4))
346
+ expect(revision.attributes).to eq(user.revision(4).attributes)
347
+ end
348
+
349
+ it "should be able to get the previous revision repeatedly" do
350
+ previous = user.revision(:previous)
351
+ expect(previous.version).to eq(4)
352
+ expect(previous.revision(:previous).version).to eq(3)
353
+ end
354
+
355
+ it "should be able to set protected attributes" do
356
+ u = Models::ActiveRecord::User.create(name: 'Brandon')
357
+ u.update_attribute :logins, 1
358
+ u.update_attribute :logins, 2
359
+
360
+ expect(u.revision(3).logins).to eq(2)
361
+ expect(u.revision(2).logins).to eq(1)
362
+ expect(u.revision(1).logins).to eq(0)
363
+ end
364
+
365
+ it "should set attributes directly" do
366
+ u = Models::ActiveRecord::User.create(name: '<Joe>')
367
+ expect(u.revision(1).name).to eq('&lt;Joe&gt;')
368
+ end
369
+
370
+ it "should set the attributes for each revision" do
371
+ u = Models::ActiveRecord::User.create(name: 'Brandon', username: 'brandon')
372
+ u.update_attributes name: 'Foobar'
373
+ u.update_attributes name: 'Awesome', username: 'keepers'
374
+
375
+ expect(u.revision(3).name).to eq('Awesome')
376
+ expect(u.revision(3).username).to eq('keepers')
377
+
378
+ expect(u.revision(2).name).to eq('Foobar')
379
+ expect(u.revision(2).username).to eq('brandon')
380
+
381
+ expect(u.revision(1).name).to eq('Brandon')
382
+ expect(u.revision(1).username).to eq('brandon')
383
+ end
384
+
385
+ it "should be able to get time for first revision" do
386
+ suspended_at = Time.zone.now
387
+ u = Models::ActiveRecord::User.create(suspended_at: suspended_at)
388
+ expect(u.revision(1).suspended_at.to_s).to eq(suspended_at.to_s)
389
+ end
390
+
391
+ it "should not raise an error when no previous audits exist" do
392
+ user.audits.destroy_all
393
+ expect { user.revision(:previous) }.to_not raise_error
394
+ end
395
+
396
+ it "should mark revision's attributes as changed" do
397
+ expect(user.revision(1).name_changed?).to eq(true)
398
+ end
399
+
400
+ it "should record new audit when saving revision" do
401
+ expect {
402
+ user.revision(1).save!
403
+ }.to change( user.audits, :count ).by(1)
404
+ end
405
+
406
+ it "should re-insert destroyed records" do
407
+ user.destroy
408
+ expect {
409
+ user.revision(1).save!
410
+ }.to change( Models::ActiveRecord::User, :count ).by(1)
411
+ end
412
+ end
413
+
414
+ describe "revision_at" do
415
+ let( :user ) { create_user }
416
+
417
+ it "should find the latest revision before the given time" do
418
+ audit = user.audits.first
419
+ audit.created_at = 1.hour.ago
420
+ audit.save!
421
+ user.update_attributes name: 'updated'
422
+ expect(user.revision_at( 2.minutes.ago ).version).to eq(1)
423
+ end
424
+
425
+ it "should be nil if given a time before audits" do
426
+ expect(user.revision_at( 1.week.ago )).to be_nil
427
+ end
428
+ end
429
+
430
+ describe "without auditing" do
431
+ it "should not save an audit when calling #save_without_auditing" do
432
+ expect {
433
+ u = Models::ActiveRecord::User.new(name: 'Brandon')
434
+ expect(u.save_without_auditing).to eq(true)
435
+ }.to_not change( Audited::Audit, :count )
436
+ end
437
+
438
+ it "should not save an audit inside of the #without_auditing block" do
439
+ expect {
440
+ Models::ActiveRecord::User.without_auditing { Models::ActiveRecord::User.create!( name: 'Brandon' ) }
441
+ }.to_not change( Audited::Audit, :count )
442
+ end
443
+
444
+ it "should reset auditing status even it raises an exception" do
445
+ Models::ActiveRecord::User.without_auditing { raise } rescue nil
446
+ expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
447
+ end
448
+
449
+ it "should be thread safe using a #without_auditing block" do
450
+ begin
451
+ t1 = Thread.new do
452
+ expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
453
+ Models::ActiveRecord::User.without_auditing do
454
+ expect(Models::ActiveRecord::User.auditing_enabled).to eq(false)
455
+ Models::ActiveRecord::User.create!( name: 'Bart' )
456
+ sleep 1
457
+ expect(Models::ActiveRecord::User.auditing_enabled).to eq(false)
458
+ end
459
+ expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
460
+ end
461
+
462
+ t2 = Thread.new do
463
+ sleep 0.5
464
+ expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
465
+ Models::ActiveRecord::User.create!( name: 'Lisa' )
466
+ end
467
+ t1.join
468
+ t2.join
469
+
470
+ expect(Models::ActiveRecord::User.find_by_name('Bart').audits.count).to eq(0)
471
+ expect(Models::ActiveRecord::User.find_by_name('Lisa').audits.count).to eq(1)
472
+ rescue ActiveRecord::StatementInvalid
473
+ STDERR.puts "Thread safety tests cannot be run with SQLite"
474
+ end
475
+ end
476
+ end
477
+
478
+ describe "comment required" do
479
+
480
+ describe "on create" do
481
+ it "should not validate when audit_comment is not supplied" do
482
+ expect(Models::ActiveRecord::CommentRequiredUser.new).not_to be_valid
483
+ end
484
+
485
+ it "should validate when audit_comment is supplied" do
486
+ expect(Models::ActiveRecord::CommentRequiredUser.new( audit_comment: 'Create')).to be_valid
487
+ end
488
+
489
+ it "should validate when audit_comment is not supplied, and auditing is disabled" do
490
+ Models::ActiveRecord::CommentRequiredUser.disable_auditing
491
+ expect(Models::ActiveRecord::CommentRequiredUser.new).to be_valid
492
+ Models::ActiveRecord::CommentRequiredUser.enable_auditing
493
+ end
494
+ end
495
+
496
+ describe "on update" do
497
+ let( :user ) { Models::ActiveRecord::CommentRequiredUser.create!( audit_comment: 'Create' ) }
498
+
499
+ it "should not validate when audit_comment is not supplied" do
500
+ expect(user.update_attributes(name: 'Test')).to eq(false)
501
+ end
502
+
503
+ it "should validate when audit_comment is supplied" do
504
+ expect(user.update_attributes(name: 'Test', audit_comment: 'Update')).to eq(true)
505
+ end
506
+
507
+ it "should validate when audit_comment is not supplied, and auditing is disabled" do
508
+ Models::ActiveRecord::CommentRequiredUser.disable_auditing
509
+ expect(user.update_attributes(name: 'Test')).to eq(true)
510
+ Models::ActiveRecord::CommentRequiredUser.enable_auditing
511
+ end
512
+ end
513
+
514
+ describe "on destroy" do
515
+ let( :user ) { Models::ActiveRecord::CommentRequiredUser.create!( audit_comment: 'Create' )}
516
+
517
+ it "should not validate when audit_comment is not supplied" do
518
+ expect(user.destroy).to eq(false)
519
+ end
520
+
521
+ it "should validate when audit_comment is supplied" do
522
+ user.audit_comment = "Destroy"
523
+ expect(user.destroy).to eq(user)
524
+ end
525
+
526
+ it "should validate when audit_comment is not supplied, and auditing is disabled" do
527
+ Models::ActiveRecord::CommentRequiredUser.disable_auditing
528
+ expect(user.destroy).to eq(user)
529
+ Models::ActiveRecord::CommentRequiredUser.enable_auditing
530
+ end
531
+ end
532
+
533
+ end
534
+
535
+ describe "attr_protected and attr_accessible" do
536
+
537
+ it "should not raise error when attr_accessible is set and protected is false" do
538
+ expect {
539
+ Models::ActiveRecord::AccessibleAfterDeclarationUser.new(name: 'No fail!')
540
+ }.to_not raise_error
541
+ end
542
+
543
+ it "should not rause an error when attr_accessible is declared before audited" do
544
+ expect {
545
+ Models::ActiveRecord::AccessibleAfterDeclarationUser.new(name: 'No fail!')
546
+ }.to_not raise_error
547
+ end
548
+ end
549
+
550
+ describe "audit_as" do
551
+ let( :user ) { Models::ActiveRecord::User.create name: 'Testing' }
552
+
553
+ it "should record user objects" do
554
+ Models::ActiveRecord::Company.audit_as( user ) do
555
+ company = Models::ActiveRecord::Company.create name: 'The auditors'
556
+ company.update_attributes name: 'The Auditors'
557
+
558
+ company.audits.each do |audit|
559
+ expect(audit.user).to eq(user)
560
+ end
561
+ end
562
+ end
563
+
564
+ it "should record usernames" do
565
+ Models::ActiveRecord::Company.audit_as( user.name ) do
566
+ company = Models::ActiveRecord::Company.create name: 'The auditors'
567
+ company.update_attributes name: 'The Auditors'
568
+
569
+ company.audits.each do |audit|
570
+ expect(audit.user).to eq(user.name)
571
+ end
572
+ end
573
+ end
574
+ end
575
+
576
+ describe "after_audit" do
577
+ let( :user ) { user = Models::ActiveRecord::UserWithAfterAudit.new }
578
+
579
+ it "should invoke after_audit callback on create" do
580
+ expect(user.bogus_attr).to be_nil
581
+ expect(user.save).to eq(true)
582
+ expect(user.bogus_attr).to eq("do something")
583
+ end
584
+ end
585
+
586
+ describe "around_audit" do
587
+ let( :user ) { user = Models::ActiveRecord::UserWithAfterAudit.new }
588
+
589
+ it "should invoke around_audit callback on create" do
590
+ expect(user.around_attr).to be_nil
591
+ expect(user.save).to eq(true)
592
+ expect(user.around_attr).to eq(user.audits.last)
593
+ end
594
+ end
595
+
596
+ describe "STI auditing" do
597
+ it "should correctly disable auditing when using STI" do
598
+ company = Models::ActiveRecord::Company::STICompany.create name: 'The auditors'
599
+ expect(company.type).to eq("Models::ActiveRecord::Company::STICompany")
600
+ expect {
601
+ Models::ActiveRecord::Company.auditing_enabled = false
602
+ company.update_attributes name: 'STI auditors'
603
+ Models::ActiveRecord::Company.auditing_enabled = true
604
+ }.to_not change( Audited.audit_class, :count )
605
+ end
606
+ end
607
+ end