changeling 0.0.7 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +32 -22
- data/Rakefile +47 -0
- data/benchmarks/benchmark_setup.rake +16 -0
- data/benchmarks/changeling_benchmark.rake +34 -0
- data/benchmarks/tire_benchmark.rake +29 -0
- data/changeling.gemspec +3 -1
- data/lib/changeling.rb +10 -0
- data/lib/changeling/async/resque_worker.rb +11 -0
- data/lib/changeling/async/sidekiq_worker.rb +16 -0
- data/lib/changeling/async/trackling.rb +27 -0
- data/lib/changeling/exceptions/async_gem_required.rb +9 -0
- data/lib/changeling/probeling.rb +6 -3
- data/lib/changeling/trackling.rb +2 -0
- data/lib/changeling/version.rb +1 -1
- data/spec/controllers/blameling_integration_spec.rb +79 -0
- data/spec/fixtures/app/application.rb +0 -5
- data/spec/fixtures/app/models/async_blog_post.rb +10 -0
- data/spec/fixtures/app/models/async_blog_post_active_record.rb +5 -0
- data/spec/fixtures/app/models/async_blog_post_no_timestamp.rb +9 -0
- data/spec/lib/changeling/async/trackling_spec.rb +126 -0
- data/spec/lib/changeling/models/logling_spec.rb +213 -213
- data/spec/lib/changeling/probeling_spec.rb +25 -25
- data/spec/lib/changeling/trackling_spec.rb +22 -20
- data/spec/spec_helper.rb +21 -5
- metadata +139 -38
- data/spec/controllers/blameling_controller_spec.rb +0 -20
- data/spec/controllers/blog_posts_controller_spec.rb +0 -20
- data/spec/controllers/current_account_controller_spec.rb +0 -20
- data/spec/controllers/no_current_user_controller_spec.rb +0 -20
@@ -2,11 +2,6 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
module RailsApp
|
4
4
|
class Application < Rails::Application
|
5
|
-
# app config here
|
6
|
-
# config.secret_token = '572c86f5ede338bd8aba8dae0fd3a326aabababc98d1e6ce34b9f5'
|
7
|
-
# routes.draw do
|
8
|
-
# resources :blog_posts
|
9
|
-
# end
|
10
5
|
end
|
11
6
|
|
12
7
|
class ApplicationController < ActionController::Base
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'resque'
|
3
|
+
require 'sidekiq'
|
4
|
+
|
5
|
+
describe Changeling::Async::Trackling do
|
6
|
+
before(:all) do
|
7
|
+
@klass = Changeling::Models::Logling
|
8
|
+
end
|
9
|
+
|
10
|
+
async_models.each_pair do |model, args|
|
11
|
+
before(:each) do
|
12
|
+
@object = model.new(args[:options])
|
13
|
+
end
|
14
|
+
|
15
|
+
context "#{model}" do
|
16
|
+
describe "without Sidekiq or Resque" do
|
17
|
+
before(:each) do
|
18
|
+
hide_const("Resque")
|
19
|
+
hide_const("Sidekiq")
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should raise the AsyncGemRequired exception" do
|
23
|
+
expect { @object.async_save_logling }.to raise_error(Changeling::Exceptions::AsyncGemRequired)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "with Sidekiq" do
|
28
|
+
before(:each) do
|
29
|
+
hide_const("Resque")
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "callbacks" do
|
33
|
+
before(:each) do
|
34
|
+
@logling = @klass.new(@object)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should not create a logling when doing the initial save of a new object" do
|
38
|
+
@klass.should_not_receive(:new)
|
39
|
+
@object.run_callbacks(:create)
|
40
|
+
end
|
41
|
+
|
42
|
+
context "after_update" do
|
43
|
+
it "should queue a logling to be made when updating an object and changes are made" do
|
44
|
+
@object.stub(:changes).and_return({ :field => 'value' })
|
45
|
+
@klass.should_receive(:new).and_return(@logling)
|
46
|
+
Changeling::Async::SidekiqWorker.should_receive(:perform_async).with(@logling.to_indexed_json)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should not queue a logling to be made when updating an object and changes are empty" do
|
50
|
+
@object.stub(:changes).and_return({})
|
51
|
+
@klass.should_not_receive(:new)
|
52
|
+
Changeling::Async::SidekiqWorker.should_not_receive(:perform_async)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should not queue a logling to be made when updating an object and no changes have been made" do
|
56
|
+
@object.stub(:changes).and_return(nil)
|
57
|
+
@klass.should_not_receive(:create)
|
58
|
+
Changeling::Async::SidekiqWorker.should_not_receive(:perform_async)
|
59
|
+
end
|
60
|
+
|
61
|
+
after(:each) do
|
62
|
+
@object.run_callbacks(:update)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "with Resque" do
|
69
|
+
before(:each) do
|
70
|
+
hide_const("Sidekiq")
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "callbacks" do
|
74
|
+
before(:each) do
|
75
|
+
@logling = @klass.new(@object)
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should not create a logling when doing the initial save of a new object" do
|
79
|
+
@klass.should_not_receive(:new)
|
80
|
+
@object.run_callbacks(:create)
|
81
|
+
end
|
82
|
+
|
83
|
+
context "after_update" do
|
84
|
+
it "should queue a logling to be made when updating an object and changes are made" do
|
85
|
+
@object.stub(:changes).and_return({ :field => 'value' })
|
86
|
+
@klass.should_receive(:new).and_return(@logling)
|
87
|
+
Resque.should_receive(:enqueue).with(Changeling::Async::ResqueWorker, @logling.to_indexed_json)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should not queue a logling to be made when updating an object and changes are empty" do
|
91
|
+
@object.stub(:changes).and_return({})
|
92
|
+
@klass.should_not_receive(:new)
|
93
|
+
Resque.should_not_receive(:enqueue)
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should not queue a logling to be made when updating an object and no changes have been made" do
|
97
|
+
@object.stub(:changes).and_return(nil)
|
98
|
+
@klass.should_not_receive(:create)
|
99
|
+
Resque.should_not_receive(:enqueue)
|
100
|
+
end
|
101
|
+
|
102
|
+
after(:each) do
|
103
|
+
@object.run_callbacks(:update)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe "with Sidekiq and Resque" do
|
110
|
+
describe "callbacks" do
|
111
|
+
before(:each) do
|
112
|
+
@logling = @klass.new(@object)
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should prefer Sidekiq to Resque" do
|
116
|
+
@object.stub(:changes).and_return({ :field => 'value' })
|
117
|
+
@klass.should_receive(:new).and_return(@logling)
|
118
|
+
Changeling::Async::SidekiqWorker.should_receive(:perform_async).with(@logling.to_indexed_json)
|
119
|
+
Resque.should_not_receive(:enqueue)
|
120
|
+
@object.run_callbacks(:update)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -7,8 +7,6 @@ describe Changeling::Models::Logling do
|
|
7
7
|
|
8
8
|
# .models is defined in spec_helper.
|
9
9
|
models.each_pair do |model, args|
|
10
|
-
puts "Testing #{model} now."
|
11
|
-
|
12
10
|
before(:each) do
|
13
11
|
@object = model.new(args[:options])
|
14
12
|
@changes = args[:changes]
|
@@ -17,287 +15,289 @@ describe Changeling::Models::Logling do
|
|
17
15
|
@logling = @klass.new(@object)
|
18
16
|
end
|
19
17
|
|
20
|
-
context "
|
21
|
-
|
22
|
-
|
18
|
+
context "#{model}" do
|
19
|
+
context "Class Methods" do
|
20
|
+
describe ".create" do
|
21
|
+
before(:each) do
|
23
22
|
|
24
|
-
|
25
|
-
|
23
|
+
@klass.should_receive(:new).with(@object).and_return(@logling)
|
24
|
+
end
|
26
25
|
|
27
|
-
|
28
|
-
|
26
|
+
it "should call new with it's parameters then save the initialized logling" do
|
27
|
+
@logling.should_receive(:save)
|
29
28
|
|
30
|
-
|
29
|
+
@klass.create(@object)
|
30
|
+
end
|
31
31
|
end
|
32
|
-
end
|
33
32
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
33
|
+
describe ".new" do
|
34
|
+
context "when passed object is a ElasticSearch response hash" do
|
35
|
+
before(:each) do
|
36
|
+
@object = {
|
37
|
+
"klass"=>"BlogPost",
|
38
|
+
"oid"=>"50b8355f7a93d04908000001",
|
39
|
+
"modifications"=>"{\"public\":[true,false]}",
|
40
|
+
"modified_at"=>"2012-11-29T20:26:07-08:00"
|
41
|
+
}
|
42
|
+
|
43
|
+
@logling = @klass.new(@object)
|
44
|
+
@changes = JSON.parse(@object['modifications'])
|
45
|
+
@before, @after = @klass.parse_changes(@changes)
|
46
|
+
@modified_time = DateTime.parse(@object['modified_at'])
|
47
|
+
end
|
49
48
|
|
50
|
-
|
51
|
-
|
52
|
-
|
49
|
+
it "should set klass as the returned klass value" do
|
50
|
+
@logling.klass.should == @object['klass'].constantize
|
51
|
+
end
|
53
52
|
|
54
|
-
|
55
|
-
|
56
|
-
|
53
|
+
it "should set oid as the returned oid value" do
|
54
|
+
@logling.oid.should == @object['oid']
|
55
|
+
end
|
57
56
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
57
|
+
it "should convert oid to an integer if it's supposed to be an integer" do
|
58
|
+
@object["oid"] = "1"
|
59
|
+
@klass.new(@object).oid.should == @object["oid"].to_i
|
60
|
+
end
|
62
61
|
|
63
|
-
|
64
|
-
|
65
|
-
|
62
|
+
it "should set the modifications as the incoming changes parameter" do
|
63
|
+
@logling.modifications.should == @changes
|
64
|
+
end
|
66
65
|
|
67
|
-
|
68
|
-
|
69
|
-
|
66
|
+
it "should set the modified_fields as the keys of the modifications" do
|
67
|
+
@logling.modified_fields.should == @changes.keys
|
68
|
+
end
|
70
69
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
70
|
+
it "should set before and after based on .parse_changes" do
|
71
|
+
@logling.before.should == @before
|
72
|
+
@logling.after.should == @after
|
73
|
+
end
|
75
74
|
|
76
|
-
|
77
|
-
|
75
|
+
it "should set modified_at as the parsed version of the returned modified_at value" do
|
76
|
+
@logling.modified_at.should == @modified_time
|
77
|
+
end
|
78
78
|
end
|
79
|
-
end
|
80
79
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
80
|
+
context "when passed object is a real object" do
|
81
|
+
before(:each) do
|
82
|
+
@before, @after = @klass.parse_changes(@changes)
|
83
|
+
end
|
85
84
|
|
86
|
-
|
87
|
-
|
88
|
-
|
85
|
+
it "should set klass as the object's class" do
|
86
|
+
@logling.klass.should == @object.class
|
87
|
+
end
|
89
88
|
|
90
|
-
|
91
|
-
|
92
|
-
|
89
|
+
it "should set oid as the object's ID" do
|
90
|
+
@logling.oid.should == @object.id
|
91
|
+
end
|
93
92
|
|
94
|
-
|
95
|
-
|
96
|
-
|
93
|
+
it "should set the modifications as the incoming changes parameter" do
|
94
|
+
@logling.modifications.should == @changes
|
95
|
+
end
|
97
96
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
97
|
+
it "should set before and after based on .parse_changes" do
|
98
|
+
@logling.before.should == @before
|
99
|
+
@logling.after.should == @after
|
100
|
+
end
|
102
101
|
|
103
|
-
|
104
|
-
|
105
|
-
|
102
|
+
it "should set the modified_fields as the keys of the modifications" do
|
103
|
+
@logling.modified_fields.should == @changes.keys
|
104
|
+
end
|
106
105
|
|
107
|
-
|
108
|
-
|
106
|
+
it "should ignore changes that are nil" do
|
107
|
+
changes = {}
|
109
108
|
|
110
|
-
|
111
|
-
|
112
|
-
|
109
|
+
@changes.keys.each do |key|
|
110
|
+
changes[key] = nil
|
111
|
+
end
|
113
112
|
|
114
|
-
|
113
|
+
@object.stub(:changes).and_return(changes)
|
115
114
|
|
116
|
-
|
117
|
-
|
115
|
+
@klass.new(@object).modifications.should be_empty
|
116
|
+
end
|
118
117
|
|
119
|
-
|
120
|
-
|
118
|
+
it "should set modified_at to the object's time of update if the object responds to the updated_at method" do
|
119
|
+
@object.should_receive(:respond_to?).with(:updated_at).and_return(true)
|
121
120
|
|
122
|
-
|
123
|
-
|
124
|
-
|
121
|
+
# Setting up a variable to prevent test flakiness from passing time.
|
122
|
+
time = Time.now
|
123
|
+
@object.stub(:updated_at).and_return(time)
|
125
124
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
125
|
+
# Create a new logling to trigger the initialize method
|
126
|
+
@logling = @klass.new(@object)
|
127
|
+
@logling.modified_at.should == @object.updated_at
|
128
|
+
end
|
130
129
|
|
131
|
-
|
132
|
-
|
130
|
+
it "should set modified_at to the current time if the object doesn't respond to updated_at" do
|
131
|
+
@object.should_receive(:respond_to?).with(:updated_at).and_return(false)
|
133
132
|
|
134
|
-
|
135
|
-
|
136
|
-
|
133
|
+
# Setting up a variable to prevent test flakiness from passing time.
|
134
|
+
time = Time.now
|
135
|
+
Time.stub(:now).and_return(time)
|
137
136
|
|
138
|
-
|
139
|
-
|
140
|
-
|
137
|
+
# Create a new logling to trigger the initialize method
|
138
|
+
@logling = @klass.new(@object)
|
139
|
+
@logling.modified_at.should == time
|
140
|
+
end
|
141
141
|
end
|
142
142
|
end
|
143
|
-
end
|
144
143
|
|
145
|
-
|
146
|
-
|
147
|
-
|
144
|
+
describe ".parse_changes" do
|
145
|
+
before(:each) do
|
146
|
+
@object.save!
|
148
147
|
|
149
|
-
|
148
|
+
@before = @object.attributes.select { |attr| @changes.keys.include?(attr) }
|
150
149
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
@after = @object.attributes.select { |attr| @changes.keys.include?(attr) }
|
156
|
-
end
|
150
|
+
@changes.each_pair do |k, v|
|
151
|
+
@object.send("#{k}=", v[1])
|
152
|
+
end
|
157
153
|
|
158
|
-
|
159
|
-
|
160
|
-
end
|
161
|
-
end
|
154
|
+
@after = @object.attributes.select { |attr| @changes.keys.include?(attr) }
|
155
|
+
end
|
162
156
|
|
163
|
-
|
164
|
-
|
165
|
-
|
157
|
+
it "should correctly match the before and after states of the object" do
|
158
|
+
@klass.parse_changes(@object.changes).should == [@before, @after]
|
159
|
+
end
|
166
160
|
end
|
167
|
-
end
|
168
161
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
162
|
+
describe ".klassify" do
|
163
|
+
it "should return the object's class as an underscored string" do
|
164
|
+
@klass.klassify(@object).should == @object.class.to_s.underscore
|
165
|
+
end
|
173
166
|
end
|
174
167
|
|
175
|
-
|
168
|
+
describe ".records_for" do
|
176
169
|
before(:each) do
|
177
|
-
@search
|
170
|
+
@search = Changeling::Support::Search
|
171
|
+
@results = []
|
178
172
|
end
|
179
173
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
174
|
+
context "length parameter" do
|
175
|
+
before(:each) do
|
176
|
+
@search.stub(:find_by).and_return(@results)
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should only return the amount specified" do
|
180
|
+
num = 5
|
181
|
+
@results.should_receive(:take).with(num).and_return([])
|
182
|
+
@klass.records_for(@object, 5)
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should return all if no amount is specified" do
|
186
|
+
@results.should_not_receive(:take)
|
187
|
+
@klass.records_for(@object)
|
188
|
+
end
|
184
189
|
end
|
185
190
|
|
186
|
-
it "should
|
187
|
-
@
|
191
|
+
it "should search with filters on the klass and oid" do
|
192
|
+
@search.should_receive(:find_by).with(hash_including({
|
193
|
+
:filters => [
|
194
|
+
{ :klass => @klass.klassify(@object) },
|
195
|
+
{ :oid => @object.id.to_s }
|
196
|
+
]
|
197
|
+
})).and_return(@results)
|
188
198
|
@klass.records_for(@object)
|
189
199
|
end
|
190
|
-
end
|
191
200
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
it "should search with a filter on the field if one is passed in" do
|
203
|
-
@search.should_receive(:find_by).with(hash_including(
|
204
|
-
:filters => [
|
205
|
-
{ :klass => @klass.klassify(@object) },
|
206
|
-
{ :oid => @object.id.to_s },
|
207
|
-
{ :modified_fields => "field" }
|
208
|
-
]
|
209
|
-
)).and_return(@results)
|
210
|
-
@klass.records_for(@object, nil, "field")
|
211
|
-
end
|
201
|
+
it "should search with a filter on the field if one is passed in" do
|
202
|
+
@search.should_receive(:find_by).with(hash_including(
|
203
|
+
:filters => [
|
204
|
+
{ :klass => @klass.klassify(@object) },
|
205
|
+
{ :oid => @object.id.to_s },
|
206
|
+
{ :modified_fields => "field" }
|
207
|
+
]
|
208
|
+
)).and_return(@results)
|
209
|
+
@klass.records_for(@object, nil, "field")
|
210
|
+
end
|
212
211
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
212
|
+
it "should sort by descending modified_at" do
|
213
|
+
@search.should_receive(:find_by).with(hash_including({
|
214
|
+
:sort => {
|
215
|
+
:field => :modified_at,
|
216
|
+
:direction => :desc
|
217
|
+
}
|
218
|
+
})).and_return(@results)
|
219
|
+
@klass.records_for(@object, nil)
|
220
|
+
end
|
221
221
|
end
|
222
222
|
end
|
223
|
-
end
|
224
223
|
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
end
|
230
|
-
|
231
|
-
describe ".to_indexed_json" do
|
232
|
-
it "should include the object's klass attribute" do
|
233
|
-
@logling.should_receive(:klass)
|
224
|
+
context "Instance Methods" do
|
225
|
+
before(:each) do
|
226
|
+
# Stub :id so that it doesn't screw up these test's expectations.
|
227
|
+
@logling.stub(:id).and_return(1)
|
234
228
|
end
|
235
229
|
|
236
|
-
|
237
|
-
|
238
|
-
|
230
|
+
describe ".to_indexed_json" do
|
231
|
+
it "should include the object's klass attribute" do
|
232
|
+
@logling.should_receive(:klass)
|
233
|
+
end
|
239
234
|
|
240
|
-
|
241
|
-
|
242
|
-
|
235
|
+
it "should include the object's oid attribute" do
|
236
|
+
@logling.should_receive(:oid)
|
237
|
+
end
|
243
238
|
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
mods.should_receive(:to_json)
|
248
|
-
end
|
239
|
+
it "should include the object's modifications attribute" do
|
240
|
+
@logling.should_receive(:modifications)
|
241
|
+
end
|
249
242
|
|
250
|
-
|
251
|
-
|
252
|
-
|
243
|
+
it "should convert the object's modifications attribute to JSON" do
|
244
|
+
mods = {}
|
245
|
+
@logling.should_receive(:modifications).and_return(mods)
|
246
|
+
mods.should_receive(:to_json)
|
247
|
+
end
|
253
248
|
|
254
|
-
|
255
|
-
|
256
|
-
|
249
|
+
it "should include the object's modified_at attribute" do
|
250
|
+
@logling.should_receive(:modified_at)
|
251
|
+
end
|
257
252
|
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
end
|
253
|
+
it "should include an array of the object's modified fields" do
|
254
|
+
@logling.should_receive(:modified_fields)
|
255
|
+
end
|
262
256
|
|
263
|
-
|
264
|
-
|
265
|
-
|
257
|
+
after(:each) do
|
258
|
+
@logling.to_indexed_json
|
259
|
+
end
|
266
260
|
end
|
267
261
|
|
268
|
-
|
269
|
-
|
270
|
-
|
262
|
+
describe ".as_json" do
|
263
|
+
before(:each) do
|
264
|
+
@json = @logling.as_json
|
265
|
+
end
|
271
266
|
|
272
|
-
|
273
|
-
|
274
|
-
|
267
|
+
it "should include the object's klass attribute" do
|
268
|
+
@json[:class].should == @object.class
|
269
|
+
end
|
275
270
|
|
276
|
-
|
277
|
-
|
278
|
-
|
271
|
+
it "should include the object's oid attribute" do
|
272
|
+
@json[:oid].should == @object.id
|
273
|
+
end
|
279
274
|
|
280
|
-
|
281
|
-
|
282
|
-
|
275
|
+
it "should include the object's modifications attribute" do
|
276
|
+
@json[:modifications].should == @changes
|
277
|
+
end
|
283
278
|
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
end
|
279
|
+
it "should include the object's modified_at attribute" do
|
280
|
+
@json[:modified_at].should == @logling.modified_at
|
281
|
+
end
|
288
282
|
|
289
|
-
|
290
|
-
|
291
|
-
|
283
|
+
after(:each) do
|
284
|
+
@logling.to_indexed_json
|
285
|
+
end
|
292
286
|
end
|
293
287
|
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
288
|
+
describe ".save" do
|
289
|
+
it "should update the ElasticSearch index" do
|
290
|
+
@logling.should_receive(:update_index)
|
291
|
+
end
|
298
292
|
|
299
|
-
|
300
|
-
|
293
|
+
it "should not update the index if there are no changes" do
|
294
|
+
@logling.stub(:modifications).and_return({})
|
295
|
+
@logling.should_not_receive(:_run_save_callbacks)
|
296
|
+
end
|
297
|
+
|
298
|
+
after(:each) do
|
299
|
+
@logling.save
|
300
|
+
end
|
301
301
|
end
|
302
302
|
end
|
303
303
|
end
|