ssickles-tire 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. data/.gitignore +14 -0
  2. data/.travis.yml +13 -0
  3. data/Gemfile +4 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.markdown +760 -0
  6. data/Rakefile +78 -0
  7. data/examples/rails-application-template.rb +249 -0
  8. data/examples/tire-dsl.rb +876 -0
  9. data/lib/tire.rb +52 -0
  10. data/lib/tire/alias.rb +296 -0
  11. data/lib/tire/configuration.rb +30 -0
  12. data/lib/tire/dsl.rb +43 -0
  13. data/lib/tire/http/client.rb +62 -0
  14. data/lib/tire/http/clients/curb.rb +61 -0
  15. data/lib/tire/http/response.rb +27 -0
  16. data/lib/tire/index.rb +345 -0
  17. data/lib/tire/logger.rb +60 -0
  18. data/lib/tire/model/callbacks.rb +40 -0
  19. data/lib/tire/model/import.rb +26 -0
  20. data/lib/tire/model/indexing.rb +128 -0
  21. data/lib/tire/model/naming.rb +100 -0
  22. data/lib/tire/model/percolate.rb +99 -0
  23. data/lib/tire/model/persistence.rb +72 -0
  24. data/lib/tire/model/persistence/attributes.rb +143 -0
  25. data/lib/tire/model/persistence/finders.rb +66 -0
  26. data/lib/tire/model/persistence/storage.rb +71 -0
  27. data/lib/tire/model/search.rb +305 -0
  28. data/lib/tire/results/collection.rb +114 -0
  29. data/lib/tire/results/item.rb +83 -0
  30. data/lib/tire/results/pagination.rb +54 -0
  31. data/lib/tire/rubyext/hash.rb +8 -0
  32. data/lib/tire/rubyext/ruby_1_8.rb +54 -0
  33. data/lib/tire/rubyext/symbol.rb +11 -0
  34. data/lib/tire/search.rb +160 -0
  35. data/lib/tire/search/facet.rb +70 -0
  36. data/lib/tire/search/filter.rb +28 -0
  37. data/lib/tire/search/highlight.rb +37 -0
  38. data/lib/tire/search/query.rb +151 -0
  39. data/lib/tire/search/scan.rb +114 -0
  40. data/lib/tire/search/sort.rb +25 -0
  41. data/lib/tire/tasks.rb +135 -0
  42. data/lib/tire/utils.rb +17 -0
  43. data/lib/tire/version.rb +22 -0
  44. data/test/fixtures/articles/1.json +1 -0
  45. data/test/fixtures/articles/2.json +1 -0
  46. data/test/fixtures/articles/3.json +1 -0
  47. data/test/fixtures/articles/4.json +1 -0
  48. data/test/fixtures/articles/5.json +1 -0
  49. data/test/integration/active_model_indexing_test.rb +51 -0
  50. data/test/integration/active_model_searchable_test.rb +114 -0
  51. data/test/integration/active_record_searchable_test.rb +446 -0
  52. data/test/integration/boolean_queries_test.rb +43 -0
  53. data/test/integration/count_test.rb +34 -0
  54. data/test/integration/custom_score_queries_test.rb +88 -0
  55. data/test/integration/dsl_search_test.rb +22 -0
  56. data/test/integration/explanation_test.rb +44 -0
  57. data/test/integration/facets_test.rb +232 -0
  58. data/test/integration/filtered_queries_test.rb +66 -0
  59. data/test/integration/filters_test.rb +63 -0
  60. data/test/integration/fuzzy_queries_test.rb +20 -0
  61. data/test/integration/highlight_test.rb +64 -0
  62. data/test/integration/index_aliases_test.rb +122 -0
  63. data/test/integration/index_mapping_test.rb +43 -0
  64. data/test/integration/index_store_test.rb +96 -0
  65. data/test/integration/mongoid_searchable_test.rb +309 -0
  66. data/test/integration/percolator_test.rb +111 -0
  67. data/test/integration/persistent_model_test.rb +117 -0
  68. data/test/integration/query_return_version_test.rb +70 -0
  69. data/test/integration/query_string_test.rb +52 -0
  70. data/test/integration/range_queries_test.rb +36 -0
  71. data/test/integration/reindex_test.rb +46 -0
  72. data/test/integration/results_test.rb +39 -0
  73. data/test/integration/scan_test.rb +56 -0
  74. data/test/integration/sort_test.rb +36 -0
  75. data/test/integration/text_query_test.rb +39 -0
  76. data/test/models/active_model_article.rb +31 -0
  77. data/test/models/active_model_article_with_callbacks.rb +49 -0
  78. data/test/models/active_model_article_with_custom_document_type.rb +7 -0
  79. data/test/models/active_model_article_with_custom_index_name.rb +7 -0
  80. data/test/models/active_record_models.rb +122 -0
  81. data/test/models/article.rb +15 -0
  82. data/test/models/mongoid_models.rb +97 -0
  83. data/test/models/persistent_article.rb +11 -0
  84. data/test/models/persistent_article_in_namespace.rb +12 -0
  85. data/test/models/persistent_article_with_casting.rb +28 -0
  86. data/test/models/persistent_article_with_defaults.rb +11 -0
  87. data/test/models/persistent_articles_with_custom_index_name.rb +10 -0
  88. data/test/models/supermodel_article.rb +17 -0
  89. data/test/models/validated_model.rb +11 -0
  90. data/test/test_helper.rb +88 -0
  91. data/test/unit/active_model_lint_test.rb +17 -0
  92. data/test/unit/configuration_test.rb +74 -0
  93. data/test/unit/http_client_test.rb +76 -0
  94. data/test/unit/http_response_test.rb +49 -0
  95. data/test/unit/index_alias_test.rb +275 -0
  96. data/test/unit/index_test.rb +841 -0
  97. data/test/unit/logger_test.rb +125 -0
  98. data/test/unit/model_callbacks_test.rb +116 -0
  99. data/test/unit/model_import_test.rb +71 -0
  100. data/test/unit/model_persistence_test.rb +516 -0
  101. data/test/unit/model_search_test.rb +899 -0
  102. data/test/unit/results_collection_test.rb +281 -0
  103. data/test/unit/results_item_test.rb +155 -0
  104. data/test/unit/rubyext_test.rb +60 -0
  105. data/test/unit/search_facet_test.rb +153 -0
  106. data/test/unit/search_filter_test.rb +42 -0
  107. data/test/unit/search_highlight_test.rb +46 -0
  108. data/test/unit/search_query_test.rb +242 -0
  109. data/test/unit/search_scan_test.rb +113 -0
  110. data/test/unit/search_sort_test.rb +50 -0
  111. data/test/unit/search_test.rb +455 -0
  112. data/test/unit/tire_test.rb +126 -0
  113. data/tire.gemspec +85 -0
  114. metadata +506 -0
