muck-solr 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (156) hide show
  1. data/CHANGE_LOG +239 -0
  2. data/LICENSE +19 -0
  3. data/README.markdown +118 -0
  4. data/README.rdoc +107 -0
  5. data/Rakefile +99 -0
  6. data/TESTING_THE_PLUGIN +25 -0
  7. data/VERSION.yml +4 -0
  8. data/config/solr.yml +15 -0
  9. data/config/solr_environment.rb +32 -0
  10. data/lib/acts_as_solr.rb +65 -0
  11. data/lib/acts_as_solr/acts_methods.rb +352 -0
  12. data/lib/acts_as_solr/class_methods.rb +236 -0
  13. data/lib/acts_as_solr/common_methods.rb +89 -0
  14. data/lib/acts_as_solr/deprecation.rb +61 -0
  15. data/lib/acts_as_solr/instance_methods.rb +165 -0
  16. data/lib/acts_as_solr/lazy_document.rb +18 -0
  17. data/lib/acts_as_solr/parser_methods.rb +203 -0
  18. data/lib/acts_as_solr/search_results.rb +68 -0
  19. data/lib/acts_as_solr/solr_fixtures.rb +13 -0
  20. data/lib/acts_as_solr/tasks.rb +10 -0
  21. data/lib/acts_as_solr/tasks/database.rake +16 -0
  22. data/lib/acts_as_solr/tasks/solr.rake +135 -0
  23. data/lib/acts_as_solr/tasks/test.rake +5 -0
  24. data/lib/solr.rb +26 -0
  25. data/lib/solr/connection.rb +177 -0
  26. data/lib/solr/document.rb +75 -0
  27. data/lib/solr/exception.rb +13 -0
  28. data/lib/solr/field.rb +36 -0
  29. data/lib/solr/importer.rb +19 -0
  30. data/lib/solr/importer/array_mapper.rb +26 -0
  31. data/lib/solr/importer/delimited_file_source.rb +38 -0
  32. data/lib/solr/importer/hpricot_mapper.rb +27 -0
  33. data/lib/solr/importer/mapper.rb +51 -0
  34. data/lib/solr/importer/solr_source.rb +41 -0
  35. data/lib/solr/importer/xpath_mapper.rb +35 -0
  36. data/lib/solr/indexer.rb +52 -0
  37. data/lib/solr/request.rb +26 -0
  38. data/lib/solr/request/add_document.rb +58 -0
  39. data/lib/solr/request/base.rb +36 -0
  40. data/lib/solr/request/commit.rb +29 -0
  41. data/lib/solr/request/delete.rb +48 -0
  42. data/lib/solr/request/dismax.rb +46 -0
  43. data/lib/solr/request/index_info.rb +22 -0
  44. data/lib/solr/request/modify_document.rb +46 -0
  45. data/lib/solr/request/optimize.rb +19 -0
  46. data/lib/solr/request/ping.rb +36 -0
  47. data/lib/solr/request/select.rb +54 -0
  48. data/lib/solr/request/spellcheck.rb +30 -0
  49. data/lib/solr/request/standard.rb +402 -0
  50. data/lib/solr/request/update.rb +23 -0
  51. data/lib/solr/response.rb +27 -0
  52. data/lib/solr/response/add_document.rb +17 -0
  53. data/lib/solr/response/base.rb +42 -0
  54. data/lib/solr/response/commit.rb +15 -0
  55. data/lib/solr/response/delete.rb +13 -0
  56. data/lib/solr/response/dismax.rb +8 -0
  57. data/lib/solr/response/index_info.rb +26 -0
  58. data/lib/solr/response/modify_document.rb +17 -0
  59. data/lib/solr/response/optimize.rb +14 -0
  60. data/lib/solr/response/ping.rb +26 -0
  61. data/lib/solr/response/ruby.rb +42 -0
  62. data/lib/solr/response/select.rb +17 -0
  63. data/lib/solr/response/spellcheck.rb +20 -0
  64. data/lib/solr/response/standard.rb +60 -0
  65. data/lib/solr/response/xml.rb +39 -0
  66. data/lib/solr/solrtasks.rb +27 -0
  67. data/lib/solr/util.rb +32 -0
  68. data/lib/solr/xml.rb +44 -0
  69. data/solr/CHANGES.txt +1207 -0
  70. data/solr/LICENSE.txt +712 -0
  71. data/solr/NOTICE.txt +90 -0
  72. data/solr/etc/jetty.xml +205 -0
  73. data/solr/etc/webdefault.xml +379 -0
  74. data/solr/lib/easymock.jar +0 -0
  75. data/solr/lib/jetty-6.1.3.jar +0 -0
  76. data/solr/lib/jetty-util-6.1.3.jar +0 -0
  77. data/solr/lib/jsp-2.1/ant-1.6.5.jar +0 -0
  78. data/solr/lib/jsp-2.1/core-3.1.1.jar +0 -0
  79. data/solr/lib/jsp-2.1/jsp-2.1.jar +0 -0
  80. data/solr/lib/jsp-2.1/jsp-api-2.1.jar +0 -0
  81. data/solr/lib/servlet-api-2.4.jar +0 -0
  82. data/solr/lib/servlet-api-2.5-6.1.3.jar +0 -0
  83. data/solr/lib/xpp3-1.1.3.4.O.jar +0 -0
  84. data/solr/solr/README.txt +52 -0
  85. data/solr/solr/bin/abc +176 -0
  86. data/solr/solr/bin/abo +176 -0
  87. data/solr/solr/bin/backup +108 -0
  88. data/solr/solr/bin/backupcleaner +142 -0
  89. data/solr/solr/bin/commit +128 -0
  90. data/solr/solr/bin/optimize +129 -0
  91. data/solr/solr/bin/readercycle +129 -0
  92. data/solr/solr/bin/rsyncd-disable +77 -0
  93. data/solr/solr/bin/rsyncd-enable +76 -0
  94. data/solr/solr/bin/rsyncd-start +145 -0
  95. data/solr/solr/bin/rsyncd-stop +105 -0
  96. data/solr/solr/bin/scripts-util +83 -0
  97. data/solr/solr/bin/snapcleaner +148 -0
  98. data/solr/solr/bin/snapinstaller +168 -0
  99. data/solr/solr/bin/snappuller +248 -0
  100. data/solr/solr/bin/snappuller-disable +77 -0
  101. data/solr/solr/bin/snappuller-enable +77 -0
  102. data/solr/solr/bin/snapshooter +109 -0
  103. data/solr/solr/conf/admin-extra.html +31 -0
  104. data/solr/solr/conf/protwords.txt +21 -0
  105. data/solr/solr/conf/schema.xml +126 -0
  106. data/solr/solr/conf/scripts.conf +24 -0
  107. data/solr/solr/conf/solrconfig.xml +458 -0
  108. data/solr/solr/conf/stopwords.txt +57 -0
  109. data/solr/solr/conf/synonyms.txt +31 -0
  110. data/solr/solr/conf/xslt/example.xsl +132 -0
  111. data/solr/solr/conf/xslt/example_atom.xsl +63 -0
  112. data/solr/solr/conf/xslt/example_rss.xsl +62 -0
  113. data/solr/start.jar +0 -0
  114. data/solr/webapps/solr.war +0 -0
  115. data/test/config/solr.yml +2 -0
  116. data/test/db/connections/mysql/connection.rb +10 -0
  117. data/test/db/connections/sqlite/connection.rb +8 -0
  118. data/test/db/migrate/001_create_books.rb +15 -0
  119. data/test/db/migrate/002_create_movies.rb +12 -0
  120. data/test/db/migrate/003_create_categories.rb +11 -0
  121. data/test/db/migrate/004_create_electronics.rb +16 -0
  122. data/test/db/migrate/005_create_authors.rb +12 -0
  123. data/test/db/migrate/006_create_postings.rb +9 -0
  124. data/test/db/migrate/007_create_posts.rb +13 -0
  125. data/test/db/migrate/008_create_gadgets.rb +11 -0
  126. data/test/fixtures/authors.yml +9 -0
  127. data/test/fixtures/books.yml +13 -0
  128. data/test/fixtures/categories.yml +7 -0
  129. data/test/fixtures/db_definitions/mysql.sql +41 -0
  130. data/test/fixtures/electronics.yml +49 -0
  131. data/test/fixtures/movies.yml +9 -0
  132. data/test/fixtures/postings.yml +10 -0
  133. data/test/functional/acts_as_solr_test.rb +413 -0
  134. data/test/functional/association_indexing_test.rb +37 -0
  135. data/test/functional/faceted_search_test.rb +163 -0
  136. data/test/functional/multi_solr_search_test.rb +57 -0
  137. data/test/models/author.rb +10 -0
  138. data/test/models/book.rb +10 -0
  139. data/test/models/category.rb +8 -0
  140. data/test/models/electronic.rb +25 -0
  141. data/test/models/gadget.rb +9 -0
  142. data/test/models/movie.rb +17 -0
  143. data/test/models/novel.rb +2 -0
  144. data/test/models/post.rb +3 -0
  145. data/test/models/posting.rb +11 -0
  146. data/test/test_helper.rb +54 -0
  147. data/test/unit/acts_methods_shoulda.rb +68 -0
  148. data/test/unit/class_methods_shoulda.rb +85 -0
  149. data/test/unit/common_methods_shoulda.rb +111 -0
  150. data/test/unit/instance_methods_shoulda.rb +318 -0
  151. data/test/unit/lazy_document_shoulda.rb +34 -0
  152. data/test/unit/parser_instance.rb +19 -0
  153. data/test/unit/parser_methods_shoulda.rb +268 -0
  154. data/test/unit/solr_instance.rb +49 -0
  155. data/test/unit/test_helper.rb +24 -0
  156. metadata +241 -0
