outoftime-sunspot 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. data/History.txt +7 -0
  2. data/Manifest.txt +104 -0
  3. data/PostInstall.txt +7 -0
  4. data/README.rdoc +115 -0
  5. data/Rakefile +27 -0
  6. data/config/hoe.rb +74 -0
  7. data/config/requirements.rb +15 -0
  8. data/lib/light_config.rb +40 -0
  9. data/lib/sunspot/adapters.rb +54 -0
  10. data/lib/sunspot/conditions.rb +50 -0
  11. data/lib/sunspot/conditions_builder.rb +37 -0
  12. data/lib/sunspot/configuration.rb +17 -0
  13. data/lib/sunspot/field.rb +108 -0
  14. data/lib/sunspot/field_builder.rb +37 -0
  15. data/lib/sunspot/indexer.rb +65 -0
  16. data/lib/sunspot/query.rb +115 -0
  17. data/lib/sunspot/query_builder.rb +30 -0
  18. data/lib/sunspot/restriction.rb +72 -0
  19. data/lib/sunspot/scope_builder.rb +33 -0
  20. data/lib/sunspot/search.rb +83 -0
  21. data/lib/sunspot/session.rb +43 -0
  22. data/lib/sunspot/type.rb +62 -0
  23. data/lib/sunspot/util.rb +13 -0
  24. data/lib/sunspot/version.rb +10 -0
  25. data/lib/sunspot.rb +50 -0
  26. data/setup.rb +1585 -0
  27. data/solr/README.txt +36 -0
  28. data/solr/etc/jetty.xml +206 -0
  29. data/solr/etc/webdefault.xml +379 -0
  30. data/solr/exampledocs/books.csv +11 -0
  31. data/solr/exampledocs/hd.xml +46 -0
  32. data/solr/exampledocs/ipod_other.xml +50 -0
  33. data/solr/exampledocs/ipod_video.xml +35 -0
  34. data/solr/exampledocs/mem.xml +58 -0
  35. data/solr/exampledocs/monitor.xml +31 -0
  36. data/solr/exampledocs/monitor2.xml +30 -0
  37. data/solr/exampledocs/mp500.xml +39 -0
  38. data/solr/exampledocs/post.jar +0 -0
  39. data/solr/exampledocs/post.sh +28 -0
  40. data/solr/exampledocs/sd500.xml +33 -0
  41. data/solr/exampledocs/solr.xml +38 -0
  42. data/solr/exampledocs/spellchecker.xml +58 -0
  43. data/solr/exampledocs/utf8-example.xml +42 -0
  44. data/solr/exampledocs/vidcard.xml +52 -0
  45. data/solr/lib/jetty-6.1.3.jar +0 -0
  46. data/solr/lib/jetty-util-6.1.3.jar +0 -0
  47. data/solr/lib/jsp-2.1/ant-1.6.5.jar +0 -0
  48. data/solr/lib/jsp-2.1/core-3.1.1.jar +0 -0
  49. data/solr/lib/jsp-2.1/jsp-2.1.jar +0 -0
  50. data/solr/lib/jsp-2.1/jsp-api-2.1.jar +0 -0
  51. data/solr/lib/servlet-api-2.5-6.1.3.jar +0 -0
  52. data/solr/solr/README.txt +52 -0
  53. data/solr/solr/bin/abc +176 -0
  54. data/solr/solr/bin/abo +176 -0
  55. data/solr/solr/bin/backup +108 -0
  56. data/solr/solr/bin/backupcleaner +142 -0
  57. data/solr/solr/bin/commit +128 -0
  58. data/solr/solr/bin/optimize +129 -0
  59. data/solr/solr/bin/readercycle +129 -0
  60. data/solr/solr/bin/rsyncd-disable +77 -0
  61. data/solr/solr/bin/rsyncd-enable +76 -0
  62. data/solr/solr/bin/rsyncd-start +145 -0
  63. data/solr/solr/bin/rsyncd-stop +105 -0
  64. data/solr/solr/bin/scripts-util +83 -0
  65. data/solr/solr/bin/snapcleaner +148 -0
  66. data/solr/solr/bin/snapinstaller +168 -0
  67. data/solr/solr/bin/snappuller +248 -0
  68. data/solr/solr/bin/snappuller-disable +77 -0
  69. data/solr/solr/bin/snappuller-enable +77 -0
  70. data/solr/solr/bin/snapshooter +109 -0
  71. data/solr/solr/conf/admin-extra.html +31 -0
  72. data/solr/solr/conf/protwords.txt +21 -0
  73. data/solr/solr/conf/schema.xml +231 -0
  74. data/solr/solr/conf/scripts.conf +24 -0
  75. data/solr/solr/conf/solrconfig.xml +394 -0
  76. data/solr/solr/conf/stopwords.txt +57 -0
  77. data/solr/solr/conf/synonyms.txt +31 -0
  78. data/solr/start.jar +0 -0
  79. data/solr/webapps/solr.war +0 -0
  80. data/tasks/deployment.rake +34 -0
  81. data/tasks/environment.rake +7 -0
  82. data/tasks/rcov.rake +6 -0
  83. data/tasks/solr.rake +12 -0
  84. data/tasks/website.rake +17 -0
  85. data/test/api/test_build_search.rb +216 -0
  86. data/test/api/test_helper.rb +4 -0
  87. data/test/api/test_indexer.rb +110 -0
  88. data/test/api/test_retrieve_search.rb +114 -0
  89. data/test/api/test_session.rb +46 -0
  90. data/test/custom_expectation.rb +53 -0
  91. data/test/integration/test_field_types.rb +62 -0
  92. data/test/integration/test_helper.rb +1 -0
  93. data/test/integration/test_keyword_search.rb +32 -0
  94. data/test/integration/test_pagination.rb +32 -0
  95. data/test/mocks/base_class.rb +2 -0
  96. data/test/mocks/comment.rb +28 -0
  97. data/test/mocks/mock_adapter.rb +25 -0
  98. data/test/mocks/post.rb +41 -0
  99. data/test/test_helper.rb +31 -0
  100. metadata +191 -0
