elasticsearch-transport 7.1.0 → 7.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,174 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ require 'spec_helper'
19
+
20
+ describe Elasticsearch::Transport::Transport::Connections::Selector do
21
+
22
+ before do
23
+ class BackupStrategySelector
24
+ include Elasticsearch::Transport::Transport::Connections::Selector::Base
25
+
26
+ def select(options={})
27
+ connections.reject do |c|
28
+ c.host[:attributes] && c.host[:attributes][:backup]
29
+ end.sample
30
+ end
31
+ end
32
+ end
33
+
34
+ after do
35
+ Object.send(:remove_const, :BackupStrategySelector)
36
+ end
37
+
38
+ let(:backup_strategy_selector) do
39
+ BackupStrategySelector.new
40
+ end
41
+
42
+ describe 'the Random selector' do
43
+
44
+ let(:connections) do
45
+ [1, 2]
46
+ end
47
+
48
+ let(:selector) do
49
+ described_class::Random.new(connections: connections)
50
+ end
51
+
52
+ it 'is initialized with connections' do
53
+ expect(selector.connections).to eq(connections)
54
+ end
55
+
56
+ describe '#select' do
57
+
58
+ let(:connections) do
59
+ (0..19).to_a
60
+ end
61
+
62
+ it 'returns a connection' do
63
+ expect(selector.select).to be_a(Integer)
64
+ end
65
+
66
+ context 'when multiple threads are used' do
67
+
68
+ it 'allows threads to select connections in parallel' do
69
+ expect(10.times.collect do
70
+ threads = []
71
+ 20.times do
72
+ threads << Thread.new do
73
+ selector.select
74
+ end
75
+ end
76
+ threads.map { |t| t.join }
77
+ selector.select
78
+ end).to all(be_a(Integer))
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ describe 'the RoundRobin selector' do
85
+
86
+ let(:connections) do
87
+ ['A', 'B', 'C']
88
+ end
89
+
90
+ let(:selector) do
91
+ described_class::RoundRobin.new(connections: connections)
92
+ end
93
+
94
+ it 'is initialized with connections' do
95
+ expect(selector.connections).to eq(connections)
96
+ end
97
+
98
+ describe '#select' do
99
+
100
+ it 'rotates over the connections' do
101
+ expect(selector.select).to eq('A')
102
+ expect(selector.select).to eq('B')
103
+ expect(selector.select).to eq('C')
104
+ expect(selector.select).to eq('A')
105
+ end
106
+
107
+ context 'when multiple threads are used' do
108
+
109
+ let(:connections) do
110
+ (0..19).to_a
111
+ end
112
+
113
+ it 'returns a connection' do
114
+ expect(selector.select).to be_a(Integer)
115
+ end
116
+
117
+ it 'allows threads to select connections in parallel' do
118
+ expect(10.times.collect do
119
+ threads = []
120
+ 20.times do
121
+ threads << Thread.new do
122
+ selector.select
123
+ end
124
+ end
125
+ threads.map { |t| t.join }
126
+ selector.select
127
+ end).to eq((0..9).to_a)
128
+ end
129
+ end
130
+ end
131
+ end
132
+
133
+ describe 'a custom selector' do
134
+
135
+ let(:connections) do
136
+ [ double(host: { hostname: 'host1' }),
137
+ double(host: { hostname: 'host2', attributes: { backup: true } }) ]
138
+ end
139
+
140
+ let(:selector) do
141
+ BackupStrategySelector.new(connections: connections)
142
+ end
143
+
144
+ it 'is initialized with connections' do
145
+ expect(selector.connections).to eq(connections)
146
+ end
147
+
148
+ describe '#select' do
149
+
150
+ it 'applies the custom strategy' do
151
+ 10.times { expect(selector.select.host[:hostname]).to eq('host1') }
152
+ end
153
+ end
154
+ end
155
+
156
+ context 'when the Base module is included in a class' do
157
+
158
+ before do
159
+ class ExampleSelector
160
+ include Elasticsearch::Transport::Transport::Connections::Selector::Base
161
+ end
162
+ end
163
+
164
+ after do
165
+ Object.send(:remove_const, :ExampleSelector)
166
+ end
167
+
168
+ it 'requires the #select method to be redefined' do
169
+ expect {
170
+ ExampleSelector.new.select
171
+ }.to raise_exception(NoMethodError)
172
+ end
173
+ end
174
+ end
@@ -33,18 +33,161 @@ describe Elasticsearch::Transport::Client do
33
33
  expect(client.transport).to be_a(Elasticsearch::Transport::Client::DEFAULT_TRANSPORT_CLASS)
