robsharp-sunspot_rails 1.1.0.2

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.
Files changed (55) hide show
  1. data/History.txt +40 -0
  2. data/LICENSE +18 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +256 -0
  5. data/Rakefile +27 -0
  6. data/TODO +8 -0
  7. data/VERSION.yml +4 -0
  8. data/dev_tasks/gemspec.rake +33 -0
  9. data/dev_tasks/rdoc.rake +24 -0
  10. data/dev_tasks/release.rake +4 -0
  11. data/dev_tasks/todo.rake +4 -0
  12. data/generators/sunspot/sunspot_generator.rb +9 -0
  13. data/generators/sunspot/templates/sunspot.yml +18 -0
  14. data/install.rb +1 -0
  15. data/lib/sunspot/rails.rb +58 -0
  16. data/lib/sunspot/rails/adapters.rb +160 -0
  17. data/lib/sunspot/rails/configuration.rb +272 -0
  18. data/lib/sunspot/rails/request_lifecycle.rb +31 -0
  19. data/lib/sunspot/rails/searchable.rb +464 -0
  20. data/lib/sunspot/rails/server.rb +173 -0
  21. data/lib/sunspot/rails/solr_logging.rb +58 -0
  22. data/lib/sunspot/rails/spec_helper.rb +19 -0
  23. data/lib/sunspot/rails/stub_session_proxy.rb +88 -0
  24. data/lib/sunspot/rails/tasks.rb +62 -0
  25. data/lib/sunspot/rails/version.rb +5 -0
  26. data/rails/init.rb +10 -0
  27. data/spec/configuration_spec.rb +102 -0
  28. data/spec/mock_app/app/controllers/application.rb +10 -0
  29. data/spec/mock_app/app/controllers/application_controller.rb +10 -0
  30. data/spec/mock_app/app/controllers/posts_controller.rb +6 -0
  31. data/spec/mock_app/app/models/author.rb +8 -0
  32. data/spec/mock_app/app/models/blog.rb +12 -0
  33. data/spec/mock_app/app/models/location.rb +2 -0
  34. data/spec/mock_app/app/models/photo_post.rb +2 -0
  35. data/spec/mock_app/app/models/post.rb +10 -0
  36. data/spec/mock_app/app/models/post_with_auto.rb +10 -0
  37. data/spec/mock_app/config/boot.rb +110 -0
  38. data/spec/mock_app/config/database.yml +4 -0
  39. data/spec/mock_app/config/environment.rb +42 -0
  40. data/spec/mock_app/config/environments/development.rb +27 -0
  41. data/spec/mock_app/config/environments/test.rb +27 -0
  42. data/spec/mock_app/config/initializers/new_rails_defaults.rb +19 -0
  43. data/spec/mock_app/config/initializers/session_store.rb +15 -0
  44. data/spec/mock_app/config/routes.rb +43 -0
  45. data/spec/mock_app/config/sunspot.yml +19 -0
  46. data/spec/mock_app/db/schema.rb +27 -0
  47. data/spec/model_lifecycle_spec.rb +63 -0
  48. data/spec/model_spec.rb +409 -0
  49. data/spec/request_lifecycle_spec.rb +52 -0
  50. data/spec/schema.rb +27 -0
  51. data/spec/server_spec.rb +36 -0
  52. data/spec/session_spec.rb +24 -0
  53. data/spec/spec_helper.rb +51 -0
  54. data/spec/stub_session_proxy_spec.rb +122 -0
  55. metadata +170 -0