@@ -0,0 +1,9 @@
1
+ class CreatePostings < ActiveRecord::Migration
2
+ def self.up
3
+ execute "CREATE TABLE postings(`guid` varchar(20) NOT NULL PRIMARY KEY, `name` varchar(200), `description` text)"
4
+ end
5
+
6
+ def self.down
7
+ drop_table :postings
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ class CreatePosts < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :posts, :force => true do |t|
4
+ t.column :name, :string
5
+ t.column :reply_counter, :integer
6
+ t.column :posted_at, :datetime
7
+ end
8
+ end
9
+
10
+ def self.down
11
+ drop_table :posts
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ class CreateGadgets < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :gadgets, :force => true do |t|
4
+ t.column :name, :string
5
+ end
6
+ end
7
+
8
+ def self.down
9
+ drop_table :gadgets
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ tom_clancy:
2
+ id: 1
3
+ name: Tom Clancy
4
+ biography: Tom Clancy (born 1947) writes novels of adventure and espionage in the international military-industrial complex that have earned him enormous popularity in the 1980s as a creator of the "techno-thriller" genre.
5
+
6
+ stephen_king:
7
+ id: 2
8
+ name: Stephen King
9
+ biography: Stephen King (born 1947) is a prolific and immensely popular author of horror fiction. In his works, King blends elements of the traditional gothic tale with those of the modern psychological thriller, detective, and science fiction genres.
@@ -0,0 +1,13 @@
1
+ splinter_cell:
2
+ id: 1
3
+ category_id: 1
4
+ name: Splinter Cell
5
+ author: Tom Clancy
6
+ published_on: <%= Date.today - 1.year %>
7
+
8
+ ruby:
9
+ id: 2
10
+ category_id: 2
11
+ name: Ruby for Dummies
12
+ author: Peter McPeterson
13
+ published_on: <%= Date.today - 2.years %>
@@ -0,0 +1,7 @@
1
+ thriller:
2
+ id: 1
3
+ name: Thriller/Novels
4
+
5
+ technical:
6
+ id: 2
7
+ name: Technical Books
@@ -0,0 +1,41 @@
1
+ DROP DATABASE IF EXISTS `actsassolr_tests`;
2
+ CREATE DATABASE IF NOT EXISTS `actsassolr_tests`;
3
+ USE `actsassolr_tests`
4
+
5
+ CREATE TABLE `books` (
6
+ `id` int(11) NOT NULL auto_increment,
7
+ `category_id` int(11),
8
+ `name` varchar(200) default NULL,
9
+ `author` varchar(200) default NULL,
10
+ PRIMARY KEY (`id`)
11
+ );
12
+
13
+ CREATE TABLE `movies` (
14
+ `id` int(11) NOT NULL auto_increment,
15
+ `name` varchar(200) default NULL,
16
+ `description` varchar(255) default NULL,
17
+ PRIMARY KEY (`id`)
18
+ );
19
+
20
+ CREATE TABLE `categories` (
21
+ `id` int(11) NOT NULL auto_increment,
22
+ `name` varchar(200) default NULL,
23
+ PRIMARY KEY (`id`)
24
+ );
25
+
26
+ CREATE TABLE `electronics` (
27
+ `id` int(11) NOT NULL auto_increment,
28
+ `name` varchar(200) default NULL,
29
+ `manufacturer` varchar(255) default NULL,
30
+ `features` varchar(255) default NULL,
31
+ `category` varchar(255) default NULL,
32
+ `price` varchar(20) default NULL,
33
+ PRIMARY KEY (`id`)
34
+ );
35
+
36
+ CREATE TABLE `authors` (
37
+ `id` int(11) NOT NULL auto_increment,
38
+ `name` varchar(200) default NULL,
39
+ `biography` text default NULL,
40
+ PRIMARY KEY (`id`)
41
+ );
@@ -0,0 +1,49 @@
1
+ ipod_video:
2
+ id: 1
3
+ name: Apple 60 GB Memory iPod with Video Playback Black
4
+ manufacturer: Apple Computer Inc.
5
+ features: iTunes, Podcasts, Audiobooks
6
+ category: Electronics
7
+ price: 599.00
8
+ created_at: <%= (Time.now - 1.year).utc %>
9
+ updated_at: <%= (Time.now - 1.month).utc %>
10
+
11
+ dell_monitor:
12
+ id: 2
13
+ name: Dell Widescreen UltraSharp 3007WFP
14
+ manufacturer: Dell, Inc
15
+ features: 30" TFT active matrix LCD, 2560 x 1600, .25mm dot pitch, 700:1 contrast
16
+ category: Electronics
17
+ price: 750.00
18
+ created_at: <%= (Time.now - 1.year).utc %>
19
+ updated_at: <%= (Time.now - 1.month).utc %>
20
+
21
+ samsung_hd:
22
+ id: 3
23
+ name: Samsung SpinPoint P120 SP2514N - hard drive - 250 GB of Memory Storage - ATA-133
24
+ manufacturer: Samsung Electronics Co. Ltd.
25
+ features: 7200RPM, 8MB cache, IDE Ultra ATA-133
26
+ category: Hard Drive
27
+ price: 319.00
28
+ created_at: <%= (Time.now - 2.years).utc %>
29
+ updated_at: <%= (Time.now - 2.months).utc %>
30
+
31
+ corsair_ram:
32
+ id: 4
33
+ name: CORSAIR XMS 2GB (2 x 1GB) 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) Dual Channel Kit System Memory - Retail
34
+ manufacturer: Corsair Microsystems Inc.
35
+ features: CAS latency 2, 2-3-3-6 timing, 2.75v, unbuffered, heat-spreader
36
+ category: Memory
37
+ price: 155.00
38
+ created_at: <%= (Time.now - 6.years).utc %>
39
+ updated_at: <%= (Time.now - 3.months).utc %>
40
+
41
+ a_data_ram:
42
+ id: 5
43
+ name: A-DATA V-Series 1GB 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) System Memory - OEM
44
+ manufacturer: A-DATA Technology Inc.
45
+ features: CAS latency 3, 2.7v
46
+ category: Memory
47
+ price: 65.79
48
+ created_at: <%= (Time.now - 9.years).utc %>
49
+ updated_at: <%= (Time.now - 4.months).utc %>
@@ -0,0 +1,9 @@
1
+ napoleon_dynamite:
2
+ id: 1
3
+ name: Napoleon Dynamite
4
+ description: Cool movie about a goofy guy
5
+
6
+ office_space:
7
+ id: 2
8
+ name: Office Space
9
+ description: Hypnotized dude loves fishing but not working
@@ -0,0 +1,10 @@
1
+ first:
2
+ guid: ABC-123
3
+ name: Posting ABC
4
+ description: First posting testing primary key as string
5
+
6
+ second:
7
+ guid: DEF-456
8
+ name: Posting DEF
9
+ description: Second posting testing primary key as string
10
+
@@ -0,0 +1,413 @@
1
+ # encoding: utf-8
2
+ require "#{File.dirname(File.expand_path(__FILE__))}/../test_helper"
3
+
4
+ class ActsAsSolrTest < Test::Unit::TestCase
5
+
6
+ fixtures :books, :movies, :electronics, :postings, :authors
7
+
8
+ # Inserting new data into Solr and making sure it's getting indexed
9
+ def test_insert_new_data
10
+ assert_equal 2, Book.count_by_solr('ruby OR splinter OR bob')
11
+ b = Book.create(:name => "Fuze in action", :author => "Bob Bobber", :category_id => 1)
12
+ assert b.valid?
13
+ assert_equal 3, Book.count_by_solr('ruby OR splinter OR bob')
14
+ end
15
+
16
+ # Check the type column stored in the index isn't stemmed by SOLR. If it is stemmed,
17
+ # then both Post and Posting will be stored as type:Post, so a query for Posts will
18
+ # return Postings and vice versa
19
+
20
+ def test_insert_new_data_doesnt_stem_type
21
+ assert_equal 0, Post.count_by_solr('aardvark')
22
+ p = Posting.new :name => 'aardvark', :description => "An interesting animal"
23
+ p.guid = '12AB'
24
+ p.save!
25
+ assert_equal 0, Post.count_by_solr('aardvark')
26
+ end
27
+
28
+ def test_type_determined_from_database_if_not_explicitly_set
29
+ assert Post.configuration[:solr_fields][:posted_at][:type] == :date
30
+ end
31
+
32
+ def test_search_includes_subclasses
33
+ Novel.create! :name => 'Wuthering Heights', :author => 'Emily Bronte'
34
+ Book.create! :name => 'Jane Eyre', :author => 'Charlotte Bronte'
35
+ assert_equal 1, Novel.find_by_solr('Bronte').total_hits
36
+ assert_equal 2, Book.find_by_solr('Bronte').total_hits
37
+ end
38
+
39
+ # Testing basic solr search:
40
+ # Model.find_by_solr 'term'
41
+ # Note that you're able to mix free-search with fields and boolean operators
42
+ def test_find_by_solr_ruby
43
+ ['ruby', 'dummy', 'name:ruby', 'name:dummy', 'name:ruby AND author:peter',
44
+ 'author:peter AND ruby', 'peter dummy'].each do |term|
45
+ records = Book.find_by_solr term
46
+ assert_equal 1, records.total
47
+ assert_equal "Peter McPeterson", records.docs.first.author
48
+ assert_equal "Ruby for Dummies", records.docs.first.name
49
+ assert_equal ({"id" => 2,
50
+ "category_id" => 2,
51
+ "name" => "Ruby for Dummies",
52
+ "author" => "Peter McPeterson", "published_on" => (Date.today - 2.years), "type" => nil}), records.docs.first.attributes
53
+ end
54
+ end
55
+
56
+ # Testing basic solr search:
57
+ # Model.find_by_solr 'term'
58
+ # Note that you're able to mix free-search with fields and boolean operators
59
+ def test_find_by_solr_splinter
60
+ ['splinter', 'name:splinter', 'name:splinter AND author:clancy',
61
+ 'author:clancy AND splinter', 'cell tom'].each do |term|
62
+ records = Book.find_by_solr term
63
+ assert_equal 1, records.total
64
+ assert_equal "Splinter Cell", records.docs.first.name
65
+ assert_equal "Tom Clancy", records.docs.first.author
66
+ assert_equal ({"id" => 1, "category_id" => 1, "name" => "Splinter Cell",
67
+ "author" => "Tom Clancy", "published_on" => (Date.today - 1.year), "type" => nil}), records.docs.first.attributes
68
+ end
69
+ end
70
+
71
+ # Testing basic solr search:
72
+ # Model.find_by_solr 'term'
73
+ # Note that you're able to mix free-search with fields and boolean operators
74
+ def test_find_by_solr_ruby_or_splinter
75
+ ['ruby OR splinter', 'ruby OR author:tom', 'name:cell OR author:peter', 'dummy OR cell'].each do |term|
76
+ records = Book.find_by_solr term
77
+ assert_equal 2, records.total
78
+ end
79
+ end
80
+
81
+ # Testing search in indexed field methods:
82
+ #
83
+ # class Movie < ActiveRecord::Base
84
+ # acts_as_solr :fields => [:name, :description, :current_time]
85
+ #
86
+ # def current_time
87
+ # Time.now.to_s
88
+ # end
89
+ #
90
+ # end
91
+ #
92
+ # The method current_time above gets indexed as being part of the
93
+ # Movie model and it's available for search as well
94
+ def test_find_with_dynamic_fields
95
+ date = Time.now.strftime('%b %d %Y')
96
+ ["dynamite AND #{date}", "description:goofy AND #{date}", "goofy napoleon #{date}",
97
+ "goofiness #{date}"].each do |term|
98
+ records = Movie.find_by_solr term
99
+ assert_equal 1, records.total
100
+ assert_equal ({"id" => 1, "name" => "Napoleon Dynamite",
101
+ "description" => "Cool movie about a goofy guy"}), records.docs.first.attributes
102
+ end
103
+ end
104
+
105
+ # Testing basic solr search that returns just the ids instead of the objects:
106
+ # Model.find_id_by_solr 'term'
107
+ # Note that you're able to mix free-search with fields and boolean operators
108
+ def test_find_id_by_solr_ruby
109
+ ['ruby', 'dummy', 'name:ruby', 'name:dummy', 'name:ruby AND author:peter',
110
+ 'author:peter AND ruby'].each do |term|
111
+ records = Book.find_id_by_solr term
112
+ assert_equal 1, records.docs.size
113
+ assert_equal [2], records.docs
114
+ end
115
+ end
116
+
117
+ # Testing basic solr search that returns just the ids instead of the objects:
118
+ # Model.find_id_by_solr 'term'
119
+ # Note that you're able to mix free-search with fields and boolean operators
120
+ def test_find_id_by_solr_splinter
121
+ ['splinter', 'name:splinter', 'name:splinter AND author:clancy',
122
+ 'author:clancy AND splinter'].each do |term|
123
+ records = Book.find_id_by_solr term
124
+ assert_equal 1, records.docs.size
125
+ assert_equal [1], records.docs
126
+ end
127
+ end
128
+
129
+ # Testing basic solr search that returns just the ids instead of the objects:
130
+ # Model.find_id_by_solr 'term'
131
+ # Note that you're able to mix free-search with fields and boolean operators
132
+ def test_find_id_by_solr_ruby_or_splinter
133
+ ['ruby OR splinter', 'ruby OR author:tom', 'name:cell OR author:peter',
134
+ 'dummy OR cell'].each do |term|
135
+ records = Book.find_id_by_solr term
136
+ assert_equal 2, records.docs.size
137
+ assert_equal [1,2], records.docs
138
+ end
139
+ end
140
+
141
+ # Testing basic solr search that returns the total number of records found:
142
+ # Model.find_count_by_solr 'term'
143
+ # Note that you're able to mix free-search with fields and boolean operators
144
+ def test_count_by_solr
145
+ ['ruby', 'dummy', 'name:ruby', 'name:dummy', 'name:ruby AND author:peter',
146
+ 'author:peter AND ruby'].each do |term|
147
+ assert_equal 1, Book.count_by_solr(term), "there should only be 1 result for search: #{term}"
148
+ end
149
+ end
150
+
151
+ # Testing basic solr search that returns the total number of records found:
152
+ # Model.find_count_by_solr 'term'
153
+ # Note that you're able to mix free-search with fields and boolean operators
154
+ def test_count_by_solr_splinter
155
+ ['splinter', 'name:splinter', 'name:splinter AND author:clancy',
156
+ 'author:clancy AND splinter', 'author:clancy cell'].each do |term|
157
+ assert_equal 1, Book.count_by_solr(term)
158
+ end
159
+ end
160
+
161
+ # Testing basic solr search that returns the total number of records found:
162
+ # Model.find_count_by_solr 'term'
163
+ # Note that you're able to mix free-search with fields and boolean operators
164
+ def test_count_by_solr_ruby_or_splinter
165
+ ['ruby OR splinter', 'ruby OR author:tom', 'name:cell OR author:peter', 'dummy OR cell'].each do |term|
166
+ assert_equal 2, Book.count_by_solr(term)
167
+ end
168
+ end
169
+
170
+ # Testing basic solr search with additional options:
171
+ # Model.find_count_by_solr 'term', :limit => 10, :offset => 0
172
+ def test_find_with_options
173
+ [1,2].each do |count|
174
+ records = Book.find_by_solr 'ruby OR splinter', :limit => count
175
+ assert_equal count, records.docs.size
176
+ end
177
+ end
178
+
179
+ # Testing self.rebuild_solr_index
180
+ # - It makes sure the index is rebuilt after a data has been lost
181
+ def test_rebuild_solr_index
182
+ assert_equal 1, Book.count_by_solr('splinter')
183
+
184
+ Book.find(:first).solr_destroy
185
+ assert_equal 0, Book.count_by_solr('splinter')
186
+
187
+ Book.rebuild_solr_index
188
+ assert_equal 1, Book.count_by_solr('splinter')
189
+ end
190
+
191
+ # Testing instance methods:
192
+ # - solr_save
193
+ # - solr_destroy
194
+ def test_solr_save_and_solr_destroy
195
+ assert_equal 1, Book.count_by_solr('splinter')
196
+
197
+ Book.find(:first).solr_destroy
198
+ assert_equal 0, Book.count_by_solr('splinter')
199
+
200
+ Book.find(:first).solr_save
201
+ assert_equal 1, Book.count_by_solr('splinter')
202
+ end
203
+
204
+ # Testing the order of results
205
+ def test_find_returns_records_in_order
206
+ records = Book.find_by_solr 'ruby^5 OR splinter'
207
+ # we boosted ruby so ruby should come first
208
+
209
+ assert_equal 2, records.total
210
+ assert_equal 'Ruby for Dummies', records.docs.first.name
211
+ assert_equal 'Splinter Cell', records.docs.last.name
212
+ end
213
+
214
+ # Testing solr search with optional :order argument
215
+ def _test_with_order_option
216
+ records = Movie.find_by_solr 'office^5 OR goofiness'
217
+ assert_equal 'Hypnotized dude loves fishing but not working', records.docs.first.description
218
+ assert_equal 'Cool movie about a goofy guy', records.docs.last.description
219
+
220
+ records = Movie.find_by_solr 'office^5 OR goofiness', :order => 'description asc'
221
+ assert_equal 'Cool movie about a goofy guy', records.docs.first.description
222
+ assert_equal 'Hypnotized dude loves fishing but not working', records.docs.last.description
223
+ end
224
+
225
+ # Testing search with omitted :field_types should
226
+ # return the same result set as if when we use it
227
+ def test_omit_field_types_in_search
228
+ records = Electronic.find_by_solr "price:[200 TO 599.99]"
229
+ assert_match(/599/, records.docs.first.price)
230
+ assert_match(/319/, records.docs.last.price)
231
+
232
+ records = Electronic.find_by_solr "price:[200 TO 599.99]", :order => 'price asc'
233
+ assert_match(/319/, records.docs.first.price)
234
+ assert_match(/599/, records.docs.last.price)
235
+
236
+ end
237
+
238
+ # Test to make sure the result returned when no matches
239
+ # are found has the same structure when there are results
240
+ def test_returns_no_matches
241
+ records = Book.find_by_solr 'rubyist'
242
+ assert_equal [], records.docs
243
+ assert_equal 0, records.total
244
+
245
+ records = Book.find_id_by_solr 'rubyist'
246
+ assert_equal [], records.docs
247
+ assert_equal 0, records.total
248
+
249
+ records = Book.find_by_solr 'rubyist', :facets => {}
250
+ assert_equal [], records.docs
251
+ assert_equal 0, records.total
252
+ assert_equal({"facet_fields"=>[]}, records.facets)
253
+ end
254
+
255
+
256
+ # Testing the :exclude_fields option when set in the
257
+ # model to make sure it doesn't get indexed
258
+ def test_exclude_fields_option
259
+ records = Electronic.find_by_solr 'audiobooks OR latency'
260
+ assert records.docs.empty?
261
+ assert_equal 0, records.total
262
+
263
+ assert_nothing_raised{
264
+ records = Electronic.find_by_solr 'features:audiobooks'
265
+ assert records.docs.empty?
266
+ assert_equal 0, records.total
267
+ }
268
+ end
269
+
270
+ # Testing the :auto_commit option set to false in the model
271
+ # should not send the commit command to Solr
272
+ def test_auto_commit_turned_off
273
+ assert_equal 0, Author.count_by_solr('raymond chandler')
274
+
275
+ original_count = Author.count
276
+ Author.create(:name => 'Raymond Chandler', :biography => 'Writes noirish detective stories')
277
+
278
+ assert_equal original_count + 1, Author.count
279
+ assert_equal 0, Author.count_by_solr('raymond chandler')
280
+ end
281
+
282
+ # Testing models that use a different key as the primary key
283
+ def test_search_on_model_with_string_id_field
284
+ records = Posting.find_by_solr 'first^5 OR second'
285
+ assert_equal 2, records.total
286
+ assert_equal 'ABC-123', records.docs.first.guid
287
+ assert_equal 'DEF-456', records.docs.last.guid
288
+ end
289
+
290
+ # Making sure the result set is ordered correctly even on
291
+ # models that use a different key as the primary key
292
+ def test_records_in_order_on_model_with_string_id_field
293
+ records = Posting.find_by_solr 'first OR second^5'
294
+ assert_equal 2, records.total
295
+ assert_equal 'DEF-456', records.docs.first.guid
296
+ assert_equal 'ABC-123', records.docs.last.guid
297
+ end
298
+
299
+ # Making sure the records are added when passing a batch size
300
+ # to rebuild_solr_index
301
+ def test_using_rebuild_solr_index_with_batch
302
+ assert_equal 2, Movie.count_by_solr('office OR napoleon')
303
+ Movie.find(:all).each(&:solr_destroy)
304
+ assert_equal 0, Movie.count_by_solr('office OR napoleon')
305
+
306
+ Movie.rebuild_solr_index 100
307
+ assert_equal 2, Movie.count_by_solr('office OR napoleon')
308
+ end
309
+
310
+ # Making sure find_by_solr with scores actually return the scores
311
+ # for each individual record
312
+ def test_find_by_solr_with_score
313
+ books = Book.find_by_solr 'ruby^10 OR splinter', :scores => true
314
+ assert_equal 2, books.total
315
+ assert (books.max_score >= 0.3 && books.max_score <= 0.6)
316
+
317
+ books.records.each { |book| assert_not_nil book.solr_score }
318
+ assert (books.docs.first.solr_score >= 0.3 && books.docs.first.solr_score <= 0.6)
319
+ assert (books.docs.last.solr_score >= 0.1 && books.docs.last.solr_score <= 0.2)
320
+ end
321
+
322
+ # Making sure nothing breaks when html entities are inside
323
+ # the content to be indexed; and on the search as well.
324
+ def test_index_and_search_with_html_entities
325
+ description = "
326
+ inverted exclamation mark &iexcl; &#161;
327
+ ¤ currency &curren; &#164;
328
+ ¢ cent &cent; &#162;
329
+ £ pound &pound; &#163;
330
+ ¥ yen &yen; &#165;
331
+ ¦ broken vertical bar &brvbar; &#166;
332
+ § section &sect; &#167;
333
+ ¨ spacing diaeresis &uml; &#168;
334
+ © copyright &copy; &#169;
335
+ ª feminine ordinal indicator &ordf; &#170;
336
+ « angle quotation mark (left) &laquo; &#171;
337
+ ¬ negation &not; &#172;
338
+ ­ soft hyphen &shy; &#173;
339
+ ® registered trademark &reg; &#174;
340
+ ™ trademark &trade; &#8482;
341
+ ¯ spacing macron &macr; &#175;
342
+ ° degree &deg; &#176;
343
+ ± plus-or-minus &plusmn; &#177;
344
+ ² superscript 2 &sup2; &#178;
345
+ ³ superscript 3 &sup3; &#179;
346
+ ´ spacing acute &acute; &#180;
347
+ µ micro &micro; &#181;
348
+ ¶ paragraph &para; &#182;
349
+ · middle dot &middot; &#183;
350
+ ¸ spacing cedilla &cedil; &#184;
351
+ ¹ superscript 1 &sup1; &#185;
352
+ º masculine ordinal indicator &ordm; &#186;
353
+ » angle quotation mark (right) &raquo; &#187;
354
+ ¼ fraction 1/4 &frac14; &#188;
355
+ ½ fraction 1/2 &frac12; &#189;
356
+ ¾ fraction 3/4 &frac34; &#190;
357
+ ¿ inverted question mark &iquest; &#191;
358
+ × multiplication &times; &#215;
359
+ ÷ division &divide; &#247
360
+ &hearts; &diams; &clubs; &spades;"
361
+
362
+ author = Author.create(:name => "Test in Action&trade; - Copyright &copy; Bob", :biography => description)
363
+ assert author.valid?
364
+ author.solr_commit
365
+
366
+ author = Author.find_by_solr 'trademark &copy &#190 &iexcl &#163'
367
+ assert_equal 1, author.total
368
+ end
369
+
370
+ def test_operator_search_option
371
+ assert_nothing_raised {
372
+ books = Movie.find_by_solr "office napoleon", :operator => :or
373
+ assert_equal 2, books.total
374
+
375
+ books = Movie.find_by_solr "office napoleon", :operator => :and
376
+ assert_equal 0, books.total
377
+ }
378
+
379
+ assert_raise RuntimeError do
380
+ Movie.find_by_solr "office napoleon", :operator => :bad
381
+ end
382
+ end
383
+
384
+ # Making sure find_by_solr with scores actually return the scores
385
+ # for each individual record and orders them accordingly
386
+ def test_find_by_solr_order_by_score
387
+ books = Book.find_by_solr 'ruby^10 OR splinter', {:scores => true, :order => 'score asc' }
388
+ assert (books.docs.collect(&:solr_score).compact.size == books.docs.size), "Each book should have a score"
389
+ assert (books.docs.last.solr_score >= 0.3 && books.docs.last.solr_score <= 0.6)
390
+
391
+ books = Book.find_by_solr 'ruby^10 OR splinter', {:scores => true, :order => 'score desc' }
392
+ assert (books.docs.first.solr_score >= 0.3 && books.docs.first.solr_score <= 0.6)
393
+ assert (books.docs.last.solr_score >= 0.1 && books.docs.last.solr_score <= 0.2)
394
+ end
395
+
396
+ # Search based on fields with the :date format
397
+ def test_indexed_date_field_format
398
+ movies = Movie.find_by_solr 'time_on_xml:[NOW-1DAY TO NOW]'
399
+ assert_equal 2, movies.total
400
+ end
401
+
402
+ def test_query_time_is_returned
403
+ results = Book.find_by_solr('ruby')
404
+ assert_not_nil(results.query_time)
405
+ assert_equal(results.query_time.class,Fixnum)
406
+ end
407
+
408
+ def test_should_not_index_the_record_when_offline_proc_returns_true
409
+ Gadget.search_disabled = true
410
+ gadget = Gadget.create(:name => "flipvideo mino")
411
+ assert_equal 0, Gadget.find_id_by_solr('flipvideo').total
412
+ end
413
+ end