tire 0.3.2 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +2 -1
- data/README.markdown +3 -1
- data/lib/tire.rb +2 -1
- data/lib/tire/configuration.rb +1 -1
- data/lib/tire/http/client.rb +51 -0
- data/lib/tire/http/clients/curb.rb +55 -0
- data/lib/tire/http/response.rb +23 -0
- data/lib/tire/index.rb +11 -17
- data/lib/tire/model/naming.rb +45 -4
- data/lib/tire/model/persistence.rb +6 -0
- data/lib/tire/model/search.rb +15 -7
- data/lib/tire/results/pagination.rb +9 -1
- data/lib/tire/search.rb +9 -9
- data/lib/tire/version.rb +7 -1
- data/test/integration/active_record_searchable_test.rb +9 -3
- data/test/integration/index_store_test.rb +10 -4
- data/test/integration/percolator_test.rb +1 -3
- data/test/models/active_model_article_with_custom_document_type.rb +7 -0
- data/test/test_helper.rb +2 -2
- data/test/unit/configuration_test.rb +2 -2
- data/test/unit/http_client_test.rb +27 -0
- data/test/unit/http_response_test.rb +45 -0
- data/test/unit/index_test.rb +13 -17
- data/test/unit/model_persistence_test.rb +19 -1
- data/test/unit/model_search_test.rb +70 -0
- data/test/unit/results_collection_test.rb +7 -0
- data/test/unit/search_test.rb +7 -6
- data/test/unit/tire_test.rb +2 -2
- metadata +182 -228
- data/lib/tire/client.rb +0 -25
- data/test/unit/client_test.rb +0 -25
data/lib/tire/version.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Tire
|
2
|
-
VERSION = "0.3.
|
2
|
+
VERSION = "0.3.3"
|
3
3
|
|
4
4
|
CHANGELOG =<<-END
|
5
5
|
IMPORTANT CHANGES LATELY:
|
@@ -24,5 +24,11 @@ module Tire
|
|
24
24
|
|
25
25
|
When there's no conflict with existing methods, Tire methods are added
|
26
26
|
to the class namespace, as well, so the change is 100% backwards-compatible.
|
27
|
+
|
28
|
+
0.3.3
|
29
|
+
---------------------------------------------------------
|
30
|
+
# Added proper will_paginate compatibility
|
31
|
+
# Added support for plugging in another HTTP library (see lib/http/clients/curb for an example)
|
32
|
+
|
27
33
|
END
|
28
34
|
end
|
@@ -35,10 +35,15 @@ module Tire
|
|
35
35
|
context "ActiveRecord integration" do
|
36
36
|
|
37
37
|
setup do
|
38
|
+
ActiveRecordArticle.destroy_all
|
38
39
|
Tire.index('active_record_articles').delete
|
40
|
+
|
39
41
|
load File.expand_path('../../models/active_record_models.rb', __FILE__)
|
40
42
|
end
|
41
|
-
teardown
|
43
|
+
teardown do
|
44
|
+
ActiveRecordArticle.destroy_all
|
45
|
+
Tire.index('active_record_articles').delete
|
46
|
+
end
|
42
47
|
|
43
48
|
should "configure mapping" do
|
44
49
|
assert_equal 'snowball', ActiveRecordArticle.mapping[:title][:analyzer]
|
@@ -90,8 +95,9 @@ module Tire
|
|
90
95
|
end
|
91
96
|
|
92
97
|
should "load records with options on query search" do
|
93
|
-
assert_equal ActiveRecordArticle.find(['1'
|
94
|
-
ActiveRecordArticle.search('"Test 1"
|
98
|
+
assert_equal ActiveRecordArticle.find(['1'], :include => 'comments').first,
|
99
|
+
ActiveRecordArticle.search('"Test 1"',
|
100
|
+
:load => { :include => 'comments' }).results.first
|
95
101
|
end
|
96
102
|
|
97
103
|
should "return empty collection for nonmatching query" do
|
@@ -7,10 +7,7 @@ module Tire
|
|
7
7
|
|
8
8
|
context "Storing the documents in index" do
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
should "store hashes under their IDs" do
|
13
|
-
|
10
|
+
setup do
|
14
11
|
Tire.index 'articles-test-ids' do
|
15
12
|
delete
|
16
13
|
create
|
@@ -23,7 +20,16 @@ module Tire
|
|
23
20
|
|
24
21
|
refresh
|
25
22
|
end
|
23
|
+
end
|
26
24
|
|
25
|
+
teardown { Tire.index('articles-test-ids').delete }
|
26
|
+
|
27
|
+
should "happen in existing index" do
|
28
|
+
assert Tire.index("articles-test-ids").exists?
|
29
|
+
assert ! Tire.index("four-oh-four-index").exists?
|
30
|
+
end
|
31
|
+
|
32
|
+
should "store hashes under their IDs" do
|
27
33
|
s = Tire.search('articles-test-ids') { query { string '*' } }
|
28
34
|
|
29
35
|
assert_equal 4, s.results.count
|
@@ -43,9 +43,7 @@ module Tire
|
|
43
43
|
assert @index.unregister_percolator_query('alert')
|
44
44
|
Tire.index('_percolator').refresh
|
45
45
|
|
46
|
-
|
47
|
-
Configuration.client.get("#{Configuration.url}/_percolator/percolator-test/alert")
|
48
|
-
end
|
46
|
+
assert Configuration.client.get("#{Configuration.url}/_percolator/percolator-test/alert").failure?
|
49
47
|
end
|
50
48
|
|
51
49
|
end
|
data/test/test_helper.rb
CHANGED
@@ -16,8 +16,8 @@ Dir[File.dirname(__FILE__) + '/models/**/*.rb'].each { |m| require m }
|
|
16
16
|
|
17
17
|
class Test::Unit::TestCase
|
18
18
|
|
19
|
-
def mock_response(body, code=200)
|
20
|
-
|
19
|
+
def mock_response(body, code=200, headers={})
|
20
|
+
Tire::HTTP::Response.new(body, code, headers)
|
21
21
|
end
|
22
22
|
|
23
23
|
def fixtures_path
|
@@ -33,7 +33,7 @@ module Tire
|
|
33
33
|
end
|
34
34
|
|
35
35
|
should "return default client" do
|
36
|
-
assert_equal Client::RestClient, Configuration.client
|
36
|
+
assert_equal HTTP::Client::RestClient, Configuration.client
|
37
37
|
end
|
38
38
|
|
39
39
|
should "return nil as logger by default" do
|
@@ -59,7 +59,7 @@ module Tire
|
|
59
59
|
assert_equal 'http://example.com', Configuration.url
|
60
60
|
Configuration.reset
|
61
61
|
assert_equal 'http://localhost:9200', Configuration.url
|
62
|
-
assert_equal Client::RestClient, Configuration.client
|
62
|
+
assert_equal HTTP::Client::RestClient, Configuration.client
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Tire
|
4
|
+
module HTTP
|
5
|
+
|
6
|
+
class ClientTest < Test::Unit::TestCase
|
7
|
+
|
8
|
+
context "RestClient" do
|
9
|
+
|
10
|
+
should "be default" do
|
11
|
+
assert_equal Client::RestClient, Configuration.client
|
12
|
+
end
|
13
|
+
|
14
|
+
should "respond to HTTP methods" do
|
15
|
+
assert_respond_to Client::RestClient, :get
|
16
|
+
assert_respond_to Client::RestClient, :post
|
17
|
+
assert_respond_to Client::RestClient, :put
|
18
|
+
assert_respond_to Client::RestClient, :delete
|
19
|
+
assert_respond_to Client::RestClient, :head
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Tire
|
4
|
+
module HTTP
|
5
|
+
|
6
|
+
class ResponseTest < Test::Unit::TestCase
|
7
|
+
|
8
|
+
context "Response" do
|
9
|
+
|
10
|
+
should "take response body, code and headers on initialization" do
|
11
|
+
response = Response.new "http response body",
|
12
|
+
200,
|
13
|
+
:content_length => 20,
|
14
|
+
:content_encoding => 'gzip'
|
15
|
+
|
16
|
+
assert_equal "http response body", response.body
|
17
|
+
assert_equal 200, response.code
|
18
|
+
end
|
19
|
+
|
20
|
+
should "not require headers" do
|
21
|
+
assert_nothing_raised do
|
22
|
+
Response.new "Forbidden", 403
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
should "return success" do
|
27
|
+
responses = []
|
28
|
+
responses << Response.new('OK', 200)
|
29
|
+
responses << Response.new('Redirect', 302)
|
30
|
+
|
31
|
+
responses.each { |response| assert response.success? }
|
32
|
+
|
33
|
+
assert ! Response.new('NotFound', 404).success?
|
34
|
+
end
|
35
|
+
|
36
|
+
should "return failure" do
|
37
|
+
assert Response.new('NotFound', 404).failure?
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
data/test/unit/index_test.rb
CHANGED
@@ -20,7 +20,7 @@ module Tire
|
|
20
20
|
end
|
21
21
|
|
22
22
|
should "return false when does not exist" do
|
23
|
-
Configuration.client.expects(:head).
|
23
|
+
Configuration.client.expects(:head).returns(mock_response('', 404))
|
24
24
|
assert ! @index.exists?
|
25
25
|
end
|
26
26
|
|
@@ -30,7 +30,7 @@ module Tire
|
|
30
30
|
end
|
31
31
|
|
32
32
|
should "not raise exception and just return false when trying to create existing index" do
|
33
|
-
Configuration.client.expects(:post).
|
33
|
+
Configuration.client.expects(:post).returns(mock_response('{"error":"IndexAlreadyExistsException[\'dummy\']"}', 400))
|
34
34
|
assert_nothing_raised { assert ! @index.create }
|
35
35
|
end
|
36
36
|
|
@@ -40,9 +40,7 @@ module Tire
|
|
40
40
|
end
|
41
41
|
|
42
42
|
should "not raise exception and just return false when deleting non-existing index" do
|
43
|
-
Configuration.client.expects(:delete).returns(mock_response('{"error":"[articles] missing"}'))
|
44
|
-
assert_nothing_raised { assert ! @index.delete }
|
45
|
-
Configuration.client.expects(:delete).raises(RestClient::BadRequest)
|
43
|
+
Configuration.client.expects(:delete).returns(mock_response('{"error":"[articles] missing"}', 404))
|
46
44
|
assert_nothing_raised { assert ! @index.delete }
|
47
45
|
end
|
48
46
|
|
@@ -229,33 +227,33 @@ module Tire
|
|
229
227
|
|
230
228
|
should "get type from document" do
|
231
229
|
Configuration.client.expects(:delete).with("#{Configuration.url}/dummy/article/1").
|
232
|
-
returns('{"ok":true,"_id":"1"}').twice
|
230
|
+
returns(mock_response('{"ok":true,"_id":"1"}')).twice
|
233
231
|
@index.remove :id => 1, :type => 'article', :title => 'Test'
|
234
232
|
@index.remove :id => 1, :type => 'article', :title => 'Test'
|
235
233
|
end
|
236
234
|
|
237
235
|
should "set default type" do
|
238
236
|
Configuration.client.expects(:delete).with("#{Configuration.url}/dummy/document/1").
|
239
|
-
returns('{"ok":true,"_id":"1"}')
|
237
|
+
returns(mock_response('{"ok":true,"_id":"1"}'))
|
240
238
|
@index.remove :id => 1, :title => 'Test'
|
241
239
|
end
|
242
240
|
|
243
241
|
should "get ID from hash" do
|
244
242
|
Configuration.client.expects(:delete).with("#{Configuration.url}/dummy/document/1").
|
245
|
-
returns('{"ok":true,"_id":"1"}')
|
243
|
+
returns(mock_response('{"ok":true,"_id":"1"}'))
|
246
244
|
@index.remove :id => 1
|
247
245
|
end
|
248
246
|
|
249
247
|
should "get ID from method" do
|
250
248
|
document = stub('document', :id => 1)
|
251
249
|
Configuration.client.expects(:delete).with("#{Configuration.url}/dummy/document/1").
|
252
|
-
returns('{"ok":true,"_id":"1"}')
|
250
|
+
returns(mock_response('{"ok":true,"_id":"1"}'))
|
253
251
|
@index.remove document
|
254
252
|
end
|
255
253
|
|
256
254
|
should "get type and ID from arguments" do
|
257
255
|
Configuration.client.expects(:delete).with("#{Configuration.url}/dummy/article/1").
|
258
|
-
returns('{"ok":true,"_id":"1"}')
|
256
|
+
returns(mock_response('{"ok":true,"_id":"1"}'))
|
259
257
|
@index.remove :article, 1
|
260
258
|
end
|
261
259
|
|
@@ -288,7 +286,7 @@ module Tire
|
|
288
286
|
json =~ /"id":"2"/ &&
|
289
287
|
json =~ /"title":"One"/ &&
|
290
288
|
json =~ /"title":"Two"/
|
291
|
-
end.returns('{}')
|
289
|
+
end.returns(mock_response('{}'), 200)
|
292
290
|
|
293
291
|
@index.bulk_store [ {:id => '1', :title => 'One'}, {:id => '2', :title => 'Two'} ]
|
294
292
|
|
@@ -305,7 +303,7 @@ module Tire
|
|
305
303
|
json =~ /"id":"2"/ &&
|
306
304
|
json =~ /"title":"One"/ &&
|
307
305
|
json =~ /"title":"Two"/
|
308
|
-
end.returns('{}')
|
306
|
+
end.returns(mock_response('{}', 200))
|
309
307
|
|
310
308
|
one = ActiveModelArticle.new 'title' => 'One'; one.id = '1'
|
311
309
|
two = ActiveModelArticle.new 'title' => 'Two'; two.id = '2'
|
@@ -315,15 +313,13 @@ module Tire
|
|
315
313
|
end
|
316
314
|
|
317
315
|
should "try again when an exception occurs" do
|
318
|
-
Configuration.client.expects(:post).
|
316
|
+
Configuration.client.expects(:post).returns(mock_response('Server error', 503)).at_least(2)
|
319
317
|
|
320
|
-
|
321
|
-
@index.bulk_store [ {:id => '1', :title => 'One'}, {:id => '2', :title => 'Two'} ]
|
322
|
-
end
|
318
|
+
assert !@index.bulk_store([ {:id => '1', :title => 'One'}, {:id => '2', :title => 'Two'} ])
|
323
319
|
end
|
324
320
|
|
325
321
|
should "display error message when collection item does not have ID" do
|
326
|
-
Configuration.client.expects(:post).with
|
322
|
+
Configuration.client.expects(:post).with{ |url, json| url == "#{Configuration.url}/_bulk" }.returns(mock_response('success', 200))
|
327
323
|
STDERR.expects(:puts).once
|
328
324
|
|
329
325
|
documents = [ { :title => 'Bogus' }, { :title => 'Real', :id => 1 } ]
|
@@ -20,6 +20,22 @@ module Tire
|
|
20
20
|
assert_equal 'another-index-name', PersistentArticleWithCustomIndexName.index.name
|
21
21
|
end
|
22
22
|
|
23
|
+
context "with index prefix" do
|
24
|
+
setup do
|
25
|
+
Model::Search.index_prefix 'prefix'
|
26
|
+
end
|
27
|
+
|
28
|
+
teardown do
|
29
|
+
Model::Search.index_prefix nil
|
30
|
+
end
|
31
|
+
|
32
|
+
should "have configured prefix in index_name" do
|
33
|
+
assert_equal 'prefix_persistent_articles', PersistentArticle.index_name
|
34
|
+
assert_equal 'prefix_persistent_articles', PersistentArticle.new(:title => 'Test').index_name
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
23
39
|
should "have document_type" do
|
24
40
|
assert_equal 'persistent_article', PersistentArticle.document_type
|
25
41
|
assert_equal 'persistent_article', PersistentArticle.new(:title => 'Test').document_type
|
@@ -395,7 +411,8 @@ module Tire
|
|
395
411
|
end.returns(mock_response('{"ok":true,"_id":"123"}'))
|
396
412
|
|
397
413
|
Configuration.client.expects(:delete).
|
398
|
-
with("#{Configuration.url}/persistent_articles/persistent_article/123")
|
414
|
+
with("#{Configuration.url}/persistent_articles/persistent_article/123").
|
415
|
+
returns(mock_response('{"ok":true,"acknowledged":true}', 200))
|
399
416
|
|
400
417
|
article = PersistentArticle.new :id => '123', :title => 'Test'
|
401
418
|
article.save
|
@@ -435,6 +452,7 @@ module Tire
|
|
435
452
|
}}
|
436
453
|
}
|
437
454
|
|
455
|
+
Tire::Index.any_instance.stubs(:exists?).returns(false)
|
438
456
|
Tire::Index.any_instance.expects(:create).with(expected)
|
439
457
|
|
440
458
|
class ::PersistentArticleWithMapping
|
@@ -68,6 +68,14 @@ module Tire
|
|
68
68
|
ActiveModelArticleWithCustomIndexName.search { query { string 'foo' } }
|
69
69
|
end
|
70
70
|
|
71
|
+
should "search in custom type" do
|
72
|
+
name = ActiveModelArticleWithCustomDocumentType.index_name
|
73
|
+
Tire::Search::Search.expects(:new).with(name, { :type => 'my_custom_type' }).returns(@stub).twice
|
74
|
+
|
75
|
+
ActiveModelArticleWithCustomDocumentType.search 'foo'
|
76
|
+
ActiveModelArticleWithCustomDocumentType.search { query { string 'foo' } }
|
77
|
+
end
|
78
|
+
|
71
79
|
should "allow to pass custom document type" do
|
72
80
|
Tire::Search::Search.
|
73
81
|
expects(:new).
|
@@ -618,6 +626,7 @@ module Tire
|
|
618
626
|
|
619
627
|
should "NOT overload existing top-level instance methods" do
|
620
628
|
ActiveRecordClassWithTireMethods.stubs(:columns).returns([])
|
629
|
+
ActiveRecordClassWithTireMethods.stubs(:column_defaults).returns({})
|
621
630
|
assert_equal "THIS IS MY INDEX!", ActiveRecordClassWithTireMethods.new.index
|
622
631
|
assert_equal 'active_record_class_with_tire_methods',
|
623
632
|
ActiveRecordClassWithTireMethods.new.tire.index.name
|
@@ -625,6 +634,67 @@ module Tire
|
|
625
634
|
|
626
635
|
end
|
627
636
|
|
637
|
+
context "with index prefix" do
|
638
|
+
class ::ModelWithoutPrefix
|
639
|
+
extend ActiveModel::Naming
|
640
|
+
extend ActiveModel::Callbacks
|
641
|
+
|
642
|
+
include Tire::Model::Search
|
643
|
+
include Tire::Model::Callbacks
|
644
|
+
end
|
645
|
+
class ::ModelWithPrefix
|
646
|
+
extend ActiveModel::Naming
|
647
|
+
extend ActiveModel::Callbacks
|
648
|
+
|
649
|
+
include Tire::Model::Search
|
650
|
+
include Tire::Model::Callbacks
|
651
|
+
|
652
|
+
tire.index_prefix 'custom_prefix'
|
653
|
+
end
|
654
|
+
|
655
|
+
class ::OtherModelWithPrefix
|
656
|
+
extend ActiveModel::Naming
|
657
|
+
extend ActiveModel::Callbacks
|
658
|
+
|
659
|
+
include Tire::Model::Search
|
660
|
+
include Tire::Model::Callbacks
|
661
|
+
|
662
|
+
index_prefix 'other_custom_prefix'
|
663
|
+
end
|
664
|
+
|
665
|
+
teardown do
|
666
|
+
# FIXME: Depends on the interface itself
|
667
|
+
Model::Search.index_prefix nil
|
668
|
+
end
|
669
|
+
|
670
|
+
should "return nil by default" do
|
671
|
+
assert_nil Model::Search.index_prefix
|
672
|
+
end
|
673
|
+
|
674
|
+
should "allow to set and retrieve the value" do
|
675
|
+
assert_nothing_raised { Model::Search.index_prefix 'app_environment' }
|
676
|
+
assert_equal 'app_environment', Model::Search.index_prefix
|
677
|
+
end
|
678
|
+
|
679
|
+
should "allow to reset the value" do
|
680
|
+
Model::Search.index_prefix 'prefix'
|
681
|
+
Model::Search.index_prefix nil
|
682
|
+
assert_nil Model::Search.index_prefix
|
683
|
+
end
|
684
|
+
|
685
|
+
should "not add any prefix by default" do
|
686
|
+
assert_equal 'model_without_prefixes', ModelWithoutPrefix.index_name
|
687
|
+
end
|
688
|
+
|
689
|
+
should "add general and custom prefixes to model index names" do
|
690
|
+
Model::Search.index_prefix 'general_prefix'
|
691
|
+
assert_equal 'general_prefix_model_without_prefixes', ModelWithoutPrefix.index_name
|
692
|
+
assert_equal 'custom_prefix_model_with_prefixes', ModelWithPrefix.index_name
|
693
|
+
assert_equal 'other_custom_prefix_other_model_with_prefixes', OtherModelWithPrefix.index_name
|
694
|
+
end
|
695
|
+
|
696
|
+
end
|
697
|
+
|
628
698
|
end
|
629
699
|
|
630
700
|
context "Results::Item" do
|
@@ -50,6 +50,13 @@ module Tire
|
|
50
50
|
assert_equal 2, collection.options[:page]
|
51
51
|
end
|
52
52
|
|
53
|
+
should "be will_paginate compatible" do
|
54
|
+
collection = Results::Collection.new(@default_response)
|
55
|
+
%w(total_pages offset current_page per_page total_entries).each do |method|
|
56
|
+
assert_respond_to collection, method
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
53
60
|
context "wrapping results" do
|
54
61
|
|
55
62
|
setup do
|