changeling 0.0.7 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,10 @@
1
+ class AsyncBlogPost
2
+ include Mongoid::Document
3
+ include Mongoid::Timestamps
4
+ include Changeling::Async::Trackling
5
+ include Changeling::Probeling
6
+
7
+ field :title
8
+ field :content
9
+ field :public, :type => Boolean
10
+ end
@@ -0,0 +1,5 @@
1
+ # Setup for the fields etc. happens in spec_helper.
2
+ class AsyncBlogPostActiveRecord < ActiveRecord::Base
3
+ include Changeling::Async::Trackling
4
+ include Changeling::Probeling
5
+ end
@@ -0,0 +1,9 @@
1
+ class AsyncBlogPostNoTimestamp
2
+ include Mongoid::Document
3
+ include Changeling::Async::Trackling
4
+ include Changeling::Probeling
5
+
6
+ field :title
7
+ field :content
8
+ field :public, :type => Boolean
9
+ end
@@ -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 "Class Methods" do
21
- describe ".create" do
22
- before(:each) do
18
+ context "#{model}" do
19
+ context "Class Methods" do
20
+ describe ".create" do
21
+ before(:each) do
23
22
 
24
- @klass.should_receive(:new).with(@object).and_return(@logling)
25
- end
23
+ @klass.should_receive(:new).with(@object).and_return(@logling)
24
+ end
26
25
 
27
- it "should call new with it's parameters then save the initialized logling" do
28
- @logling.should_receive(:save)
26
+ it "should call new with it's parameters then save the initialized logling" do
27
+ @logling.should_receive(:save)
29
28
 
30
- @klass.create(@object)
29
+ @klass.create(@object)
30
+ end
31
31
  end
32
- end
33
32
 
34
- describe ".new" do
35
- context "when passed object is a ElasticSearch response hash" do
36
- before(:each) do
37
- @object = {
38
- "klass"=>"BlogPost",
39
- "oid"=>"50b8355f7a93d04908000001",
40
- "modifications"=>"{\"public\":[true,false]}",
41
- "modified_at"=>"2012-11-29T20:26:07-08:00"
42
- }
43
-
44
- @logling = @klass.new(@object)
45
- @changes = JSON.parse(@object['modifications'])
46
- @before, @after = @klass.parse_changes(@changes)
47
- @modified_time = DateTime.parse(@object['modified_at'])
48
- end
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
- it "should set klass as the returned klass value" do
51
- @logling.klass.should == @object['klass'].constantize
52
- end
49
+ it "should set klass as the returned klass value" do
50
+ @logling.klass.should == @object['klass'].constantize
51
+ end
53
52
 
54
- it "should set oid as the returned oid value" do
55
- @logling.oid.should == @object['oid']
56
- end
53
+ it "should set oid as the returned oid value" do
54
+ @logling.oid.should == @object['oid']
55
+ end
57
56
 
58
- it "should convert oid to an integer if it's supposed to be an integer" do
59
- @object["oid"] = "1"
60
- @klass.new(@object).oid.should == @object["oid"].to_i
61
- end
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
- it "should set the modifications as the incoming changes parameter" do
64
- @logling.modifications.should == @changes
65
- end
62
+ it "should set the modifications as the incoming changes parameter" do
63
+ @logling.modifications.should == @changes
64
+ end
66
65
 
67
- it "should set the modified_fields as the keys of the modifications" do
68
- @logling.modified_fields.should == @changes.keys
69
- end
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
- it "should set before and after based on .parse_changes" do
72
- @logling.before.should == @before
73
- @logling.after.should == @after
74
- end
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
- it "should set modified_at as the parsed version of the returned modified_at value" do
77
- @logling.modified_at.should == @modified_time
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
- context "when passed object is a real object" do
82
- before(:each) do
83
- @before, @after = @klass.parse_changes(@changes)
84
- end
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
- it "should set klass as the object's class" do
87
- @logling.klass.should == @object.class
88
- end
85
+ it "should set klass as the object's class" do
86
+ @logling.klass.should == @object.class
87
+ end
89
88
 
90
- it "should set oid as the object's ID" do
91
- @logling.oid.should == @object.id
92
- end
89
+ it "should set oid as the object's ID" do
90
+ @logling.oid.should == @object.id
91
+ end
93
92
 
94
- it "should set the modifications as the incoming changes parameter" do
95
- @logling.modifications.should == @changes
96
- end
93
+ it "should set the modifications as the incoming changes parameter" do
94
+ @logling.modifications.should == @changes
95
+ end
97
96
 
98
- it "should set before and after based on .parse_changes" do
99
- @logling.before.should == @before
100
- @logling.after.should == @after
101
- end
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
- it "should set the modified_fields as the keys of the modifications" do
104
- @logling.modified_fields.should == @changes.keys
105
- end
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
- it "should ignore changes that are nil" do
108
- changes = {}
106
+ it "should ignore changes that are nil" do
107
+ changes = {}
109
108
 
110
- @changes.keys.each do |key|
111
- changes[key] = nil
112
- end
109
+ @changes.keys.each do |key|
110
+ changes[key] = nil
111
+ end
113
112
 
114
- @object.stub(:changes).and_return(changes)
113
+ @object.stub(:changes).and_return(changes)
115
114
 
116
- @klass.new(@object).modifications.should be_empty
117
- end
115
+ @klass.new(@object).modifications.should be_empty
116
+ end
118
117
 
