elasticsearch-transport 7.1.0 → 7.2.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.
@@ -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