sphinx 0.9.9.2117 → 0.9.10

Sign up to get free protection for your applications and to get access to all the features.
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