34
34
  end
35
35
 
36
- it 'uses Faraday as the default transport' do
36
+ it 'preserves the Faraday default user agent header' do
37
37
  expect(client.transport.connections.first.connection.headers['User-Agent']).to match(/Faraday/)
38
38
  end
39
39
 
40
+ it 'identifies the Ruby client in the User-Agent header' do
41
+ expect(client.transport.connections.first.connection.headers['User-Agent']).to match(/elasticsearch-ruby\/#{Elasticsearch::Transport::VERSION}/)
42
+ end
43
+
44
+ it 'identifies the Ruby version in the User-Agent header' do
45
+ expect(client.transport.connections.first.connection.headers['User-Agent']).to match(/#{RUBY_VERSION}/)
46
+ end
47
+
48
+ it 'identifies the host_os in the User-Agent header' do
49
+ expect(client.transport.connections.first.connection.headers['User-Agent']).to match(/#{RbConfig::CONFIG['host_os'].split('_').first[/[a-z]+/i].downcase}/)
50
+ end
51
+
52
+ it 'identifies the target_cpu in the User-Agent header' do
53
+ expect(client.transport.connections.first.connection.headers['User-Agent']).to match(/#{RbConfig::CONFIG['target_cpu']}/)
54
+ end
55
+
40
56
  it 'sets the \'Content-Type\' header to \'application/json\' by default' do
41
- expect(client.transport.options[:transport_options][:headers]['Content-Type']).to eq('application/json')
57
+ expect(client.transport.connections.first.connection.headers['Content-Type']).to eq('application/json')
42
58
  end
43
59
 
44
60
  it 'uses localhost by default' do
45
61
  expect(client.transport.hosts[0][:host]).to eq('localhost')
46
62
  end
47
63
 
64
+ context 'when a User-Agent header is specified as client option' do
65
+
66
+ let(:client) do
67
+ described_class.new(transport_options: { headers: { 'User-Agent' => 'testing' } })
68
+ end
69
+
70
+ it 'sets the specified User-Agent header' do
71
+ expect(client.transport.connections.first.connection.headers['User-Agent']).to eq('testing')
72
+ end
73
+ end
74
+
75
+ context 'when a user-agent header is specified as client option in lower-case' do
76
+
77
+ let(:client) do
78
+ described_class.new(transport_options: { headers: { 'user-agent' => 'testing' } })
79
+ end
80
+
81
+ it 'sets the specified User-Agent header' do
82
+ expect(client.transport.connections.first.connection.headers['User-Agent']).to eq('testing')
83
+ end
84
+ end
85
+
86
+ context 'when a Content-Type header is specified as client option' do
87
+
88
+ let(:client) do
89
+ described_class.new(transport_options: { headers: { 'Content-Type' => 'testing' } })
90
+ end
91
+
92
+ it 'sets the specified Content-Type header' do
93
+ expect(client.transport.connections.first.connection.headers['Content-Type']).to eq('testing')
94
+ end
95
+ end
96
+
97
+ context 'when a content-type header is specified as client option in lower-case' do
98
+
99
+ let(:client) do
100
+ described_class.new(transport_options: { headers: { 'content-type' => 'testing' } })
101
+ end
102
+
103
+ it 'sets the specified Content-Type header' do
104
+ expect(client.transport.connections.first.connection.headers['Content-Type']).to eq('testing')
105
+ end
106
+ end
107
+
108
+ context 'when the Curb transport class is used', unless: jruby? do
109
+
110
+ let(:client) do
111
+ described_class.new(transport_class: Elasticsearch::Transport::Transport::HTTP::Curb)
112
+ end
113
+
114
+ it 'preserves the Curb default user agent header' do
115
+ expect(client.transport.connections.first.connection.headers['User-Agent']).to match(/Curb/)
116
+ end
117
+
118
+ it 'identifies the Ruby client in the User-Agent header' do
119
+ expect(client.transport.connections.first.connection.headers['User-Agent']).to match(/elasticsearch-ruby\/#{Elasticsearch::Transport::VERSION}/)
120
+ end
121
+
122
+ it 'identifies the Ruby version in the User-Agent header' do
123
+ expect(client.transport.connections.first.connection.headers['User-Agent']).to match(/#{RUBY_VERSION}/)
124
+ end
125
+
126
+ it 'identifies the host_os in the User-Agent header' do
127
+ expect(client.transport.connections.first.connection.headers['User-Agent']).to match(/#{RbConfig::CONFIG['host_os'].split('_').first[/[a-z]+/i].downcase}/)
128
+ end
129
+
130
+ it 'identifies the target_cpu in the User-Agent header' do
131
+ expect(client.transport.connections.first.connection.headers['User-Agent']).to match(/#{RbConfig::CONFIG['target_cpu']}/)
132
+ end
133
+
134
+ it 'sets the \'Content-Type\' header to \'application/json\' by default' do
135
+ expect(client.transport.connections.first.connection.headers['Content-Type']).to eq('application/json')
136
+ end
137
+
138
+ it 'uses localhost by default' do
139
+ expect(client.transport.hosts[0][:host]).to eq('localhost')
140
+ end
141
+
142
+ context 'when a User-Agent header is specified as a client option' do
143
+
144
+ let(:client) do
145
+ described_class.new(transport_class: Elasticsearch::Transport::Transport::HTTP::Curb,
146
+ transport_options: { headers: { 'User-Agent' => 'testing' } })
147
+ end
148
+
149
+ it 'sets the specified User-Agent header' do
150
+ expect(client.transport.connections.first.connection.headers['User-Agent']).to eq('testing')
151
+ end
152
+ end
153
+
154
+ context 'when a user-agent header is specified as a client option as lower-case' do
155
+
156
+ let(:client) do
157
+ described_class.new(transport_class: Elasticsearch::Transport::Transport::HTTP::Curb,
158
+ transport_options: { headers: { 'user-agent' => 'testing' } })
159
+ end
160
+
161
+ it 'sets the specified User-Agent header' do
162
+ expect(client.transport.connections.first.connection.headers['User-Agent']).to eq('testing')
163
+ end
164
+ end
165
+
166
+ context 'when a Content-Type header is specified as client option' do
167
+
168
+ let(:client) do
169
+ described_class.new(transport_class: Elasticsearch::Transport::Transport::HTTP::Curb,
170
+ transport_options: { headers: { 'Content-Type' => 'testing' } })
171
+ end
172
+
173
+ it 'sets the specified Content-Type header' do
174
+ expect(client.transport.connections.first.connection.headers['Content-Type']).to eq('testing')
175
+ end
176
+ end
177
+
178
+ context 'when a content-type header is specified as client option in lower-case' do
179
+
180
+ let(:client) do
181
+ described_class.new(transport_class: Elasticsearch::Transport::Transport::HTTP::Curb,
182
+ transport_options: { headers: { 'content-type' => 'testing' } })
183
+ end
184
+
185
+ it 'sets the specified Content-Type header' do
186
+ expect(client.transport.connections.first.connection.headers['Content-Type']).to eq('testing')
187
+ end
188
+ end
189
+ end
190
+
48
191
  describe 'adapter' do
49
192
 
50
193
  context 'when no adapter is specified' do
@@ -127,6 +270,48 @@ describe Elasticsearch::Transport::Client do
127
270
  end
128
271
  end
129
272
 
273
+ context 'when cloud credentials are provided' do
274
+
275
+ let(:client) do
276
+ described_class.new(cloud_id: 'name:bG9jYWxob3N0JGFiY2QkZWZnaA==', user: 'elastic', password: 'changeme')
277
+ end
278
+
279
+ let(:hosts) do
280
+ client.transport.hosts
281
+ end
282
+
283
+ it 'extracts the cloud credentials' do
284
+ expect(hosts[0][:host]).to eq('abcd.localhost')
285
+ expect(hosts[0][:protocol]).to eq('https')
286
+ expect(hosts[0][:user]).to eq('elastic')
287
+ expect(hosts[0][:password]).to eq('changeme')
288
+ expect(hosts[0][:port]).to eq(9243)
289
+ end
290
+
291
+ it 'creates the correct full url' do
292
+ expect(client.transport.__full_url(client.transport.hosts[0])).to eq('https://elastic:changeme@abcd.localhost:9243')
293
+ end
294
+
295
+ context 'when a port is specified' do
296
+
297
+ let(:client) do
298
+ described_class.new(cloud_id: 'name:bG9jYWxob3N0JGFiY2QkZWZnaA==', user: 'elastic', password: 'changeme', port: 9200 )
299
+ end
300
+
301
+ it 'sets the specified port along with the cloud credentials' do
302
+ expect(hosts[0][:host]).to eq('abcd.localhost')
303
+ expect(hosts[0][:protocol]).to eq('https')
304
+ expect(hosts[0][:user]).to eq('elastic')
305
+ expect(hosts[0][:password]).to eq('changeme')
306
+ expect(hosts[0][:port]).to eq(9200)
307
+ end
308
+
309
+ it 'creates the correct full url' do
310
+ expect(client.transport.__full_url(client.transport.hosts[0])).to eq('https://elastic:changeme@abcd.localhost:9200')
311
+ end
312
+ end
313
+ end
314
+
130
315
  shared_examples_for 'a client that extracts hosts' do
131
316
 
132
317
  context 'when the hosts are a String' do
@@ -1053,6 +1238,141 @@ describe Elasticsearch::Transport::Client do
1053
1238
  }.to raise_exception(Elasticsearch::Transport::Transport::Errors::BadRequest)
1054
1239
  end
1055
1240
  end
1241
+
1242
+ context 'when the \'compression\' option is set to true' do
1243
+
1244
+ context 'when using Faraday as the transport' do
1245
+
1246
+ context 'when using the Net::HTTP adapter' do
1247
+
1248
+ let(:client) do
1249
+ described_class.new(hosts: ELASTICSEARCH_HOSTS, compression: true, adapter: :net_http)
1250
+ end
1251
+
1252
+ it 'compresses the request and decompresses the response' do
1253
+ expect(client.perform_request('GET', '/').body).to be_a(Hash)
1254
+ end
1255
+
1256
+ it 'sets the Accept-Encoding header' do
1257
+ expect(client.transport.connections[0].connection.headers['Accept-Encoding'])
1258
+ end
1259
+
1260
+ it 'preserves the other headers' do
1261
+ expect(client.transport.connections[0].connection.headers['User-Agent'])
1262
+ end
1263
+ end
1264
+
1265
+ context 'when using the HTTPClient adapter' do
1266
+
1267
+ let(:client) do
1268
+ described_class.new(hosts: ELASTICSEARCH_HOSTS, compression: true, adapter: :httpclient)
1269
+ end
1270
+
1271
+ it 'compresses the request and decompresses the response' do
1272
+ expect(client.perform_request('GET', '/').body).to be_a(Hash)
1273
+ end
1274
+
1275
+ it 'sets the Accept-Encoding header' do
1276
+ expect(client.transport.connections[0].connection.headers['Accept-Encoding'])
1277
+ end
1278
+
1279
+ it 'preserves the other headers' do
1280
+ expect(client.transport.connections[0].connection.headers['User-Agent'])
1281
+ end
1282
+ end
1283
+
1284
+ context 'when using the Patron adapter', unless: jruby? do
1285
+
1286
+ let(:client) do
1287
+ described_class.new(hosts: ELASTICSEARCH_HOSTS, compression: true, adapter: :patron)
1288
+ end
1289
+
1290
+ it 'compresses the request and decompresses the response' do
1291
+ expect(client.perform_request('GET', '/').body).to be_a(Hash)
1292
+ end
1293
+
1294
+ it 'sets the Accept-Encoding header' do
1295
+ expect(client.transport.connections[0].connection.headers['Accept-Encoding'])
1296
+ end
1297
+
1298
+ it 'preserves the other headers' do
1299
+ expect(client.transport.connections[0].connection.headers['User-Agent'])
1300
+ end
1301
+ end
1302
+
1303
+ context 'when using the Net::HTTP::Persistent adapter' do
1304
+
1305
+ let(:client) do
1306
+ described_class.new(hosts: ELASTICSEARCH_HOSTS, compression: true, adapter: :net_http_persistent)
1307
+ end
1308
+
1309
+ it 'compresses the request and decompresses the response' do
1310
+ expect(client.perform_request('GET', '/').body).to be_a(Hash)
1311
+ end
1312
+
1313
+ it 'sets the Accept-Encoding header' do
1314
+ expect(client.transport.connections[0].connection.headers['Accept-Encoding'])
1315
+ end
1316
+
1317
+ it 'preserves the other headers' do
1318
+ expect(client.transport.connections[0].connection.headers['User-Agent'])
1319
+ end
1320
+ end
1321
+
1322
+ context 'when using the Typhoeus adapter' do
1323
+
1324
+ let(:client) do
1325
+ described_class.new(hosts: ELASTICSEARCH_HOSTS, compression: true, adapter: :typhoeus)
1326
+ end
1327
+
1328
+ it 'compresses the request and decompresses the response' do
1329
+ expect(client.perform_request('GET', '/').body).to be_a(Hash)
1330
+ end
1331
+
1332
+ it 'sets the Accept-Encoding header' do
1333
+ expect(client.transport.connections[0].connection.headers['Accept-Encoding'])
1334
+ end
1335
+
1336
+ it 'preserves the other headers' do
1337
+ expect(client.transport.connections[0].connection.headers['User-Agent'])
1338
+ end
1339
+ end
1340
+ end
1341
+ end
1342
+
1343
+ context 'when using Curb as the transport', unless: jruby? do
1344
+
1345
+ let(:client) do
1346
+ described_class.new(hosts: ELASTICSEARCH_HOSTS,
1347
+ compression: true,
1348
+ transport_class: Elasticsearch::Transport::Transport::HTTP::Curb)
1349
+ end
1350
+
1351
+ it 'compresses the request and decompresses the response' do
1352
+ expect(client.perform_request('GET', '/').body).to be_a(Hash)
1353
+ end
1354
+
1355
+ it 'sets the Accept-Encoding header' do
1356
+ expect(client.transport.connections[0].connection.headers['Accept-Encoding'])
1357
+ end
1358
+
1359
+ it 'preserves the other headers' do
1360
+ expect(client.transport.connections[0].connection.headers['User-Agent'])
1361
+ end
1362
+ end
1363
+
1364
+ context 'when using Manticore as the transport', if: jruby? do
1365
+
1366
+ let(:client) do
1367
+ described_class.new(hosts: ELASTICSEARCH_HOSTS,
1368
+ compression: true,
1369
+ transport_class: Elasticsearch::Transport::Transport::HTTP::Manticore)
1370
+ end
1371
+
1372
+ it 'compresses the request and decompresses the response' do
1373
+ expect(client.perform_request('GET', '/').body).to be_a(Hash)
1374
+ end
1375
+ end
1056
1376
  end
1057
1377
 
1058
1378
  describe '#perform_request' do
@@ -1064,7 +1384,7 @@ describe Elasticsearch::Transport::Client do
1064
1384
  client.perform_request('DELETE', 'myindex') rescue
1065
1385
  client.perform_request('PUT', 'myindex', {}, { settings: { number_of_shards: 2, number_of_replicas: 0 } })
1066
1386
  client.perform_request('PUT', 'myindex/mydoc/1', { routing: 'XYZ', timeout: '1s' }, { foo: 'bar' })
1067
- client.perform_request('GET', '_cluster/health?wait_for_status=green', {})
1387
+ client.perform_request('GET', '_cluster/health?wait_for_status=green&timeout=2s', {})
1068
1388
  end
1069
1389
 
1070
1390
  let(:response) do