substantial-sunspot_rails 2.0.0.pre.111215
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/.gitignore +7 -0
- data/.rspec +1 -0
- data/History.txt +66 -0
- data/LICENSE +18 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +265 -0
- data/Rakefile +12 -0
- data/TODO +8 -0
- data/dev_tasks/rdoc.rake +24 -0
- data/dev_tasks/release.rake +4 -0
- data/dev_tasks/spec.rake +107 -0
- data/dev_tasks/todo.rake +4 -0
- data/gemfiles/rails-2.3.14 +15 -0
- data/gemfiles/rails-3.0.11 +15 -0
- data/gemfiles/rails-3.1.3 +15 -0
- data/generators/sunspot/sunspot_generator.rb +9 -0
- data/generators/sunspot/templates/sunspot.yml +18 -0
- data/install.rb +1 -0
- data/lib/generators/sunspot_rails.rb +9 -0
- data/lib/generators/sunspot_rails/install/install_generator.rb +13 -0
- data/lib/generators/sunspot_rails/install/templates/config/sunspot.yml +17 -0
- data/lib/substantial-sunspot_rails.rb +1 -0
- data/lib/sunspot/rails.rb +65 -0
- data/lib/sunspot/rails/adapters.rb +83 -0
- data/lib/sunspot/rails/configuration.rb +340 -0
- data/lib/sunspot/rails/init.rb +5 -0
- data/lib/sunspot/rails/log_subscriber.rb +33 -0
- data/lib/sunspot/rails/railtie.rb +36 -0
- data/lib/sunspot/rails/railties/controller_runtime.rb +36 -0
- data/lib/sunspot/rails/request_lifecycle.rb +36 -0
- data/lib/sunspot/rails/searchable.rb +480 -0
- data/lib/sunspot/rails/server.rb +106 -0
- data/lib/sunspot/rails/solr_instrumentation.rb +18 -0
- data/lib/sunspot/rails/solr_logging.rb +62 -0
- data/lib/sunspot/rails/spec_helper.rb +26 -0
- data/lib/sunspot/rails/stub_session_proxy.rb +142 -0
- data/lib/sunspot/rails/tasks.rb +84 -0
- data/lib/sunspot_rails.rb +12 -0
- data/spec/configuration_spec.rb +195 -0
- data/spec/model_lifecycle_spec.rb +63 -0
- data/spec/model_spec.rb +595 -0
- data/spec/rails_template/app/controllers/application_controller.rb +10 -0
- data/spec/rails_template/app/controllers/posts_controller.rb +6 -0
- data/spec/rails_template/app/models/author.rb +8 -0
- data/spec/rails_template/app/models/blog.rb +12 -0
- data/spec/rails_template/app/models/location.rb +2 -0
- data/spec/rails_template/app/models/photo_post.rb +2 -0
- data/spec/rails_template/app/models/post.rb +11 -0
- data/spec/rails_template/app/models/post_with_auto.rb +10 -0
- data/spec/rails_template/app/models/post_with_default_scope.rb +11 -0
- data/spec/rails_template/config/boot.rb +127 -0
- data/spec/rails_template/config/preinitializer.rb +22 -0
- data/spec/rails_template/config/routes.rb +9 -0
- data/spec/rails_template/config/sunspot.yml +22 -0
- data/spec/rails_template/db/schema.rb +27 -0
- data/spec/request_lifecycle_spec.rb +61 -0
- data/spec/schema.rb +27 -0
- data/spec/searchable_spec.rb +12 -0
- data/spec/server_spec.rb +33 -0
- data/spec/session_spec.rb +57 -0
- data/spec/shared_examples/indexed_after_save.rb +8 -0
- data/spec/shared_examples/not_indexed_after_save.rb +8 -0
- data/spec/spec_helper.rb +48 -0
- data/spec/stub_session_proxy_spec.rb +122 -0
- data/substantial-sunspot_rails.gemspec +43 -0
- metadata +228 -0
@@ -0,0 +1,195 @@
|
|
1
|
+
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe Sunspot::Rails::Configuration, "default values without a sunspot.yml" do
|
4
|
+
before(:each) do
|
5
|
+
File.stub!(:exist?).and_return(false) # simulate sunspot.yml not existing
|
6
|
+
@config = Sunspot::Rails::Configuration.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should handle the 'hostname' property when not set" do
|
10
|
+
@config.hostname.should == 'localhost'
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should handle the 'path' property when not set" do
|
14
|
+
@config.path.should == '/solr'
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "port" do
|
18
|
+
it "should default to port 8981 in test" do
|
19
|
+
::Rails.stub!(:env => 'test')
|
20
|
+
@config = Sunspot::Rails::Configuration.new
|
21
|
+
@config.port.should == 8981
|
22
|
+
end
|
23
|
+
it "should default to port 8982 in development" do
|
24
|
+
::Rails.stub!(:env => 'development')
|
25
|
+
@config = Sunspot::Rails::Configuration.new
|
26
|
+
@config.port.should == 8982
|
27
|
+
end
|
28
|
+
it "should default to 8983 in production" do
|
29
|
+
::Rails.stub!(:env => 'production')
|
30
|
+
@config = Sunspot::Rails::Configuration.new
|
31
|
+
@config.port.should == 8983
|
32
|
+
end
|
33
|
+
it "should generally default to 8983" do
|
34
|
+
::Rails.stub!(:env => 'staging')
|
35
|
+
@config = Sunspot::Rails::Configuration.new
|
36
|
+
@config.port.should == 8983
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should handle the 'log_level' property when not set" do
|
41
|
+
@config.log_level.should == 'INFO'
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should handle the 'log_file' property" do
|
45
|
+
@config.log_file.should =~ /log\/solr_test.log/
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should handle the 'solr_home' property when not set" do
|
49
|
+
Rails.should_receive(:root).at_least(1).and_return('/some/path')
|
50
|
+
@config.solr_home.should == '/some/path/solr'
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should handle the 'data_path' property when not set" do
|
54
|
+
Rails.should_receive(:root).at_least(1).and_return('/some/path')
|
55
|
+
@config.data_path.should == '/some/path/solr/data/test'
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should handle the 'pid_dir' property when not set" do
|
59
|
+
Rails.should_receive(:root).at_least(1).and_return('/some/path')
|
60
|
+
@config.pid_dir.should == '/some/path/solr/pids/test'
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should handle the 'auto_commit_after_request' propery when not set" do
|
64
|
+
@config.auto_commit_after_request?.should == true
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should handle the 'auto_commit_after_delete_request' propery when not set" do
|
68
|
+
@config.auto_commit_after_delete_request?.should == false
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should handle the 'bind_address' property when not set" do
|
72
|
+
@config.bind_address.should be_nil
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should handle the 'disabled' property when not set" do
|
76
|
+
@config.disabled?.should be_false
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe Sunspot::Rails::Configuration, "user provided sunspot.yml" do
|
81
|
+
before(:each) do
|
82
|
+
::Rails.stub!(:env => 'config_test')
|
83
|
+
@config = Sunspot::Rails::Configuration.new
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should handle the 'hostname' property when set" do
|
87
|
+
@config.hostname.should == 'some.host'
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should handle the 'port' property when set" do
|
91
|
+
@config.port.should == 1234
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should handle the 'path' property when set" do
|
95
|
+
@config.path.should == '/solr/idx'
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should handle the 'log_level' propery when set" do
|
99
|
+
@config.log_level.should == 'WARNING'
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should handle the 'solr_home' propery when set" do
|
103
|
+
@config.solr_home.should == '/my_superior_path'
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should handle the 'data_path' property when set" do
|
107
|
+
@config.data_path.should == '/my_superior_path/data'
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should handle the 'pid_dir' property when set" do
|
111
|
+
@config.pid_dir.should == '/my_superior_path/pids'
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should handle the 'solr_home' property when set" do
|
115
|
+
@config.solr_home.should == '/my_superior_path'
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should handle the 'auto_commit_after_request' propery when set" do
|
119
|
+
@config.auto_commit_after_request?.should == false
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should handle the 'auto_commit_after_delete_request' propery when set" do
|
123
|
+
@config.auto_commit_after_delete_request?.should == true
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should handle the 'bind_address' property when set" do
|
127
|
+
@config.bind_address.should == "127.0.0.1"
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe Sunspot::Rails::Configuration, "with disabled: true in sunspot.yml" do
|
132
|
+
before(:each) do
|
133
|
+
::Rails.stub!(:env => 'config_disabled_test')
|
134
|
+
@config = Sunspot::Rails::Configuration.new
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should handle the 'disabled' property when set" do
|
138
|
+
@config.disabled?.should be_true
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
describe Sunspot::Rails::Configuration, "with ENV['SOLR_URL'] overriding sunspot.yml" do
|
143
|
+
before(:all) do
|
144
|
+
ENV['SOLR_URL'] = 'http://environment.host:5432/solr/env'
|
145
|
+
end
|
146
|
+
|
147
|
+
before(:each) do
|
148
|
+
::Rails.stub!(:env => 'config_test')
|
149
|
+
@config = Sunspot::Rails::Configuration.new
|
150
|
+
end
|
151
|
+
|
152
|
+
after(:all) do
|
153
|
+
ENV.delete('SOLR_URL')
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should handle the 'hostname' property when set" do
|
157
|
+
@config.hostname.should == 'environment.host'
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should handle the 'port' property when set" do
|
161
|
+
@config.port.should == 5432
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should handle the 'path' property when set" do
|
165
|
+
@config.path.should == '/solr/env'
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
describe Sunspot::Rails::Configuration, "with ENV['WEBSOLR_URL'] overriding sunspot.yml" do
|
170
|
+
before(:all) do
|
171
|
+
ENV['WEBSOLR_URL'] = 'http://index.websolr.test/solr/a1b2c3d4e5f'
|
172
|
+
end
|
173
|
+
|
174
|
+
before(:each) do
|
175
|
+
::Rails.stub!(:env => 'config_test')
|
176
|
+
@config = Sunspot::Rails::Configuration.new
|
177
|
+
end
|
178
|
+
|
179
|
+
after(:all) do
|
180
|
+
ENV.delete('WEBSOLR_URL')
|
181
|
+
end
|
182
|
+
|
183
|
+
it "should handle the 'hostname' property when set" do
|
184
|
+
@config.hostname.should == 'index.websolr.test'
|
185
|
+
end
|
186
|
+
|
187
|
+
it "should handle the 'port' property when set" do
|
188
|
+
@config.port.should == 80
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should handle the 'path' property when set" do
|
192
|
+
@config.path.should == '/solr/a1b2c3d4e5f'
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe 'searchable with lifecycle' do
|
4
|
+
describe 'on create' do
|
5
|
+
before :each do
|
6
|
+
@post = PostWithAuto.create
|
7
|
+
Sunspot.commit
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should automatically index' do
|
11
|
+
PostWithAuto.search.results.should == [@post]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'on update' do
|
16
|
+
before :each do
|
17
|
+
@post = PostWithAuto.create
|
18
|
+
@post.update_attributes(:title => 'Test 1')
|
19
|
+
Sunspot.commit
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should automatically update index' do
|
23
|
+
PostWithAuto.search { with :title, 'Test 1' }.results.should == [@post]
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should index model if relevant attribute changed" do
|
27
|
+
@post = PostWithAuto.create!
|
28
|
+
@post.title = 'new title'
|
29
|
+
@post.should_receive :solr_index
|
30
|
+
@post.save!
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should not index model if relevant attribute not changed" do
|
34
|
+
@post = PostWithAuto.create!
|
35
|
+
@post.updated_at = Date.tomorrow
|
36
|
+
@post.should_not_receive :solr_index
|
37
|
+
@post.save!
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe 'on destroy' do
|
42
|
+
before :each do
|
43
|
+
@post = PostWithAuto.create
|
44
|
+
@post.destroy
|
45
|
+
Sunspot.commit
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should automatically remove it from the index' do
|
49
|
+
PostWithAuto.search_ids.should be_empty
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe 'searchable with lifecycle - ignoring specific attributes' do
|
55
|
+
before(:each) do
|
56
|
+
@post = PostWithAuto.create
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should not reindex the object on an update_at change, because it is marked as to-ignore" do
|
60
|
+
Sunspot.should_not_receive(:index).with(@post)
|
61
|
+
@post.update_attribute :updated_at, 123.seconds.from_now
|
62
|
+
end
|
63
|
+
end
|
data/spec/model_spec.rb
ADDED
@@ -0,0 +1,595 @@
|
|
1
|
+
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
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
|
+
|
19
|
+
it "should not blow up if there's a default scope specifying order" do
|
20
|
+
posts = Array.new(2) { |j| PostWithDefaultScope.create! :title => (10-j).to_s }
|
21
|
+
lambda { PostWithDefaultScope.index(:batch_size => 1) }.should_not raise_error
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'single table inheritence' do
|
26
|
+
before :each do
|
27
|
+
@post = PhotoPost.create!
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should not break auto-indexing' do
|
31
|
+
@post.title = 'Title'
|
32
|
+
lambda { @post.save! }.should_not raise_error
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe 'index!()' do
|
37
|
+
before :each do
|
38
|
+
@post = Post.create!
|
39
|
+
@post.index!
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should immediately index and commit' do
|
43
|
+
Post.search.results.should == [@post]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe 'remove_from_index()' do
|
48
|
+
before :each do
|
49
|
+
@post = Post.create!
|
50
|
+
@post.index!
|
51
|
+
@post.remove_from_index
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should not commit immediately' do
|
55
|
+
Post.search.results.should == [@post]
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should remove the model from the index' do
|
59
|
+
Sunspot.commit
|
60
|
+
Post.search.results.should be_empty
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe 'remove_from_index!()' do
|
65
|
+
before :each do
|
66
|
+
@post = Post.create!
|
67
|
+
@post.index!
|
68
|
+
@post.remove_from_index!
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should immediately remove the model and commit' do
|
72
|
+
Post.search.results.should be_empty
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe 'remove_all_from_index' do
|
77
|
+
before :each do
|
78
|
+
@posts = Array.new(2) { Post.create! }.each { |post| Sunspot.index(post) }
|
79
|
+
Sunspot.commit
|
80
|
+
Post.remove_all_from_index
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should not commit immediately' do
|
84
|
+
Post.search.results.to_set.should == @posts.to_set
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should remove all instances from the index' do
|
88
|
+
Sunspot.commit
|
89
|
+
Post.search.results.should be_empty
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe 'remove_all_from_index!' do
|
94
|
+
before :each do
|
95
|
+
Array.new(2) { Post.create! }.each { |post| Sunspot.index(post) }
|
96
|
+
Sunspot.commit
|
97
|
+
Post.remove_all_from_index!
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'should remove all instances from the index and commit immediately' do
|
101
|
+
Post.search.results.should be_empty
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe 'search()' do
|
106
|
+
before :each do
|
107
|
+
@post = Post.create!(:title => 'Test Post')
|
108
|
+
@post.index!
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'should return results specified by search' do
|
112
|
+
Post.search do
|
113
|
+
with :title, 'Test Post'
|
114
|
+
end.results.should == [@post]
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'should not return results excluded by search' do
|
118
|
+
Post.search do
|
119
|
+
with :title, 'Bogus Post'
|
120
|
+
end.results.should be_empty
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'should use the include option on the data accessor when specified' do
|
124
|
+
Post.should_receive(:all).with(hash_including(:include => [:blog])).and_return([@post])
|
125
|
+
Post.search do
|
126
|
+
with :title, 'Test Post'
|
127
|
+
data_accessor_for(Post).include = [:blog]
|
128
|
+
end.results.should == [@post]
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'should pass :include option from search call to data accessor' do
|
132
|
+
Post.should_receive(:all).with(hash_including(:include => [:blog])).and_return([@post])
|
133
|
+
Post.search(:include => [:blog]) do
|
134
|
+
with :title, 'Test Post'
|
135
|
+
end.results.should == [@post]
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'should use the select option from search call to data accessor' do
|
139
|
+
Post.should_receive(:all).with(hash_including(:select => 'title, published_at')).and_return([@post])
|
140
|
+
Post.search(:select => 'title, published_at') do
|
141
|
+
with :title, 'Test Post'
|
142
|
+
end.results.should == [@post]
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'should not allow bogus options to search' do
|
146
|
+
lambda { Post.search(:bogus => :option) }.should raise_error(ArgumentError)
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'should use the select option on the data accessor when specified' do
|
150
|
+
Post.should_receive(:all).with(hash_including(:select => 'title, published_at')).and_return([@post])
|
151
|
+
Post.search do
|
152
|
+
with :title, 'Test Post'
|
153
|
+
data_accessor_for(Post).select = [:title, :published_at]
|
154
|
+
end.results.should == [@post]
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'should not use the select option on the data accessor when not specified' do
|
158
|
+
Post.should_receive(:all).with(hash_not_including(:select)).and_return([@post])
|
159
|
+
Post.search do
|
160
|
+
with :title, 'Test Post'
|
161
|
+
end.results.should == [@post]
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'should gracefully handle nonexistent records' do
|
165
|
+
post2 = Post.create!(:title => 'Test Post')
|
166
|
+
post2.index!
|
167
|
+
post2.destroy
|
168
|
+
Post.search do
|
169
|
+
with :title, 'Test Post'
|
170
|
+
end.results.should == [@post]
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'should use an ActiveRecord object for coordinates' do
|
174
|
+
post = Post.new(:title => 'Test Post')
|
175
|
+
post.location = Location.create!(:lat => 40.0, :lng => -70.0)
|
176
|
+
post.save
|
177
|
+
post.index!
|
178
|
+
Post.search { with(:location).near(40.0, -70.0) }.results.should == [post]
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
|
183
|
+
describe 'search_ids()' do
|
184
|
+
before :each do
|
185
|
+
@posts = Array.new(2) { Post.create! }.each { |post| post.index }
|
186
|
+
Sunspot.commit
|
187
|
+
end
|
188
|
+
|
189
|
+
it 'should return IDs' do
|
190
|
+
Post.search_ids.to_set.should == @posts.map { |post| post.id }.to_set
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
describe 'searchable?()' do
|
195
|
+
it 'should not be true for models that have not been configured for search' do
|
196
|
+
Location.should_not be_searchable
|
197
|
+
end
|
198
|
+
|
199
|
+
it 'should be true for models that have been configured for search' do
|
200
|
+
Post.should be_searchable
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
describe 'index_orphans()' do
|
205
|
+
before :each do
|
206
|
+
@posts = Array.new(2) { Post.create }.each { |post| post.index }
|
207
|
+
Sunspot.commit
|
208
|
+
@posts.first.destroy
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'should return IDs of objects that are in the index but not the database' do
|
212
|
+
Post.index_orphans.should == [@posts.first.id]
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
describe 'clean_index_orphans()' do
|
217
|
+
before :each do
|
218
|
+
@posts = Array.new(2) { Post.create }.each { |post| post.index }
|
219
|
+
Sunspot.commit
|
220
|
+
@posts.first.destroy
|
221
|
+
end
|
222
|
+
|
223
|
+
it 'should remove orphans from the index' do
|
224
|
+
Post.clean_index_orphans
|
225
|
+
Sunspot.commit
|
226
|
+
Post.search.results.should == [@posts.last]
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
describe 'reindex()' do
|
231
|
+
before :each do
|
232
|
+
@posts = Array.new(2) { Post.create }
|
233
|
+
end
|
234
|
+
|
235
|
+
it 'should index all instances' do
|
236
|
+
Post.reindex(:batch_size => nil)
|
237
|
+
Sunspot.commit
|
238
|
+
Post.search.results.to_set.should == @posts.to_set
|
239
|
+
end
|
240
|
+
|
241
|
+
it 'should remove all currently indexed instances' do
|
242
|
+
old_post = Post.create!
|
243
|
+
old_post.index!
|
244
|
+
old_post.destroy
|
245
|
+
Post.reindex
|
246
|
+
Sunspot.commit
|
247
|
+
Post.search.results.to_set.should == @posts.to_set
|
248
|
+
end
|
249
|
+
|
250
|
+
end
|
251
|
+
|
252
|
+
describe 'reindex() with real data' do
|
253
|
+
before :each do
|
254
|
+
@posts = Array.new(2) { Post.create }
|
255
|
+
end
|
256
|
+
|
257
|
+
it 'should index all instances' do
|
258
|
+
Post.reindex(:batch_size => nil)
|
259
|
+
Sunspot.commit
|
260
|
+
Post.search.results.to_set.should == @posts.to_set
|
261
|
+
end
|
262
|
+
|
263
|
+
it 'should remove all currently indexed instances' do
|
264
|
+
old_post = Post.create!
|
265
|
+
old_post.index!
|
266
|
+
old_post.destroy
|
267
|
+
Post.reindex
|
268
|
+
Sunspot.commit
|
269
|
+
Post.search.results.to_set.should == @posts.to_set
|
270
|
+
end
|
271
|
+
|
272
|
+
describe "using batch sizes" do
|
273
|
+
it 'should index with a specified batch size' do
|
274
|
+
Post.reindex(:batch_size => 1)
|
275
|
+
Sunspot.commit
|
276
|
+
Post.search.results.to_set.should == @posts.to_set
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
|
282
|
+
|
283
|
+
describe "reindex()" do
|
284
|
+
|
285
|
+
before(:each) do
|
286
|
+
@posts = Array.new(2) { Post.create }
|
287
|
+
end
|
288
|
+
|
289
|
+
describe "when not using batches" do
|
290
|
+
|
291
|
+
it "should select all if the batch_size is nil" do
|
292
|
+
Post.should_receive(:all).with(:include => []).and_return([])
|
293
|
+
Post.reindex(:batch_size => nil)
|
294
|
+
end
|
295
|
+
|
296
|
+
it "should search for models with includes" do
|
297
|
+
Post.should_receive(:all).with(:include => :author).and_return([])
|
298
|
+
Post.reindex(:batch_size => nil, :include => :author)
|
299
|
+
end
|
300
|
+
|
301
|
+
describe ':if constraints' do
|
302
|
+
before do
|
303
|
+
Post.sunspot_options[:if] = proc { |model| model.id != @posts.first.id }
|
304
|
+
end
|
305
|
+
|
306
|
+
after do
|
307
|
+
Post.sunspot_options[:if] = nil
|
308
|
+
end
|
309
|
+
|
310
|
+
it 'should only index those models where :if constraints pass' do
|
311
|
+
Post.reindex(:batch_size => nil)
|
312
|
+
|
313
|
+
Post.search.results.should_not include(@posts.first)
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
end
|
318
|
+
|
319
|
+
describe "when using batches" do
|
320
|
+
it "should commit after indexing each batch" do
|
321
|
+
Sunspot.should_receive(:commit).twice
|
322
|
+
Post.reindex(:batch_size => 1)
|
323
|
+
end
|
324
|
+
|
325
|
+
it "should commit after indexing everything" do
|
326
|
+
Sunspot.should_receive(:commit).once
|
327
|
+
Post.reindex(:batch_commit => false)
|
328
|
+
end
|
329
|
+
|
330
|
+
describe ':if constraints' do
|
331
|
+
before do
|
332
|
+
Post.sunspot_options[:if] = proc { |model| model.id != @posts.first.id }
|
333
|
+
end
|
334
|
+
|
335
|
+
after do
|
336
|
+
Post.sunspot_options[:if] = nil
|
337
|
+
end
|
338
|
+
|
339
|
+
it 'should only index those models where :if constraints pass' do
|
340
|
+
Post.reindex(:batch_size => 50)
|
341
|
+
|
342
|
+
Post.search.results.should_not include(@posts.first)
|
343
|
+
end
|
344
|
+
end
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
describe "more_like_this()" do
|
349
|
+
before(:each) do
|
350
|
+
@posts = [
|
351
|
+
Post.create!(:title => 'Post123', :body => "one two three"),
|
352
|
+
Post.create!(:title => 'Post345', :body => "three four five"),
|
353
|
+
Post.create!(:title => 'Post456', :body => "four five six"),
|
354
|
+
Post.create!(:title => 'Post234', :body => "two three four"),
|
355
|
+
]
|
356
|
+
@posts_with_auto = [
|
357
|
+
PostWithAuto.create!(:body => "one two three"),
|
358
|
+
PostWithAuto.create!(:body => "four five six")
|
359
|
+
]
|
360
|
+
@posts.each { |p| p.index! }
|
361
|
+
end
|
362
|
+
|
363
|
+
it "should return results" do
|
364
|
+
@posts.first.more_like_this.results.should == [@posts[3], @posts[1]]
|
365
|
+
end
|
366
|
+
|
367
|
+
it "should return results for specified classes" do
|
368
|
+
@posts.first.more_like_this(Post, PostWithAuto).results.to_set.should ==
|
369
|
+
Set[@posts_with_auto[0], @posts[1], @posts[3]]
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
describe 'more_like_this_ids()' do
|
374
|
+
before :each do
|
375
|
+
@posts = [
|
376
|
+
Post.create!(:title => 'Post123', :body => "one two three"),
|
377
|
+
Post.create!(:title => 'Post345', :body => "three four five"),
|
378
|
+
Post.create!(:title => 'Post456', :body => "four five six"),
|
379
|
+
Post.create!(:title => 'Post234', :body => "two three four"),
|
380
|
+
]
|
381
|
+
@posts.each { |p| p.index! }
|
382
|
+
end
|
383
|
+
|
384
|
+
it 'should return IDs' do
|
385
|
+
@posts.first.more_like_this_ids.to_set.should == [@posts[3], @posts[1]].map { |post| post.id }.to_set
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
describe ':if constraint' do
|
390
|
+
subject do
|
391
|
+
PostWithAuto.new(:title => 'Post123')
|
392
|
+
end
|
393
|
+
|
394
|
+
after do
|
395
|
+
subject.class.sunspot_options[:if] = nil
|
396
|
+
end
|
397
|
+
|
398
|
+
context 'Symbol' do
|
399
|
+
context 'constraint returns true' do
|
400
|
+
# searchable :if => :returns_true
|
401
|
+
before do
|
402
|
+
subject.should_receive(:returns_true).and_return(true)
|
403
|
+
subject.class.sunspot_options[:if] = :returns_true
|
404
|
+
end
|
405
|
+
|
406
|
+
it_should_behave_like 'indexed after save'
|
407
|
+
end
|
408
|
+
|
409
|
+
context 'constraint returns false' do
|
410
|
+
# searchable :if => :returns_false
|
411
|
+
before do
|
412
|
+
subject.should_receive(:returns_false).and_return(false)
|
413
|
+
subject.class.sunspot_options[:if] = :returns_false
|
414
|
+
end
|
415
|
+
|
416
|
+
it_should_behave_like 'not indexed after save'
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
context 'String' do
|
421
|
+
context 'constraint returns true' do
|
422
|
+
# searchable :if => 'returns_true'
|
423
|
+
before do
|
424
|
+
subject.should_receive(:returns_true).and_return(true)
|
425
|
+
subject.class.sunspot_options[:if] = 'returns_true'
|
426
|
+
end
|
427
|
+
|
428
|
+
it_should_behave_like 'indexed after save'
|
429
|
+
end
|
430
|
+
|
431
|
+
context 'constraint returns false' do
|
432
|
+
# searchable :if => 'returns_false'
|
433
|
+
before do
|
434
|
+
subject.should_receive(:returns_false).and_return(false)
|
435
|
+
subject.class.sunspot_options[:if] = 'returns_false'
|
436
|
+
end
|
437
|
+
|
438
|
+
it_should_behave_like 'not indexed after save'
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
442
|
+
context 'Proc' do
|
443
|
+
context 'constraint returns true' do
|
444
|
+
# searchable :if => proc { true }
|
445
|
+
before do
|
446
|
+
subject.class.sunspot_options[:if] = proc { true }
|
447
|
+
end
|
448
|
+
|
449
|
+
it_should_behave_like 'indexed after save'
|
450
|
+
end
|
451
|
+
|
452
|
+
context 'constraint returns false' do
|
453
|
+
# searchable :if => proc { false }
|
454
|
+
before do
|
455
|
+
subject.class.sunspot_options[:if] = proc { false }
|
456
|
+
end
|
457
|
+
|
458
|
+
it_should_behave_like 'not indexed after save'
|
459
|
+
end
|
460
|
+
end
|
461
|
+
|
462
|
+
context 'Array' do
|
463
|
+
context 'all constraints returns true' do
|
464
|
+
# searchable :if => [:returns_true_1, :returns_true_2]
|
465
|
+
before do
|
466
|
+
subject.should_receive(:returns_true_1).and_return(true)
|
467
|
+
subject.should_receive(:returns_true_2).and_return(true)
|
468
|
+
subject.class.sunspot_options[:if] = [:returns_true_1, 'returns_true_2']
|
469
|
+
end
|
470
|
+
|
471
|
+
it_should_behave_like 'indexed after save'
|
472
|
+
end
|
473
|
+
|
474
|
+
context 'one constraint returns false' do
|
475
|
+
# searchable :if => [:returns_true, :returns_false]
|
476
|
+
before do
|
477
|
+
subject.should_receive(:returns_true).and_return(true)
|
478
|
+
subject.should_receive(:returns_false).and_return(false)
|
479
|
+
subject.class.sunspot_options[:if] = [:returns_true, 'returns_false']
|
480
|
+
end
|
481
|
+
|
482
|
+
it_should_behave_like 'not indexed after save'
|
483
|
+
end
|
484
|
+
end
|
485
|
+
|
486
|
+
it 'removes the model from the index if the constraint does not match' do
|
487
|
+
subject.save!
|
488
|
+
Sunspot.commit
|
489
|
+
subject.class.search.results.should include(subject)
|
490
|
+
|
491
|
+
subject.class.sunspot_options[:if] = proc { false }
|
492
|
+
subject.save!
|
493
|
+
Sunspot.commit
|
494
|
+
subject.class.search.results.should_not include(subject)
|
495
|
+
end
|
496
|
+
end
|
497
|
+
|
498
|
+
describe ':unless constraint' do
|
499
|
+
subject do
|
500
|
+
PostWithAuto.new(:title => 'Post123')
|
501
|
+
end
|
502
|
+
|
503
|
+
after do
|
504
|
+
subject.class.sunspot_options[:unless] = nil
|
505
|
+
end
|
506
|
+
|
507
|
+
context 'Symbol' do
|
508
|
+
context 'constraint returns true' do
|
509
|
+
# searchable :unless => :returns_true
|
510
|
+
before do
|
511
|
+
subject.should_receive(:returns_true).and_return(true)
|
512
|
+
subject.class.sunspot_options[:unless] = :returns_true
|
513
|
+
end
|
514
|
+
|
515
|
+
it_should_behave_like 'not indexed after save'
|
516
|
+
end
|
517
|
+
|
518
|
+
context 'constraint returns false' do
|
519
|
+
# searchable :unless => :returns_false
|
520
|
+
before do
|
521
|
+
subject.should_receive(:returns_false).and_return(false)
|
522
|
+
subject.class.sunspot_options[:unless] = :returns_false
|
523
|
+
end
|
524
|
+
|
525
|
+
it_should_behave_like 'indexed after save'
|
526
|
+
end
|
527
|
+
end
|
528
|
+
|
529
|
+
context 'String' do
|
530
|
+
context 'constraint returns true' do
|
531
|
+
# searchable :unless => 'returns_true'
|
532
|
+
before do
|
533
|
+
subject.should_receive(:returns_true).and_return(true)
|
534
|
+
subject.class.sunspot_options[:unless] = 'returns_true'
|
535
|
+
end
|
536
|
+
|
537
|
+
it_should_behave_like 'not indexed after save'
|
538
|
+
end
|
539
|
+
|
540
|
+
context 'constraint returns false' do
|
541
|
+
# searchable :unless => 'returns_false'
|
542
|
+
before do
|
543
|
+
subject.should_receive(:returns_false).and_return(false)
|
544
|
+
subject.class.sunspot_options[:unless] = 'returns_false'
|
545
|
+
end
|
546
|
+
|
547
|
+
it_should_behave_like 'indexed after save'
|
548
|
+
end
|
549
|
+
end
|
550
|
+
|
551
|
+
context 'Proc' do
|
552
|
+
context 'constraint returns true' do
|
553
|
+
# searchable :unless => proc { true }
|
554
|
+
before do
|
555
|
+
subject.class.sunspot_options[:unless] = proc { |model| model == subject } # true
|
556
|
+
end
|
557
|
+
|
558
|
+
it_should_behave_like 'not indexed after save'
|
559
|
+
end
|
560
|
+
|
561
|
+
context 'constraint returns false' do
|
562
|
+
# searchable :unless => proc { false }
|
563
|
+
before do
|
564
|
+
subject.class.sunspot_options[:unless] = proc { false }
|
565
|
+
end
|
566
|
+
|
567
|
+
it_should_behave_like 'indexed after save'
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
context 'Array' do
|
572
|
+
context 'all constraints returns true' do
|
573
|
+
# searchable :unless => [:returns_true_1, :returns_true_2]
|
574
|
+
before do
|
575
|
+
subject.should_receive(:returns_true_1).and_return(true)
|
576
|
+
subject.should_receive(:returns_true_2).and_return(true)
|
577
|
+
subject.class.sunspot_options[:unless] = [:returns_true_1, 'returns_true_2']
|
578
|
+
end
|
579
|
+
|
580
|
+
it_should_behave_like 'not indexed after save'
|
581
|
+
end
|
582
|
+
|
583
|
+
context 'one constraint returns false' do
|
584
|
+
# searchable :unless => [:returns_true, :returns_false]
|
585
|
+
before do
|
586
|
+
subject.should_receive(:returns_true).and_return(true)
|
587
|
+
subject.should_receive(:returns_false).and_return(false)
|
588
|
+
subject.class.sunspot_options[:unless] = [:returns_true, 'returns_false']
|
589
|
+
end
|
590
|
+
|
591
|
+
it_should_behave_like 'indexed after save'
|
592
|
+
end
|
593
|
+
end
|
594
|
+
end
|
595
|
+
end
|