119
- it "should set modified_at to the object's time of update if the object responds to the updated_at method" do
120
- @object.should_receive(:respond_to?).with(:updated_at).and_return(true)
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
- # Setting up a variable to prevent test flakiness from passing time.
123
- time = Time.now
124
- @object.stub(:updated_at).and_return(time)
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
- # Create a new logling to trigger the initialize method
127
- @logling = @klass.new(@object)
128
- @logling.modified_at.should == @object.updated_at
129
- end
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
- it "should set modified_at to the current time if the object doesn't respond to updated_at" do
132
- @object.should_receive(:respond_to?).with(:updated_at).and_return(false)
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
- # Setting up a variable to prevent test flakiness from passing time.
135
- time = Time.now
136
- Time.stub(:now).and_return(time)
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
- # Create a new logling to trigger the initialize method
139
- @logling = @klass.new(@object)
140
- @logling.modified_at.should == time
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
- describe ".parse_changes" do
146
- before(:each) do
147
- @object.save!
144
+ describe ".parse_changes" do
145
+ before(:each) do
146
+ @object.save!
148
147
 
149
- @before = @object.attributes.select { |attr| @changes.keys.include?(attr) }
148
+ @before = @object.attributes.select { |attr| @changes.keys.include?(attr) }
150
149
 
151
- @changes.each_pair do |k, v|
152
- @object.send("#{k}=", v[1])
153
- end
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
- it "should correctly match the before and after states of the object" do
159
- @klass.parse_changes(@object.changes).should == [@before, @after]
160
- end
161
- end
154
+ @after = @object.attributes.select { |attr| @changes.keys.include?(attr) }
155
+ end
162
156
 
163
- describe ".klassify" do
164
- it "should return the object's class as an underscored string" do
165
- @klass.klassify(@object).should == @object.class.to_s.underscore
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
- describe ".records_for" do
170
- before(:each) do
171
- @search = Changeling::Support::Search
172
- @results = []
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
- context "length parameter" do
168
+ describe ".records_for" do
176
169
  before(:each) do
177
- @search.stub(:find_by).and_return(@results)
170
+ @search = Changeling::Support::Search
171
+ @results = []
178
172
  end
179
173
 
180
- it "should only return the amount specified" do
181
- num = 5
182
- @results.should_receive(:take).with(num).and_return([])
183
- @klass.records_for(@object, 5)
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 return all if no amount is specified" do
187
- @results.should_not_receive(:take)
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
- it "should search with filters on the klass and oid" do
193
- @search.should_receive(:find_by).with(hash_including({
194
- :filters => [
195
- { :klass => @klass.klassify(@object) },
196
- { :oid => @object.id.to_s }
197
- ]
198
- })).and_return(@results)
199
- @klass.records_for(@object)
200
- end
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
- it "should sort by descending modified_at" do
214
- @search.should_receive(:find_by).with(hash_including({
215
- :sort => {
216
- :field => :modified_at,
217
- :direction => :desc
218
- }
219
- })).and_return(@results)
220
- @klass.records_for(@object, nil)
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
- context "Instance Methods" do
226
- before(:each) do
227
- # Stub :id so that it doesn't screw up these test's expectations.
228
- @logling.stub(:id).and_return(1)
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
- it "should include the object's oid attribute" do
237
- @logling.should_receive(:oid)
238
- end
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
- it "should include the object's modifications attribute" do
241
- @logling.should_receive(:modifications)
242
- end
235
+ it "should include the object's oid attribute" do
236
+ @logling.should_receive(:oid)
237
+ end
243
238
 
244
- it "should convert the object's modifications attribute to JSON" do
245
- mods = {}
246
- @logling.should_receive(:modifications).and_return(mods)
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
- it "should include the object's modified_at attribute" do
251
- @logling.should_receive(:modified_at)
252
- end
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
- it "should include an array of the object's modified fields" do
255
- @logling.should_receive(:modified_fields)
256
- end
249
+ it "should include the object's modified_at attribute" do
250
+ @logling.should_receive(:modified_at)
251
+ end
257
252
 
258
- after(:each) do
259
- @logling.to_indexed_json
260
- end
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
- describe ".as_json" do
264
- before(:each) do
265
- @json = @logling.as_json
257
+ after(:each) do
258
+ @logling.to_indexed_json
259
+ end
266
260
  end
267
261
 
268
- it "should include the object's klass attribute" do
269
- @json[:class].should == @object.class
270
- end
262
+ describe ".as_json" do
263
+ before(:each) do
264
+ @json = @logling.as_json
265
+ end
271
266
 
272
- it "should include the object's oid attribute" do
273
- @json[:oid].should == @object.id
274
- end
267
+ it "should include the object's klass attribute" do
268
+ @json[:class].should == @object.class
269
+ end
275
270
 
276
- it "should include the object's modifications attribute" do
277
- @json[:modifications].should == @changes
278
- end
271
+ it "should include the object's oid attribute" do
272
+ @json[:oid].should == @object.id
273
+ end
279
274
 
280
- it "should include the object's modified_at attribute" do
281
- @json[:modified_at].should == @logling.modified_at
282
- end
275
+ it "should include the object's modifications attribute" do
276
+ @json[:modifications].should == @changes
277
+ end
283
278
 
284
- after(:each) do
285
- @logling.to_indexed_json
286
- end
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
- describe ".save" do
290
- it "should update the ElasticSearch index" do
291
- @logling.should_receive(:update_index)
283
+ after(:each) do
284
+ @logling.to_indexed_json
285
+ end
292
286
  end
293
287
 
294
- it "should not update the index if there are no changes" do
295
- @logling.stub(:modifications).and_return({})
296
- @logling.should_not_receive(:_run_save_callbacks)
297
- end
288
+ describe ".save" do
289
+ it "should update the ElasticSearch index" do
290
+ @logling.should_receive(:update_index)
291
+ end
298
292
 
299
- after(:each) do
300
- @logling.save
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