@@ -0,0 +1,57 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one or more
2
+ # contributor license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright ownership.
4
+ # The ASF licenses this file to You under the Apache License, Version 2.0
5
+ # (the "License"); you may not use this file except in compliance with
6
+ # the License. You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ #-----------------------------------------------------------------------
17
+ # a couple of test stopwords to test that the words are really being
18
+ # configured from this file:
19
+ stopworda
20
+ stopwordb
21
+
22
+ #Standard english stop words taken from Lucene's StopAnalyzer
23
+ an
24
+ and
25
+ are
26
+ as
27
+ at
28
+ be
29
+ but
30
+ by
31
+ for
32
+ if
33
+ in
34
+ into
35
+ is
36
+ it
37
+ no
38
+ not
39
+ of
40
+ on
41
+ or
42
+ s
43
+ such
44
+ t
45
+ that
46
+ the
47
+ their
48
+ then
49
+ there
50
+ these
51
+ they
52
+ this
53
+ to
54
+ was
55
+ will
56
+ with
57
+
@@ -0,0 +1,31 @@
1
+ # The ASF licenses this file to You under the Apache License, Version 2.0
2
+ # (the "License"); you may not use this file except in compliance with
3
+ # the License. You may obtain a copy of the License at
4
+ #
5
+ # http://www.apache.org/licenses/LICENSE-2.0
6
+ #
7
+ # Unless required by applicable law or agreed to in writing, software
8
+ # distributed under the License is distributed on an "AS IS" BASIS,
9
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and
11
+ # limitations under the License.
12
+
13
+ #-----------------------------------------------------------------------
14
+ #some test synonym mappings unlikely to appear in real input text
15
+ aaa => aaaa
16
+ bbb => bbbb1 bbbb2
17
+ ccc => cccc1,cccc2
18
+ a\=>a => b\=>b
19
+ a\,a => b\,b
20
+ fooaaa,baraaa,bazaaa
21
+
22
+ # Some synonym groups specific to this example
23
+ GB,gib,gigabyte,gigabytes
24
+ MB,mib,megabyte,megabytes
25
+ Television, Televisions, TV, TVs
26
+ #notice we use "gib" instead of "GiB" so any WordDelimiterFilter coming
27
+ #after us won't split it into two words.
28
+
29
+ # Synonym mappings can be used for spelling correction too
30
+ pixima => pixma
31
+
data/solr/start.jar ADDED
Binary file
Binary file
@@ -0,0 +1,34 @@
1
+ desc 'Release the website and new gem version'
2
+ task :deploy => [:check_version, :website, :release] do
3
+ puts "Remember to create SVN tag:"
4
+ puts "svn copy svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/trunk " +
5
+ "svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/tags/REL-#{VERS} "
6
+ puts "Suggested comment:"
7
+ puts "Tagging release #{CHANGES}"
8
+ end
9
+
10
+ desc 'Runs tasks website_generate and install_gem as a local deployment of the gem'
11
+ task :local_deploy => [:website_generate, :install_gem]
12
+
13
+ task :check_version do
14
+ unless ENV['VERSION']
15
+ puts 'Must pass a VERSION=x.y.z release version'
16
+ exit
17
+ end
18
+ unless ENV['VERSION'] == VERS
19
+ puts "Please update your version.rb to match the release version, currently #{VERS}"
20
+ exit
21
+ end
22
+ end
23
+
24
+ desc 'Install the package as a gem, without generating documentation(ri/rdoc)'
25
+ task :install_gem_no_doc => [:clean, :package] do
26
+ sh "#{'sudo ' unless Hoe::WINDOZE }gem install pkg/*.gem --no-rdoc --no-ri"
27
+ end
28
+
29
+ namespace :manifest do
30
+ desc 'Recreate Manifest.txt to include ALL files'
31
+ task :refresh do
32
+ `rake check_manifest | patch -p0 > Manifest.txt`
33
+ end
34
+ end
@@ -0,0 +1,7 @@
1
+ task :ruby_env do
2
+ RUBY_APP = if RUBY_PLATFORM =~ /java/
3
+ "jruby"
4
+ else
5
+ "ruby"
6
+ end unless defined? RUBY_APP
7
+ end
data/tasks/rcov.rake ADDED
@@ -0,0 +1,6 @@
1
+ require 'rcov/rcovtask'
2
+ Rcov::RcovTask.new do |t|
3
+ t.test_files = FileList['test/**/test_*.rb']
4
+ t.rcov_opts << "--sort coverage"
5
+ t.rcov_opts << "--only-uncovered"
6
+ end
data/tasks/solr.rake ADDED
@@ -0,0 +1,12 @@
1
+ namespace :solr do
2
+ namespace :test do
3
+ desc 'Start Solr server'
4
+ task :start do
5
+ FileUtils.cd File.join(File.dirname(__FILE__), '..', 'solr') do
6
+ Kernel.fork do
7
+ Kernel.exec("java -jar start.jar 2> #{File.join('..', 'log', 'test_solr.log')}")
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,17 @@
1
+ desc 'Generate website files'
2
+ task :website_generate => :ruby_env do
3
+ (Dir['website/**/*.txt'] - Dir['website/version*.txt']).each do |txt|
4
+ sh %{ #{RUBY_APP} script/txt2html #{txt} > #{txt.gsub(/txt$/,'html')} }
5
+ end
6
+ end
7
+
8
+ desc 'Upload website files to rubyforge'
9
+ task :website_upload do
10
+ host = "#{rubyforge_username}@rubyforge.org"
11
+ remote_dir = "/var/www/gforge-projects/#{PATH}/"
12
+ local_dir = 'website'
13
+ sh %{rsync -aCv #{local_dir}/ #{host}:#{remote_dir}}
14
+ end
15
+
16
+ desc 'Generate and upload website files'
17
+ task :website => [:website_generate, :website_upload, :publish_docs]
@@ -0,0 +1,216 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class TestBuildSearch < Test::Unit::TestCase
4
+ CONFIG = Sunspot::Configuration.build
5
+
6
+ test 'should search by keywords' do
7
+ connection.expects(:query).with('(keyword search) AND (type:Post)', :filter_queries => [], :start => 0, :rows => CONFIG.pagination.default_per_page).times(2)
8
+ session.search Post, :keywords => 'keyword search'
9
+ session.search Post do
10
+ keywords 'keyword search'
11
+ end
12
+ end
13
+
14
+ test 'should scope by exact match with a string' do
15
+ connection.expects(:query).with('(type:Post)', :filter_queries => ['title_s:My\ Pet\ Post'], :start => 0, :rows => CONFIG.pagination.default_per_page).times(2)
16
+ session.search Post, :conditions => { :title => 'My Pet Post' }
17
+ session.search Post do
18
+ with.title 'My Pet Post'
19
+ end
20
+ end
21
+
22
+ test 'should ignore nonexistant fields in hash scope' do
23
+ connection.expects(:query).with('(type:Post)', :filter_queries => [], :start => 0, :rows => CONFIG.pagination.default_per_page)
24
+ session.search Post, :conditions => { :bogus => 'Field' }
25
+ end
26
+
27
+ test 'should raise an ArgumentError for nonexistant fields in block scope' do
28
+ lambda do
29
+ session.search Post do
30
+ with.bogus 'Field'
31
+ end
32
+ end.should raise_error(ArgumentError)
33
+ end
34
+
35
+ test 'should scope by exact match with time' do
36
+ connection.expects(:query).with('(type:Post)', :filter_queries => ['published_at_d:1983\-07\-08T09\:00\:00Z'], :start => 0, :rows => CONFIG.pagination.default_per_page).times(2)
37
+ time = Time.parse('1983-07-08 05:00:00 -0400')
38
+ session.search Post, :conditions => { :published_at => time }
39
+ session.search Post do
40
+ with.published_at time
41
+ end
42
+ end
43
+
44
+ test 'should scope by less than match with float' do
45
+ connection.expects(:query).with('(type:Post)', :filter_queries => ['average_rating_f:[* TO 3\.0]'], :start => 0, :rows => CONFIG.pagination.default_per_page).times(2)
46
+
47
+ session.search Post, :conditions => { :average_rating => 3.0 } do
48
+ conditions.interpret :average_rating, :less_than
49
+ end
50
+
51
+ session.search Post do
52
+ with.average_rating.less_than 3.0
53
+ end
54
+ end
55
+
56
+ test 'should scope by greater than match with float' do
57
+ connection.expects(:query).with('(type:Post)', :filter_queries => ['average_rating_f:[3\.0 TO *]'], :start => 0, :rows => CONFIG.pagination.default_per_page).times(2)
58
+ session.search Post, :conditions => { :average_rating => 3.0 } do
59
+ conditions.interpret :average_rating, :greater_than
60
+ end
61
+ session.search Post do
62
+ with.average_rating.greater_than 3.0
63
+ end
64
+ end
65
+
66
+ test 'should scope by between match with float' do
67
+ connection.expects(:query).with('(type:Post)', :filter_queries => ['average_rating_f:[2\.0 TO 4\.0]'], :start => 0, :rows => CONFIG.pagination.default_per_page).times(2)
68
+ session.search Post, :conditions => { :average_rating => [2.0, 4.0] } do
69
+ conditions.interpret :average_rating, :between
70
+ end
71
+ session.search Post do
72
+ with.average_rating.between 2.0..4.0
73
+ end
74
+ end
75
+
76
+ test 'should scope by any match with integer' do
77
+ connection.expects(:query).with('(type:Post)', :filter_queries => ['category_ids_im:(2 OR 7 OR 12)'], :start => 0, :rows => CONFIG.pagination.default_per_page).times(2)
78
+ session.search Post, :conditions => { :category_ids => [2, 7, 12] }
79
+ session.search Post do
80
+ with.category_ids.any_of [2, 7, 12]
81
+ end
82
+ end
83
+
84
+ test 'should scope by all match with integer' do
85
+ connection.expects(:query).with('(type:Post)', :filter_queries => ['category_ids_im:(2 AND 7 AND 12)'], :start => 0, :rows => CONFIG.pagination.default_per_page).times(2)
86
+ session.search Post, :conditions => { :category_ids => [2, 7, 12] } do
87
+ conditions.interpret :category_ids, :all_of
88
+ end
89
+ session.search Post do
90
+ with.category_ids.all_of [2, 7, 12]
91
+ end
92
+ end
93
+
94
+ test 'should allow setting of default conditions' do
95
+ connection.expects(:query).with('(type:Post)', :filter_queries => ['average_rating_f:2\.0'], :start => 0, :rows => CONFIG.pagination.default_per_page)
96
+ session.search Post do
97
+ conditions.default :average_rating, 2.0
98
+ end
99
+ end
100
+
101
+ test 'should not use default condition value if condition provided' do
102
+ connection.expects(:query).with('(type:Post)', :filter_queries => ['average_rating_f:3\.0'], :start => 0, :rows => CONFIG.pagination.default_per_page)
103
+ session.search Post, :conditions => { :average_rating => 3.0 } do
104
+ conditions.default :average_rating, 2.0
105
+ end
106
+ end
107
+
108
+ test 'should paginate using default per_page' do
109
+ connection.expects(:query).with('(type:Post)', :filter_queries => [], :rows => 30, :start => 30).times(2)
110
+ session.search Post, :page => 2
111
+ session.search Post do
112
+ paginate :page => 2
113
+ end
114
+ end
115
+
116
+ test 'should paginate using provided per_page' do
117
+ connection.expects(:query).with('(type:Post)', :filter_queries => [], :rows => 15, :start => 45).times(2)
118
+ session.search Post, :page => 4, :per_page => 15
119
+ session.search Post do
120
+ paginate :page => 4, :per_page => 15
121
+ end
122
+ end
123
+
124
+ test 'should order' do
125
+ connection.expects(:query).with('(type:Post)', :filter_queries => [], :sort => [{ :average_rating_f => :descending }], :start => 0, :rows => CONFIG.pagination.default_per_page).times(2)
126
+ session.search Post, :order => 'average_rating desc'
127
+ session.search Post do
128
+ order_by :average_rating, :desc
129
+ end
130
+ end
131
+
132
+ test 'should build search for multiple types' do
133
+ connection.expects(:query).with('(type:(Post OR Comment))', :filter_queries => [], :start => 0, :rows => CONFIG.pagination.default_per_page)
134
+ session.search(Post, Comment)
135
+ end
136
+
137
+ test 'should allow search on fields common to all types' do
138
+ connection.expects(:query).with('(type:(Post OR Comment))', :filter_queries => ['published_at_d:1983\-07\-08T09\:00\:00Z'], :start => 0, :rows => CONFIG.pagination.default_per_page).times(2)
139
+ time = Time.parse('1983-07-08 05:00:00 -0400')
140
+ session.search Post, Comment, :conditions => { :published_at => time }
141
+ session.search Post, Comment do
142
+ with.published_at time
143
+ end
144
+ end
145
+
146
+ test 'should raise exception if search scoped to field not common to all types' do
147
+ lambda do
148
+ session.search Post, Comment do
149
+ with.blog_id 1
150
+ end
151
+ end.should raise_error(ArgumentError)
152
+ end
153
+
154
+ test 'should raise exception if search scoped to field configured differently between types' do
155
+ lambda do
156
+ session.search Post, Comment do
157
+ with.average_rating 2.2 # this is a float in Post but an integer in Comment
158
+ end
159
+ end.should raise_error(ArgumentError)
160
+ end
161
+
162
+ test 'should ignore condition if field is not common to all types' do
163
+ connection.expects(:query).with('(type:(Post OR Comment))', :filter_queries => [], :start => 0, :rows => CONFIG.pagination.default_per_page)
164
+ session.search Post, Comment, :conditions => { :blog_id => 1 }
165
+ end
166
+
167
+ test 'should raise ArgumentError if bogus field scoped' do
168
+ lambda do
169
+ session.search Post do
170
+ with.bogus.equal_to :field
171
+ end
172
+ end.should raise_error(ArgumentError)
173
+ end
174
+
175
+ test 'should raise NoMethodError if bogus operator referenced' do
176
+ lambda do
177
+ session.search Post do
178
+ with.category_ids.resembling :bogus_condition
179
+ end
180
+ end.should raise_error(NoMethodError)
181
+ end
182
+
183
+ test 'should raise ArgumentError if no :page argument given to paginate' do
184
+ lambda do
185
+ session.search Post do
186
+ paginate
187
+ end
188
+ end.should raise_error(ArgumentError)
189
+ end
190
+
191
+ test 'should raise ArgumentError if bogus argument given to paginate' do
192
+ lambda do
193
+ session.search Post do
194
+ paginate :page => 4, :ugly => :puppy
195
+ end
196
+ end.should raise_error(ArgumentError)
197
+ end
198
+
199
+ test 'should raise NoMethodError if more than one argument passed to scope method' do # or should it?
200
+ lambda do
201
+ session.search Post do
202
+ with.category_ids 4, 5
203
+ end
204
+ end.should raise_error(NoMethodError)
205
+ end
206
+
207
+ private
208
+
209
+ def connection
210
+ @connection ||= stub
211
+ end
212
+
213
+ def session
214
+ @session ||= Sunspot::Session.new(CONFIG, connection)
215
+ end
216
+ end
@@ -0,0 +1,4 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'test_helper')
2
+
3
+ gem 'mocha', '~>0.9'
4
+ require 'mocha'
@@ -0,0 +1,110 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class TestIndexer < Test::Unit::TestCase
4
+ CONFIG = Sunspot::Configuration.build
5
+
6
+ describe 'when indexing an object' do
7
+ test 'should index id and type' do
8
+ connection.expects(:add).with(has_entries(:id => "Post #{post.id}", :type => ['Post', 'BaseClass']))
9
+ session.index post
10
+ end
11
+
12
+ test 'should index text' do
13
+ post :title => 'A Title', :body => 'A Post'
14
+ connection.expects(:add).with(has_entries(:title_text => 'A Title', :body_text => 'A Post'))
15
+ session.index post
16
+ end
17
+
18
+ test 'should correctly index a string attribute field' do
19
+ post :title => 'A Title'
20
+ connection.expects(:add).with(has_entries(:title_s => 'A Title'))
21
+ session.index post
22
+ end
23
+
24
+ test 'should correctly index an integer attribute field' do
25
+ post :blog_id => 4
26
+ connection.expects(:add).with(has_entries(:blog_id_i => '4'))
27
+ session.index post
28
+ end
29
+
30
+ test 'should correctly index a float attribute field' do
31
+ post :average_rating => 2.23
32
+ connection.expects(:add).with(has_entries(:average_rating_f => '2.23'))
33
+ session.index post
34
+ end
35
+
36
+ test 'should allow indexing by a multiple-value field' do
37
+ post :category_ids => [3, 14]
38
+ connection.expects(:add).with(has_entries(:category_ids_im => ['3', '14']))
39
+ session.index post
40
+ end
41
+
42
+ test 'should correctly index a time field' do
43
+ post :published_at => Time.parse('1983-07-08 05:00:00 -0400')
44
+ connection.expects(:add).with(has_entries(:published_at_d => '1983-07-08T09:00:00Z'))
45
+ session.index post
46
+ end
47
+
48
+ test 'should correctly index a virtual field' do
49
+ post :title => 'The Blog Post'
50
+ connection.expects(:add).with(has_entries(:sort_title_s => 'blog post'))
51
+ session.index post
52
+ end
53
+
54
+ test 'should correctly index a field that is defined on a superclass' do
55
+ Sunspot.setup(BaseClass) { string :author_name }
56
+ post :author_name => 'Mat Brown'
57
+ connection.expects(:add).with(has_entries(:author_name_s => 'Mat Brown'))
58
+ session.index post
59
+ end
60
+
61
+ test 'should remove an object from the index' do
62
+ connection.expects(:delete).with("Post #{post.id}")
63
+ session.remove(post)
64
+ end
65
+
66
+ test 'should be able to remove everything from the index' do
67
+ connection.expects(:delete_by_query).with("type:[* TO *]")
68
+ session.remove_all
69
+ end
70
+
71
+ test 'should be able to remove everything of a given class from the index' do
72
+ connection.expects(:delete_by_query).with("type:Post")
73
+ session.remove_all(Post)
74
+ end
75
+ end
76
+
77
+ test 'should throw a NoMethodError only if a nonexistent type is defined' do
78
+ lambda { Sunspot.setup(Post) { string :author_name }}.should_not raise_error
79
+ lambda { Sunspot.setup(Post) { bogus :journey }}.should raise_error(NoMethodError)
80
+ end
81
+
82
+ test 'should throw a NoMethodError if a nonexistent field argument is passed' do
83
+ lambda { Sunspot.setup(Post) { string :author_name, :bogus => :argument }}.should raise_error(ArgumentError)
84
+ end
85
+
86
+ test 'should throw an ArgumentError if an attempt is made to index an object that has no configuration' do
87
+ lambda { session.index(Time.now) }.should raise_error(ArgumentError)
88
+ end
89
+
90
+ test 'should throw an ArgumentError if single-value field tries to index multiple values' do
91
+ lambda do
92
+ Sunspot.setup(Post) { string :author_name }
93
+ session.index(post(:author_name => ['Mat Brown', 'Matthew Brown']))
94
+ end.should raise_error(ArgumentError)
95
+ end
96
+
97
+ private
98
+
99
+ def connection
100
+ @connection ||= stub
101
+ end
102
+
103
+ def session
104
+ @session ||= Sunspot::Session.new(CONFIG, connection)
105
+ end
106
+
107
+ def post(attrs = {})
108
+ @post ||= Post.new(attrs)
109
+ end
110
+ end
@@ -0,0 +1,114 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class TestRetrieveSearch < Test::Unit::TestCase
4
+ CONFIG = Sunspot::Configuration.build
5
+
6
+ test 'should load search result' do
7
+ post = Post.new
8
+ stub_results(post)
9
+
10
+ session.search(Post).results.should == [post]
11
+ end
12
+
13
+ test 'should load multiple search results in order' do
14
+ post_1, post_2 = Post.new, Post.new
15
+ stub_results(post_1, post_2)
16
+ session.search(Post).results.should == [post_1, post_2]
17
+ stub_results(post_2, post_1)
18
+ session.search(Post).results.should == [post_2, post_1]
19
+ end
20
+
21
+ test 'should return search total as attribute of results if pagination is provided' do
22
+ stub_results(Post.new, 4)
23
+ session.search(Post, :page => 1).results.total_entries.should == 4
24
+ end
25
+
26
+ test 'should return vanilla array if pagination is provided but WillPaginate is not available' do
27
+ stub_results(Post.new)
28
+ without_class(WillPaginate) do
29
+ session.search(Post, :page => 1).results.should_not respond_to(:total_entries)
30
+ end
31
+ end
32
+
33
+ test 'should return total' do
34
+ stub_results(Post.new, Post.new, 4)
35
+ session.search(Post, :page => 1).total.should == 4
36
+ end
37
+
38
+ test 'should give access to order through hash and object' do
39
+ stub_results
40
+ search = session.search(Post, :order => 'sort_title asc')
41
+ search.attributes[:order].should == 'sort_title asc'
42
+ search.order.should == 'sort_title asc'
43
+ end
44
+
45
+ test 'should give nil order if no order set' do
46
+ stub_results
47
+ search = session.search(Post)
48
+ search.attributes.should have_key(:order)
49
+ search.attributes[:order].should be_nil
50
+ search.order.should be_nil
51
+ end
52
+
53
+ test 'should give access to page and per-page through hash and object' do
54
+ stub_results
55
+ search = session.search(Post, :page => 2, :per_page => 15)
56
+ search.attributes[:page].should == 2
57
+ search.attributes[:per_page].should == 15
58
+ search.page.should == 2
59
+ search.per_page.should == 15
60
+ end
61
+
62
+ test 'should give access to keywords' do
63
+ stub_results
64
+ search = session.search(Post, :keywords => 'some keywords')
65
+ search.attributes[:keywords].should == 'some keywords'
66
+ search.keywords.should == 'some keywords'
67
+ end
68
+
69
+ test 'should have nil keywords if no keywords given' do
70
+ stub_results
71
+ search = session.search(Post)
72
+ search.attributes.should have_key(:keywords)
73
+ search.attributes[:keywords].should be_nil
74
+ search.keywords.should be_nil
75
+ end
76
+
77
+ test 'should give access to conditions' do
78
+ stub_results
79
+ search = session.search(Post, :conditions => { :blog_id => 1 })
80
+ search.attributes[:conditions][:blog_id].should == 1
81
+ search.conditions.blog_id.should == 1
82
+ end
83
+
84
+ test 'should have nil values for fields with unspecified conditions' do
85
+ stub_results
86
+ search = session.search(Post)
87
+ %w(title blog_id category_ids average_rating published_at sort_title).each do |field_name|
88
+ search.attributes[:conditions].should have_key(field_name.to_sym)
89
+ search.attributes[:conditions][field_name.to_sym].should == nil
90
+ search.conditions.should respond_to(field_name)
91
+ search.conditions.send(field_name).should == nil
92
+ end
93
+ end
94
+
95
+ private
96
+
97
+ def stub_results(*results)
98
+ total_hits = if results.last.is_a?(Integer) then results.pop
99
+ else results.length
100
+ end
101
+ response = stub
102
+ response.stubs(:hits).returns(results.map { |result| { 'id' => "#{result.class.name} #{result.id}" }})
103
+ response.stubs(:total_hits).returns(total_hits)
104
+ connection.stubs(:query).returns(response)
105
+ end
106
+
107
+ def connection
108
+ @connection ||= Object.new
109
+ end
110
+
111
+ def session
112
+ @session ||= Sunspot::Session.new(CONFIG, connection)
113
+ end
114
+ end
@@ -0,0 +1,46 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class TestSession < Test::Unit::TestCase
4
+ context 'using singleton session' do
5
+ before do
6
+ Sunspot.reset!
7
+ connection.expects(:add)
8
+ connection.expects(:query)
9
+ end
10
+
11
+ test 'should open connection with defaults if nothing specified' do
12
+ Solr::Connection.stubs(:new).with('http://localhost:8983/solr', :autocommit => :on).returns(connection)
13
+ Sunspot.index(Post.new)
14
+ Sunspot.search(Post)
15
+ end
16
+
17
+ test 'should open a connection with custom host' do
18
+ Solr::Connection.stubs(:new).with('http://127.0.0.1:8981/solr', :autocommit => :on).returns(connection)
19
+ Sunspot.config.solr.url = 'http://127.0.0.1:8981/solr'
20
+ Sunspot.index(Post.new)
21
+ Sunspot.search(Post)
22
+ end
23
+ end
24
+
25
+ context 'using custom session' do
26
+ before do
27
+ connection.expects(:add)
28
+ connection.expects(:query)
29
+ end
30
+
31
+ test 'should open a connection with custom host' do
32
+ Solr::Connection.stubs(:new).with('http://127.0.0.1:8982/solr', :autocommit => :on).returns(connection)
33
+ session = Sunspot::Session.new do |config|
34
+ config.solr.url = 'http://127.0.0.1:8982/solr'
35
+ end
36
+ session.index(Post.new)
37
+ session.search(Post)
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def connection
44
+ @connection ||= stub_everything('Connection')
45
+ end
46
+ end