@@ -0,0 +1,17 @@
1
+ require 'test_helper'
2
+
3
+ module Tire
4
+ module Model
5
+
6
+ class ActiveModelLintTest < Test::Unit::TestCase
7
+
8
+ include ActiveModel::Lint::Tests
9
+
10
+ def setup
11
+ @model = PersistentArticle.new :title => 'Test'
12
+ end
13
+
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,74 @@
1
+ require 'test_helper'
2
+
3
+ module Tire
4
+
5
+ class ConfigurationTest < Test::Unit::TestCase
6
+
7
+ def teardown
8
+ Tire::Configuration.reset
9
+ ENV['ELASTICSEARCH_URL'] = nil
10
+ end
11
+
12
+ context "Configuration" do
13
+ setup do
14
+ Configuration.instance_variable_set(:@url, nil)
15
+ Configuration.instance_variable_set(:@client, nil)
16
+ end
17
+
18
+ teardown do
19
+ Configuration.reset
20
+ end
21
+
22
+ should "return default URL" do
23
+ assert_equal 'http://localhost:9200', Configuration.url
24
+ end
25
+
26
+ should "use environment variable, if present" do
27
+ ENV['ELASTICSEARCH_URL'] = 'http://es.example.com'
28
+ assert_equal 'http://es.example.com', Configuration.url
29
+ end
30
+
31
+ should "allow setting and retrieving the URL" do
32
+ assert_nothing_raised { Configuration.url 'http://example.com' }
33
+ assert_equal 'http://example.com', Configuration.url
34
+ end
35
+
36
+ should "strip trailing slash from the URL" do
37
+ assert_nothing_raised { Configuration.url 'http://slash.com:9200/' }
38
+ assert_equal 'http://slash.com:9200', Configuration.url
39
+ end
40
+
41
+ should "return default client" do
42
+ assert_equal HTTP::Client::RestClient, Configuration.client
43
+ end
44
+
45
+ should "return nil as logger by default" do
46
+ assert_nil Configuration.logger
47
+ end
48
+
49
+ should "return set and return logger" do
50
+ Configuration.logger STDERR
51
+ assert_not_nil Configuration.logger
52
+ assert_instance_of Tire::Logger, Configuration.logger
53
+ end
54
+
55
+ should "allow to reset the configuration for specific property" do
56
+ Configuration.url 'http://example.com'
57
+ assert_equal 'http://example.com', Configuration.url
58
+ Configuration.reset :url
59
+ assert_equal 'http://localhost:9200', Configuration.url
60
+ end
61
+
62
+ should "allow to reset the configuration for all properties" do
63
+ Configuration.url 'http://example.com'
64
+ Configuration.wrapper Hash
65
+ assert_equal 'http://example.com', Configuration.url
66
+ Configuration.reset
67
+ assert_equal 'http://localhost:9200', Configuration.url
68
+ assert_equal HTTP::Client::RestClient, Configuration.client
69
+ end
70
+ end
71
+
72
+ end
73
+
74
+ end
@@ -0,0 +1,76 @@
1
+ require 'test_helper'
2
+ require 'tire/http/clients/curb'
3
+
4
+ module Tire
5
+ module HTTP
6
+
7
+ class ClientTest < Test::Unit::TestCase
8
+
9
+ context "RestClient" do
10
+
11
+ should "be default" do
12
+ assert_equal Client::RestClient, Configuration.client
13
+ end
14
+
15
+ should "respond to HTTP methods" do
16
+ assert_respond_to Client::RestClient, :get
17
+ assert_respond_to Client::RestClient, :post
18
+ assert_respond_to Client::RestClient, :put
19
+ assert_respond_to Client::RestClient, :delete
20
+ assert_respond_to Client::RestClient, :head
21
+ end
22
+
23
+ should "not rescue generic exceptions" do
24
+ Client::RestClient.expects(:get).raises(RuntimeError, "Something bad happened in YOUR code")
25
+
26
+ assert_raise(RuntimeError) do
27
+ Client::RestClient.get 'http://example.com'
28
+ end
29
+ end
30
+
31
+ should "not rescue ServerBrokeConnection errors" do
32
+ Client::RestClient.expects(:get).raises(RestClient::ServerBrokeConnection)
33
+
34
+ assert_raise(RestClient::ServerBrokeConnection) do
35
+ Client::RestClient.get 'http://example.com'
36
+ end
37
+ end
38
+
39
+ should "not rescue RequestTimeout errors" do
40
+ Client::RestClient.expects(:get).raises(RestClient::RequestTimeout)
41
+
42
+ assert_raise(RestClient::RequestTimeout) do
43
+ Client::RestClient.get 'http://example.com'
44
+ end
45
+ end
46
+
47
+ end
48
+
49
+ context "Curb" do
50
+ setup do
51
+ Configuration.client Client::Curb
52
+ end
53
+
54
+ teardown do
55
+ Configuration.client Client::RestClient
56
+ end
57
+
58
+ should "use POST method if request body passed" do
59
+ ::Curl::Easy.any_instance.expects(:http_post)
60
+
61
+ response = Configuration.client.get "http://localhost:3000", '{ "query_string" : { "query" : "apple" }}'
62
+ end
63
+
64
+ should "use GET method if request body is nil" do
65
+ ::Curl::Easy.any_instance.expects(:http_get)
66
+
67
+ response = Configuration.client.get "http://localhost:9200/articles/article/1"
68
+ end
69
+
70
+ end
71
+
72
+
73
+ end
74
+ end
75
+
76
+ end
@@ -0,0 +1,49 @@
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
+ should "return string representation" do
41
+ assert_equal "200 : Hello", Response.new('Hello', 200).to_s
42
+ end
43
+
44
+ end
45
+
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,275 @@
1
+ require 'test_helper'
2
+
3
+ module Tire
4
+
5
+ class IndexAliasTest < Test::Unit::TestCase
6
+
7
+ context "Index Alias" do
8
+ teardown { Configuration.reset }
9
+
10
+ context "initialization" do
11
+
12
+ should "have a name and defaults" do
13
+ @alias = Alias.new :name => 'dummy'
14
+ assert_equal 'dummy', @alias.name
15
+ assert @alias.indices.empty?
16
+ end
17
+
18
+ should "have indices" do
19
+ @alias = Alias.new :indices => ['index_A', 'index_B']
20
+ assert_equal ['index_A', 'index_B'], @alias.indices.to_a
21
+ end
22
+
23
+ should "have single index" do
24
+ @alias = Alias.new :index => 'index_A'
25
+ assert_equal ['index_A'], @alias.indices.to_a
26
+ assert_equal ['index_A'], @alias.index.to_a
27
+ end
28
+
29
+ should "have properties" do
30
+ @alias = Alias.new :routing => '1'
31
+ assert_equal '1', @alias.routing
32
+ end
33
+
34
+ should "allow to add indices in a block" do
35
+ @alias = Alias.new do
36
+ index 'index_A'
37
+ index 'index_B'
38
+ end
39
+ assert_equal ['index_A', 'index_B'], @alias.indices.to_a
40
+
41
+ @alias = Alias.new do |a|
42
+ a.index 'index_A'
43
+ a.index 'index_B'
44
+ end
45
+ assert_equal ['index_A', 'index_B'], @alias.indices.to_a
46
+ end
47
+
48
+ should "allow to define filter with DSL" do
49
+ @alias = Alias.new do
50
+ filter :terms, :username => 'mary'
51
+ end
52
+
53
+ assert_equal( { :terms => { :username => 'mary' } }, @alias.filter )
54
+ end
55
+
56
+ should "allow chaining" do
57
+ @alias = Alias.new.name('my_alias').index('index_1').index('index_2').routing('1')
58
+
59
+ assert_equal 'my_alias', @alias.name
60
+ assert_equal ['index_1', 'index_2'], @alias.indices.to_a
61
+ assert_equal '1', @alias.routing
62
+ end
63
+
64
+ should "be converted to JSON" do
65
+ @alias = Alias.new :name => 'index_anne',
66
+ :indices => ['index_2012_04', 'index_2012_03', 'index_2012_02'],
67
+ :routing => 1,
68
+ :filter => { :terms => { :user => 'anne' } }
69
+ # p @alias.to_json
70
+ result = MultiJson.decode @alias.to_json
71
+
72
+ assert_equal 3, result['actions'].size
73
+ assert_equal 'index_2012_04', result['actions'][0]['add']['index']
74
+ end
75
+
76
+ should "be converted to string" do
77
+ @alias = Alias.new :name => 'my_alias'
78
+ assert_equal 'my_alias', @alias.to_s
79
+ end
80
+
81
+ end
82
+
83
+ context "updating" do
84
+ setup do
85
+ Configuration.client.expects(:get).
86
+ returns( mock_response( %q|{"index_A":{"aliases":{}},"index_B":{"aliases":{"alias_john":{"filter":{"term":{"user":"john"}}},"alias_martha":{"filter":{"term":{"user":"martha"}}}}},"mongoid_articles":{"aliases":{}},"index_C":{"aliases":{"alias_martha":{"filter":{"term":{"user":"martha"}}}}}}|), 200 ).at_least_once
87
+ end
88
+
89
+ should "add indices to alias" do
90
+ Configuration.client.expects(:post).with do |url, json|
91
+ # puts json
92
+ MultiJson.decode(json)['actions'].any? do |a|
93
+ a['add']['index'] == 'index_A' &&
94
+ a['add']['alias'] == 'alias_martha'
95
+ end
96
+ end.returns(mock_response('{}'), 200)
97
+
98
+ a = Alias.find('alias_martha')
99
+ a.indices.push 'index_A'
100
+ a.save
101
+ end
102
+
103
+ should "remove indices from alias" do
104
+ Configuration.client.expects(:post).with do |url, json|
105
+ # puts json
106
+ MultiJson.decode(json)['actions'].any? do |a|
107
+ a['remove'] &&
108
+ a['remove']['index'] == 'index_A' &&
109
+ a['remove']['alias'] == 'alias_martha'
110
+ end
111
+ end.returns(mock_response('{}'), 200)
112
+
113
+ a = Alias.find('alias_martha')
114
+ a.indices.delete 'index_A'
115
+ a.save
116
+ end
117
+
118
+ should "change alias configuration" do
119
+ Configuration.client.expects(:post).with do |url, json|
120
+ # puts json
121
+ MultiJson.decode(json)['actions'].all? { |a| a['add']['routing'] == 'martha' }
122
+ end.returns(mock_response('{}'), 200)
123
+
124
+ a = Alias.find('alias_martha')
125
+ a.routing('martha')
126
+ a.save
127
+ end
128
+
129
+ end
130
+
131
+ context "saving" do
132
+
133
+ should "send data to ElasticSearch" do
134
+ Configuration.client.expects(:post).with do |url, json|
135
+ url == "#{Configuration.url}/_aliases" &&
136
+ json =~ /"index":"index_2012_05"/ &&
137
+ json =~ /"alias":"index_current"/
138
+ end.returns(mock_response('{}'), 200)
139
+
140
+ @alias = Alias.new :name => 'index_current', :index => 'index_2012_05'
141
+ @alias.save
142
+ end
143
+
144
+ should "log request" do
145
+ Tire.configure { logger '/dev/null' }
146
+
147
+ Configuration.client.expects(:post)
148
+ Configuration.logger.expects(:log_request)
149
+ Alias.new( :name => 'index_current', :index => 'index_2012_05' ).save
150
+ end
151
+
152
+ end
153
+
154
+ context "finding" do
155
+ setup do
156
+ Configuration.client.expects(:get).with do |url, json|
157
+ url == "#{Configuration.url}/_aliases"
158
+ end.returns( mock_response( %q|{"index_A":{"aliases":{}},"index_B":{"aliases":{"alias_john":{"filter":{"term":{"user":"john"}}},"alias_martha":{"filter":{"term":{"user":"martha"}}}}},"index_C":{"aliases":{"alias_martha":{"filter":{"term":{"user":"martha"}}}}}}|), 200 )
159
+ end
160
+
161
+ should "find all aliases" do
162
+ aliases = Alias.all
163
+ # p aliases
164
+ assert_equal 2, aliases.size
165
+ assert_equal ['index_B', 'index_C'], aliases.select { |a| a.name == 'alias_martha'}.first.indices.to_a.sort
166
+ end
167
+
168
+ should "find aliases for a specific index" do
169
+ Configuration.client.unstub(:get)
170
+ Configuration.client.expects(:get).with do |url, json|
171
+ url == "#{Configuration.url}/index_C/_aliases"
172
+ end.returns( mock_response( %q|{"index_C":{"aliases":{"alias_martha":{"filter":{"term":{"user":"martha"}}}}}}|), 200 )
173
+
174
+ aliases = Alias.all('index_C')
175
+ # p aliases
176
+ assert_equal 1, aliases.size
177
+ assert_equal ['index_C'], aliases.last.indices.to_a
178
+ end
179
+
180
+ should "find an alias" do
181
+ a = Alias.find('alias_martha')
182
+ assert_instance_of Alias, a
183
+ assert_equal ['index_B', 'index_C'], a.indices.to_a.sort
184
+ end
185
+
186
+ should "find an alias and configure it with a block" do
187
+ a = Alias.find('alias_martha') do |a|
188
+ a.indices.delete 'index_A'
189
+ a.indices.add 'index_D'
190
+ end
191
+
192
+ assert_equal ['index_B', 'index_C', 'index_D'], a.indices.to_a.sort
193
+ end
194
+
195
+ end
196
+
197
+ context "creating" do
198
+ setup do
199
+ Configuration.client.expects(:post).with do |url, json|
200
+ url == "#{Configuration.url}/_aliases" &&
201
+ json =~ /"index":"index_2012_05"/ &&
202
+ json =~ /"alias":"index_current"/
203
+ end.returns(mock_response('{}'), 200)
204
+ end
205
+
206
+ should "create the alias" do
207
+ Alias.create :name => 'index_current', :index => 'index_2012_05'
208
+ end
209
+
210
+ should "create the alias with a block" do
211
+ Alias.create :name => 'index_current' do
212
+ index 'index_2012_05'
213
+ end
214
+ end
215
+
216
+ end
217
+
218
+ end
219
+
220
+ context "IndexCollection" do
221
+
222
+ should "be intialized with an array or arguments list" do
223
+ c1 = Alias::IndexCollection.new ['1', '2', '3']
224
+ c2 = Alias::IndexCollection.new '1', '2', '3'
225
+ assert_equal c1.to_a, c2.to_a
226
+ end
227
+
228
+ should "be iterable" do
229
+ c = Alias::IndexCollection.new '1', '2', '3'
230
+ assert_respond_to c, :each
231
+ assert_respond_to c, :size
232
+ assert_equal [1, 2, 3], c.map(&:to_i)
233
+ end
234
+
235
+ should "allow adding values" do
236
+ c = Alias::IndexCollection.new '1', '2'
237
+ c.add '3'
238
+ assert_equal 3, c.size
239
+ assert_equal ['1', '2', '3'], c.add_indices
240
+ assert_equal [], c.remove_indices
241
+ end
242
+
243
+ should "allow removing values" do
244
+ c = Alias::IndexCollection.new '1', '2'
245
+ c.remove '1'
246
+ assert_equal 1, c.size
247
+ assert_equal ['2'], c.add_indices
248
+ assert_equal ['1'], c.remove_indices
249
+ end
250
+
251
+ should "clear everything" do
252
+ c = Alias::IndexCollection.new '1', '2'
253
+ c.clear
254
+ assert_equal 0, c.size
255
+ assert_equal [], c.add_indices
256
+ assert_equal ['1', '2'], c.remove_indices
257
+ end
258
+
259
+ should "respond to empty" do
260
+ c = Alias::IndexCollection.new
261
+ assert c.empty?, "#{c.inspect} should be empty"
262
+ end
263
+
264
+ should "remove values with a block" do
265
+ c = Alias::IndexCollection.new '1', '2', '3'
266
+
267
+ c.delete_if { |a| a.to_i > 1 }
268
+ assert_equal 1, c.size
269
+ assert_equal ['1'], c.add_indices
270
+ assert_equal ['2', '3'], c.remove_indices
271
+ end
272
+
273
+ end
274
+ end
275
+ end