forked from karmi/retire
-
Notifications
You must be signed in to change notification settings - Fork 0
/
search_test.rb
374 lines (292 loc) · 11.1 KB
/
search_test.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
require 'test_helper'
module Tire
class SearchTest < Test::Unit::TestCase
context "Search" do
setup { Configuration.reset }
should "be initialized with single index" do
s = Search::Search.new('index') { query { string 'foo' } }
assert_match %r|/index/_search|, s.url
end
should "be initialized with multiple indices" do
s = Search::Search.new(['index1','index2']) { query { string 'foo' } }
assert_match %r|/index1,index2/_search|, s.url
end
should "be initialized with multiple indices as string" do
s = Search::Search.new(['index1,index2,index3']) { query { string 'foo' } }
assert_match %r|/index1,index2,index3/_search|, s.url
end
should "allow to search all indices by leaving index empty" do
s = Search::Search.new { query { string 'foo' } }
assert_match %r|localhost:9200/_search|, s.url
end
should "allow to limit results with document type" do
s = Search::Search.new('index', :type => 'bar') do
query { string 'foo' }
end
assert_match %r|index/bar/_search|, s.url
end
should "allow to pass block to query" do
Search::Query.any_instance.expects(:instance_eval)
Search::Search.new('index') do
query { string 'foo' }
end
end
should "allow to pass block with argument to query (use variables from outer scope)" do
def foo; 'bar'; end
Search::Query.any_instance.expects(:instance_eval).never
Search::Search.new('index') do |search|
search.query do |query|
query.string foo
end
end
end
should "store indices as an array" do
s = Search::Search.new('index1') do;end
assert_equal ['index1'], s.indices
s = Search::Search.new(['index1', 'index2']) do;end
assert_equal ['index1', 'index2'], s.indices
end
should "return curl snippet for debugging" do
s = Search::Search.new('index') do
query { string 'title:foo' }
end
assert_equal %q|curl -X GET "http://localhost:9200/index/_search?pretty=true" -d | +
%q|'{"query":{"query_string":{"query":"title:foo"}}}'|,
s.to_curl
end
should "return curl snippet with multiple indices for debugging" do
s = Search::Search.new(['index_1', 'index_2']) do
query { string 'title:foo' }
end
assert_match /index_1,index_2/, s.to_curl
end
should "return itself as a Hash" do
s = Search::Search.new('index') do
query { string 'title:foo' }
end
assert_nothing_raised do
assert_instance_of Hash, s.to_hash
assert_equal "title:foo", s.to_hash[:query][:query_string][:query]
end
end
should "allow chaining" do
assert_nothing_raised do
Search::Search.new('index').query { }.
sort { by :title, 'desc' }.
size(5).
sort { by :name, 'asc' }.
from(1)
end
end
should "perform the search lazily" do
response = mock_response '{"took":1,"hits":[]}', 200
Configuration.client.expects(:get).returns(response)
Results::Collection.expects(:new).returns([])
s = Search::Search.new('index')
assert_not_nil s.results
assert_not_nil s.response
end
should "allow the search criteria to be chained" do
s = Search::Search.new('index').query { string 'foo' }
assert_nil s.filters, "Should NOT have filters"
s.expects(:perform).once
s.filter :term, :other_field => 'bar'
assert s.filters.size == 1, "Should have filters"
s.results
end
should "print debugging information on exception and return false" do
::RestClient::Request.any_instance.
expects(:execute).
raises(::RestClient::InternalServerError)
STDERR.expects(:puts)
s = Search::Search.new('index')
assert_raise Search::SearchRequestFailed do
s.perform
end
end
should "log request, but not response, when logger is set" do
Configuration.logger STDERR
Configuration.client.expects(:get).returns(mock_response( '{"took":1,"hits":[]}', 200 ))
Results::Collection.expects(:new).returns([])
Configuration.logger.expects(:log_request).returns(true)
Configuration.logger.expects(:log_response).with(200, 1, '')
Search::Search.new('index').perform
end
should "log the original exception on failed request" do
Configuration.logger STDERR
Configuration.client.expects(:get).raises(Errno::ECONNREFUSED)
Configuration.logger.expects(:log_response).with('N/A', 'N/A', '')
assert_raise Errno::ECONNREFUSED do
Search::Search.new('index').perform
end
end
should "allow to set the server url" do
search = Search::Search.new('indexA')
Configuration.url 'http://es1.example.com'
Configuration.client.
expects(:get).
with do |url, payload|
url == 'http://es1.example.com/indexA/_search'
end.
returns(mock_response( '{"took":1,"hits":{"total": 0, "hits" : []}}', 200 ))
search.perform
end
context "sort" do
should "allow sorting by multiple fields" do
s = Search::Search.new('index') do
sort do
by :title, 'desc'
by :_score
end
end
hash = MultiJson.decode( s.to_json )
assert_equal [{'title' => 'desc'}, '_score'], hash['sort']
end
end
context "facets" do
should "retrieve terms facets" do
s = Search::Search.new('index') do
facet('foo1') { terms :bar, :global => true }
facet('foo2', :global => true) { terms :bar }
facet('foo3') { terms :baz }
end
assert_equal 3, s.facets.keys.size
assert_not_nil s.facets['foo1']
assert_not_nil s.facets['foo2']
assert_not_nil s.facets['foo3']
end
should "retrieve date histogram facets" do
s = Search::Search.new('index') do
facet('date') { date :published_on }
end
assert_equal 1, s.facets.keys.size
assert_not_nil s.facets['date']
end
end
context "filter" do
should "allow to specify filter" do
s = Search::Search.new('index') do
filter :terms, :tags => ['foo']
end
assert_equal 1, s.filters.size
assert_not_nil s.filters.first
assert_not_nil s.filters.first[:terms]
assert_equal( {:terms => {:tags => ['foo']}}.to_json,
s.to_hash[:filter].to_json )
end
should "allow to add multiple filters" do
s = Search::Search.new('index') do
filter :terms, :tags => ['foo']
filter :term, :words => 125
end
assert_equal 2, s.filters.size
assert_not_nil s.filters.first[:terms]
assert_not_nil s.filters.last[:term]
assert_equal( { :and => [ {:terms => {:tags => ['foo']}}, {:term => {:words => 125}} ] }.to_json,
s.to_hash[:filter].to_json )
end
end
context "highlight" do
should "allow to specify highlight for single field" do
s = Search::Search.new('index') do
highlight :body
end
assert_not_nil s.highlight
assert_instance_of Tire::Search::Highlight, s.highlight
end
should "allow to specify highlight for more fields" do
s = Search::Search.new('index') do
highlight :body, :title
end
assert_not_nil s.highlight
assert_instance_of Tire::Search::Highlight, s.highlight
end
should "allow to specify highlight with for more fields with options" do
s = Search::Search.new('index') do
highlight :body, :title => { :fragment_size => 150, :number_of_fragments => 3 }
end
assert_not_nil s.highlight
assert_instance_of Tire::Search::Highlight, s.highlight
end
end
context "with from/size" do
should "set the values in request" do
s = Search::Search.new('index') do
size 5
from 3
end
hash = MultiJson.decode( s.to_json )
assert_equal 5, hash['size']
assert_equal 3, hash['from']
end
should "set the size value in options" do
Results::Collection.any_instance.stubs(:total).returns(50)
s = Search::Search.new('index') do
size 5
end
assert_equal 5, s.options[:size]
end
should "set the from value in options" do
Results::Collection.any_instance.stubs(:total).returns(50)
s = Search::Search.new('index') do
from 5
end
assert_equal 5, s.options[:from]
end
end
context "when limiting returned fields" do
should "set the fields limit in request" do
s = Search::Search.new('index') do
fields :title
end
hash = MultiJson.decode( s.to_json )
assert_equal ['title'], hash['fields']
end
should "take multiple fields as an Array" do
s = Search::Search.new('index') do
fields [:title, :tags]
end
hash = MultiJson.decode( s.to_json )
assert_equal ['title', 'tags'], hash['fields']
end
should "take multiple fields as splat argument" do
s = Search::Search.new('index') do
fields :title, :tags
end
hash = MultiJson.decode( s.to_json )
assert_equal ['title', 'tags'], hash['fields']
end
end
context "boolean queries" do
should "wrap other queries" do
# TODO: Try to get rid of the `boolean` method
#
# TODO: Try to get rid of multiple `should`, `must`, invocations, and wrap queries like this:
# boolean do
# should do
# string 'foo'
# string 'bar'
# end
# end
s = Search::Search.new('index') do
query do
boolean do
should { string 'foo' }
should { string 'moo' }
must { string 'title:bar' }
must { terms :tags, ['baz'] }
end
end
end
hash = MultiJson.decode(s.to_json)
query = hash['query']['bool']
# p hash
assert_equal 2, query['should'].size
assert_equal 2, query['must'].size
assert_equal( { 'query_string' => { 'query' => 'foo' } }, query['should'].first)
assert_equal( { 'terms' => { 'tags' => ['baz'] } }, query['must'].last)
end
end
end
end
end