sphinx 0.9.9.2117
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 +4 -0
- data/README.rdoc +243 -0
- data/Rakefile +45 -0
- data/VERSION.yml +5 -0
- data/init.rb +1 -0
- data/lib/sphinx/buffered_io.rb +26 -0
- data/lib/sphinx/client.rb +2426 -0
- data/lib/sphinx/constants.rb +179 -0
- data/lib/sphinx/indifferent_access.rb +152 -0
- data/lib/sphinx/request.rb +121 -0
- data/lib/sphinx/response.rb +71 -0
- data/lib/sphinx/server.rb +170 -0
- data/lib/sphinx/timeout.rb +31 -0
- data/lib/sphinx.rb +51 -0
- data/spec/client_response_spec.rb +170 -0
- data/spec/client_spec.rb +669 -0
- data/spec/client_validations_spec.rb +859 -0
- data/spec/fixtures/default_search.php +8 -0
- data/spec/fixtures/default_search_index.php +8 -0
- data/spec/fixtures/excerpt_custom.php +11 -0
- data/spec/fixtures/excerpt_default.php +8 -0
- data/spec/fixtures/excerpt_flags.php +12 -0
- data/spec/fixtures/field_weights.php +9 -0
- data/spec/fixtures/filter.php +9 -0
- data/spec/fixtures/filter_exclude.php +9 -0
- data/spec/fixtures/filter_float_range.php +9 -0
- data/spec/fixtures/filter_float_range_exclude.php +9 -0
- data/spec/fixtures/filter_range.php +9 -0
- data/spec/fixtures/filter_range_exclude.php +9 -0
- data/spec/fixtures/filter_range_int64.php +10 -0
- data/spec/fixtures/filter_ranges.php +10 -0
- data/spec/fixtures/filters.php +10 -0
- data/spec/fixtures/filters_different.php +13 -0
- data/spec/fixtures/geo_anchor.php +9 -0
- data/spec/fixtures/group_by_attr.php +9 -0
- data/spec/fixtures/group_by_attrpair.php +9 -0
- data/spec/fixtures/group_by_day.php +9 -0
- data/spec/fixtures/group_by_day_sort.php +9 -0
- data/spec/fixtures/group_by_month.php +9 -0
- data/spec/fixtures/group_by_week.php +9 -0
- data/spec/fixtures/group_by_year.php +9 -0
- data/spec/fixtures/group_distinct.php +10 -0
- data/spec/fixtures/id_range.php +9 -0
- data/spec/fixtures/id_range64.php +9 -0
- data/spec/fixtures/index_weights.php +9 -0
- data/spec/fixtures/keywords.php +8 -0
- data/spec/fixtures/limits.php +9 -0
- data/spec/fixtures/limits_cutoff.php +9 -0
- data/spec/fixtures/limits_max.php +9 -0
- data/spec/fixtures/limits_max_cutoff.php +9 -0
- data/spec/fixtures/match_all.php +9 -0
- data/spec/fixtures/match_any.php +9 -0
- data/spec/fixtures/match_boolean.php +9 -0
- data/spec/fixtures/match_extended.php +9 -0
- data/spec/fixtures/match_extended2.php +9 -0
- data/spec/fixtures/match_fullscan.php +9 -0
- data/spec/fixtures/match_phrase.php +9 -0
- data/spec/fixtures/max_query_time.php +9 -0
- data/spec/fixtures/miltiple_queries.php +12 -0
- data/spec/fixtures/ranking_bm25.php +9 -0
- data/spec/fixtures/ranking_fieldmask.php +9 -0
- data/spec/fixtures/ranking_matchany.php +9 -0
- data/spec/fixtures/ranking_none.php +9 -0
- data/spec/fixtures/ranking_proximity.php +9 -0
- data/spec/fixtures/ranking_proximity_bm25.php +9 -0
- data/spec/fixtures/ranking_wordcount.php +9 -0
- data/spec/fixtures/retries.php +9 -0
- data/spec/fixtures/retries_delay.php +9 -0
- data/spec/fixtures/select.php +9 -0
- data/spec/fixtures/set_override.php +11 -0
- data/spec/fixtures/sort_attr_asc.php +9 -0
- data/spec/fixtures/sort_attr_desc.php +9 -0
- data/spec/fixtures/sort_expr.php +9 -0
- data/spec/fixtures/sort_extended.php +9 -0
- data/spec/fixtures/sort_relevance.php +9 -0
- data/spec/fixtures/sort_time_segments.php +9 -0
- data/spec/fixtures/sphinxapi.php +1633 -0
- data/spec/fixtures/update_attributes.php +8 -0
- data/spec/fixtures/update_attributes_mva.php +8 -0
- data/spec/fixtures/weights.php +9 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/sphinx/sphinx-id64.conf +67 -0
- data/spec/sphinx/sphinx.conf +67 -0
- data/spec/sphinx/sphinx_test.sql +88 -0
- data/sphinx.gemspec +127 -0
- metadata +142 -0
data/spec/client_spec.rb
ADDED
@@ -0,0 +1,669 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe Sphinx::Client, 'disconnected' do
|
4
|
+
context 'in with_server method' do
|
5
|
+
before :each do
|
6
|
+
@sphinx = Sphinx::Client.new
|
7
|
+
@servers = [{:host => 'localhost', :port => 1}, {:host => 'localhost', :port => 2}]
|
8
|
+
end
|
9
|
+
|
10
|
+
context 'without retries' do
|
11
|
+
it 'should use single Server instance' do
|
12
|
+
2.times do
|
13
|
+
cnt = 0
|
14
|
+
@sphinx.send(:with_server) { |server| cnt += 1; server.should == @sphinx.servers[0] }
|
15
|
+
cnt.should == 1
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should raise an exception on error' do
|
20
|
+
2.times do
|
21
|
+
cnt = 0
|
22
|
+
expect {
|
23
|
+
@sphinx.send(:with_server) { |server| cnt += 1; server.should == @sphinx.servers[0]; raise Sphinx::SphinxConnectError }
|
24
|
+
}.to raise_error(Sphinx::SphinxConnectError)
|
25
|
+
cnt.should == 1
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should select server based on index' do
|
30
|
+
@sphinx.SetServers(@servers)
|
31
|
+
cnt = 0
|
32
|
+
@sphinx.send(:with_server, 0) { |server| cnt += 1; server.should == @sphinx.servers[0] }
|
33
|
+
cnt.should == 1
|
34
|
+
cnt = 0
|
35
|
+
@sphinx.send(:with_server, 1) { |server| cnt += 1; server.should == @sphinx.servers[1] }
|
36
|
+
cnt.should == 1
|
37
|
+
cnt = 0
|
38
|
+
@sphinx.send(:with_server, 2) { |server| cnt += 1; server.should == @sphinx.servers[0] }
|
39
|
+
cnt.should == 1
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should select given server' do
|
43
|
+
@sphinx.SetServers(@servers)
|
44
|
+
cnt = 0
|
45
|
+
@sphinx.send(:with_server, @sphinx.servers[0]) { |server| cnt += 1; server.should == @sphinx.servers[0] }
|
46
|
+
cnt.should == 1
|
47
|
+
cnt = 0
|
48
|
+
@sphinx.send(:with_server, @sphinx.servers[1]) { |server| cnt += 1; server.should == @sphinx.servers[1] }
|
49
|
+
cnt.should == 1
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'with retries' do
|
54
|
+
before :each do
|
55
|
+
@sphinx.SetConnectTimeout(0, 3)
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should raise an exception on error' do
|
59
|
+
cnt = 0
|
60
|
+
expect {
|
61
|
+
@sphinx.send(:with_server) { |server| cnt += 1; server.should == @sphinx.servers[0]; raise Sphinx::SphinxConnectError }
|
62
|
+
}.to raise_error(Sphinx::SphinxConnectError)
|
63
|
+
cnt.should == 3
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should round-robin servers and raise an exception on error' do
|
67
|
+
@sphinx.SetServers(@servers)
|
68
|
+
cnt = 0
|
69
|
+
expect {
|
70
|
+
@sphinx.send(:with_server) { |server| cnt += 1; server.should == @sphinx.servers[(cnt - 1) % 2]; raise Sphinx::SphinxConnectError }
|
71
|
+
}.to raise_error(Sphinx::SphinxConnectError)
|
72
|
+
cnt.should == 3
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'should round-robin servers with respect to passed index and raise an exception on error' do
|
76
|
+
@sphinx.SetServers(@servers)
|
77
|
+
cnt = 0
|
78
|
+
expect {
|
79
|
+
@sphinx.send(:with_server, 1) { |server| cnt += 1; server.should == @sphinx.servers[cnt % 2]; raise Sphinx::SphinxConnectError }
|
80
|
+
}.to raise_error(Sphinx::SphinxConnectError)
|
81
|
+
cnt.should == 3
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should round-robin with respect to attempts number passed' do
|
85
|
+
@sphinx.SetServers(@servers)
|
86
|
+
cnt = 0
|
87
|
+
expect {
|
88
|
+
@sphinx.send(:with_server, 0, 5) { |server| cnt += 1; server.should == @sphinx.servers[(cnt - 1) % 2]; raise Sphinx::SphinxConnectError }
|
89
|
+
}.to raise_error(Sphinx::SphinxConnectError)
|
90
|
+
cnt.should == 5
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'in with_socket method' do
|
96
|
+
before :each do
|
97
|
+
@sphinx = Sphinx::Client.new
|
98
|
+
@socket = mock('TCPSocket')
|
99
|
+
end
|
100
|
+
|
101
|
+
context 'without retries' do
|
102
|
+
before :each do
|
103
|
+
@server = mock('Server')
|
104
|
+
@server.should_receive(:get_socket).and_yield(@socket).and_return(@socket)
|
105
|
+
@server.should_receive(:free_socket).with(@socket).at_least(1)
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'should initialize session' do
|
109
|
+
@socket.should_receive(:write).with([1].pack('N'))
|
110
|
+
@socket.should_receive(:read).with(4).and_return([1].pack('N'))
|
111
|
+
cnt = 0
|
112
|
+
@sphinx.send(:with_socket, @server) { |socket| cnt += 1; socket.should == @socket }
|
113
|
+
cnt.should == 1
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'should raise exception when searchd protocol is not 1+' do
|
117
|
+
@socket.should_receive(:write).with([1].pack('N'))
|
118
|
+
@socket.should_receive(:read).with(4).and_return([0].pack('N'))
|
119
|
+
cnt = 0
|
120
|
+
expect {
|
121
|
+
@sphinx.send(:with_socket, @server) { cnt += 1; }
|
122
|
+
}.to raise_error(Sphinx::SphinxConnectError, 'expected searchd protocol version 1+, got version \'0\'')
|
123
|
+
cnt.should == 0
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'should handle request timeouts' do
|
127
|
+
@socket.should_receive(:write).with([1].pack('N'))
|
128
|
+
@socket.should_receive(:read).with(4).and_return([1].pack('N'))
|
129
|
+
@sphinx.SetRequestTimeout(1)
|
130
|
+
cnt = 0
|
131
|
+
expect {
|
132
|
+
@sphinx.send(:with_socket, @server) { cnt += 1; sleep 2 }
|
133
|
+
}.to raise_error(Sphinx::SphinxResponseError, 'failed to read searchd response (msg=time\'s up!)')
|
134
|
+
cnt.should == 1
|
135
|
+
|
136
|
+
@sphinx.GetLastError.should == 'failed to read searchd response (msg=time\'s up!)'
|
137
|
+
@sphinx.IsConnectError.should be_false
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'should re-reaise Sphinx errors' do
|
141
|
+
@socket.should_receive(:write).with([1].pack('N'))
|
142
|
+
@socket.should_receive(:read).with(4).and_return([1].pack('N'))
|
143
|
+
cnt = 0
|
144
|
+
expect {
|
145
|
+
@sphinx.send(:with_socket, @server) { cnt += 1; raise Sphinx::SphinxInternalError, 'hello' }
|
146
|
+
}.to raise_error(Sphinx::SphinxInternalError, 'hello')
|
147
|
+
cnt.should == 1
|
148
|
+
|
149
|
+
@sphinx.GetLastError.should == 'hello'
|
150
|
+
@sphinx.IsConnectError.should be_false
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context 'with retries' do
|
155
|
+
before :each do
|
156
|
+
@sphinx.SetRequestTimeout(0, 3)
|
157
|
+
# two more times yielding - retries
|
158
|
+
@server = mock('Server')
|
159
|
+
@server.should_receive(:get_socket).at_least(1).times.and_yield(@socket).and_return(@socket)
|
160
|
+
@server.should_receive(:free_socket).with(@socket).at_least(1)
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'should raise an exception on error' do
|
164
|
+
@socket.should_receive(:write).exactly(3).times.with([1].pack('N'))
|
165
|
+
@socket.should_receive(:read).exactly(3).times.with(4).and_return([1].pack('N'))
|
166
|
+
cnt = 0
|
167
|
+
expect {
|
168
|
+
@sphinx.send(:with_socket, @server) { cnt += 1; raise Sphinx::SphinxInternalError, 'hello' }
|
169
|
+
}.to raise_error(Sphinx::SphinxInternalError, 'hello')
|
170
|
+
cnt.should == 3
|
171
|
+
|
172
|
+
@sphinx.GetLastError.should == 'hello'
|
173
|
+
@sphinx.IsConnectError.should be_false
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
context 'in parse_response method' do
|
179
|
+
before :each do
|
180
|
+
@sphinx = Sphinx::Client.new
|
181
|
+
@socket = mock('TCPSocket')
|
182
|
+
end
|
183
|
+
|
184
|
+
it 'should receive response' do
|
185
|
+
@socket.should_receive(:read).with(8).and_return([Sphinx::SEARCHD_OK, 1, 4].pack('n2N'))
|
186
|
+
@socket.should_receive(:read).with(4).and_return([0].pack('N'))
|
187
|
+
@sphinx.send(:parse_response, @socket, 1)
|
188
|
+
end
|
189
|
+
|
190
|
+
it 'should raise exception on zero-sized response' do
|
191
|
+
@socket.should_receive(:read).with(8).and_return([Sphinx::SEARCHD_OK, 1, 0].pack('n2N'))
|
192
|
+
expect {
|
193
|
+
@sphinx.send(:parse_response, @socket, 1)
|
194
|
+
}.to raise_error(Sphinx::SphinxResponseError, 'received zero-sized searchd response')
|
195
|
+
end
|
196
|
+
|
197
|
+
it 'should raise exception when response is incomplete' do
|
198
|
+
@socket.should_receive(:read).with(8).and_return([Sphinx::SEARCHD_OK, 1, 4].pack('n2N'))
|
199
|
+
@socket.should_receive(:read).with(4).and_return('')
|
200
|
+
expect {
|
201
|
+
@sphinx.send(:parse_response, @socket, 1)
|
202
|
+
}.to raise_error(Sphinx::SphinxResponseError)
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'should set warning message when SEARCHD_WARNING received' do
|
206
|
+
@socket.should_receive(:read).with(8).and_return([Sphinx::SEARCHD_WARNING, 1, 14].pack('n2N'))
|
207
|
+
@socket.should_receive(:read).with(14).and_return([5].pack('N') + 'helloworld')
|
208
|
+
@sphinx.send(:parse_response, @socket, 1).should == 'world'
|
209
|
+
@sphinx.GetLastWarning.should == 'hello'
|
210
|
+
end
|
211
|
+
|
212
|
+
it 'should raise exception when SEARCHD_ERROR received' do
|
213
|
+
@socket.should_receive(:read).with(8).and_return([Sphinx::SEARCHD_ERROR, 1, 9].pack('n2N'))
|
214
|
+
@socket.should_receive(:read).with(9).and_return([1].pack('N') + 'hello')
|
215
|
+
expect {
|
216
|
+
@sphinx.send(:parse_response, @socket, 1)
|
217
|
+
}.to raise_error(Sphinx::SphinxInternalError, 'searchd error: hello')
|
218
|
+
end
|
219
|
+
|
220
|
+
it 'should raise exception when SEARCHD_RETRY received' do
|
221
|
+
@socket.should_receive(:read).with(8).and_return([Sphinx::SEARCHD_RETRY, 1, 9].pack('n2N'))
|
222
|
+
@socket.should_receive(:read).with(9).and_return([1].pack('N') + 'hello')
|
223
|
+
expect {
|
224
|
+
@sphinx.send(:parse_response, @socket, 1)
|
225
|
+
}.to raise_error(Sphinx::SphinxTemporaryError, 'temporary searchd error: hello')
|
226
|
+
end
|
227
|
+
|
228
|
+
it 'should raise exception when unknown status received' do
|
229
|
+
@socket.should_receive(:read).with(8).and_return([65535, 1, 9].pack('n2N'))
|
230
|
+
@socket.should_receive(:read).with(9).and_return([1].pack('N') + 'hello')
|
231
|
+
expect {
|
232
|
+
@sphinx.send(:parse_response, @socket, 1)
|
233
|
+
}.to raise_error(Sphinx::SphinxUnknownError, 'unknown status code: \'65535\'')
|
234
|
+
end
|
235
|
+
|
236
|
+
it 'should set warning when server is older than client' do
|
237
|
+
@socket.should_receive(:read).with(8).and_return([Sphinx::SEARCHD_OK, 1, 9].pack('n2N'))
|
238
|
+
@socket.should_receive(:read).with(9).and_return([1].pack('N') + 'hello')
|
239
|
+
@sphinx.send(:parse_response, @socket, 5)
|
240
|
+
@sphinx.GetLastWarning.should == 'searchd command v.0.1 older than client\'s v.0.5, some options might not work'
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
context 'in Query method' do
|
245
|
+
before :each do
|
246
|
+
@sphinx = sphinx_create_client
|
247
|
+
end
|
248
|
+
|
249
|
+
it 'should generate valid request with default parameters' do
|
250
|
+
expected = sphinx_fixture('default_search')
|
251
|
+
@sock.should_receive(:write).with(expected)
|
252
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
253
|
+
end
|
254
|
+
|
255
|
+
it 'should generate valid request with default parameters and index' do
|
256
|
+
expected = sphinx_fixture('default_search_index')
|
257
|
+
@sock.should_receive(:write).with(expected)
|
258
|
+
sphinx_safe_call { @sphinx.Query('query', 'index') }
|
259
|
+
end
|
260
|
+
|
261
|
+
it 'should generate valid request with limits' do
|
262
|
+
expected = sphinx_fixture('limits')
|
263
|
+
@sock.should_receive(:write).with(expected)
|
264
|
+
@sphinx.SetLimits(10, 20)
|
265
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
266
|
+
end
|
267
|
+
|
268
|
+
it 'should generate valid request with limits and max number to retrieve' do
|
269
|
+
expected = sphinx_fixture('limits_max')
|
270
|
+
@sock.should_receive(:write).with(expected)
|
271
|
+
@sphinx.SetLimits(10, 20, 30)
|
272
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
273
|
+
end
|
274
|
+
|
275
|
+
it 'should generate valid request with limits and cutoff to retrieve' do
|
276
|
+
expected = sphinx_fixture('limits_cutoff')
|
277
|
+
@sock.should_receive(:write).with(expected)
|
278
|
+
@sphinx.SetLimits(10, 20, 30, 40)
|
279
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
280
|
+
end
|
281
|
+
|
282
|
+
it 'should generate valid request with max query time specified' do
|
283
|
+
expected = sphinx_fixture('max_query_time')
|
284
|
+
@sock.should_receive(:write).with(expected)
|
285
|
+
@sphinx.SetMaxQueryTime(1000)
|
286
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
287
|
+
end
|
288
|
+
|
289
|
+
describe 'with match' do
|
290
|
+
[ :all, :any, :phrase, :boolean, :extended, :fullscan, :extended2 ].each do |match|
|
291
|
+
it "should generate valid request for SPH_MATCH_#{match.to_s.upcase}" do
|
292
|
+
expected = sphinx_fixture("match_#{match}")
|
293
|
+
@sock.should_receive(:write).with(expected)
|
294
|
+
@sphinx.SetMatchMode(Sphinx::const_get("SPH_MATCH_#{match.to_s.upcase}"))
|
295
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
296
|
+
end
|
297
|
+
|
298
|
+
it "should generate valid request for \"#{match}\"" do
|
299
|
+
expected = sphinx_fixture("match_#{match}")
|
300
|
+
@sock.should_receive(:write).with(expected)
|
301
|
+
@sphinx.SetMatchMode(match.to_s)
|
302
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
303
|
+
end
|
304
|
+
|
305
|
+
it "should generate valid request for :#{match}" do
|
306
|
+
expected = sphinx_fixture("match_#{match}")
|
307
|
+
@sock.should_receive(:write).with(expected)
|
308
|
+
@sphinx.SetMatchMode(match)
|
309
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
describe 'with rank' do
|
315
|
+
[ :proximity_bm25, :bm25, :none, :wordcount, :proximity, :matchany, :fieldmask ].each do |rank|
|
316
|
+
it "should generate valid request for SPH_RANK_#{rank.to_s.upcase}" do
|
317
|
+
expected = sphinx_fixture("ranking_#{rank}")
|
318
|
+
@sock.should_receive(:write).with(expected)
|
319
|
+
@sphinx.SetRankingMode(Sphinx::Client.const_get("SPH_RANK_#{rank.to_s.upcase}"))
|
320
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
321
|
+
end
|
322
|
+
|
323
|
+
it "should generate valid request for \"#{rank}\"" do
|
324
|
+
expected = sphinx_fixture("ranking_#{rank}")
|
325
|
+
@sock.should_receive(:write).with(expected)
|
326
|
+
@sphinx.SetRankingMode(rank.to_s)
|
327
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
328
|
+
end
|
329
|
+
|
330
|
+
it "should generate valid request for :#{rank}" do
|
331
|
+
expected = sphinx_fixture("ranking_#{rank}")
|
332
|
+
@sock.should_receive(:write).with(expected)
|
333
|
+
@sphinx.SetRankingMode(rank)
|
334
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
335
|
+
end
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
describe 'with sorting' do
|
340
|
+
[ :attr_desc, :relevance, :attr_asc, :time_segments, :extended, :expr ].each do |mode|
|
341
|
+
it "should generate valid request for SPH_SORT_#{mode.to_s.upcase}" do
|
342
|
+
expected = sphinx_fixture("sort_#{mode}")
|
343
|
+
@sock.should_receive(:write).with(expected)
|
344
|
+
@sphinx.SetSortMode(Sphinx::Client.const_get("SPH_SORT_#{mode.to_s.upcase}"), mode == :relevance ? '' : 'sortby')
|
345
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
346
|
+
end
|
347
|
+
|
348
|
+
it "should generate valid request for \"#{mode}\"" do
|
349
|
+
expected = sphinx_fixture("sort_#{mode}")
|
350
|
+
@sock.should_receive(:write).with(expected)
|
351
|
+
@sphinx.SetSortMode(mode.to_s, mode == :relevance ? '' : 'sortby')
|
352
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
353
|
+
end
|
354
|
+
|
355
|
+
it "should generate valid request for :#{mode}" do
|
356
|
+
expected = sphinx_fixture("sort_#{mode}")
|
357
|
+
@sock.should_receive(:write).with(expected)
|
358
|
+
@sphinx.SetSortMode(mode, mode == :relevance ? '' : 'sortby')
|
359
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
it 'should generate valid request with weights' do
|
365
|
+
expected = sphinx_fixture('weights')
|
366
|
+
@sock.should_receive(:write).with(expected)
|
367
|
+
@sphinx.SetWeights([10, 20, 30, 40])
|
368
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
369
|
+
end
|
370
|
+
|
371
|
+
it 'should generate valid request with field weights' do
|
372
|
+
expected = sphinx_fixture('field_weights')
|
373
|
+
@sock.should_receive(:write).with(expected)
|
374
|
+
@sphinx.SetFieldWeights({'field1' => 10, 'field2' => 20})
|
375
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
376
|
+
end
|
377
|
+
|
378
|
+
it 'should generate valid request with index weights' do
|
379
|
+
expected = sphinx_fixture('index_weights')
|
380
|
+
@sock.should_receive(:write).with(expected)
|
381
|
+
@sphinx.SetIndexWeights({'index1' => 10, 'index2' => 20})
|
382
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
383
|
+
end
|
384
|
+
|
385
|
+
it 'should generate valid request with ID range' do
|
386
|
+
expected = sphinx_fixture('id_range')
|
387
|
+
@sock.should_receive(:write).with(expected)
|
388
|
+
@sphinx.SetIDRange(10, 20)
|
389
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
390
|
+
end
|
391
|
+
|
392
|
+
it 'should generate valid request with ID range and 64-bit ints' do
|
393
|
+
expected = sphinx_fixture('id_range64')
|
394
|
+
@sock.should_receive(:write).with(expected)
|
395
|
+
@sphinx.SetIDRange(8589934591, 17179869183)
|
396
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
397
|
+
end
|
398
|
+
|
399
|
+
it 'should generate valid request with values filter' do
|
400
|
+
expected = sphinx_fixture('filter')
|
401
|
+
@sock.should_receive(:write).with(expected)
|
402
|
+
@sphinx.SetFilter('attr', [10, 20, 30])
|
403
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
404
|
+
end
|
405
|
+
|
406
|
+
it 'should generate valid request with two values filters' do
|
407
|
+
expected = sphinx_fixture('filters')
|
408
|
+
@sock.should_receive(:write).with(expected)
|
409
|
+
@sphinx.SetFilter('attr2', [40, 50])
|
410
|
+
@sphinx.SetFilter('attr1', [10, 20, 30])
|
411
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
412
|
+
end
|
413
|
+
|
414
|
+
it 'should generate valid request with values filter excluded' do
|
415
|
+
expected = sphinx_fixture('filter_exclude')
|
416
|
+
@sock.should_receive(:write).with(expected)
|
417
|
+
@sphinx.SetFilter('attr', [10, 20, 30], true)
|
418
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
419
|
+
end
|
420
|
+
|
421
|
+
it 'should generate valid request with values filter range' do
|
422
|
+
expected = sphinx_fixture('filter_range')
|
423
|
+
@sock.should_receive(:write).with(expected)
|
424
|
+
@sphinx.SetFilterRange('attr', 10, 20)
|
425
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
426
|
+
end
|
427
|
+
|
428
|
+
it 'should generate valid request with two filter ranges' do
|
429
|
+
expected = sphinx_fixture('filter_ranges')
|
430
|
+
@sock.should_receive(:write).with(expected)
|
431
|
+
@sphinx.SetFilterRange('attr2', 30, 40)
|
432
|
+
@sphinx.SetFilterRange('attr1', 10, 20)
|
433
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
434
|
+
end
|
435
|
+
|
436
|
+
it 'should generate valid request with filter range excluded' do
|
437
|
+
expected = sphinx_fixture('filter_range_exclude')
|
438
|
+
@sock.should_receive(:write).with(expected)
|
439
|
+
@sphinx.SetFilterRange('attr', 10, 20, true)
|
440
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
441
|
+
end
|
442
|
+
|
443
|
+
it 'should generate valid request with signed int64-based filter range' do
|
444
|
+
expected = sphinx_fixture('filter_range_int64')
|
445
|
+
@sock.should_receive(:write).with(expected)
|
446
|
+
@sphinx.SetFilterRange('attr1', -10, 20)
|
447
|
+
@sphinx.SetFilterRange('attr2', -1099511627770, 1099511627780)
|
448
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
449
|
+
end
|
450
|
+
|
451
|
+
it 'should generate valid request with float filter range' do
|
452
|
+
expected = sphinx_fixture('filter_float_range')
|
453
|
+
@sock.should_receive(:write).with(expected)
|
454
|
+
@sphinx.SetFilterFloatRange('attr', 10.5, 20.3)
|
455
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
456
|
+
end
|
457
|
+
|
458
|
+
it 'should generate valid request with float filter excluded' do
|
459
|
+
expected = sphinx_fixture('filter_float_range_exclude')
|
460
|
+
@sock.should_receive(:write).with(expected)
|
461
|
+
@sphinx.SetFilterFloatRange('attr', 10.5, 20.3, true)
|
462
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
463
|
+
end
|
464
|
+
|
465
|
+
it 'should generate valid request with different filters' do
|
466
|
+
expected = sphinx_fixture('filters_different')
|
467
|
+
@sock.should_receive(:write).with(expected)
|
468
|
+
@sphinx.SetFilterRange('attr1', 10, 20, true)
|
469
|
+
@sphinx.SetFilter('attr3', [30, 40, 50])
|
470
|
+
@sphinx.SetFilterRange('attr1', 60, 70)
|
471
|
+
@sphinx.SetFilter('attr2', [80, 90, 100], true)
|
472
|
+
@sphinx.SetFilterFloatRange('attr1', 60.8, 70.5)
|
473
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
474
|
+
end
|
475
|
+
|
476
|
+
it 'should generate valid request with geographical anchor point' do
|
477
|
+
expected = sphinx_fixture('geo_anchor')
|
478
|
+
@sock.should_receive(:write).with(expected)
|
479
|
+
@sphinx.SetGeoAnchor('attrlat', 'attrlong', 20.3, 40.7)
|
480
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
481
|
+
end
|
482
|
+
|
483
|
+
describe 'with group by' do
|
484
|
+
[ :day, :week, :month, :year, :attr, :attrpair ].each do |groupby|
|
485
|
+
it "should generate valid request for SPH_GROUPBY_#{groupby.to_s.upcase}" do
|
486
|
+
expected = sphinx_fixture("group_by_#{groupby}")
|
487
|
+
@sock.should_receive(:write).with(expected)
|
488
|
+
@sphinx.SetGroupBy('attr', Sphinx::const_get("SPH_GROUPBY_#{groupby.to_s.upcase}"))
|
489
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
490
|
+
end
|
491
|
+
|
492
|
+
it "should generate valid request for \"#{groupby}\"" do
|
493
|
+
expected = sphinx_fixture("group_by_#{groupby}")
|
494
|
+
@sock.should_receive(:write).with(expected)
|
495
|
+
@sphinx.SetGroupBy('attr', groupby.to_s)
|
496
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
497
|
+
end
|
498
|
+
|
499
|
+
it "should generate valid request for :#{groupby}" do
|
500
|
+
expected = sphinx_fixture("group_by_#{groupby}")
|
501
|
+
@sock.should_receive(:write).with(expected)
|
502
|
+
@sphinx.SetGroupBy('attr', groupby)
|
503
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
504
|
+
end
|
505
|
+
end
|
506
|
+
|
507
|
+
it 'should generate valid request for SPH_GROUPBY_DAY with sort' do
|
508
|
+
expected = sphinx_fixture('group_by_day_sort')
|
509
|
+
@sock.should_receive(:write).with(expected)
|
510
|
+
@sphinx.SetGroupBy('attr', Sphinx::SPH_GROUPBY_DAY, 'somesort')
|
511
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
512
|
+
end
|
513
|
+
|
514
|
+
it 'should generate valid request with count-distinct attribute' do
|
515
|
+
expected = sphinx_fixture('group_distinct')
|
516
|
+
@sock.should_receive(:write).with(expected)
|
517
|
+
@sphinx.SetGroupBy('attr', Sphinx::SPH_GROUPBY_DAY)
|
518
|
+
@sphinx.SetGroupDistinct('attr')
|
519
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
520
|
+
end
|
521
|
+
end
|
522
|
+
|
523
|
+
it 'should generate valid request with retries count specified' do
|
524
|
+
expected = sphinx_fixture('retries')
|
525
|
+
@sock.should_receive(:write).with(expected)
|
526
|
+
@sphinx.SetRetries(10)
|
527
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
528
|
+
end
|
529
|
+
|
530
|
+
it 'should generate valid request with retries count and delay specified' do
|
531
|
+
expected = sphinx_fixture('retries_delay')
|
532
|
+
@sock.should_receive(:write).with(expected)
|
533
|
+
@sphinx.SetRetries(10, 20)
|
534
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
535
|
+
end
|
536
|
+
|
537
|
+
it 'should generate valid request for SetOverride' do
|
538
|
+
expected = sphinx_fixture('set_override')
|
539
|
+
@sock.should_receive(:write).with(expected)
|
540
|
+
@sphinx.SetOverride('attr1', Sphinx::SPH_ATTR_INTEGER, { 10 => 20 })
|
541
|
+
@sphinx.SetOverride('attr2', Sphinx::SPH_ATTR_FLOAT, { 11 => 30.3 })
|
542
|
+
@sphinx.SetOverride('attr3', Sphinx::SPH_ATTR_BIGINT, { 12 => 1099511627780 })
|
543
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
544
|
+
end
|
545
|
+
|
546
|
+
it 'should generate valid request for SetSelect' do
|
547
|
+
expected = sphinx_fixture('select')
|
548
|
+
@sock.should_receive(:write).with(expected)
|
549
|
+
@sphinx.SetSelect('attr1, attr2')
|
550
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
551
|
+
end
|
552
|
+
end
|
553
|
+
|
554
|
+
context 'in RunQueries method' do
|
555
|
+
before(:each) do
|
556
|
+
@sphinx = sphinx_create_client
|
557
|
+
end
|
558
|
+
|
559
|
+
it 'should generate valid request for multiple queries' do
|
560
|
+
expected = sphinx_fixture('miltiple_queries')
|
561
|
+
@sock.should_receive(:write).with(expected)
|
562
|
+
|
563
|
+
@sphinx.SetRetries(10, 20)
|
564
|
+
@sphinx.AddQuery('test1')
|
565
|
+
@sphinx.SetGroupBy('attr', Sphinx::SPH_GROUPBY_DAY)
|
566
|
+
@sphinx.AddQuery('test2')
|
567
|
+
|
568
|
+
sphinx_safe_call { @sphinx.RunQueries }
|
569
|
+
end
|
570
|
+
end
|
571
|
+
|
572
|
+
context 'in BuildExcerpts method' do
|
573
|
+
before :each do
|
574
|
+
@sphinx = sphinx_create_client
|
575
|
+
end
|
576
|
+
|
577
|
+
it 'should generate valid request with default parameters' do
|
578
|
+
expected = sphinx_fixture('excerpt_default')
|
579
|
+
@sock.should_receive(:write).with(expected)
|
580
|
+
sphinx_safe_call { @sphinx.BuildExcerpts(['10', '20'], 'index', 'word1 word2') }
|
581
|
+
end
|
582
|
+
|
583
|
+
it 'should generate valid request with custom parameters' do
|
584
|
+
expected = sphinx_fixture('excerpt_custom')
|
585
|
+
@sock.should_receive(:write).with(expected)
|
586
|
+
sphinx_safe_call do
|
587
|
+
@sphinx.BuildExcerpts(['10', '20'], 'index', 'word1 word2', { 'before_match' => 'before',
|
588
|
+
'after_match' => 'after',
|
589
|
+
'chunk_separator' => 'separator',
|
590
|
+
'limit' => 10 })
|
591
|
+
end
|
592
|
+
end
|
593
|
+
|
594
|
+
it 'should generate valid request with custom parameters as symbols' do
|
595
|
+
expected = sphinx_fixture('excerpt_custom')
|
596
|
+
@sock.should_receive(:write).with(expected)
|
597
|
+
sphinx_safe_call do
|
598
|
+
@sphinx.BuildExcerpts(['10', '20'], 'index', 'word1 word2', { :before_match => 'before',
|
599
|
+
:after_match => 'after',
|
600
|
+
:chunk_separator => 'separator',
|
601
|
+
:limit => 10 })
|
602
|
+
end
|
603
|
+
end
|
604
|
+
|
605
|
+
it 'should generate valid request with flags' do
|
606
|
+
expected = sphinx_fixture('excerpt_flags')
|
607
|
+
@sock.should_receive(:write).with(expected)
|
608
|
+
sphinx_safe_call do
|
609
|
+
@sphinx.BuildExcerpts(['10', '20'], 'index', 'word1 word2', { 'exact_phrase' => true,
|
610
|
+
'single_passage' => true,
|
611
|
+
'use_boundaries' => true,
|
612
|
+
'weight_order' => true,
|
613
|
+
'query_mode' => true })
|
614
|
+
end
|
615
|
+
end
|
616
|
+
|
617
|
+
it 'should generate valid request with flags as symbols' do
|
618
|
+
expected = sphinx_fixture('excerpt_flags')
|
619
|
+
@sock.should_receive(:write).with(expected)
|
620
|
+
sphinx_safe_call do
|
621
|
+
@sphinx.BuildExcerpts(['10', '20'], 'index', 'word1 word2', { :exact_phrase => true,
|
622
|
+
:single_passage => true,
|
623
|
+
:use_boundaries => true,
|
624
|
+
:weight_order => true,
|
625
|
+
:query_mode => true })
|
626
|
+
end
|
627
|
+
end
|
628
|
+
end
|
629
|
+
|
630
|
+
context 'in BuildKeywords method' do
|
631
|
+
before :each do
|
632
|
+
@sphinx = sphinx_create_client
|
633
|
+
end
|
634
|
+
|
635
|
+
it 'should generate valid request' do
|
636
|
+
expected = sphinx_fixture('keywords')
|
637
|
+
@sock.should_receive(:write).with(expected)
|
638
|
+
sphinx_safe_call { @sphinx.BuildKeywords('test', 'index', true) }
|
639
|
+
end
|
640
|
+
end
|
641
|
+
|
642
|
+
context 'in UpdateAttributes method' do
|
643
|
+
before :each do
|
644
|
+
@sphinx = sphinx_create_client
|
645
|
+
end
|
646
|
+
|
647
|
+
it 'should generate valid request' do
|
648
|
+
expected = sphinx_fixture('update_attributes')
|
649
|
+
@sock.should_receive(:write).with(expected)
|
650
|
+
sphinx_safe_call { @sphinx.UpdateAttributes('index', ['group'], { 123 => [456] }) }
|
651
|
+
end
|
652
|
+
|
653
|
+
it 'should generate valid request for MVA' do
|
654
|
+
expected = sphinx_fixture('update_attributes_mva')
|
655
|
+
@sock.should_receive(:write).with(expected)
|
656
|
+
sphinx_safe_call { @sphinx.UpdateAttributes('index', ['group', 'category'], { 123 => [ [456, 789], [1, 2, 3] ] }, true) }
|
657
|
+
end
|
658
|
+
end
|
659
|
+
|
660
|
+
context 'in EscapeString method' do
|
661
|
+
before :each do
|
662
|
+
@sphinx = Sphinx::Client.new
|
663
|
+
end
|
664
|
+
|
665
|
+
it 'should escape special characters' do
|
666
|
+
@sphinx.escape_string("escaping-sample@query/string").should == "escaping\\-sample\\@query\\/string"
|
667
|
+
end
|
668
|
+
end
|
669
|
+
end
|