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/lib/tire/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Tire
2
- VERSION = "0.3.2"
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 { Tire.index('active_record_articles').delete }
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', '2'], :include => 'comments'),
94
- ActiveRecordArticle.search('"Test 1" OR "Test 2"', :load => { :include => 'comments' }).results
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
- teardown { Tire.index('articles-test-ids').delete }
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
- assert_raise(RestClient::ResourceNotFound) do
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
@@ -0,0 +1,7 @@
1
+ # Example ActiveModel class with custom document type
2
+
3
+ require File.expand_path('../active_model_article', __FILE__)
4
+
5
+ class ActiveModelArticleWithCustomDocumentType < ActiveModelArticle
6
+ document_type 'my_custom_type'
7
+ 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
- stub(:body => body, :code => code)
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
@@ -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).raises(RestClient::ResourceNotFound)
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).raises(RestClient::BadRequest)
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).raises(RestClient::RequestFailed).at_least(2)
316
+ Configuration.client.expects(:post).returns(mock_response('Server error', 503)).at_least(2)
319
317
 
320
- assert_raise(RestClient::RequestFailed) do
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 { |url, json| url == "#{Configuration.url}/_bulk" }
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