@@ -0,0 +1,409 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe 'ActiveRecord mixin' do
4
+ describe 'index()' do
5
+ before :each do
6
+ @post = Post.create!
7
+ @post.index
8
+ end
9
+
10
+ it 'should not commit the model' do
11
+ Post.search.results.should be_empty
12
+ end
13
+
14
+ it 'should index the model' do
15
+ Sunspot.commit
16
+ Post.search.results.should == [@post]
17
+ end
18
+ end
19
+
20
+ describe 'single table inheritence' do
21
+ before :each do
22
+ @post = PhotoPost.create!
23
+ end
24
+
25
+ it 'should not break auto-indexing' do
26
+ @post.title = 'Title'
27
+ lambda { @post.save! }.should_not raise_error
28
+ end
29
+ end
30
+
31
+ describe 'index!()' do
32
+ before :each do
33
+ @post = Post.create!
34
+ @post.index!
35
+ end
36
+
37
+ it 'should immediately index and commit' do
38
+ Post.search.results.should == [@post]
39
+ end
40
+ end
41
+
42
+ describe 'remove_from_index()' do
43
+ before :each do
44
+ @post = Post.create!
45
+ @post.index!
46
+ @post.remove_from_index
47
+ end
48
+
49
+ it 'should not commit immediately' do
50
+ Post.search.results.should == [@post]
51
+ end
52
+
53
+ it 'should remove the model from the index' do
54
+ Sunspot.commit
55
+ Post.search.results.should be_empty
56
+ end
57
+ end
58
+
59
+ describe 'remove_from_index!()' do
60
+ before :each do
61
+ @post = Post.create!
62
+ @post.index!
63
+ @post.remove_from_index!
64
+ end
65
+
66
+ it 'should immediately remove the model and commit' do
67
+ Post.search.results.should be_empty
68
+ end
69
+ end
70
+
71
+ describe 'remove_all_from_index' do
72
+ before :each do
73
+ @posts = Array.new(10) { Post.create! }.each { |post| Sunspot.index(post) }
74
+ Sunspot.commit
75
+ Post.remove_all_from_index
76
+ end
77
+
78
+ it 'should not commit immediately' do
79
+ Post.search.results.to_set.should == @posts.to_set
80
+ end
81
+
82
+ it 'should remove all instances from the index' do
83
+ Sunspot.commit
84
+ Post.search.results.should be_empty
85
+ end
86
+ end
87
+
88
+ describe 'remove_all_from_index!' do
89
+ before :each do
90
+ Array.new(10) { Post.create! }.each { |post| Sunspot.index(post) }
91
+ Sunspot.commit
92
+ Post.remove_all_from_index!
93
+ end
94
+
95
+ it 'should remove all instances from the index and commit immediately' do
96
+ Post.search.results.should be_empty
97
+ end
98
+ end
99
+
100
+ describe 'search()' do
101
+ before :each do
102
+ @post = Post.create!(:title => 'Test Post')
103
+ @post.index!
104
+ end
105
+
106
+ it 'should return results specified by search' do
107
+ Post.search do
108
+ with :title, 'Test Post'
109
+ end.results.should == [@post]
110
+ end
111
+
112
+ it 'should not return results excluded by search' do
113
+ Post.search do
114
+ with :title, 'Bogus Post'
115
+ end.results.should be_empty
116
+ end
117
+
118
+ it 'should find ActiveRecord objects with an integer, not a string' do
119
+ Post.should_receive(:all).with(hash_including(:conditions => { "id" => [@post.id.to_i] })).and_return([@post])
120
+ Post.search do
121
+ with :title, 'Test Post'
122
+ end.results.should == [@post]
123
+ end
124
+
125
+ it 'should use the include option on the data accessor when specified' do
126
+ Post.should_receive(:find).with(anything(), hash_including(:include => [:blog])).and_return([@post])
127
+ Post.search do
128
+ with :title, 'Test Post'
129
+ data_accessor_for(Post).include = [:blog]
130
+ end.results.should == [@post]
131
+ end
132
+
133
+ it 'should pass :include option from search call to data accessor' do
134
+ Post.should_receive(:find).with(anything(), hash_including(:include => [:blog])).and_return([@post])
135
+ Post.search(:include => [:blog]) do
136
+ with :title, 'Test Post'
137
+ end.results.should == [@post]
138
+ end
139
+
140
+ it 'should use the select option from search call to data accessor' do
141
+ Post.should_receive(:find).with(anything(), hash_including(:select => 'title, published_at')).and_return([@post])
142
+ Post.search(:select => 'title, published_at') do
143
+ with :title, 'Test Post'
144
+ end.results.should == [@post]
145
+ end
146
+
147
+ it 'should not allow bogus options to search' do
148
+ lambda { Post.search(:bogus => :option) }.should raise_error(ArgumentError)
149
+ end
150
+
151
+ it 'should use the select option on the data accessor when specified' do
152
+ Post.should_receive(:find).with(anything(), hash_including(:select => 'title, published_at')).and_return([@post])
153
+ Post.search do
154
+ with :title, 'Test Post'
155
+ data_accessor_for(Post).select = [:title, :published_at]
156
+ end.results.should == [@post]
157
+ end
158
+
159
+ it 'should not use the select option on the data accessor when not specified' do
160
+ Post.should_receive(:find).with(anything(), hash_not_including(:select)).and_return([@post])
161
+ Post.search do
162
+ with :title, 'Test Post'
163
+ end.results.should == [@post]
164
+ end
165
+
166
+ it 'should gracefully handle nonexistent records' do
167
+ post2 = Post.create!(:title => 'Test Post')
168
+ post2.index!
169
+ post2.destroy
170
+ Post.search do
171
+ with :title, 'Test Post'
172
+ end.results.should == [@post]
173
+ end
174
+
175
+ it 'should use an ActiveRecord object for coordinates' do
176
+ post = Post.new(:title => 'Test Post')
177
+ post.location = Location.create!(:lat => 40.0, :lng => -70.0)
178
+ post.save
179
+ post.index!
180
+ Post.search { near([40.0, -70.0], :distance => 1) }.results.should == [post]
181
+ end
182
+
183
+ end
184
+
185
+ describe 'search_ids()' do
186
+ before :each do
187
+ @posts = Array.new(2) { Post.create! }.each { |post| post.index }
188
+ Sunspot.commit
189
+ end
190
+
191
+ it 'should return IDs' do
192
+ Post.search_ids.to_set.should == @posts.map { |post| post.id }.to_set
193
+ end
194
+ end
195
+
196
+ describe 'searchable?()' do
197
+ it 'should not be true for models that have not been configured for search' do
198
+ Location.should_not be_searchable
199
+ end
200
+
201
+ it 'should be true for models that have been configured for search' do
202
+ Post.should be_searchable
203
+ end
204
+ end
205
+
206
+ describe 'index_orphans()' do
207
+ before :each do
208
+ @posts = Array.new(2) { Post.create }.each { |post| post.index }
209
+ Sunspot.commit
210
+ @posts.first.destroy
211
+ end
212
+
213
+ it 'should return IDs of objects that are in the index but not the database' do
214
+ Post.index_orphans.should == [@posts.first.id]
215
+ end
216
+ end
217
+
218
+ describe 'clean_index_orphans()' do
219
+ before :each do
220
+ @posts = Array.new(2) { Post.create }.each { |post| post.index }
221
+ Sunspot.commit
222
+ @posts.first.destroy
223
+ end
224
+
225
+ it 'should remove orphans from the index' do
226
+ Post.clean_index_orphans
227
+ Sunspot.commit
228
+ Post.search.results.should == [@posts.last]
229
+ end
230
+ end
231
+
232
+ describe 'reindex()' do
233
+ before :each do
234
+ @posts = Array.new(2) { Post.create }
235
+ end
236
+
237
+ it 'should index all instances' do
238
+ Post.reindex(:batch_size => nil)
239
+ Sunspot.commit
240
+ Post.search.results.to_set.should == @posts.to_set
241
+ end
242
+
243
+ it 'should remove all currently indexed instances' do
244
+ old_post = Post.create!
245
+ old_post.index!
246
+ old_post.destroy
247
+ Post.reindex
248
+ Sunspot.commit
249
+ Post.search.results.to_set.should == @posts.to_set
250
+ end
251
+
252
+ end
253
+
254
+ describe 'reindex() with real data' do
255
+ before :each do
256
+ @posts = Array.new(2) { Post.create }
257
+ end
258
+
259
+ it 'should index all instances' do
260
+ Post.reindex(:batch_size => nil)
261
+ Sunspot.commit
262
+ Post.search.results.to_set.should == @posts.to_set
263
+ end
264
+
265
+ it 'should remove all currently indexed instances' do
266
+ old_post = Post.create!
267
+ old_post.index!
268
+ old_post.destroy
269
+ Post.reindex
270
+ Sunspot.commit
271
+ Post.search.results.to_set.should == @posts.to_set
272
+ end
273
+
274
+ describe "using batch sizes" do
275
+ it 'should index with a specified batch size' do
276
+ Post.reindex(:batch_size => 1)
277
+ Sunspot.commit
278
+ Post.search.results.to_set.should == @posts.to_set
279
+ end
280
+ end
281
+ end
282
+
283
+
284
+
285
+ describe "reindex()" do
286
+
287
+ before(:each) do
288
+ @posts = Array.new(10) { Post.create }
289
+ end
290
+
291
+ describe "when not using batches" do
292
+
293
+ it "should select all if the batch_size is nil" do
294
+ Post.should_receive(:all).with(:include => []).and_return([])
295
+ Post.reindex(:batch_size => nil)
296
+ end
297
+
298
+ it "should search for models with includes" do
299
+ Post.should_receive(:all).with(:include => :author).and_return([])
300
+ Post.reindex(:batch_size => nil, :include => :author)
301
+ end
302
+
303
+ end
304
+
305
+ describe "when using batches" do
306
+
307
+ it "should use the default options" do
308
+ Post.should_receive(:all).with do |params|
309
+ params[:limit].should == 500
310
+ params[:include].should == []
311
+ params[:conditions].should == ['posts.id > ?', 0]
312
+ params[:order].should == 'id'
313
+ end.and_return(@posts)
314
+ Post.reindex
315
+ end
316
+
317
+ it "should set the conditions using the overridden table attributes" do
318
+ @posts = Array.new(10) { Author.create }
319
+ Author.should_receive(:all).with do |params|
320
+ params[:conditions].should == ['writers.writer_id > ?', 0]
321
+ params[:order].should == 'writer_id'
322
+ end.and_return(@posts)
323
+ Author.reindex
324
+ end
325
+
326
+ it "should count the number of records to index" do
327
+ Post.should_receive(:count).and_return(10)
328
+ Post.reindex
329
+ end
330
+
331
+ it "should override the batch_size" do
332
+ Post.should_receive(:all).with do |params|
333
+ params[:limit].should == 20
334
+ @posts
335
+ end.and_return(@posts)
336
+ Post.reindex(:batch_size => 20)
337
+ end
338
+
339
+ it "should set the include option" do
340
+ Post.should_receive(:all).with do |params|
341
+ params[:include].should == [{:author => :address}]
342
+ @posts
343
+ end.and_return(@posts)
344
+ Post.reindex(:include => [{:author => :address}])
345
+ end
346
+
347
+ it "should set the include option from the searchable options" do
348
+ @blogs = Array.new(10) { Blog.create }
349
+ Blog.should_receive(:all).with do |params|
350
+ params[:include].should == [{ :posts => :author }, :comments]
351
+ @blogs
352
+ end.and_return(@blogs)
353
+ Blog.reindex
354
+ end
355
+
356
+ it "should commit after indexing each batch" do
357
+ Sunspot.should_receive(:commit).twice
358
+ Post.reindex(:batch_size => 5)
359
+ end
360
+
361
+ it "should commit after indexing everything" do
362
+ Sunspot.should_receive(:commit).once
363
+ Post.reindex(:batch_commit => false)
364
+ end
365
+
366
+ end
367
+ end
368
+
369
+ describe "more_like_this()" do
370
+ before(:each) do
371
+ @posts = [
372
+ Post.create!(:title => 'Post123', :body => "one two three"),
373
+ Post.create!(:title => 'Post345', :body => "three four five"),
374
+ Post.create!(:title => 'Post456', :body => "four five six"),
375
+ Post.create!(:title => 'Post234', :body => "two three four"),
376
+ ]
377
+ @posts_with_auto = [
378
+ PostWithAuto.create!(:body => "one two three"),
379
+ PostWithAuto.create!(:body => "four five six")
380
+ ]
381
+ @posts.each { |p| p.index! }
382
+ end
383
+
384
+ it "should return results" do
385
+ @posts.first.more_like_this.results.should == [@posts[3], @posts[1]]
386
+ end
387
+
388
+ it "should return results for specified classes" do
389
+ @posts.first.more_like_this(Post, PostWithAuto).results.to_set.should ==
390
+ Set[@posts_with_auto[0], @posts[1], @posts[3]]
391
+ end
392
+ end
393
+
394
+ describe 'more_like_this_ids()' do
395
+ before :each do
396
+ @posts = [
397
+ Post.create!(:title => 'Post123', :body => "one two three"),
398
+ Post.create!(:title => 'Post345', :body => "three four five"),
399
+ Post.create!(:title => 'Post456', :body => "four five six"),
400
+ Post.create!(:title => 'Post234', :body => "two three four"),
401
+ ]
402
+ @posts.each { |p| p.index! }
403
+ end
404
+
405
+ it 'should return IDs' do
406
+ @posts.first.more_like_this_ids.to_set.should == [@posts[3], @posts[1]].map { |post| post.id }.to_set
407
+ end
408
+ end
409
+ end
@@ -0,0 +1,52 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe 'request lifecycle', :type => :controller do
4
+ before(:each) do
5
+ Sunspot::Rails.configuration = @configuration = Sunspot::Rails::Configuration.new
6
+ end
7
+
8
+ after(:each) do
9
+ Sunspot::Rails.configuration = nil
10
+ end
11
+ controller_name :posts
12
+
13
+ it 'should automatically commit after each action if specified' do
14
+ @configuration.user_configuration = { 'auto_commit_after_request' => true }
15
+ Sunspot.should_receive(:commit_if_dirty)
16
+ post :create, :post => { :title => 'Test 1' }
17
+ end
18
+
19
+ it 'should not commit, if configuration is set to false' do
20
+ @configuration.user_configuration = { 'auto_commit_after_request' => false }
21
+ Sunspot.should_not_receive(:commit_if_dirty)
22
+ post :create, :post => { :title => 'Test 1' }
23
+ end
24
+
25
+ it 'should commit if configuration is not specified' do
26
+ @configuration.user_configuration = {}
27
+ Sunspot.should_receive(:commit_if_dirty)
28
+ post :create, :post => { :title => 'Test 1' }
29
+ end
30
+
31
+ ### auto_commit_if_delete_dirty
32
+
33
+ it 'should automatically commit after each delete if specified' do
34
+ @configuration.user_configuration = { 'auto_commit_after_request' => false,
35
+ 'auto_commit_after_delete_request' => true }
36
+ Sunspot.should_receive(:commit_if_delete_dirty)
37
+ post :create, :post => { :title => 'Test 1' }
38
+ end
39
+
40
+ it 'should not automatically commit on delete if configuration is set to false' do
41
+ @configuration.user_configuration = { 'auto_commit_after_request' => false,
42
+ 'auto_commit_after_delete_request' => false }
43
+ Sunspot.should_not_receive(:commit_if_delete_dirty)
44
+ post :create, :post => { :title => 'Test 1' }
45
+ end
46
+
47
+ it 'should not automatically commit on delete if configuration is not specified' do
48
+ @configuration.user_configuration = { 'auto_commit_after_request' => false }
49
+ Sunspot.should_not_receive(:commit_if_delete_dirty)
50
+ post :create, :post => { :title => 'Test 1' }
51
+ end
52
+ end