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