es_client 0.1.0
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.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +8 -0
- data/Guardfile +48 -0
- data/LICENSE.txt +22 -0
- data/README.md +99 -0
- data/ROADMAP.md +9 -0
- data/Rakefile +7 -0
- data/es_client.gemspec +29 -0
- data/lib/es_client.rb +45 -0
- data/lib/es_client/active_record/adapter.rb +81 -0
- data/lib/es_client/active_record/glue.rb +72 -0
- data/lib/es_client/active_record/shortcuts.rb +17 -0
- data/lib/es_client/client.rb +71 -0
- data/lib/es_client/index.rb +93 -0
- data/lib/es_client/logger.rb +57 -0
- data/lib/es_client/response.rb +24 -0
- data/lib/es_client/version.rb +3 -0
- data/spec/es_client/active_record/adapter_spec.rb +106 -0
- data/spec/es_client/active_record/glue_spec.rb +68 -0
- data/spec/es_client/active_record/shortcuts_spec.rb +13 -0
- data/spec/es_client/index_spec.rb +40 -0
- data/spec/es_client/logger_spec.rb +18 -0
- data/spec/es_client/responce_spec.rb +25 -0
- data/spec/es_client/transport_spec.rb +51 -0
- data/spec/es_client_spec.rb +40 -0
- data/spec/integration/es_client/index_spec.rb +156 -0
- data/spec/spec_helper.rb +113 -0
- metadata +182 -0
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe EsClient::ActiveRecord::Shortcuts do
|
4
|
+
it '#es_doc' do
|
5
|
+
record = RspecUser.new.tap(&:save)
|
6
|
+
expect(record.es_doc).to eq record.es_client_document
|
7
|
+
end
|
8
|
+
|
9
|
+
it '#es_find' do
|
10
|
+
RspecUser.new(id: 1).save
|
11
|
+
expect(RspecUser.es_find(1)).to eq RspecUser.es_client.find(1)
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe EsClient::Index do
|
4
|
+
describe 'exists' do
|
5
|
+
it 'index not exists' do
|
6
|
+
index = EsClient::Index.new('test_index')
|
7
|
+
allow(EsClient.client).to receive(:head).with('/test_index').and_return(double(:response, success?: false))
|
8
|
+
expect(index.exists?).to eq false
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'index exists' do
|
12
|
+
index = EsClient::Index.new('test_index')
|
13
|
+
allow(EsClient.client).to receive(:head).with('/test_index').and_return(double(:response, success?: true))
|
14
|
+
expect(index.exists?).to eq true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'create' do
|
19
|
+
it 'create index' do
|
20
|
+
index = EsClient::Index.new('test_index')
|
21
|
+
allow(EsClient.client).to receive(:post).with('/test_index', {}).and_return(double(:response, success?: true))
|
22
|
+
expect(index.create.success?).to eq true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'delete' do
|
27
|
+
it 'create index' do
|
28
|
+
index = EsClient::Index.new('test_index')
|
29
|
+
allow(EsClient.client).to receive(:delete).with('/test_index').and_return(double(:response, success?: true))
|
30
|
+
expect(index.delete.success?).to eq true
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'recreate index' do
|
35
|
+
index = EsClient::Index.new('test_index')
|
36
|
+
expect(index).to receive(:delete)
|
37
|
+
expect(index).to receive(:create)
|
38
|
+
index.recreate
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe EsClient::Logger do
|
4
|
+
it 'log request' do
|
5
|
+
Excon.stub({}, {body: '{"took": 10}'})
|
6
|
+
transport = EsClient::Client.new('http://example.com', {})
|
7
|
+
expect(EsClient.logger).to receive(:debug).with(Regexp.new(Regexp.escape('[200](10 msec) curl')))
|
8
|
+
transport.get('/example', mock: true)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'log exception' do
|
12
|
+
transport = EsClient::Client.new('http://example.com', {})
|
13
|
+
allow(transport.http).to receive(:request) { raise Excon::Errors::SocketError.new(StandardError.new) }
|
14
|
+
allow(transport).to receive(:reconnect!)
|
15
|
+
expect(EsClient.logger).to receive(:error).with(/SocketError.*?curl/m)
|
16
|
+
expect { transport.get('/example',) }.to raise_error
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe EsClient::Response do
|
4
|
+
describe '#success?' do
|
5
|
+
it 'return true on success code' do
|
6
|
+
expect(EsClient::Response.new('', 200).success?).to be_truthy
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'return false on failure code' do
|
10
|
+
expect(EsClient::Response.new('', 500).success?).to be_falsey
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#failure?' do
|
15
|
+
it 'return true on failure code' do
|
16
|
+
expect(EsClient::Response.new('', 500).failure?).to be_truthy
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#decoded' do
|
21
|
+
it 'return decoded json' do
|
22
|
+
expect(EsClient::Response.new('{"key": "value"}', 200).decoded).to eq('key' => 'value')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe EsClient::Client do
|
4
|
+
describe 'request' do
|
5
|
+
it 'initialize excon' do
|
6
|
+
expect(Excon).to receive(:new).with('http://example.com', {persistent: true}).and_return(double(:http).as_null_object)
|
7
|
+
EsClient::Client.new('http://example.com', {persistent: true}).get('/example')
|
8
|
+
end
|
9
|
+
|
10
|
+
context 'success' do
|
11
|
+
before do
|
12
|
+
Excon.stub({}, {})
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'make request' do
|
16
|
+
transport = EsClient::Client.new('http://example.com', {})
|
17
|
+
expect(transport.http).to receive(:request).with(hash_including(method: :options)).and_return(double(:response).as_null_object)
|
18
|
+
transport.request(method: :options, path: '/example', mock: true)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'make get request' do
|
22
|
+
transport = EsClient::Client.new('http://example.com', {})
|
23
|
+
expect(transport.http).to receive(:request).with(hash_including(method: :get)).and_return(double(:response).as_null_object)
|
24
|
+
transport.get('/example', mock: true)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'make post request' do
|
28
|
+
transport = EsClient::Client.new('http://example.com', {})
|
29
|
+
expect(transport.http).to receive(:request).with(hash_including(method: :post)).and_return(double(:response).as_null_object)
|
30
|
+
transport.post('/example', mock: true)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'failure' do
|
35
|
+
it 'reconnect on failed request' do
|
36
|
+
transport = EsClient::Client.new('http://example.com', {})
|
37
|
+
allow(transport.http).to receive(:request) { raise Excon::Errors::SocketError.new(StandardError.new) }
|
38
|
+
expect(transport).to receive(:reconnect!)
|
39
|
+
expect { transport.get('/example', mock: true) }.to raise_error
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'retry failed request' do
|
43
|
+
transport = EsClient::Client.new('http://example.com', {})
|
44
|
+
allow(transport.http).to receive(:request) { raise Excon::Errors::SocketError.new(StandardError.new) }
|
45
|
+
allow(transport).to receive(:reconnect!)
|
46
|
+
expect(transport.http).to receive(:request).twice
|
47
|
+
expect { transport.get('/example', mock: true) }.to raise_error
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe EsClient do
|
4
|
+
it 'has a version number' do
|
5
|
+
expect(EsClient::VERSION).not_to be nil
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'has http connection' do
|
9
|
+
expect(EsClient.client).to be_instance_of(::EsClient::Client)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'http connection persistent by default' do
|
13
|
+
expect(EsClient.client.http.data[:persistent]).to eq true
|
14
|
+
end
|
15
|
+
|
16
|
+
describe 'index_prefix' do
|
17
|
+
after do
|
18
|
+
EsClient.index_prefix = nil
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'set index name prefix' do
|
22
|
+
EsClient.index_prefix = 'prefix'
|
23
|
+
expect(EsClient::Index.new('test').name).to eq 'prefix_test'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#with_log_level' do
|
28
|
+
it 'execute block with integer log level' do
|
29
|
+
EsClient.with_log_level 2 do
|
30
|
+
expect(EsClient.logger.level).to eq 2
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'execute block with symbol log level' do
|
35
|
+
EsClient.with_log_level :error do
|
36
|
+
expect(EsClient.logger.level).to eq 3
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe EsClient::Index do
|
4
|
+
describe 'exists' do
|
5
|
+
it 'index not exists' do
|
6
|
+
index = EsClient::Index.new('test_index')
|
7
|
+
index.delete
|
8
|
+
expect(index.exists?).to eq false
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'index not exists' do
|
12
|
+
index = EsClient::Index.new('test_index')
|
13
|
+
index.create
|
14
|
+
expect(index.exists?).to eq true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'create' do
|
19
|
+
it 'create index' do
|
20
|
+
index = EsClient::Index.new('test_index')
|
21
|
+
index.delete
|
22
|
+
expect(index.create.success?).to eq true
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'create index with mapping and settings' do
|
26
|
+
index = EsClient::Index.new('test_index', mappings: {product: {properties: {sku: {type: 'string'}}}}, settings: {number_of_shards: 1})
|
27
|
+
index.delete
|
28
|
+
expect(index.create.success?).to eq true
|
29
|
+
expect(index.get_mapping).to eq({'product' => {'properties' => {'sku' => {'type' => 'string'}}}})
|
30
|
+
expect(index.get_settings['index']['number_of_shards']).to eq '1'
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'create index error' do
|
34
|
+
index = EsClient::Index.new('test_index')
|
35
|
+
index.create
|
36
|
+
expect(index.create.success?).to eq false
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe 'delete' do
|
41
|
+
it 'delete index' do
|
42
|
+
index = EsClient::Index.new('test_index')
|
43
|
+
index.create
|
44
|
+
expect(index.delete.success?).to eq true
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'delete index error' do
|
48
|
+
index = EsClient::Index.new('test_index')
|
49
|
+
index.delete
|
50
|
+
expect(index.delete.success?).to eq false
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe 'mapping' do
|
55
|
+
it 'update mapping' do
|
56
|
+
index = EsClient::Index.new('test_index')
|
57
|
+
index.recreate
|
58
|
+
expect(index.put_mapping('product', {properties: {sku: {type: 'string'}}}).success?).to eq true
|
59
|
+
expect(index.get_mapping).to eq({'product' => {'properties' => {'sku' => {'type' => 'string'}}}})
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe 'settings' do
|
64
|
+
it 'update settings' do
|
65
|
+
index = EsClient::Index.new('test_index')
|
66
|
+
index.recreate
|
67
|
+
expect(index.put_settings({refresh_interval: '2s'}).success?).to eq true
|
68
|
+
expect(index.get_settings['index']['refresh_interval']).to eq '2s'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe 'save document' do
|
73
|
+
it 'save document' do
|
74
|
+
index = EsClient::Index.new('test_index')
|
75
|
+
index.recreate
|
76
|
+
expect(index.save_document('test', nil, {}).success?).to eq true
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe 'update document' do
|
81
|
+
it 'update document' do
|
82
|
+
index = EsClient::Index.new('test_index')
|
83
|
+
index.recreate
|
84
|
+
index.save_document('test', 1, {id: 1, name: 'test', description: 'text'})
|
85
|
+
index.update_document('test', 1, {name: 'test1'})
|
86
|
+
expect(index.find('test', 1)['name']).to eq 'test1'
|
87
|
+
expect(index.find('test', 1)['description']).to eq 'text'
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe 'destroy document' do
|
92
|
+
it 'destroy document' do
|
93
|
+
index = EsClient::Index.new('test_index')
|
94
|
+
index.recreate
|
95
|
+
index.save_document('test', 1, {id: 1, name: 'test'})
|
96
|
+
expect(index.destroy_document('test', 1).success?).to eq true
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe 'find' do
|
101
|
+
it 'find document' do
|
102
|
+
index = EsClient::Index.new('test_index')
|
103
|
+
index.recreate
|
104
|
+
index.save_document('test', 1, {id: 1, name: 'test'})
|
105
|
+
expect(index.find('test', 1)['name']).to eq 'test'
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe 'bulk' do
|
110
|
+
it 'perform bulk indexing' do
|
111
|
+
index = EsClient::Index.new('test_index')
|
112
|
+
index.recreate
|
113
|
+
index.bulk(:index, 'test', [{id: 1, name: 'test'}])
|
114
|
+
expect(index.find('test', 1)['name']).to eq 'test'
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'perform bulk update' do
|
118
|
+
index = EsClient::Index.new('test_index')
|
119
|
+
index.recreate
|
120
|
+
index.save_document('test', 1, {id: 1, name: 'test'})
|
121
|
+
index.bulk(:update, 'test', [{id: 1, name: 'updated name'}])
|
122
|
+
expect(index.find('test', 1)['name']).to eq 'updated name'
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'perform bulk update with options' do
|
126
|
+
index = EsClient::Index.new('test_index')
|
127
|
+
index.recreate
|
128
|
+
index.bulk(:update, 'test', [{id: 1, name: 'updated name', bulk_options: {doc_as_upsert: true}}])
|
129
|
+
expect(index.find('test', 1)['name']).to eq 'updated name'
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'perform bulk delete' do
|
133
|
+
index = EsClient::Index.new('test_index')
|
134
|
+
index.recreate
|
135
|
+
index.save_document('test', 1, {id: 1, name: 'test'})
|
136
|
+
index.bulk(:delete, 'test', [{id: 1}])
|
137
|
+
expect(index.find('test', 1)).to be_nil
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'refresh index' do
|
142
|
+
index = EsClient::Index.new('test_index')
|
143
|
+
index.recreate
|
144
|
+
expect(index.refresh.success?).to eq true
|
145
|
+
end
|
146
|
+
|
147
|
+
describe 'search' do
|
148
|
+
it 'perform query' do
|
149
|
+
index = EsClient::Index.new('test_index')
|
150
|
+
index.recreate
|
151
|
+
index.save_document('test', 1, {id: 1, name: 'test'})
|
152
|
+
index.refresh
|
153
|
+
expect(index.search({query: {ids: {values: [1]}}}, type: 'test').decoded['hits']['hits'].length).to eq 1
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
require 'es_client'
|
3
|
+
require 'byebug'
|
4
|
+
require 'active_model'
|
5
|
+
require 'ruby-progressbar'
|
6
|
+
|
7
|
+
RSpec.configure do |c|
|
8
|
+
c.order = :rand
|
9
|
+
end
|
10
|
+
|
11
|
+
EsClient.setup do |config|
|
12
|
+
config.log_path = File.expand_path('../../log/elasticsearch.log', __FILE__)
|
13
|
+
config.host = 'http://localhost:9201'
|
14
|
+
end
|
15
|
+
|
16
|
+
class RspecActiveRecordBase
|
17
|
+
include ActiveModel::AttributeMethods
|
18
|
+
include ActiveModel::Serialization
|
19
|
+
include ActiveModel::Serializers::JSON
|
20
|
+
include ActiveModel::Naming
|
21
|
+
|
22
|
+
extend ActiveModel::Callbacks
|
23
|
+
define_model_callbacks :save, :destroy
|
24
|
+
|
25
|
+
attr_reader :attributes
|
26
|
+
|
27
|
+
def initialize(attributes = {})
|
28
|
+
@attributes = attributes
|
29
|
+
end
|
30
|
+
|
31
|
+
def id
|
32
|
+
@attributes[:id]
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_indexed_json
|
36
|
+
@attributes.to_json
|
37
|
+
end
|
38
|
+
|
39
|
+
def method_missing(id, *args, &block)
|
40
|
+
attributes[id.to_sym] || attributes[id.to_s] || super
|
41
|
+
end
|
42
|
+
|
43
|
+
def new_record?
|
44
|
+
false
|
45
|
+
end
|
46
|
+
|
47
|
+
def persisted?
|
48
|
+
!new_record?
|
49
|
+
end
|
50
|
+
|
51
|
+
def save
|
52
|
+
run_callbacks(:save) {}
|
53
|
+
end
|
54
|
+
|
55
|
+
def destroy
|
56
|
+
run_callbacks(:destroy) { @destroyed = true }
|
57
|
+
end
|
58
|
+
|
59
|
+
def destroyed?
|
60
|
+
!!@destroyed
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.find_in_batches(options={})
|
64
|
+
i = 0
|
65
|
+
2.times do
|
66
|
+
yield [new(id: i += 1), new(id: i += 1)]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.count
|
71
|
+
4
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class RspecUser < RspecActiveRecordBase
|
76
|
+
include ::EsClient::ActiveRecord::Glue
|
77
|
+
include ::EsClient::ActiveRecord::Shortcuts
|
78
|
+
|
79
|
+
def self.setup_index
|
80
|
+
es_client.index.recreate
|
81
|
+
populate
|
82
|
+
es_client.index.refresh
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.test_data
|
86
|
+
[
|
87
|
+
{
|
88
|
+
id: 1,
|
89
|
+
name: 'alex',
|
90
|
+
created_at: 3.day.ago
|
91
|
+
},
|
92
|
+
{
|
93
|
+
id: 2,
|
94
|
+
name: 'bob',
|
95
|
+
created_at: 2.day.ago
|
96
|
+
},
|
97
|
+
{
|
98
|
+
id: 3,
|
99
|
+
name: 'john',
|
100
|
+
created_at: 1.day.ago
|
101
|
+
}
|
102
|
+
]
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.populate
|
106
|
+
test_data.each do |attrs|
|
107
|
+
u = new(attrs)
|
108
|
+
u.id = attrs[:id]
|
109
|
+
u.save
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|