cia 0.5.7 → 0.5.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/cia/attribute_change.rb +3 -2
- data/lib/cia/event.rb +2 -1
- data/lib/cia/version.rb +1 -1
- metadata +116 -26
- checksums.yaml +0 -7
- data/.travis.yml +0 -12
- data/Appraisals +0 -8
- data/Gemfile +0 -10
- data/Gemfile.lock +0 -55
- data/MIGRATION.rb +0 -20
- data/Rakefile +0 -11
- data/Readme.md +0 -106
- data/cia.gemspec +0 -13
- data/gemfiles/rails2.gemfile +0 -14
- data/gemfiles/rails2.gemfile.lock +0 -45
- data/gemfiles/rails3.gemfile +0 -13
- data/gemfiles/rails3.gemfile.lock +0 -55
- data/spec/cia/attribute_change_spec.rb +0 -100
- data/spec/cia/event_spec.rb +0 -57
- data/spec/cia_spec.rb +0 -439
- data/spec/spec_helper.rb +0 -120
data/lib/cia/attribute_change.rb
CHANGED
@@ -11,7 +11,7 @@ module CIA
|
|
11
11
|
validates_presence_of :event, :attribute_name
|
12
12
|
|
13
13
|
if ActiveRecord::VERSION::MAJOR > 2
|
14
|
-
scope :previous,
|
14
|
+
scope :previous, lambda { order("id desc") }
|
15
15
|
else
|
16
16
|
named_scope :previous, :order => "id desc"
|
17
17
|
end
|
@@ -19,7 +19,8 @@ module CIA
|
|
19
19
|
delegate :created_at, :to => :event
|
20
20
|
|
21
21
|
def self.on_attribute(attribute)
|
22
|
-
|
22
|
+
conditions = {:attribute_name => attribute}
|
23
|
+
ActiveRecord::VERSION::MAJOR == 2 ? scoped(:conditions => conditions) : where(conditions)
|
23
24
|
end
|
24
25
|
|
25
26
|
def self.max_value_size
|
data/lib/cia/event.rb
CHANGED
data/lib/cia/version.rb
CHANGED
metadata
CHANGED
@@ -1,27 +1,126 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cia
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.8
|
5
|
+
prerelease:
|
5
6
|
platform: ruby
|
6
7
|
authors:
|
7
8
|
- Michael Grosser
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date:
|
12
|
+
date: 2014-09-03 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: json
|
15
16
|
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
16
18
|
requirements:
|
17
|
-
- - '>='
|
19
|
+
- - ! '>='
|
18
20
|
- !ruby/object:Gem::Version
|
19
21
|
version: '0'
|
20
22
|
type: :runtime
|
21
23
|
prerelease: false
|
22
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
23
26
|
requirements:
|
24
|
-
- - '>='
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: bump
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rspec
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '2'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '2'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: wwtd
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: activerecord
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: sqlite3
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
25
124
|
- !ruby/object:Gem::Version
|
26
125
|
version: '0'
|
27
126
|
description:
|
@@ -30,51 +129,42 @@ executables: []
|
|
30
129
|
extensions: []
|
31
130
|
extra_rdoc_files: []
|
32
131
|
files:
|
33
|
-
- .travis.yml
|
34
|
-
- Appraisals
|
35
|
-
- Gemfile
|
36
|
-
- Gemfile.lock
|
37
|
-
- MIGRATION.rb
|
38
|
-
- Rakefile
|
39
|
-
- Readme.md
|
40
|
-
- cia.gemspec
|
41
|
-
- gemfiles/rails2.gemfile
|
42
|
-
- gemfiles/rails2.gemfile.lock
|
43
|
-
- gemfiles/rails3.gemfile
|
44
|
-
- gemfiles/rails3.gemfile.lock
|
45
132
|
- lib/cia.rb
|
46
133
|
- lib/cia/attribute_change.rb
|
47
134
|
- lib/cia/auditable.rb
|
48
135
|
- lib/cia/event.rb
|
49
136
|
- lib/cia/source_validation.rb
|
50
137
|
- lib/cia/version.rb
|
51
|
-
|
52
|
-
- spec/cia/event_spec.rb
|
53
|
-
- spec/cia_spec.rb
|
54
|
-
- spec/spec_helper.rb
|
55
|
-
homepage: http://github.com/grosser/cia
|
138
|
+
homepage: https://github.com/grosser/cia
|
56
139
|
licenses:
|
57
140
|
- MIT
|
58
|
-
metadata: {}
|
59
141
|
post_install_message:
|
60
142
|
rdoc_options: []
|
61
143
|
require_paths:
|
62
144
|
- lib
|
63
145
|
required_ruby_version: !ruby/object:Gem::Requirement
|
146
|
+
none: false
|
64
147
|
requirements:
|
65
|
-
- - '>='
|
148
|
+
- - ! '>='
|
66
149
|
- !ruby/object:Gem::Version
|
67
150
|
version: '0'
|
151
|
+
segments:
|
152
|
+
- 0
|
153
|
+
hash: 3646470647389073675
|
68
154
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
155
|
+
none: false
|
69
156
|
requirements:
|
70
|
-
- - '>='
|
157
|
+
- - ! '>='
|
71
158
|
- !ruby/object:Gem::Version
|
72
159
|
version: '0'
|
160
|
+
segments:
|
161
|
+
- 0
|
162
|
+
hash: 3646470647389073675
|
73
163
|
requirements: []
|
74
164
|
rubyforge_project:
|
75
|
-
rubygems_version:
|
165
|
+
rubygems_version: 1.8.23
|
76
166
|
signing_key:
|
77
|
-
specification_version:
|
167
|
+
specification_version: 3
|
78
168
|
summary: Audit model events like update/create/delete + attribute changes + group
|
79
169
|
them by transaction, in normalized table layout for easy query access.
|
80
170
|
test_files: []
|
checksums.yaml
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
---
|
2
|
-
SHA1:
|
3
|
-
metadata.gz: 095757bdffb2cf6dd9966a37562bd4a61958fd20
|
4
|
-
data.tar.gz: d01a2b7a29c0791224934dcf4a012a20cc60c512
|
5
|
-
SHA512:
|
6
|
-
metadata.gz: 377d5103d09854f5dac67ae4fcc9e84ee3bc94ec51519a19b5dfa97b3482bb15198dda28a543121eb5a44ff6a765b947c95f045982e080b90aa978c46a6d6a55
|
7
|
-
data.tar.gz: 4d940a36f27b7108e609509ae6b76d8eba745b33f59cb634ac5b1ec0530a85d056ab4857a63e133b1fb5f0f4d884c096705a4c5b255844c1c5b6a743785b64d6
|
data/.travis.yml
DELETED
data/Appraisals
DELETED
data/Gemfile
DELETED
data/Gemfile.lock
DELETED
@@ -1,55 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
cia (0.5.7)
|
5
|
-
json
|
6
|
-
|
7
|
-
GEM
|
8
|
-
remote: https://rubygems.org/
|
9
|
-
specs:
|
10
|
-
activemodel (3.2.11)
|
11
|
-
activesupport (= 3.2.11)
|
12
|
-
builder (~> 3.0.0)
|
13
|
-
activerecord (3.2.11)
|
14
|
-
activemodel (= 3.2.11)
|
15
|
-
activesupport (= 3.2.11)
|
16
|
-
arel (~> 3.0.2)
|
17
|
-
tzinfo (~> 0.3.29)
|
18
|
-
activesupport (3.2.11)
|
19
|
-
i18n (~> 0.6)
|
20
|
-
multi_json (~> 1.0)
|
21
|
-
appraisal (0.5.1)
|
22
|
-
bundler
|
23
|
-
rake
|
24
|
-
arel (3.0.2)
|
25
|
-
builder (3.0.4)
|
26
|
-
bump (0.3.9)
|
27
|
-
diff-lcs (1.1.3)
|
28
|
-
i18n (0.6.1)
|
29
|
-
json (1.8.1)
|
30
|
-
multi_json (1.5.0)
|
31
|
-
rake (10.0.3)
|
32
|
-
rspec (2.12.0)
|
33
|
-
rspec-core (~> 2.12.0)
|
34
|
-
rspec-expectations (~> 2.12.0)
|
35
|
-
rspec-mocks (~> 2.12.0)
|
36
|
-
rspec-core (2.12.2)
|
37
|
-
rspec-expectations (2.12.1)
|
38
|
-
diff-lcs (~> 1.1.3)
|
39
|
-
rspec-mocks (2.12.1)
|
40
|
-
sqlite3 (1.3.6)
|
41
|
-
tzinfo (0.3.35)
|
42
|
-
wwtd (0.4.4)
|
43
|
-
|
44
|
-
PLATFORMS
|
45
|
-
ruby
|
46
|
-
|
47
|
-
DEPENDENCIES
|
48
|
-
activerecord
|
49
|
-
appraisal
|
50
|
-
bump
|
51
|
-
cia!
|
52
|
-
rake
|
53
|
-
rspec (~> 2)
|
54
|
-
sqlite3
|
55
|
-
wwtd
|
data/MIGRATION.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
create_table :cia_events do |t|
|
2
|
-
t.integer :actor_id
|
3
|
-
t.string :actor_type
|
4
|
-
t.string :source_type, :action, :null => false
|
5
|
-
t.integer :source_id, :null => false
|
6
|
-
t.string :ip_address
|
7
|
-
t.string :message
|
8
|
-
t.string :source_display_name
|
9
|
-
t.timestamp :created_at#, :null => false
|
10
|
-
end
|
11
|
-
|
12
|
-
create_table :cia_attribute_changes do |t|
|
13
|
-
t.integer :cia_event_id, :source_id, :null => false
|
14
|
-
t.string :attribute_name, :source_type, :null => false
|
15
|
-
t.string :old_value, :new_value
|
16
|
-
end
|
17
|
-
|
18
|
-
# DOWN
|
19
|
-
# drop_table :cia_events
|
20
|
-
# drop_table :cia_attribute_changes
|
data/Rakefile
DELETED
data/Readme.md
DELETED
@@ -1,106 +0,0 @@
|
|
1
|
-
Central Internal Auditing
|
2
|
-
============================
|
3
|
-
|
4
|
-
Audit model actions like update/create/destroy/<custom> + attribute changes.
|
5
|
-
|
6
|
-
- normalized and queryable through table layout
|
7
|
-
- actors and subjects are polymorphic
|
8
|
-
- works on ActiveRecord 2 and 3
|
9
|
-
|
10
|
-
Table layout:
|
11
|
-
|
12
|
-
Event (actor/ip/time/updated subject + message)
|
13
|
-
-> has many attribute changes (changed password from foo to bar on subject)
|
14
|
-
|
15
|
-
|
16
|
-
Install
|
17
|
-
=======
|
18
|
-
gem install cia
|
19
|
-
Or
|
20
|
-
|
21
|
-
rails plugin install git://github.com/grosser/cia.git
|
22
|
-
|
23
|
-
`rails g migration add_cia` + paste [Migration](https://raw.github.com/grosser/cia/master/MIGRATION.rb)
|
24
|
-
|
25
|
-
|
26
|
-
Usage
|
27
|
-
=====
|
28
|
-
|
29
|
-
```Ruby
|
30
|
-
class User < ActiveRecord::Base
|
31
|
-
include CIA::Auditable
|
32
|
-
audited_attributes :email, :crypted_password
|
33
|
-
end
|
34
|
-
|
35
|
-
class ApplicationController < ActionController::Base
|
36
|
-
around_filter :scope_auditing
|
37
|
-
|
38
|
-
def scope_auditing
|
39
|
-
CIA.audit :actor => current_user, :ip_address => request.remote_ip do
|
40
|
-
yield
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
# quick access
|
46
|
-
User.last.cia_events
|
47
|
-
changes = User.last.cia_attribute_changes
|
48
|
-
last_passwords = changes.where(:attribute_name => "crypted_password").map(&:new_value)
|
49
|
-
|
50
|
-
# exceptions (raised by default)
|
51
|
-
CIA.exception_handler = lambda{|e| raise e unless Rails.env.production? }
|
52
|
-
|
53
|
-
# conditional auditing
|
54
|
-
class User < ActiveRecord::Base
|
55
|
-
audited_attributes :email, :if => :interesting?
|
56
|
-
|
57
|
-
def interesting?
|
58
|
-
...
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
# adding an actor e.g. for user creation
|
63
|
-
CIA.current_actor = @user
|
64
|
-
|
65
|
-
# custom changes
|
66
|
-
class User < ActiveRecord::Base
|
67
|
-
def cia_changes
|
68
|
-
changes.merge("this" => ["always", "changes"])
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
# using after_commit, useful if the CIA::Event is stored in a different database then the audited class
|
73
|
-
class User < ActiveRecord::Base
|
74
|
-
include CIA::Auditable
|
75
|
-
audited_attributes :email, :crypted_password, :callback => :after_commit
|
76
|
-
end
|
77
|
-
|
78
|
-
# passing arbitrary attributes into the .audit method
|
79
|
-
CIA.non_recordable_attributes = [:my_pretty_audit_property]
|
80
|
-
CIA.audit(:actor => current_user, :my_pretty_audit_property => "12345") do
|
81
|
-
...
|
82
|
-
end
|
83
|
-
|
84
|
-
# storing complex objects in old/new and reducing it's size if it's to big (serialized via json)
|
85
|
-
value = CIA::AttributeChange.serialize_for_storage(["some", "complex"*1000, "object"]){|too_big| too_big.delete_at(1); too_big }
|
86
|
-
CIA::AttributeChange.create!(:old_value => value)
|
87
|
-
|
88
|
-
# add something to current transaction or start a new audit
|
89
|
-
CIA.audit :bar => :baz, :foo => :bang do
|
90
|
-
CIA.amend_audit :foo => :bar do
|
91
|
-
puts CIA.current_transaction
|
92
|
-
end
|
93
|
-
end
|
94
|
-
-> {:foo => :bar, :bar => :baz}
|
95
|
-
```
|
96
|
-
|
97
|
-
|
98
|
-
# TODO
|
99
|
-
- reuse AR3+ previous_changes in a nice way
|
100
|
-
|
101
|
-
Author
|
102
|
-
======
|
103
|
-
[Michael Grosser](http://grosser.it)<br/>
|
104
|
-
michael@grosser.it<br/>
|
105
|
-
License: MIT<br/>
|
106
|
-
[](http://travis-ci.org/grosser/cia)
|
data/cia.gemspec
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
$LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
|
2
|
-
name = "cia"
|
3
|
-
require "#{name}/version"
|
4
|
-
|
5
|
-
Gem::Specification.new name, CIA::VERSION do |s|
|
6
|
-
s.summary = "Audit model events like update/create/delete + attribute changes + group them by transaction, in normalized table layout for easy query access."
|
7
|
-
s.authors = ["Michael Grosser"]
|
8
|
-
s.email = "michael@grosser.it"
|
9
|
-
s.homepage = "http://github.com/grosser/#{name}"
|
10
|
-
s.files = `git ls-files`.split("\n")
|
11
|
-
s.license = 'MIT'
|
12
|
-
s.add_runtime_dependency "json"
|
13
|
-
end
|
data/gemfiles/rails2.gemfile
DELETED
@@ -1,45 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: ../
|
3
|
-
specs:
|
4
|
-
cia (0.5.6)
|
5
|
-
json
|
6
|
-
|
7
|
-
GEM
|
8
|
-
remote: https://rubygems.org/
|
9
|
-
specs:
|
10
|
-
activerecord (2.3.14)
|
11
|
-
activesupport (= 2.3.14)
|
12
|
-
activesupport (2.3.14)
|
13
|
-
after_commit (1.0.10)
|
14
|
-
activerecord (>= 1.15.6, < 3.0.0)
|
15
|
-
appraisal (0.4.1)
|
16
|
-
bundler
|
17
|
-
rake
|
18
|
-
bump (0.3.9)
|
19
|
-
diff-lcs (1.1.3)
|
20
|
-
json (1.8.1)
|
21
|
-
rake (0.9.2.2)
|
22
|
-
rspec (2.10.0)
|
23
|
-
rspec-core (~> 2.10.0)
|
24
|
-
rspec-expectations (~> 2.10.0)
|
25
|
-
rspec-mocks (~> 2.10.0)
|
26
|
-
rspec-core (2.10.1)
|
27
|
-
rspec-expectations (2.10.0)
|
28
|
-
diff-lcs (~> 1.1.3)
|
29
|
-
rspec-mocks (2.10.1)
|
30
|
-
sqlite3 (1.3.6)
|
31
|
-
wwtd (0.4.4)
|
32
|
-
|
33
|
-
PLATFORMS
|
34
|
-
ruby
|
35
|
-
|
36
|
-
DEPENDENCIES
|
37
|
-
activerecord (= 2.3.14)
|
38
|
-
after_commit
|
39
|
-
appraisal
|
40
|
-
bump
|
41
|
-
cia!
|
42
|
-
rake
|
43
|
-
rspec (~> 2)
|
44
|
-
sqlite3
|
45
|
-
wwtd
|
data/gemfiles/rails3.gemfile
DELETED
@@ -1,55 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: ../
|
3
|
-
specs:
|
4
|
-
cia (0.5.6)
|
5
|
-
json
|
6
|
-
|
7
|
-
GEM
|
8
|
-
remote: https://rubygems.org/
|
9
|
-
specs:
|
10
|
-
activemodel (3.2.3)
|
11
|
-
activesupport (= 3.2.3)
|
12
|
-
builder (~> 3.0.0)
|
13
|
-
activerecord (3.2.3)
|
14
|
-
activemodel (= 3.2.3)
|
15
|
-
activesupport (= 3.2.3)
|
16
|
-
arel (~> 3.0.2)
|
17
|
-
tzinfo (~> 0.3.29)
|
18
|
-
activesupport (3.2.3)
|
19
|
-
i18n (~> 0.6)
|
20
|
-
multi_json (~> 1.0)
|
21
|
-
appraisal (0.5.1)
|
22
|
-
bundler
|
23
|
-
rake
|
24
|
-
arel (3.0.2)
|
25
|
-
builder (3.0.4)
|
26
|
-
bump (0.3.9)
|
27
|
-
diff-lcs (1.1.3)
|
28
|
-
i18n (0.6.1)
|
29
|
-
json (1.8.1)
|
30
|
-
multi_json (1.5.0)
|
31
|
-
rake (10.0.3)
|
32
|
-
rspec (2.12.0)
|
33
|
-
rspec-core (~> 2.12.0)
|
34
|
-
rspec-expectations (~> 2.12.0)
|
35
|
-
rspec-mocks (~> 2.12.0)
|
36
|
-
rspec-core (2.12.2)
|
37
|
-
rspec-expectations (2.12.1)
|
38
|
-
diff-lcs (~> 1.1.3)
|
39
|
-
rspec-mocks (2.12.1)
|
40
|
-
sqlite3 (1.3.6)
|
41
|
-
tzinfo (0.3.35)
|
42
|
-
wwtd (0.4.4)
|
43
|
-
|
44
|
-
PLATFORMS
|
45
|
-
ruby
|
46
|
-
|
47
|
-
DEPENDENCIES
|
48
|
-
activerecord (= 3.2.3)
|
49
|
-
appraisal
|
50
|
-
bump
|
51
|
-
cia!
|
52
|
-
rake
|
53
|
-
rspec (~> 2)
|
54
|
-
sqlite3
|
55
|
-
wwtd
|
@@ -1,100 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
require 'spec_helper'
|
3
|
-
|
4
|
-
describe CIA::AttributeChange do
|
5
|
-
it "stores times as db format" do
|
6
|
-
t = Time.now
|
7
|
-
create_change(:old_value => t).reload.old_value.sub(/\.\d+$/,'').should == t.to_s(:db)
|
8
|
-
end
|
9
|
-
|
10
|
-
it "stores dates as db format" do
|
11
|
-
create_change(:old_value => Date.new(2012)).reload.old_value.should == "2012-01-01"
|
12
|
-
end
|
13
|
-
|
14
|
-
it "stores booleans as db format" do
|
15
|
-
create_change(:old_value => false).reload.old_value.should == "f"
|
16
|
-
create_change(:old_value => true).reload.old_value.should == "t"
|
17
|
-
end
|
18
|
-
|
19
|
-
it "stores nil as nil" do
|
20
|
-
create_change(:old_value => nil).reload.old_value.should == nil
|
21
|
-
end
|
22
|
-
|
23
|
-
it "delegates create_at to event" do
|
24
|
-
t = Time.now
|
25
|
-
event = CIA::Event.new(:created_at => t)
|
26
|
-
change = CIA::AttributeChange.new(:event => event)
|
27
|
-
change.created_at.should == event.created_at
|
28
|
-
end
|
29
|
-
|
30
|
-
describe ".previous" do
|
31
|
-
it "finds by id desc" do
|
32
|
-
CIA::AttributeChange.delete_all
|
33
|
-
a = create_change
|
34
|
-
b = create_change
|
35
|
-
CIA::AttributeChange.previous.should == [b,a]
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
describe ".on_attribute" do
|
40
|
-
it "finds with attribute" do
|
41
|
-
a = create_change :attribute_name => :xxx
|
42
|
-
b = create_change :attribute_name => :yyy
|
43
|
-
CIA::AttributeChange.on_attribute(:xxx).all.should == [a]
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
describe "enforcing presence of source" do
|
48
|
-
it "requires a source when associated event requires a source" do
|
49
|
-
event = CIA::Event.new { |event| event.id = 1 }
|
50
|
-
event.stub(:source_must_be_present? => true)
|
51
|
-
change = CIA::AttributeChange.new(:event => event, :attribute_name => 'awesomeness')
|
52
|
-
|
53
|
-
change.valid?.should be_false
|
54
|
-
change.errors.full_messages.should =~ ["Source can't be blank"]
|
55
|
-
end
|
56
|
-
|
57
|
-
it "does not require a source when associated event does not" do
|
58
|
-
event = CIA::Event.new { |event| event.id = 1 }
|
59
|
-
event.stub(:source_must_be_present? => false)
|
60
|
-
change = CIA::AttributeChange.new(:event => event, :attribute_name => 'awesomeness',
|
61
|
-
:source_type => 'ObscureType', :source_id => 101)
|
62
|
-
|
63
|
-
change.valid?.should be_true
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
describe ".max_value_size" do
|
68
|
-
it "is the width of the old/new column" do
|
69
|
-
CIA::AttributeChange.max_value_size.should == 255
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
describe ".serialize_for_storage" do
|
74
|
-
it "stores as json" do
|
75
|
-
CIA::AttributeChange.serialize_for_storage([["xxx"]]){}.should == '[["xxx"]]'
|
76
|
-
end
|
77
|
-
|
78
|
-
it "calls the block to remove an item" do
|
79
|
-
CIA::AttributeChange.serialize_for_storage([["xxx"], ["x"*300], ["yyy"]]){ |array| array.delete_at(1); array }.should == '[["xxx"],["yyy"]]'
|
80
|
-
end
|
81
|
-
|
82
|
-
it "blows up if block fails to reduce size to prevent loops" do
|
83
|
-
expect{
|
84
|
-
CIA::AttributeChange.serialize_for_storage([["xxx"], ["x"*300], ["yyy"]]){ |array| array }
|
85
|
-
}.to raise_error
|
86
|
-
end
|
87
|
-
|
88
|
-
it "takes multibyte into account" do
|
89
|
-
called = false
|
90
|
-
CIA::AttributeChange.serialize_for_storage(["å" * 200]){ |array| called = true; "x" }
|
91
|
-
called.should == true
|
92
|
-
end
|
93
|
-
|
94
|
-
it "does not go crazy on multibytes" do
|
95
|
-
called = false
|
96
|
-
CIA::AttributeChange.serialize_for_storage(["å" * 100]){ |array| called = true; "x" }
|
97
|
-
called.should == false
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
data/spec/cia/event_spec.rb
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe CIA::Event do
|
4
|
-
it "has many attribute_changes" do
|
5
|
-
change = create_change
|
6
|
-
change.event.attribute_changes.should == [change]
|
7
|
-
change.event.destroy
|
8
|
-
expect{ change.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
9
|
-
end
|
10
|
-
|
11
|
-
context "attribute_change_hash" do
|
12
|
-
it "is empty for empty changes" do
|
13
|
-
create_event.attribute_change_hash.should == {}
|
14
|
-
end
|
15
|
-
|
16
|
-
it "contains all changes" do
|
17
|
-
change = create_change(:old_value => "a", :new_value => "b")
|
18
|
-
change = create_change(:attribute_name => "foo", :old_value => "b", :new_value => nil, :event => change.event)
|
19
|
-
change.event.attribute_change_hash.should == {"bar" => ["a", "b"], "foo" => ["b", nil]}
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
context ".previous" do
|
24
|
-
it "is sorted id desc" do
|
25
|
-
events = [create_event(:created_at => 3.days.ago), create_event(:created_at => 2.days.ago), create_event(:created_at => 1.day.ago)].map(&:id)
|
26
|
-
CIA::Event.previous.map(&:id).should == events.reverse
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
context "validations" do
|
31
|
-
let(:source_attributes){ {:source => nil, :source_id => 99999, :source_type => "Car"} }
|
32
|
-
|
33
|
-
it "validates source" do
|
34
|
-
expect{
|
35
|
-
create_event(source_attributes)
|
36
|
-
}.to raise_error
|
37
|
-
end
|
38
|
-
|
39
|
-
it "does not validates source when action is destroy" do
|
40
|
-
create_event(source_attributes.merge(:action => "destroy"))
|
41
|
-
end
|
42
|
-
|
43
|
-
it "does not validates source when updating" do
|
44
|
-
create_event.update_attributes!(:source_id => 9999)
|
45
|
-
end
|
46
|
-
|
47
|
-
it "does not validates source when source_display_name is present" do
|
48
|
-
create_event(:source => nil, :source_id => -111, :source_type => 'FakeTypeHere', :source_display_name => 'abc')
|
49
|
-
end
|
50
|
-
|
51
|
-
it "validates source when source_display_name is blank" do
|
52
|
-
expect{
|
53
|
-
create_event(:source => nil, :source_id => -111, :source_type => 'FakeTypeHere', :source_display_name => '')
|
54
|
-
}.to raise_error
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
data/spec/cia_spec.rb
DELETED
@@ -1,439 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe CIA do
|
4
|
-
it "has a VERSION" do
|
5
|
-
CIA::VERSION.should =~ /^[\.\da-z]+$/
|
6
|
-
end
|
7
|
-
|
8
|
-
describe ".audit" do
|
9
|
-
it "has no transaction when it starts" do
|
10
|
-
CIA.current_transaction.should == nil
|
11
|
-
end
|
12
|
-
|
13
|
-
it "starts a new transaction" do
|
14
|
-
result = 1
|
15
|
-
CIA.audit({:a => 1}) do
|
16
|
-
result = CIA.current_transaction
|
17
|
-
end
|
18
|
-
result.should == {:a => 1}
|
19
|
-
end
|
20
|
-
|
21
|
-
it "stops the transaction after the block" do
|
22
|
-
CIA.audit({}){}
|
23
|
-
CIA.current_transaction.should == nil
|
24
|
-
end
|
25
|
-
|
26
|
-
it "returns the block content" do
|
27
|
-
CIA.audit({}){ 1 }.should == 1
|
28
|
-
end
|
29
|
-
|
30
|
-
it "is threadsafe" do
|
31
|
-
Thread.new do
|
32
|
-
CIA.audit({}) do
|
33
|
-
sleep 0.04
|
34
|
-
end
|
35
|
-
end
|
36
|
-
sleep 0.01
|
37
|
-
CIA.current_transaction.should == nil
|
38
|
-
sleep 0.04 # so next tests dont fail
|
39
|
-
end
|
40
|
-
|
41
|
-
it "can stack" do
|
42
|
-
states = []
|
43
|
-
CIA.audit(:a => 1) do
|
44
|
-
states << CIA.current_transaction
|
45
|
-
CIA.audit(:b => 1) do
|
46
|
-
states << CIA.current_transaction
|
47
|
-
end
|
48
|
-
states << CIA.current_transaction
|
49
|
-
end
|
50
|
-
states << CIA.current_transaction
|
51
|
-
states.should == [{:a => 1}, {:b => 1}, {:a => 1}, nil]
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
describe ".amend_audit" do
|
56
|
-
it "opens a new transaction when none exists" do
|
57
|
-
t = nil
|
58
|
-
CIA.amend_audit(:actor => 111){ t = CIA.current_transaction }
|
59
|
-
t.should == {:actor => 111}
|
60
|
-
end
|
61
|
-
|
62
|
-
it "amends a running transaction" do
|
63
|
-
t = nil
|
64
|
-
CIA.amend_audit(:actor => 222, :ip_address => 123) do
|
65
|
-
CIA.amend_audit(:actor => 111) { t = CIA.current_transaction }
|
66
|
-
end
|
67
|
-
t.should == {:actor => 111, :ip_address => 123}
|
68
|
-
end
|
69
|
-
|
70
|
-
it "returns to old state after transaction" do
|
71
|
-
CIA.amend_audit(:actor => 222, :ip_address => 123) do
|
72
|
-
CIA.amend_audit(:actor => 111) { }
|
73
|
-
end
|
74
|
-
CIA.current_transaction.should == nil
|
75
|
-
|
76
|
-
CIA.amend_audit(:actor => 111) { }
|
77
|
-
CIA.current_transaction.should == nil
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
describe ".record" do
|
82
|
-
let(:object) { Car.new }
|
83
|
-
|
84
|
-
around do |example|
|
85
|
-
CIA.audit :actor => User.create! do
|
86
|
-
example.call
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
it "tracks create" do
|
91
|
-
expect{
|
92
|
-
object.save!
|
93
|
-
}.to change{ CIA::Event.count }.by(+1)
|
94
|
-
CIA::Event.last.action.should == "create"
|
95
|
-
end
|
96
|
-
|
97
|
-
it "tracks delete" do
|
98
|
-
object.save!
|
99
|
-
expect{
|
100
|
-
object.destroy
|
101
|
-
}.to change{ CIA::Event.count }.by(+1)
|
102
|
-
CIA::Event.last.action.should == "destroy"
|
103
|
-
end
|
104
|
-
|
105
|
-
it "tracks update" do
|
106
|
-
object.save!
|
107
|
-
expect{
|
108
|
-
object.update_attributes(:wheels => 3)
|
109
|
-
}.to change{ CIA::Event.count }.by(+1)
|
110
|
-
CIA::Event.last.action.should == "update"
|
111
|
-
end
|
112
|
-
|
113
|
-
it "does not track failed changes" do
|
114
|
-
car = Car.create!(:wheels => 1).id
|
115
|
-
expect{
|
116
|
-
expect{ FailCar.new(:wheels => 4).save }.to raise_error(FailCar::Oops)
|
117
|
-
car = FailCar.find(car)
|
118
|
-
expect{ car.update_attributes(:wheels => 2) }.to raise_error(FailCar::Oops)
|
119
|
-
expect{ car.destroy }.to raise_error(FailCar::Oops)
|
120
|
-
}.to_not change{ CIA::Event.count }
|
121
|
-
end
|
122
|
-
|
123
|
-
it "is rolled back if auditing fails" do
|
124
|
-
CIA.should_receive(:record).and_raise("XXX")
|
125
|
-
expect{
|
126
|
-
expect{
|
127
|
-
CIA.audit{ object.save! }
|
128
|
-
}.to raise_error("XXX")
|
129
|
-
}.to_not change{ object.class.count }
|
130
|
-
end
|
131
|
-
|
132
|
-
it "is ok with non-attribute methods passed into .audit if they are set as non-recordable" do
|
133
|
-
CIA.non_recordable_attributes = [:foo]
|
134
|
-
expect {
|
135
|
-
CIA.audit(:actor => User.create!, :foo => 'bar') {
|
136
|
-
object.save!
|
137
|
-
}
|
138
|
-
}.to change{ CIA::Event.count }.by(+1)
|
139
|
-
end
|
140
|
-
|
141
|
-
context "nested classes with multiple audited_attributes" do
|
142
|
-
let(:object){ NestedCar.new }
|
143
|
-
|
144
|
-
it "has the exclusive sub-classes attributes of the nested class" do
|
145
|
-
object.class.audited_attributes.should == ["drivers"]
|
146
|
-
end
|
147
|
-
|
148
|
-
it "does not record twice for nested classes" do
|
149
|
-
expect{
|
150
|
-
CIA.audit{ object.save! }
|
151
|
-
}.to change{ CIA::Event.count }.by(+1)
|
152
|
-
end
|
153
|
-
|
154
|
-
it "does not record twice for super classes" do
|
155
|
-
expect{
|
156
|
-
CIA.audit{ Car.new.save! }
|
157
|
-
}.to change{ CIA::Event.count }.by(+1)
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
context "nested classes with 1 audited_attributes" do
|
162
|
-
let(:object){ InheritedCar.new }
|
163
|
-
|
164
|
-
it "has the super-classes attributes" do
|
165
|
-
object.class.audited_attributes.should == ["wheels"]
|
166
|
-
end
|
167
|
-
|
168
|
-
it "does not record twice for nested classes" do
|
169
|
-
expect{
|
170
|
-
CIA.audit{ object.save! }
|
171
|
-
}.to change{ CIA::Event.count }.by(+1)
|
172
|
-
end
|
173
|
-
|
174
|
-
it "does not record twice for super classes" do
|
175
|
-
expect{
|
176
|
-
CIA.audit{ Car.new.save! }
|
177
|
-
}.to change{ CIA::Event.count }.by(+1)
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
|
-
context "custom changes" do
|
182
|
-
let(:object) { CarWithCustomChanges.new }
|
183
|
-
|
184
|
-
it "tracks custom changes" do
|
185
|
-
object.save!
|
186
|
-
expect{
|
187
|
-
object.update_attributes(:wheels => 3)
|
188
|
-
}.to change{ CIA::Event.count }.by(+1)
|
189
|
-
CIA::Event.last.action.should == "update"
|
190
|
-
CIA::Event.last.attribute_change_hash.should == {
|
191
|
-
"wheels" => [nil, "3"],
|
192
|
-
"foo" => ["bar", "baz"]
|
193
|
-
}
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
context ":if" do
|
198
|
-
let(:object) { CarWithIf.new }
|
199
|
-
|
200
|
-
it "tracks if :if is true" do
|
201
|
-
expect{
|
202
|
-
object.tested = true
|
203
|
-
object.save!
|
204
|
-
}.to change{ CIA::Event.count }.by(+1)
|
205
|
-
CIA::Event.last.action.should == "create"
|
206
|
-
end
|
207
|
-
|
208
|
-
it "does not track if :if is false" do
|
209
|
-
expect{
|
210
|
-
object.save!
|
211
|
-
}.to_not change{ CIA::Event.count }
|
212
|
-
CIA::Event.last.should == nil
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
context ":unless" do
|
217
|
-
let(:object) { CarWithUnless.new }
|
218
|
-
|
219
|
-
it "tracks if :unless is false" do
|
220
|
-
expect{
|
221
|
-
object.save!
|
222
|
-
}.to change{ CIA::Event.count }.by(+1)
|
223
|
-
CIA::Event.last.action.should == "create"
|
224
|
-
end
|
225
|
-
|
226
|
-
it "does not track if :unless is true" do
|
227
|
-
expect{
|
228
|
-
object.tested = true
|
229
|
-
object.save!
|
230
|
-
}.to_not change{ CIA::Event.count }
|
231
|
-
CIA::Event.last.should == nil
|
232
|
-
end
|
233
|
-
end
|
234
|
-
|
235
|
-
context "events" do
|
236
|
-
def parse_event_changes(event)
|
237
|
-
event.attribute_changes.map { |c| [c.attribute_name, c.old_value, c.new_value] }
|
238
|
-
end
|
239
|
-
|
240
|
-
def no_audit_created!
|
241
|
-
event = nil
|
242
|
-
expect{
|
243
|
-
event = yield
|
244
|
-
}.to_not change{ CIA::Event.count }
|
245
|
-
|
246
|
-
event.should == nil
|
247
|
-
end
|
248
|
-
|
249
|
-
it "records attributes in transaction" do
|
250
|
-
event = nil
|
251
|
-
CIA.audit :actor => User.create!, :ip_address => "1.2.3.4" do
|
252
|
-
event = CIA.record(:destroy, Car.create!)
|
253
|
-
end
|
254
|
-
event.ip_address.should == "1.2.3.4"
|
255
|
-
end
|
256
|
-
|
257
|
-
it "records attribute creations" do
|
258
|
-
source = Car.create!
|
259
|
-
source.wheels = 4
|
260
|
-
event = CIA.record(:update, source).reload
|
261
|
-
|
262
|
-
parse_event_changes(event).should == [["wheels", nil, "4"]]
|
263
|
-
end
|
264
|
-
|
265
|
-
it "can act on attributes in before_save" do
|
266
|
-
x = nil
|
267
|
-
CIA.current_transaction[:hacked_before_save_action] = lambda{|event| x = event.attribute_changes.size }
|
268
|
-
source = Car.create!
|
269
|
-
source.wheels = 4
|
270
|
-
CIA.record(:update, source)
|
271
|
-
x.should == 1
|
272
|
-
end
|
273
|
-
|
274
|
-
it "records multiple attributes" do
|
275
|
-
source = CarWith3Attributes.create!
|
276
|
-
source.wheels = 4
|
277
|
-
source.drivers = 2
|
278
|
-
source.color = "red"
|
279
|
-
event = CIA.record(:update, source).reload
|
280
|
-
parse_event_changes(event).should =~ [["wheels", nil, "4"], ["drivers", nil, "2"], ["color", nil, "red"]]
|
281
|
-
end
|
282
|
-
|
283
|
-
it "records attribute changes" do
|
284
|
-
source = Car.create!(:wheels => 2)
|
285
|
-
source.wheels = 4
|
286
|
-
event = CIA.record(:update, source).reload
|
287
|
-
parse_event_changes(event).should == [["wheels", "2", "4"]]
|
288
|
-
end
|
289
|
-
|
290
|
-
it "records attribute deletions" do
|
291
|
-
source = Car.create!(:wheels => 2)
|
292
|
-
source.wheels = nil
|
293
|
-
event = CIA.record(:update, source).reload
|
294
|
-
parse_event_changes(event).should == [["wheels", "2", nil]]
|
295
|
-
end
|
296
|
-
|
297
|
-
it "does not record unaudited attribute changes" do
|
298
|
-
source = Car.create!
|
299
|
-
source.drivers = 2
|
300
|
-
no_audit_created!{ CIA.record(:update, source) }
|
301
|
-
end
|
302
|
-
|
303
|
-
it "records audit_message as message even if there are no changes" do
|
304
|
-
source = CarWithAMessage.create!
|
305
|
-
source.audit_message = "Foo"
|
306
|
-
event = CIA.record(:update, source)
|
307
|
-
|
308
|
-
event.message.should == "Foo"
|
309
|
-
parse_event_changes(event).should == []
|
310
|
-
end
|
311
|
-
|
312
|
-
it "does not record after saving with an audit_message" do
|
313
|
-
source = CarWithAMessage.create!
|
314
|
-
source.audit_message = "Foo"
|
315
|
-
CIA.record(:update, source)
|
316
|
-
|
317
|
-
no_audit_created!{ CIA.record(:update, source) }
|
318
|
-
end
|
319
|
-
|
320
|
-
it "does not record if it's empty and there are no changes" do
|
321
|
-
source = CarWithAMessage.create!
|
322
|
-
source.audit_message = " "
|
323
|
-
no_audit_created!{ CIA.record(:update, source) }
|
324
|
-
end
|
325
|
-
|
326
|
-
it "record non-updates even without changes" do
|
327
|
-
source = Car.create!
|
328
|
-
event = CIA.record(:create, source)
|
329
|
-
parse_event_changes(event).should == []
|
330
|
-
end
|
331
|
-
end
|
332
|
-
|
333
|
-
context "exception_handler" do
|
334
|
-
before do
|
335
|
-
$stderr.stub(:puts)
|
336
|
-
CIA.stub(:current_transaction).and_raise(StandardError.new("foo"))
|
337
|
-
end
|
338
|
-
|
339
|
-
def capture_exception
|
340
|
-
begin
|
341
|
-
old = CIA.exception_handler
|
342
|
-
ex = nil
|
343
|
-
CIA.exception_handler = lambda{|e| ex = e }
|
344
|
-
yield
|
345
|
-
ex
|
346
|
-
ensure
|
347
|
-
CIA.exception_handler = old
|
348
|
-
end
|
349
|
-
end
|
350
|
-
|
351
|
-
it "raises exceptions by the transaction" do
|
352
|
-
ex = nil
|
353
|
-
begin
|
354
|
-
object.save!
|
355
|
-
rescue Object => e
|
356
|
-
ex = e
|
357
|
-
end
|
358
|
-
ex.inspect.should == '#<StandardError: foo>'
|
359
|
-
end
|
360
|
-
|
361
|
-
it "can capture exception via handler" do
|
362
|
-
ex = capture_exception do
|
363
|
-
object.save!
|
364
|
-
end
|
365
|
-
ex.inspect.should == '#<StandardError: foo>'
|
366
|
-
end
|
367
|
-
end
|
368
|
-
|
369
|
-
context "with after_commit" do
|
370
|
-
let(:object){ CarWithTransactions.new(:wheels => 1) }
|
371
|
-
|
372
|
-
it "still tracks" do
|
373
|
-
expect{
|
374
|
-
CIA.audit{ object.save! }
|
375
|
-
}.to change{ CIA::Event.count }.by(+1)
|
376
|
-
CIA::Event.last.attribute_change_hash.should == {"wheels" => [nil, "1"]}
|
377
|
-
end
|
378
|
-
|
379
|
-
it "unsets temp-changes after the save" do
|
380
|
-
object.save!
|
381
|
-
|
382
|
-
# does not re-track old changes
|
383
|
-
expect{
|
384
|
-
CIA.audit{ object.update_attributes(:drivers => 2) }
|
385
|
-
}.to change{ CIA::Event.count }.by(+1)
|
386
|
-
CIA::Event.last.attribute_change_hash.should == {"drivers" => [nil, "2"]}
|
387
|
-
|
388
|
-
# empty changes
|
389
|
-
expect{
|
390
|
-
CIA.audit{ object.update_attributes(:drivers => 2) }
|
391
|
-
}.to_not change{ CIA::Event.count }
|
392
|
-
end
|
393
|
-
|
394
|
-
it "is not rolled back if auditing fails" do
|
395
|
-
CIA.should_receive(:record).and_raise("XXX")
|
396
|
-
begin
|
397
|
-
expect{
|
398
|
-
CIA.audit{ object.save! }
|
399
|
-
}.to change{ object.class.count }.by(+1)
|
400
|
-
rescue RuntimeError => e
|
401
|
-
# errors from after_commit are never raised in rails 3+
|
402
|
-
raise e if ActiveRecord::VERSION::MAJOR != 2 || e.message != "XXX"
|
403
|
-
end
|
404
|
-
end
|
405
|
-
end
|
406
|
-
end
|
407
|
-
|
408
|
-
context ".current_actor" do
|
409
|
-
it "is nil when nothing is set" do
|
410
|
-
CIA.current_actor.should == nil
|
411
|
-
end
|
412
|
-
|
413
|
-
it "is nil when no actor is set" do
|
414
|
-
CIA.audit do
|
415
|
-
CIA.current_actor.should == nil
|
416
|
-
end
|
417
|
-
end
|
418
|
-
|
419
|
-
it "is the current :actor" do
|
420
|
-
CIA.audit :actor => 111 do
|
421
|
-
CIA.current_actor.should == 111
|
422
|
-
end
|
423
|
-
end
|
424
|
-
end
|
425
|
-
|
426
|
-
context ".current_actor=" do
|
427
|
-
it "does nothing if no transaction is running" do
|
428
|
-
CIA.current_actor = 111
|
429
|
-
CIA.current_transaction.should == nil
|
430
|
-
end
|
431
|
-
|
432
|
-
it "sets when transaction is started" do
|
433
|
-
CIA.audit :actor => 222 do
|
434
|
-
CIA.current_actor = 111
|
435
|
-
CIA.current_transaction.should == {:actor => 111}
|
436
|
-
end
|
437
|
-
end
|
438
|
-
end
|
439
|
-
end
|
data/spec/spec_helper.rb
DELETED
@@ -1,120 +0,0 @@
|
|
1
|
-
require 'cia'
|
2
|
-
require 'after_commit' if ActiveRecord::VERSION::MAJOR == 2
|
3
|
-
|
4
|
-
RSpec.configure do |config|
|
5
|
-
config.before do
|
6
|
-
CIA::Event.delete_all
|
7
|
-
CIA::AttributeChange.delete_all
|
8
|
-
CIA.non_recordable_attributes = nil
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
ActiveRecord::Base.establish_connection(
|
13
|
-
:adapter => "sqlite3",
|
14
|
-
:database => ":memory:"
|
15
|
-
)
|
16
|
-
|
17
|
-
ActiveRecord::Schema.verbose = false
|
18
|
-
ActiveRecord::Schema.define(:version => 1) do
|
19
|
-
eval(File.read(File.expand_path('../../MIGRATION.rb', __FILE__)))
|
20
|
-
|
21
|
-
create_table :cars do |t|
|
22
|
-
t.integer :wheels
|
23
|
-
t.integer :drivers
|
24
|
-
t.string :color
|
25
|
-
end
|
26
|
-
|
27
|
-
create_table :users do |t|
|
28
|
-
t.string :email
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
class User < ActiveRecord::Base
|
33
|
-
end
|
34
|
-
|
35
|
-
class Car < ActiveRecord::Base
|
36
|
-
include CIA::Auditable
|
37
|
-
audit_attribute :wheels
|
38
|
-
end
|
39
|
-
|
40
|
-
class CarWithAMessage < ActiveRecord::Base
|
41
|
-
self.table_name = "cars"
|
42
|
-
include CIA::Auditable
|
43
|
-
audit_attribute :wheels
|
44
|
-
attr_accessor :audit_message
|
45
|
-
end
|
46
|
-
|
47
|
-
class CarWith3Attributes < ActiveRecord::Base
|
48
|
-
self.table_name = "cars"
|
49
|
-
include CIA::Auditable
|
50
|
-
audit_attribute :wheels, :color, :drivers
|
51
|
-
end
|
52
|
-
|
53
|
-
class CarWithIf < ActiveRecord::Base
|
54
|
-
self.table_name = "cars"
|
55
|
-
include CIA::Auditable
|
56
|
-
audit_attribute :wheels, :if => :tested
|
57
|
-
attr_accessor :tested
|
58
|
-
end
|
59
|
-
|
60
|
-
class CarWithUnless < ActiveRecord::Base
|
61
|
-
self.table_name = "cars"
|
62
|
-
include CIA::Auditable
|
63
|
-
audit_attribute :wheels, :unless => :tested
|
64
|
-
attr_accessor :tested
|
65
|
-
end
|
66
|
-
|
67
|
-
class CarWithCustomChanges < ActiveRecord::Base
|
68
|
-
self.table_name = "cars"
|
69
|
-
include CIA::Auditable
|
70
|
-
audit_attribute :wheels, :foo
|
71
|
-
|
72
|
-
def cia_changes
|
73
|
-
changes.merge("foo" => ["bar", "baz"])
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
class FailCar < ActiveRecord::Base
|
78
|
-
self.table_name = "cars"
|
79
|
-
include CIA::Auditable
|
80
|
-
audit_attribute :wheels
|
81
|
-
|
82
|
-
class Oops < Exception
|
83
|
-
end
|
84
|
-
|
85
|
-
after_update { |x| raise Oops }
|
86
|
-
after_create { |x| raise Oops }
|
87
|
-
after_destroy { |x| raise Oops }
|
88
|
-
end
|
89
|
-
|
90
|
-
class CarWithTransactions < ActiveRecord::Base
|
91
|
-
self.table_name = "cars"
|
92
|
-
include CIA::Auditable
|
93
|
-
audit_attribute :wheels, :drivers, :callback => :after_commit
|
94
|
-
end
|
95
|
-
|
96
|
-
class NestedCar < Car
|
97
|
-
audit_attribute :drivers
|
98
|
-
end
|
99
|
-
|
100
|
-
class InheritedCar < Car
|
101
|
-
end
|
102
|
-
|
103
|
-
def create_event(options={})
|
104
|
-
CIA::Event.create!({:source => Car.create!, :actor => User.create!, :action => "update"}.merge(options))
|
105
|
-
end
|
106
|
-
|
107
|
-
def create_change(options={})
|
108
|
-
event = options.delete(:event) || create_event
|
109
|
-
CIA::AttributeChange.create!({:event => event, :source => event.source, :attribute_name => "bar"}.merge(options))
|
110
|
-
end
|
111
|
-
|
112
|
-
# simulate a hacked cia event
|
113
|
-
CIA::Event.class_eval do
|
114
|
-
before_save :hacked_before_save
|
115
|
-
attr_accessor :hacked_before_save_action
|
116
|
-
|
117
|
-
def hacked_before_save
|
118
|
-
hacked_before_save_action.call(self) if hacked_before_save_action
|
119
|
-
end
|
120
|
-
end
|