sphinx 0.9.9.2117 → 0.9.10

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/spec/client_spec.rb CHANGED
@@ -1,669 +1,471 @@
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
1
+ require File.dirname(__FILE__) + '/../init'
2
+
3
+ class SphinxSpecError < StandardError; end
4
+
5
+ module SphinxFixtureHelper
6
+ def sphinx_fixture(name)
7
+ `php #{File.dirname(__FILE__)}/fixtures/#{name}.php`
8
+ end
9
+ end
10
+
11
+ module SphinxApiCall
12
+ def create_sphinx
13
+ @sphinx = Sphinx::Client.new
14
+ @sock = mock('TCPSocket')
15
+ @sphinx.stub!(:Connect).and_return(@sock)
16
+ @sphinx.stub!(:GetResponse).and_raise(SphinxSpecError)
17
+ return @sphinx
18
+ end
19
+
20
+ def safe_call
21
+ yield
22
+ rescue SphinxSpecError
23
+ end
24
+ end
25
+
26
+ describe 'The Connect method of Sphinx::Client' do
27
+ before(:each) do
28
+ @sphinx = Sphinx::Client.new
29
+ @sock = mock('TCPSocket')
30
+ end
31
+
32
+ it 'should establish TCP connection to the server and initialize session' do
33
+ TCPSocket.should_receive(:new).with('localhost', 3312).and_return(@sock)
34
+ @sock.should_receive(:recv).with(4).and_return([1].pack('N'))
35
+ @sock.should_receive(:send).with([1].pack('N'), 0)
36
+ @sphinx.send(:Connect).should be(@sock)
37
+ end
38
+
39
+ it 'should raise exception when searchd protocol is not 1+' do
40
+ TCPSocket.should_receive(:new).with('localhost', 3312).and_return(@sock)
41
+ @sock.should_receive(:send).with([1].pack('N'), 0)
42
+ @sock.should_receive(:recv).with(4).and_return([0].pack('N'))
43
+ @sock.should_receive(:close)
44
+ lambda { @sphinx.send(:Connect) }.should raise_error(Sphinx::SphinxConnectError)
45
+ @sphinx.GetLastError.should == 'expected searchd protocol version 1+, got version \'0\''
46
+ end
47
+
48
+ it 'should raise exception on connection error' do
49
+ TCPSocket.should_receive(:new).with('localhost', 3312).and_raise(Errno::EBADF)
50
+ lambda { @sphinx.send(:Connect) }.should raise_error(Sphinx::SphinxConnectError)
51
+ @sphinx.GetLastError.should == 'connection to localhost:3312 failed (errno=9, msg=Bad file descriptor)'
52
+ end
53
+
54
+ it 'should use custom host and port' do
55
+ @sphinx.SetServer('anotherhost', 55555)
56
+ TCPSocket.should_receive(:new).with('anotherhost', 55555).and_raise(Errno::EBADF)
57
+ lambda { @sphinx.send(:Connect) }.should raise_error(Sphinx::SphinxConnectError)
58
+ end
59
+ end
60
+
61
+ describe 'The GetResponse method of Sphinx::Client' do
62
+ before(:each) do
63
+ @sphinx = Sphinx::Client.new
64
+ @sock = mock('TCPSocket')
65
+ @sock.should_receive(:close)
66
+ end
67
+
68
+ it 'should receive response' do
69
+ @sock.should_receive(:recv).with(8).and_return([Sphinx::Client::SEARCHD_OK, 1, 4].pack('n2N'))
70
+ @sock.should_receive(:recv).with(4).and_return([0].pack('N'))
71
+ @sphinx.send(:GetResponse, @sock, 1)
72
+ end
73
+
74
+ it 'should raise exception on zero-sized response' do
75
+ @sock.should_receive(:recv).with(8).and_return([Sphinx::Client::SEARCHD_OK, 1, 0].pack('n2N'))
76
+ lambda { @sphinx.send(:GetResponse, @sock, 1) }.should raise_error(Sphinx::SphinxResponseError)
77
+ end
78
+
79
+ it 'should raise exception when response is incomplete' do
80
+ @sock.should_receive(:recv).with(8).and_return([Sphinx::Client::SEARCHD_OK, 1, 4].pack('n2N'))
81
+ @sock.should_receive(:recv).with(4).and_raise(EOFError)
82
+ lambda { @sphinx.send(:GetResponse, @sock, 1) }.should raise_error(Sphinx::SphinxResponseError)
83
+ end
84
+
85
+ it 'should set warning message when SEARCHD_WARNING received' do
86
+ @sock.should_receive(:recv).with(8).and_return([Sphinx::Client::SEARCHD_WARNING, 1, 14].pack('n2N'))
87
+ @sock.should_receive(:recv).with(14).and_return([5].pack('N') + 'helloworld')
88
+ @sphinx.send(:GetResponse, @sock, 1).should == 'world'
89
+ @sphinx.GetLastWarning.should == 'hello'
90
+ end
91
+
92
+ it 'should raise exception when SEARCHD_ERROR received' do
93
+ @sock.should_receive(:recv).with(8).and_return([Sphinx::Client::SEARCHD_ERROR, 1, 9].pack('n2N'))
94
+ @sock.should_receive(:recv).with(9).and_return([1].pack('N') + 'hello')
95
+ lambda { @sphinx.send(:GetResponse, @sock, 1) }.should raise_error(Sphinx::SphinxInternalError)
96
+ @sphinx.GetLastError.should == 'searchd error: hello'
97
+ end
98
+
99
+ it 'should raise exception when SEARCHD_RETRY received' do
100
+ @sock.should_receive(:recv).with(8).and_return([Sphinx::Client::SEARCHD_RETRY, 1, 9].pack('n2N'))
101
+ @sock.should_receive(:recv).with(9).and_return([1].pack('N') + 'hello')
102
+ lambda { @sphinx.send(:GetResponse, @sock, 1) }.should raise_error(Sphinx::SphinxTemporaryError)
103
+ @sphinx.GetLastError.should == 'temporary searchd error: hello'
104
+ end
105
+
106
+ it 'should raise exception when unknown status received' do
107
+ @sock.should_receive(:recv).with(8).and_return([65535, 1, 9].pack('n2N'))
108
+ @sock.should_receive(:recv).with(9).and_return([1].pack('N') + 'hello')
109
+ lambda { @sphinx.send(:GetResponse, @sock, 1) }.should raise_error(Sphinx::SphinxUnknownError)
110
+ @sphinx.GetLastError.should == 'unknown status code: \'65535\''
111
+ end
112
+
113
+ it 'should set warning when server is older than client' do
114
+ @sock.should_receive(:recv).with(8).and_return([Sphinx::Client::SEARCHD_OK, 1, 9].pack('n2N'))
115
+ @sock.should_receive(:recv).with(9).and_return([1].pack('N') + 'hello')
116
+ @sphinx.send(:GetResponse, @sock, 5)
117
+ @sphinx.GetLastWarning.should == 'searchd command v.0.1 older than client\'s v.0.5, some options might not work'
118
+ end
119
+ end
120
+
121
+ describe 'The Query method of Sphinx::Client' do
122
+ include SphinxFixtureHelper
123
+ include SphinxApiCall
124
+
125
+ before(:each) do
126
+ @sphinx = create_sphinx
127
+ end
128
+
129
+ it 'should generate valid request with default parameters' do
130
+ expected = sphinx_fixture('default_search')
131
+ @sock.should_receive(:send).with(expected, 0)
132
+ @sphinx.Query('query') rescue nil?
133
+ end
134
+
135
+ it 'should generate valid request with default parameters and index' do
136
+ expected = sphinx_fixture('default_search_index')
137
+ @sock.should_receive(:send).with(expected, 0)
138
+ @sphinx.Query('query', 'index') rescue nil?
139
+ end
140
+
141
+ it 'should generate valid request with limits' do
142
+ expected = sphinx_fixture('limits')
143
+ @sock.should_receive(:send).with(expected, 0)
144
+ @sphinx.SetLimits(10, 20)
145
+ @sphinx.Query('query') rescue nil?
146
+ end
147
+
148
+ it 'should generate valid request with limits and max number to retrieve' do
149
+ expected = sphinx_fixture('limits_max')
150
+ @sock.should_receive(:send).with(expected, 0)
151
+ @sphinx.SetLimits(10, 20, 30)
152
+ @sphinx.Query('query') rescue nil?
153
+ end
154
+
155
+ it 'should generate valid request with limits and cutoff to retrieve' do
156
+ expected = sphinx_fixture('limits_cutoff')
157
+ @sock.should_receive(:send).with(expected, 0)
158
+ @sphinx.SetLimits(10, 20, 30, 40)
159
+ @sphinx.Query('query') rescue nil?
160
+ end
161
+
162
+ it 'should generate valid request with max query time specified' do
163
+ expected = sphinx_fixture('max_query_time')
164
+ @sock.should_receive(:send).with(expected, 0)
165
+ @sphinx.SetMaxQueryTime(1000)
166
+ @sphinx.Query('query') rescue nil?
167
+ end
168
+
169
+ describe 'with match' do
170
+ [ :all, :any, :phrase, :boolean, :extended, :fullscan, :extended2 ].each do |match|
171
+ it "should generate valid request for SPH_MATCH_#{match.to_s.upcase}" do
172
+ expected = sphinx_fixture("match_#{match}")
173
+ @sock.should_receive(:send).with(expected, 0)
174
+ @sphinx.SetMatchMode(Sphinx::Client::const_get("SPH_MATCH_#{match.to_s.upcase}"))
175
+ @sphinx.Query('query') rescue nil?
176
+ end
177
+ end
178
+ end
179
+
180
+ describe 'with rank' do
181
+ [ :proximity_bm25, :bm25, :none, :wordcount, :proximity, :matchany, :fieldmask, :sph04 ].each do |rank|
182
+ it "should generate valid request for SPH_RANK_#{rank.to_s.upcase}" do
183
+ expected = sphinx_fixture("ranking_#{rank}")
184
+ @sock.should_receive(:send).with(expected, 0)
185
+ @sphinx.SetRankingMode(Sphinx::Client.const_get("SPH_RANK_#{rank.to_s.upcase}"))
186
+ @sphinx.Query('query') rescue nil?
187
+ end
188
+ end
189
+ end
190
+
191
+ describe 'with sorting' do
192
+ [ :attr_desc, :relevance, :attr_asc, :time_segments, :extended, :expr ].each do |mode|
193
+ it "should generate valid request for SPH_SORT_#{mode.to_s.upcase}" do
194
+ expected = sphinx_fixture("sort_#{mode}")
195
+ @sock.should_receive(:send).with(expected, 0)
196
+ @sphinx.SetSortMode(Sphinx::Client.const_get("SPH_SORT_#{mode.to_s.upcase}"), mode == :relevance ? '' : 'sortby')
197
+ @sphinx.Query('query') rescue nil?
198
+ end
199
+ end
200
+ end
201
+
202
+ it 'should generate valid request with weights' do
203
+ expected = sphinx_fixture('weights')
204
+ @sock.should_receive(:send).with(expected, 0)
205
+ @sphinx.SetWeights([10, 20, 30, 40])
206
+ @sphinx.Query('query') rescue nil?
207
+ end
208
+
209
+ it 'should generate valid request with field weights' do
210
+ expected = sphinx_fixture('field_weights')
211
+ @sock.should_receive(:send).with(expected, 0)
212
+ @sphinx.SetFieldWeights({'field1' => 10, 'field2' => 20})
213
+ @sphinx.Query('query') rescue nil?
214
+ end
215
+
216
+ it 'should generate valid request with index weights' do
217
+ expected = sphinx_fixture('index_weights')
218
+ @sock.should_receive(:send).with(expected, 0)
219
+ @sphinx.SetIndexWeights({'index1' => 10, 'index2' => 20})
220
+ @sphinx.Query('query') rescue nil?
221
+ end
222
+
223
+ it 'should generate valid request with ID range' do
224
+ expected = sphinx_fixture('id_range')
225
+ @sock.should_receive(:send).with(expected, 0)
226
+ @sphinx.SetIDRange(10, 20)
227
+ @sphinx.Query('query') rescue nil?
228
+ end
229
+
230
+ it 'should generate valid request with ID range and 64-bit ints' do
231
+ expected = sphinx_fixture('id_range64')
232
+ @sock.should_receive(:send).with(expected, 0)
233
+ @sphinx.SetIDRange(8589934591, 17179869183)
234
+ @sphinx.Query('query') rescue nil?
235
+ end
236
+
237
+ it 'should generate valid request with values filter' do
238
+ expected = sphinx_fixture('filter')
239
+ @sock.should_receive(:send).with(expected, 0)
240
+ @sphinx.SetFilter('attr', [10, 20, 30])
241
+ @sphinx.Query('query') rescue nil?
242
+ end
243
+
244
+ it 'should generate valid request with two values filters' do
245
+ expected = sphinx_fixture('filters')
246
+ @sock.should_receive(:send).with(expected, 0)
247
+ @sphinx.SetFilter('attr2', [40, 50])
248
+ @sphinx.SetFilter('attr1', [10, 20, 30])
249
+ @sphinx.Query('query') rescue nil?
250
+ end
251
+
252
+ it 'should generate valid request with values filter excluded' do
253
+ expected = sphinx_fixture('filter_exclude')
254
+ @sock.should_receive(:send).with(expected, 0)
255
+ @sphinx.SetFilter('attr', [10, 20, 30], true)
256
+ @sphinx.Query('query') rescue nil?
257
+ end
258
+
259
+ it 'should generate valid request with values filter range' do
260
+ expected = sphinx_fixture('filter_range')
261
+ @sock.should_receive(:send).with(expected, 0)
262
+ @sphinx.SetFilterRange('attr', 10, 20)
263
+ @sphinx.Query('query') rescue nil?
264
+ end
265
+
266
+ it 'should generate valid request with two filter ranges' do
267
+ expected = sphinx_fixture('filter_ranges')
268
+ @sock.should_receive(:send).with(expected, 0)
269
+ @sphinx.SetFilterRange('attr2', 30, 40)
270
+ @sphinx.SetFilterRange('attr1', 10, 20)
271
+ @sphinx.Query('query') rescue nil?
272
+ end
273
+
274
+ it 'should generate valid request with filter range excluded' do
275
+ expected = sphinx_fixture('filter_range_exclude')
276
+ @sock.should_receive(:send).with(expected, 0)
277
+ @sphinx.SetFilterRange('attr', 10, 20, true)
278
+ @sphinx.Query('query') rescue nil?
279
+ end
280
+
281
+ it 'should generate valid request with signed int64-based filter range' do
282
+ expected = sphinx_fixture('filter_range_int64')
283
+ @sock.should_receive(:send).with(expected, 0)
284
+ @sphinx.SetFilterRange('attr1', -10, 20)
285
+ @sphinx.SetFilterRange('attr2', -1099511627770, 1099511627780)
286
+ safe_call { @sphinx.Query('query') }
287
+ end
288
+
289
+ it 'should generate valid request with float filter range' do
290
+ expected = sphinx_fixture('filter_float_range')
291
+ @sock.should_receive(:send).with(expected, 0)
292
+ @sphinx.SetFilterFloatRange('attr', 10.5, 20.3)
293
+ @sphinx.Query('query') rescue nil?
294
+ end
295
+
296
+ it 'should generate valid request with float filter excluded' do
297
+ expected = sphinx_fixture('filter_float_range_exclude')
298
+ @sock.should_receive(:send).with(expected, 0)
299
+ @sphinx.SetFilterFloatRange('attr', 10.5, 20.3, true)
300
+ @sphinx.Query('query') rescue nil?
301
+ end
302
+
303
+ it 'should generate valid request with different filters' do
304
+ expected = sphinx_fixture('filters_different')
305
+ @sock.should_receive(:send).with(expected, 0)
306
+ @sphinx.SetFilterRange('attr1', 10, 20, true)
307
+ @sphinx.SetFilter('attr3', [30, 40, 50])
308
+ @sphinx.SetFilterRange('attr1', 60, 70)
309
+ @sphinx.SetFilter('attr2', [80, 90, 100], true)
310
+ @sphinx.SetFilterFloatRange('attr1', 60.8, 70.5)
311
+ @sphinx.Query('query') rescue nil?
312
+ end
313
+
314
+ it 'should generate valid request with geographical anchor point' do
315
+ expected = sphinx_fixture('geo_anchor')
316
+ @sock.should_receive(:send).with(expected, 0)
317
+ @sphinx.SetGeoAnchor('attrlat', 'attrlong', 20.3, 40.7)
318
+ @sphinx.Query('query') rescue nil?
319
+ end
320
+
321
+ describe 'with group by' do
322
+ [ :day, :week, :month, :year, :attr, :attrpair ].each do |groupby|
323
+ it "should generate valid request for SPH_GROUPBY_#{groupby.to_s.upcase}" do
324
+ expected = sphinx_fixture("group_by_#{groupby}")
325
+ @sock.should_receive(:send).with(expected, 0)
326
+ @sphinx.SetGroupBy('attr', Sphinx::Client::const_get("SPH_GROUPBY_#{groupby.to_s.upcase}"))
327
+ @sphinx.Query('query') rescue nil?
328
+ end
329
+ end
330
+
331
+ it 'should generate valid request for SPH_GROUPBY_DAY with sort' do
332
+ expected = sphinx_fixture('group_by_day_sort')
333
+ @sock.should_receive(:send).with(expected, 0)
334
+ @sphinx.SetGroupBy('attr', Sphinx::Client::SPH_GROUPBY_DAY, 'somesort')
335
+ @sphinx.Query('query') rescue nil?
336
+ end
337
+
338
+ it 'should generate valid request with count-distinct attribute' do
339
+ expected = sphinx_fixture('group_distinct')
340
+ @sock.should_receive(:send).with(expected, 0)
341
+ @sphinx.SetGroupBy('attr', Sphinx::Client::SPH_GROUPBY_DAY)
342
+ @sphinx.SetGroupDistinct('attr')
343
+ @sphinx.Query('query') rescue nil?
344
+ end
345
+ end
346
+
347
+ it 'should generate valid request with retries count specified' do
348
+ expected = sphinx_fixture('retries')
349
+ @sock.should_receive(:send).with(expected, 0)
350
+ @sphinx.SetRetries(10)
351
+ @sphinx.Query('query') rescue nil?
352
+ end
353
+
354
+ it 'should generate valid request with retries count and delay specified' do
355
+ expected = sphinx_fixture('retries_delay')
356
+ @sock.should_receive(:send).with(expected, 0)
357
+ @sphinx.SetRetries(10, 20)
358
+ @sphinx.Query('query') rescue nil?
359
+ end
360
+
361
+ it 'should generate valid request for SetOverride' do
362
+ expected = sphinx_fixture('set_override')
363
+ @sock.should_receive(:send).with(expected, 0)
364
+ @sphinx.SetOverride('attr1', Sphinx::Client::SPH_ATTR_INTEGER, { 10 => 20 })
365
+ @sphinx.SetOverride('attr2', Sphinx::Client::SPH_ATTR_FLOAT, { 11 => 30.3 })
366
+ @sphinx.SetOverride('attr3', Sphinx::Client::SPH_ATTR_BIGINT, { 12 => 1099511627780 })
367
+ @sphinx.Query('query') rescue nil?
368
+ end
369
+
370
+ it 'should generate valid request for SetSelect' do
371
+ expected = sphinx_fixture('select')
372
+ @sock.should_receive(:send).with(expected, 0)
373
+ @sphinx.SetSelect('attr1, attr2')
374
+ @sphinx.Query('query') rescue nil?
375
+ end
376
+ end
377
+
378
+ describe 'The RunQueries method of Sphinx::Client' do
379
+ include SphinxFixtureHelper
380
+
381
+ before(:each) do
382
+ @sphinx = Sphinx::Client.new
383
+ @sock = mock('TCPSocket')
384
+ @sphinx.stub!(:Connect).and_return(@sock)
385
+ @sphinx.stub!(:GetResponse).and_raise(Sphinx::SphinxError)
386
+ end
387
+
388
+ it 'should generate valid request for multiple queries' do
389
+ expected = sphinx_fixture('miltiple_queries')
390
+ @sock.should_receive(:send).with(expected, 0)
391
+
392
+ @sphinx.SetRetries(10, 20)
393
+ @sphinx.AddQuery('test1')
394
+ @sphinx.SetGroupBy('attr', Sphinx::Client::SPH_GROUPBY_DAY)
395
+ @sphinx.AddQuery('test2') rescue nil?
396
+
397
+ @sphinx.RunQueries rescue nil?
398
+ end
399
+ end
400
+
401
+ describe 'The BuildExcerpts method of Sphinx::Client' do
402
+ include SphinxFixtureHelper
403
+
404
+ before(:each) do
405
+ @sphinx = Sphinx::Client.new
406
+ @sock = mock('TCPSocket')
407
+ @sphinx.stub!(:Connect).and_return(@sock)
408
+ @sphinx.stub!(:GetResponse).and_raise(Sphinx::SphinxError)
409
+ end
410
+
411
+ it 'should generate valid request with default parameters' do
412
+ expected = sphinx_fixture('excerpt_default')
413
+ @sock.should_receive(:send).with(expected, 0)
414
+ @sphinx.BuildExcerpts(['10', '20'], 'index', 'word1 word2') rescue nil?
415
+ end
416
+
417
+ it 'should generate valid request with custom parameters' do
418
+ expected = sphinx_fixture('excerpt_custom')
419
+ @sock.should_receive(:send).with(expected, 0)
420
+ @sphinx.BuildExcerpts(['10', '20'], 'index', 'word1 word2', { 'before_match' => 'before',
421
+ 'after_match' => 'after',
422
+ 'chunk_separator' => 'separator',
423
+ 'limit' => 10 }) rescue nil?
424
+ end
425
+
426
+ it 'should generate valid request with flags' do
427
+ expected = sphinx_fixture('excerpt_flags')
428
+ @sock.should_receive(:send).with(expected, 0)
429
+ @sphinx.BuildExcerpts(['10', '20'], 'index', 'word1 word2', { 'exact_phrase' => true,
430
+ 'single_passage' => true,
431
+ 'use_boundaries' => true,
432
+ 'weight_order' => true,
433
+ 'query_mode' => true }) rescue nil?
434
+ end
435
+ end
436
+
437
+ describe 'The BuildKeywords method of Sphinx::Client' do
438
+ include SphinxFixtureHelper
439
+ include SphinxApiCall
440
+
441
+ before(:each) do
442
+ @sphinx = create_sphinx
443
+ end
444
+
445
+ it 'should generate valid request' do
446
+ expected = sphinx_fixture('keywords')
447
+ @sock.should_receive(:send).with(expected, 0)
448
+ safe_call { @sphinx.BuildKeywords('test', 'index', true) }
449
+ end
450
+ end
451
+
452
+ describe 'The UpdateAttributes method of Sphinx::Client' do
453
+ include SphinxFixtureHelper
454
+ include SphinxApiCall
455
+
456
+ before(:each) do
457
+ @sphinx = create_sphinx
458
+ end
459
+
460
+ it 'should generate valid request' do
461
+ expected = sphinx_fixture('update_attributes')
462
+ @sock.should_receive(:send).with(expected, 0)
463
+ safe_call { @sphinx.UpdateAttributes('index', ['group'], { 123 => [456] }) }
464
+ end
465
+
466
+ it 'should generate valid request for MVA' do
467
+ expected = sphinx_fixture('update_attributes_mva')
468
+ @sock.should_receive(:send).with(expected, 0)
469
+ safe_call { @sphinx.UpdateAttributes('index', ['group', 'category'], { 123 => [ [456, 789], [1, 2, 3] ] }, true) }
470
+ end
471
+ end