opensearch-transport 1.0.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
- checksums.yaml.gz.sig +3 -0
- data/.gitignore +17 -0
- data/Gemfile +47 -0
- data/LICENSE +202 -0
- data/README.md +551 -0
- data/Rakefile +89 -0
- data/lib/opensearch/transport/client.rb +354 -0
- data/lib/opensearch/transport/redacted.rb +84 -0
- data/lib/opensearch/transport/transport/base.rb +450 -0
- data/lib/opensearch/transport/transport/connections/collection.rb +136 -0
- data/lib/opensearch/transport/transport/connections/connection.rb +169 -0
- data/lib/opensearch/transport/transport/connections/selector.rb +101 -0
- data/lib/opensearch/transport/transport/errors.rb +100 -0
- data/lib/opensearch/transport/transport/http/curb.rb +140 -0
- data/lib/opensearch/transport/transport/http/faraday.rb +101 -0
- data/lib/opensearch/transport/transport/http/manticore.rb +188 -0
- data/lib/opensearch/transport/transport/loggable.rb +94 -0
- data/lib/opensearch/transport/transport/response.rb +46 -0
- data/lib/opensearch/transport/transport/serializer/multi_json.rb +62 -0
- data/lib/opensearch/transport/transport/sniffer.rb +111 -0
- data/lib/opensearch/transport/version.rb +31 -0
- data/lib/opensearch/transport.rb +46 -0
- data/lib/opensearch-transport.rb +27 -0
- data/opensearch-transport.gemspec +92 -0
- data/spec/opensearch/connections/collection_spec.rb +275 -0
- data/spec/opensearch/connections/selector_spec.rb +183 -0
- data/spec/opensearch/transport/base_spec.rb +313 -0
- data/spec/opensearch/transport/client_spec.rb +1818 -0
- data/spec/opensearch/transport/sniffer_spec.rb +284 -0
- data/spec/spec_helper.rb +99 -0
- data/test/integration/transport_test.rb +108 -0
- data/test/profile/client_benchmark_test.rb +141 -0
- data/test/test_helper.rb +97 -0
- data/test/unit/connection_test.rb +145 -0
- data/test/unit/response_test.rb +41 -0
- data/test/unit/serializer_test.rb +42 -0
- data/test/unit/transport_base_test.rb +673 -0
- data/test/unit/transport_curb_test.rb +143 -0
- data/test/unit/transport_faraday_test.rb +237 -0
- data/test/unit/transport_manticore_test.rb +191 -0
- data.tar.gz.sig +1 -0
- metadata +456 -0
- metadata.gz.sig +1 -0
@@ -0,0 +1,1818 @@
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
2
|
+
#
|
3
|
+
# The OpenSearch Contributors require contributions made to
|
4
|
+
# this file be licensed under the Apache-2.0 license or a
|
5
|
+
# compatible open source license.
|
6
|
+
#
|
7
|
+
# Modifications Copyright OpenSearch Contributors. See
|
8
|
+
# GitHub history for details.
|
9
|
+
#
|
10
|
+
# Licensed to Elasticsearch B.V. under one or more contributor
|
11
|
+
# license agreements. See the NOTICE file distributed with
|
12
|
+
# this work for additional information regarding copyright
|
13
|
+
# ownership. Elasticsearch B.V. licenses this file to you under
|
14
|
+
# the Apache License, Version 2.0 (the "License"); you may
|
15
|
+
# not use this file except in compliance with the License.
|
16
|
+
# You may obtain a copy of the License at
|
17
|
+
#
|
18
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
19
|
+
#
|
20
|
+
# Unless required by applicable law or agreed to in writing,
|
21
|
+
# software distributed under the License is distributed on an
|
22
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
23
|
+
# KIND, either express or implied. See the License for the
|
24
|
+
# specific language governing permissions and limitations
|
25
|
+
# under the License.
|
26
|
+
|
27
|
+
require 'spec_helper'
|
28
|
+
require 'opensearch'
|
29
|
+
|
30
|
+
describe OpenSearch::Transport::Client do
|
31
|
+
let(:client) do
|
32
|
+
described_class.new.tap do |_client|
|
33
|
+
allow(_client).to receive(:__build_connections)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'has a default transport' do
|
38
|
+
expect(client.transport).to be_a(OpenSearch::Transport::Client::DEFAULT_TRANSPORT_CLASS)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'preserves the Faraday default user agent header' do
|
42
|
+
expect(client.transport.connections.first.connection.headers['User-Agent']).to match(/Faraday/)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'identifies the Ruby client in the User-Agent header' do
|
46
|
+
expect(client.transport.connections.first.connection.headers['User-Agent']).to match(/opensearch-ruby\/#{OpenSearch::Transport::VERSION}/)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'identifies the Ruby version in the User-Agent header' do
|
50
|
+
expect(client.transport.connections.first.connection.headers['User-Agent']).to match(/#{RUBY_VERSION}/)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'identifies the host_os in the User-Agent header' do
|
54
|
+
expect(client.transport.connections.first.connection.headers['User-Agent']).to match(/#{RbConfig::CONFIG['host_os'].split('_').first[/[a-z]+/i].downcase}/)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'identifies the target_cpu in the User-Agent header' do
|
58
|
+
expect(client.transport.connections.first.connection.headers['User-Agent']).to match(/#{RbConfig::CONFIG['target_cpu']}/)
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'sets the \'Content-Type\' header to \'application/json\' by default' do
|
62
|
+
expect(client.transport.connections.first.connection.headers['Content-Type']).to eq('application/json')
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'uses localhost by default' do
|
66
|
+
expect(client.transport.hosts[0][:host]).to eq('localhost')
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'when a User-Agent header is specified as client option' do
|
70
|
+
let(:client) do
|
71
|
+
described_class.new(transport_options: { headers: { 'User-Agent' => 'testing' } })
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'sets the specified User-Agent header' do
|
75
|
+
expect(client.transport.connections.first.connection.headers['User-Agent']).to eq('testing')
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'when an encoded api_key is provided' do
|
80
|
+
let(:client) do
|
81
|
+
described_class.new(api_key: 'an_api_key')
|
82
|
+
end
|
83
|
+
let(:authorization_header) do
|
84
|
+
client.transport.connections.first.connection.headers['Authorization']
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'Adds the ApiKey header to the connection' do
|
88
|
+
expect(authorization_header).to eq('ApiKey an_api_key')
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'when an un-encoded api_key is provided' do
|
93
|
+
let(:client) do
|
94
|
+
described_class.new(api_key: { id: 'my_id', api_key: 'my_api_key' })
|
95
|
+
end
|
96
|
+
let(:authorization_header) do
|
97
|
+
client.transport.connections.first.connection.headers['Authorization']
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'Adds the ApiKey header to the connection' do
|
101
|
+
expect(authorization_header).to eq("ApiKey #{Base64.strict_encode64('my_id:my_api_key')}")
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context 'when basic auth and api_key are provided' do
|
106
|
+
let(:client) do
|
107
|
+
described_class.new(
|
108
|
+
api_key: { id: 'my_id', api_key: 'my_api_key' },
|
109
|
+
host: 'https://admin:admin@localhost:9200'
|
110
|
+
)
|
111
|
+
end
|
112
|
+
let(:authorization_header) do
|
113
|
+
client.transport.connections.first.connection.headers['Authorization']
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'removes basic auth credentials' do
|
117
|
+
expect(authorization_header).not_to match(/^Basic/)
|
118
|
+
expect(authorization_header).to match(/^ApiKey/)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
context 'when a user-agent header is specified as client option in lower-case' do
|
123
|
+
|
124
|
+
let(:client) do
|
125
|
+
described_class.new(transport_options: { headers: { 'user-agent' => 'testing' } })
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'sets the specified User-Agent header' do
|
129
|
+
expect(client.transport.connections.first.connection.headers['User-Agent']).to eq('testing')
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
context 'when a Content-Type header is specified as client option' do
|
134
|
+
|
135
|
+
let(:client) do
|
136
|
+
described_class.new(transport_options: { headers: { 'Content-Type' => 'testing' } })
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'sets the specified Content-Type header' do
|
140
|
+
expect(client.transport.connections.first.connection.headers['Content-Type']).to eq('testing')
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
context 'when a content-type header is specified as client option in lower-case' do
|
145
|
+
|
146
|
+
let(:client) do
|
147
|
+
described_class.new(transport_options: { headers: { 'content-type' => 'testing' } })
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'sets the specified Content-Type header' do
|
151
|
+
expect(client.transport.connections.first.connection.headers['Content-Type']).to eq('testing')
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
context 'when the Curb transport class is used', unless: jruby? do
|
156
|
+
|
157
|
+
let(:client) do
|
158
|
+
described_class.new(transport_class: OpenSearch::Transport::Transport::HTTP::Curb)
|
159
|
+
end
|
160
|
+
|
161
|
+
it 'preserves the Curb default user agent header' do
|
162
|
+
expect(client.transport.connections.first.connection.headers['User-Agent']).to match(/Curb/)
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'identifies the Ruby client in the User-Agent header' do
|
166
|
+
expect(client.transport.connections.first.connection.headers['User-Agent']).to match(/opensearch-ruby\/#{OpenSearch::Transport::VERSION}/)
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'identifies the Ruby version in the User-Agent header' do
|
170
|
+
expect(client.transport.connections.first.connection.headers['User-Agent']).to match(/#{RUBY_VERSION}/)
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'identifies the host_os in the User-Agent header' do
|
174
|
+
expect(client.transport.connections.first.connection.headers['User-Agent']).to match(/#{RbConfig::CONFIG['host_os'].split('_').first[/[a-z]+/i].downcase}/)
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'identifies the target_cpu in the User-Agent header' do
|
178
|
+
expect(client.transport.connections.first.connection.headers['User-Agent']).to match(/#{RbConfig::CONFIG['target_cpu']}/)
|
179
|
+
end
|
180
|
+
|
181
|
+
it 'sets the \'Content-Type\' header to \'application/json\' by default' do
|
182
|
+
expect(client.transport.connections.first.connection.headers['Content-Type']).to eq('application/json')
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'uses localhost by default' do
|
186
|
+
expect(client.transport.hosts[0][:host]).to eq('localhost')
|
187
|
+
end
|
188
|
+
|
189
|
+
context 'when a User-Agent header is specified as a client option' do
|
190
|
+
|
191
|
+
let(:client) do
|
192
|
+
described_class.new(transport_class: OpenSearch::Transport::Transport::HTTP::Curb,
|
193
|
+
transport_options: { headers: { 'User-Agent' => 'testing' } })
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'sets the specified User-Agent header' do
|
197
|
+
expect(client.transport.connections.first.connection.headers['User-Agent']).to eq('testing')
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
context 'when a user-agent header is specified as a client option as lower-case' do
|
202
|
+
|
203
|
+
let(:client) do
|
204
|
+
described_class.new(transport_class: OpenSearch::Transport::Transport::HTTP::Curb,
|
205
|
+
transport_options: { headers: { 'user-agent' => 'testing' } })
|
206
|
+
end
|
207
|
+
|
208
|
+
it 'sets the specified User-Agent header' do
|
209
|
+
expect(client.transport.connections.first.connection.headers['User-Agent']).to eq('testing')
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
context 'when a Content-Type header is specified as client option' do
|
214
|
+
|
215
|
+
let(:client) do
|
216
|
+
described_class.new(transport_class: OpenSearch::Transport::Transport::HTTP::Curb,
|
217
|
+
transport_options: { headers: { 'Content-Type' => 'testing' } })
|
218
|
+
end
|
219
|
+
|
220
|
+
it 'sets the specified Content-Type header' do
|
221
|
+
expect(client.transport.connections.first.connection.headers['Content-Type']).to eq('testing')
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
context 'when a content-type header is specified as client option in lower-case' do
|
226
|
+
|
227
|
+
let(:client) do
|
228
|
+
described_class.new(transport_class: OpenSearch::Transport::Transport::HTTP::Curb,
|
229
|
+
transport_options: { headers: { 'content-type' => 'testing' } })
|
230
|
+
end
|
231
|
+
|
232
|
+
it 'sets the specified Content-Type header' do
|
233
|
+
expect(client.transport.connections.first.connection.headers['Content-Type']).to eq('testing')
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
describe 'adapter' do
|
239
|
+
context 'when no adapter is specified' do
|
240
|
+
fork do
|
241
|
+
let(:client) { described_class.new }
|
242
|
+
let(:adapter) { client.transport.connections.all.first.connection.builder.adapter }
|
243
|
+
|
244
|
+
it 'uses Faraday NetHttp' do
|
245
|
+
expect(adapter).to eq Faraday::Adapter::NetHttp
|
246
|
+
end
|
247
|
+
end unless jruby?
|
248
|
+
end
|
249
|
+
|
250
|
+
context 'when the adapter is patron' do
|
251
|
+
let(:adapter) do
|
252
|
+
client.transport.connections.all.first.connection.builder.adapter
|
253
|
+
end
|
254
|
+
|
255
|
+
let(:client) do
|
256
|
+
described_class.new(adapter: :patron)
|
257
|
+
end
|
258
|
+
|
259
|
+
it 'uses Faraday with the adapter' do
|
260
|
+
expect(adapter).to eq Faraday::Adapter::Patron
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
context 'when the adapter is typhoeus' do
|
265
|
+
let(:adapter) do
|
266
|
+
client.transport.connections.all.first.connection.builder.adapter
|
267
|
+
end
|
268
|
+
|
269
|
+
let(:client) do
|
270
|
+
described_class.new(adapter: :typhoeus)
|
271
|
+
end
|
272
|
+
|
273
|
+
it 'uses Faraday with the adapter' do
|
274
|
+
expect(adapter).to eq Faraday::Adapter::Typhoeus
|
275
|
+
end
|
276
|
+
end unless jruby?
|
277
|
+
|
278
|
+
context 'when the adapter is specified as a string key' do
|
279
|
+
let(:adapter) do
|
280
|
+
client.transport.connections.all.first.connection.builder.adapter
|
281
|
+
end
|
282
|
+
|
283
|
+
let(:client) do
|
284
|
+
described_class.new(adapter: :patron)
|
285
|
+
end
|
286
|
+
|
287
|
+
it 'uses Faraday with the adapter' do
|
288
|
+
expect(adapter).to eq Faraday::Adapter::Patron
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
context 'when the adapter can be detected', unless: jruby? do
|
293
|
+
|
294
|
+
around do |example|
|
295
|
+
require 'patron'; load 'patron.rb'
|
296
|
+
example.run
|
297
|
+
end
|
298
|
+
|
299
|
+
let(:adapter) do
|
300
|
+
client.transport.connections.all.first.connection.builder.adapter
|
301
|
+
end
|
302
|
+
|
303
|
+
it 'uses the detected adapter' do
|
304
|
+
expect(adapter).to eq Faraday::Adapter::Patron
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
context 'when the Faraday adapter is configured' do
|
309
|
+
|
310
|
+
let(:client) do
|
311
|
+
described_class.new do |faraday|
|
312
|
+
faraday.adapter :patron
|
313
|
+
faraday.response :logger
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
let(:adapter) do
|
318
|
+
client.transport.connections.all.first.connection.builder.adapter
|
319
|
+
end
|
320
|
+
|
321
|
+
let(:handlers) do
|
322
|
+
client.transport.connections.all.first.connection.builder.handlers
|
323
|
+
end
|
324
|
+
|
325
|
+
it 'sets the adapter' do
|
326
|
+
expect(adapter).to eq Faraday::Adapter::Patron
|
327
|
+
end
|
328
|
+
|
329
|
+
it 'sets the logger' do
|
330
|
+
expect(handlers).to include(Faraday::Response::Logger)
|
331
|
+
end
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
shared_examples_for 'a client that extracts hosts' do
|
336
|
+
|
337
|
+
context 'when the host is a String' do
|
338
|
+
|
339
|
+
context 'when there is a protocol specified' do
|
340
|
+
|
341
|
+
context 'when credentials are specified \'http://USERNAME:PASSWORD@myhost:8080\'' do
|
342
|
+
|
343
|
+
let(:host) do
|
344
|
+
'http://USERNAME:PASSWORD@myhost:8080'
|
345
|
+
end
|
346
|
+
|
347
|
+
it 'extracts the credentials' do
|
348
|
+
expect(hosts[0][:user]).to eq('USERNAME')
|
349
|
+
expect(hosts[0][:password]).to eq('PASSWORD')
|
350
|
+
end
|
351
|
+
|
352
|
+
it 'extracts the host' do
|
353
|
+
expect(hosts[0][:host]).to eq('myhost')
|
354
|
+
end
|
355
|
+
|
356
|
+
it 'extracts the port' do
|
357
|
+
expect(hosts[0][:port]).to be(8080)
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
context 'when there is a trailing slash \'http://myhost/\'' do
|
362
|
+
|
363
|
+
let(:host) do
|
364
|
+
'http://myhost/'
|
365
|
+
end
|
366
|
+
|
367
|
+
it 'extracts the host' do
|
368
|
+
expect(hosts[0][:host]).to eq('myhost')
|
369
|
+
expect(hosts[0][:scheme]).to eq('http')
|
370
|
+
expect(hosts[0][:path]).to eq('')
|
371
|
+
end
|
372
|
+
|
373
|
+
it 'extracts the scheme' do
|
374
|
+
expect(hosts[0][:scheme]).to eq('http')
|
375
|
+
end
|
376
|
+
|
377
|
+
it 'extracts the path' do
|
378
|
+
expect(hosts[0][:path]).to eq('')
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
context 'when there is a trailing slash with a path \'http://myhost/foo/bar/\'' do
|
383
|
+
|
384
|
+
let(:host) do
|
385
|
+
'http://myhost/foo/bar/'
|
386
|
+
end
|
387
|
+
|
388
|
+
it 'extracts the host' do
|
389
|
+
expect(hosts[0][:host]).to eq('myhost')
|
390
|
+
expect(hosts[0][:scheme]).to eq('http')
|
391
|
+
expect(hosts[0][:path]).to eq('/foo/bar')
|
392
|
+
end
|
393
|
+
end
|
394
|
+
|
395
|
+
context 'when the protocol is http' do
|
396
|
+
|
397
|
+
context 'when there is no port specified \'http://myhost\'' do
|
398
|
+
|
399
|
+
let(:host) do
|
400
|
+
'http://myhost'
|
401
|
+
end
|
402
|
+
|
403
|
+
it 'extracts the host' do
|
404
|
+
expect(hosts[0][:host]).to eq('myhost')
|
405
|
+
end
|
406
|
+
|
407
|
+
it 'extracts the protocol' do
|
408
|
+
expect(hosts[0][:protocol]).to eq('http')
|
409
|
+
end
|
410
|
+
|
411
|
+
it 'defaults to port 9200' do
|
412
|
+
expect(hosts[0][:port]).to be(9200)
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
context 'when there is a port specified \'http://myhost:7101\'' do
|
417
|
+
|
418
|
+
let(:host) do
|
419
|
+
'http://myhost:7101'
|
420
|
+
end
|
421
|
+
|
422
|
+
it 'extracts the host' do
|
423
|
+
expect(hosts[0][:host]).to eq('myhost')
|
424
|
+
end
|
425
|
+
|
426
|
+
it 'extracts the protocol' do
|
427
|
+
expect(hosts[0][:protocol]).to eq('http')
|
428
|
+
end
|
429
|
+
|
430
|
+
it 'extracts the port' do
|
431
|
+
expect(hosts[0][:port]).to be(7101)
|
432
|
+
end
|
433
|
+
|
434
|
+
context 'when there is a path specified \'http://myhost:7101/api\'' do
|
435
|
+
|
436
|
+
let(:host) do
|
437
|
+
'http://myhost:7101/api'
|
438
|
+
end
|
439
|
+
|
440
|
+
it 'sets the path' do
|
441
|
+
expect(hosts[0][:host]).to eq('myhost')
|
442
|
+
expect(hosts[0][:protocol]).to eq('http')
|
443
|
+
expect(hosts[0][:path]).to eq('/api')
|
444
|
+
expect(hosts[0][:port]).to be(7101)
|
445
|
+
end
|
446
|
+
|
447
|
+
it 'extracts the host' do
|
448
|
+
expect(hosts[0][:host]).to eq('myhost')
|
449
|
+
end
|
450
|
+
|
451
|
+
it 'extracts the protocol' do
|
452
|
+
expect(hosts[0][:protocol]).to eq('http')
|
453
|
+
end
|
454
|
+
|
455
|
+
it 'extracts the port' do
|
456
|
+
expect(hosts[0][:port]).to be(7101)
|
457
|
+
end
|
458
|
+
|
459
|
+
it 'extracts the path' do
|
460
|
+
expect(hosts[0][:path]).to eq('/api')
|
461
|
+
end
|
462
|
+
end
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
466
|
+
context 'when the protocol is https' do
|
467
|
+
|
468
|
+
context 'when there is no port specified \'https://myhost\'' do
|
469
|
+
|
470
|
+
let(:host) do
|
471
|
+
'https://myhost'
|
472
|
+
end
|
473
|
+
|
474
|
+
it 'extracts the host' do
|
475
|
+
expect(hosts[0][:host]).to eq('myhost')
|
476
|
+
end
|
477
|
+
|
478
|
+
it 'extracts the protocol' do
|
479
|
+
expect(hosts[0][:protocol]).to eq('https')
|
480
|
+
end
|
481
|
+
|
482
|
+
it 'defaults to port 443' do
|
483
|
+
expect(hosts[0][:port]).to be(443)
|
484
|
+
end
|
485
|
+
end
|
486
|
+
|
487
|
+
context 'when there is a port specified \'https://myhost:7101\'' do
|
488
|
+
|
489
|
+
let(:host) do
|
490
|
+
'https://myhost:7101'
|
491
|
+
end
|
492
|
+
|
493
|
+
it 'extracts the host' do
|
494
|
+
expect(hosts[0][:host]).to eq('myhost')
|
495
|
+
end
|
496
|
+
|
497
|
+
it 'extracts the protocol' do
|
498
|
+
expect(hosts[0][:protocol]).to eq('https')
|
499
|
+
end
|
500
|
+
|
501
|
+
it 'extracts the port' do
|
502
|
+
expect(hosts[0][:port]).to be(7101)
|
503
|
+
end
|
504
|
+
|
505
|
+
context 'when there is a path specified \'https://myhost:7101/api\'' do
|
506
|
+
|
507
|
+
let(:host) do
|
508
|
+
'https://myhost:7101/api'
|
509
|
+
end
|
510
|
+
|
511
|
+
it 'extracts the host' do
|
512
|
+
expect(hosts[0][:host]).to eq('myhost')
|
513
|
+
end
|
514
|
+
|
515
|
+
it 'extracts the protocol' do
|
516
|
+
expect(hosts[0][:protocol]).to eq('https')
|
517
|
+
end
|
518
|
+
|
519
|
+
it 'extracts the port' do
|
520
|
+
expect(hosts[0][:port]).to be(7101)
|
521
|
+
end
|
522
|
+
|
523
|
+
it 'extracts the path' do
|
524
|
+
expect(hosts[0][:path]).to eq('/api')
|
525
|
+
end
|
526
|
+
end
|
527
|
+
end
|
528
|
+
|
529
|
+
context 'when IPv6 format is used' do
|
530
|
+
|
531
|
+
around do |example|
|
532
|
+
original_setting = Faraday.ignore_env_proxy
|
533
|
+
Faraday.ignore_env_proxy = true
|
534
|
+
example.run
|
535
|
+
Faraday.ignore_env_proxy = original_setting
|
536
|
+
end
|
537
|
+
|
538
|
+
let(:host) do
|
539
|
+
'https://[2090:db8:85a3:9811::1f]:8080'
|
540
|
+
end
|
541
|
+
|
542
|
+
it 'extracts the host' do
|
543
|
+
expect(hosts[0][:host]).to eq('[2090:db8:85a3:9811::1f]')
|
544
|
+
end
|
545
|
+
|
546
|
+
it 'extracts the protocol' do
|
547
|
+
expect(hosts[0][:protocol]).to eq('https')
|
548
|
+
end
|
549
|
+
|
550
|
+
it 'extracts the port' do
|
551
|
+
expect(hosts[0][:port]).to be(8080)
|
552
|
+
end
|
553
|
+
|
554
|
+
it 'creates the correct full url' do
|
555
|
+
expect(client.transport.__full_url(client.transport.hosts[0])).to eq('https://[2090:db8:85a3:9811::1f]:8080')
|
556
|
+
end
|
557
|
+
end
|
558
|
+
end
|
559
|
+
end
|
560
|
+
|
561
|
+
context 'when no protocol is specified \'myhost\'' do
|
562
|
+
|
563
|
+
let(:host) do
|
564
|
+
'myhost'
|
565
|
+
end
|
566
|
+
|
567
|
+
it 'defaults to http' do
|
568
|
+
expect(hosts[0][:host]).to eq('myhost')
|
569
|
+
expect(hosts[0][:protocol]).to eq('http')
|
570
|
+
end
|
571
|
+
|
572
|
+
it 'uses port 9200' do
|
573
|
+
expect(hosts[0][:port]).to be(9200)
|
574
|
+
end
|
575
|
+
end
|
576
|
+
end
|
577
|
+
|
578
|
+
context 'when the host is a Hash' do
|
579
|
+
|
580
|
+
let(:host) do
|
581
|
+
{ :host => 'myhost', :scheme => 'https' }
|
582
|
+
end
|
583
|
+
|
584
|
+
it 'extracts the host' do
|
585
|
+
expect(hosts[0][:host]).to eq('myhost')
|
586
|
+
end
|
587
|
+
|
588
|
+
it 'extracts the protocol' do
|
589
|
+
expect(hosts[0][:protocol]).to eq('https')
|
590
|
+
end
|
591
|
+
|
592
|
+
it 'extracts the port' do
|
593
|
+
expect(hosts[0][:port]).to be(9200)
|
594
|
+
end
|
595
|
+
|
596
|
+
context 'when IPv6 format is used' do
|
597
|
+
|
598
|
+
around do |example|
|
599
|
+
original_setting = Faraday.ignore_env_proxy
|
600
|
+
Faraday.ignore_env_proxy = true
|
601
|
+
example.run
|
602
|
+
Faraday.ignore_env_proxy = original_setting
|
603
|
+
end
|
604
|
+
|
605
|
+
let(:host) do
|
606
|
+
{ host: '[2090:db8:85a3:9811::1f]', scheme: 'https', port: '443' }
|
607
|
+
end
|
608
|
+
|
609
|
+
it 'extracts the host' do
|
610
|
+
expect(hosts[0][:host]).to eq('[2090:db8:85a3:9811::1f]')
|
611
|
+
expect(hosts[0][:scheme]).to eq('https')
|
612
|
+
expect(hosts[0][:port]).to be(443)
|
613
|
+
end
|
614
|
+
|
615
|
+
it 'creates the correct full url' do
|
616
|
+
expect(client.transport.__full_url(client.transport.hosts[0])).to eq('https://[2090:db8:85a3:9811::1f]:443')
|
617
|
+
end
|
618
|
+
end
|
619
|
+
|
620
|
+
context 'when the host is localhost as a IPv6 address' do
|
621
|
+
|
622
|
+
around do |example|
|
623
|
+
original_setting = Faraday.ignore_env_proxy
|
624
|
+
Faraday.ignore_env_proxy = true
|
625
|
+
example.run
|
626
|
+
Faraday.ignore_env_proxy = original_setting
|
627
|
+
end
|
628
|
+
|
629
|
+
let(:host) do
|
630
|
+
{ host: '[::1]' }
|
631
|
+
end
|
632
|
+
|
633
|
+
it 'extracts the host' do
|
634
|
+
expect(hosts[0][:host]).to eq('[::1]')
|
635
|
+
expect(hosts[0][:port]).to be(9200)
|
636
|
+
end
|
637
|
+
|
638
|
+
it 'creates the correct full url' do
|
639
|
+
expect(client.transport.__full_url(client.transport.hosts[0])).to eq('http://[::1]:9200')
|
640
|
+
end
|
641
|
+
end
|
642
|
+
|
643
|
+
context 'when the port is specified as a String' do
|
644
|
+
|
645
|
+
let(:host) do
|
646
|
+
{ host: 'myhost', scheme: 'https', port: '443' }
|
647
|
+
end
|
648
|
+
|
649
|
+
it 'extracts the host' do
|
650
|
+
expect(hosts[0][:host]).to eq('myhost')
|
651
|
+
end
|
652
|
+
|
653
|
+
it 'extracts the protocol' do
|
654
|
+
expect(hosts[0][:scheme]).to eq('https')
|
655
|
+
end
|
656
|
+
|
657
|
+
it 'converts the port to an integer' do
|
658
|
+
expect(hosts[0][:port]).to be(443)
|
659
|
+
end
|
660
|
+
end
|
661
|
+
|
662
|
+
context 'when the port is specified as an Integer' do
|
663
|
+
|
664
|
+
let(:host) do
|
665
|
+
{ host: 'myhost', scheme: 'https', port: 443 }
|
666
|
+
end
|
667
|
+
|
668
|
+
it 'extracts the host' do
|
669
|
+
expect(hosts[0][:host]).to eq('myhost')
|
670
|
+
end
|
671
|
+
|
672
|
+
it 'extracts the protocol' do
|
673
|
+
expect(hosts[0][:scheme]).to eq('https')
|
674
|
+
end
|
675
|
+
|
676
|
+
it 'extracts port as an integer' do
|
677
|
+
expect(hosts[0][:port]).to be(443)
|
678
|
+
end
|
679
|
+
end
|
680
|
+
end
|
681
|
+
|
682
|
+
context 'when the hosts are a Hashie:Mash' do
|
683
|
+
|
684
|
+
let(:host) do
|
685
|
+
Hashie::Mash.new(host: 'myhost', scheme: 'https')
|
686
|
+
end
|
687
|
+
|
688
|
+
it 'extracts the host' do
|
689
|
+
expect(hosts[0][:host]).to eq('myhost')
|
690
|
+
end
|
691
|
+
|
692
|
+
it 'extracts the protocol' do
|
693
|
+
expect(hosts[0][:scheme]).to eq('https')
|
694
|
+
end
|
695
|
+
|
696
|
+
it 'converts the port to an integer' do
|
697
|
+
expect(hosts[0][:port]).to be(9200)
|
698
|
+
end
|
699
|
+
|
700
|
+
context 'when the port is specified as a String' do
|
701
|
+
|
702
|
+
let(:host) do
|
703
|
+
Hashie::Mash.new(host: 'myhost', scheme: 'https', port: '443')
|
704
|
+
end
|
705
|
+
|
706
|
+
it 'extracts the host' do
|
707
|
+
expect(hosts[0][:host]).to eq('myhost')
|
708
|
+
end
|
709
|
+
|
710
|
+
it 'extracts the protocol' do
|
711
|
+
expect(hosts[0][:scheme]).to eq('https')
|
712
|
+
end
|
713
|
+
|
714
|
+
it 'converts the port to an integer' do
|
715
|
+
expect(hosts[0][:port]).to be(443)
|
716
|
+
end
|
717
|
+
end
|
718
|
+
|
719
|
+
context 'when the port is specified as an Integer' do
|
720
|
+
|
721
|
+
let(:host) do
|
722
|
+
Hashie::Mash.new(host: 'myhost', scheme: 'https', port: 443)
|
723
|
+
end
|
724
|
+
|
725
|
+
it 'extracts the host' do
|
726
|
+
expect(hosts[0][:host]).to eq('myhost')
|
727
|
+
end
|
728
|
+
|
729
|
+
it 'extracts the protocol' do
|
730
|
+
expect(hosts[0][:scheme]).to eq('https')
|
731
|
+
end
|
732
|
+
|
733
|
+
it 'extracts port as an integer' do
|
734
|
+
expect(hosts[0][:port]).to be(443)
|
735
|
+
end
|
736
|
+
end
|
737
|
+
end
|
738
|
+
|
739
|
+
context 'when the hosts are an array' do
|
740
|
+
|
741
|
+
context 'when there is one host' do
|
742
|
+
|
743
|
+
let(:host) do
|
744
|
+
['myhost']
|
745
|
+
end
|
746
|
+
|
747
|
+
it 'extracts the host' do
|
748
|
+
expect(hosts[0][:host]).to eq('myhost')
|
749
|
+
end
|
750
|
+
|
751
|
+
it 'extracts the protocol' do
|
752
|
+
expect(hosts[0][:protocol]).to eq('http')
|
753
|
+
end
|
754
|
+
|
755
|
+
it 'defaults to port 9200' do
|
756
|
+
expect(hosts[0][:port]).to be(9200)
|
757
|
+
end
|
758
|
+
end
|
759
|
+
|
760
|
+
context 'when there is one host with a protocol and no port' do
|
761
|
+
|
762
|
+
let(:host) do
|
763
|
+
['http://myhost']
|
764
|
+
end
|
765
|
+
|
766
|
+
it 'extracts the host' do
|
767
|
+
expect(hosts[0][:host]).to eq('myhost')
|
768
|
+
end
|
769
|
+
|
770
|
+
it 'extracts the protocol' do
|
771
|
+
expect(hosts[0][:scheme]).to eq('http')
|
772
|
+
end
|
773
|
+
|
774
|
+
it 'defaults to port 9200' do
|
775
|
+
expect(hosts[0][:port]).to be(9200)
|
776
|
+
end
|
777
|
+
end
|
778
|
+
|
779
|
+
context 'when there is one host with a protocol and the default http port explicitly provided' do
|
780
|
+
let(:host) do
|
781
|
+
['http://myhost:80']
|
782
|
+
end
|
783
|
+
|
784
|
+
it 'respects the explicit port' do
|
785
|
+
expect(hosts[0][:port]).to be(80)
|
786
|
+
end
|
787
|
+
end
|
788
|
+
|
789
|
+
context 'when there is one host with a protocol and the default https port explicitly provided' do
|
790
|
+
let(:host) do
|
791
|
+
['https://myhost:443']
|
792
|
+
end
|
793
|
+
|
794
|
+
it 'respects the explicit port' do
|
795
|
+
expect(hosts[0][:port]).to be(443)
|
796
|
+
end
|
797
|
+
end
|
798
|
+
|
799
|
+
context 'when there is one host with a protocol and no port' do
|
800
|
+
|
801
|
+
let(:host) do
|
802
|
+
['https://myhost']
|
803
|
+
end
|
804
|
+
|
805
|
+
it 'extracts the host' do
|
806
|
+
expect(hosts[0][:host]).to eq('myhost')
|
807
|
+
end
|
808
|
+
|
809
|
+
it 'extracts the protocol' do
|
810
|
+
expect(hosts[0][:scheme]).to eq('https')
|
811
|
+
end
|
812
|
+
|
813
|
+
it 'defaults to port 443' do
|
814
|
+
expect(hosts[0][:port]).to be(443)
|
815
|
+
end
|
816
|
+
end
|
817
|
+
|
818
|
+
context 'when there is one host with a protocol, path, and no port' do
|
819
|
+
|
820
|
+
let(:host) do
|
821
|
+
['http://myhost/foo/bar']
|
822
|
+
end
|
823
|
+
|
824
|
+
it 'extracts the host' do
|
825
|
+
expect(hosts[0][:host]).to eq('myhost')
|
826
|
+
end
|
827
|
+
|
828
|
+
it 'extracts the protocol' do
|
829
|
+
expect(hosts[0][:scheme]).to eq('http')
|
830
|
+
end
|
831
|
+
|
832
|
+
it 'defaults to port 9200' do
|
833
|
+
expect(hosts[0][:port]).to be(9200)
|
834
|
+
end
|
835
|
+
|
836
|
+
it 'extracts the path' do
|
837
|
+
expect(hosts[0][:path]).to eq('/foo/bar')
|
838
|
+
end
|
839
|
+
end
|
840
|
+
|
841
|
+
context 'when there is more than one host' do
|
842
|
+
|
843
|
+
let(:host) do
|
844
|
+
['host1', 'host2']
|
845
|
+
end
|
846
|
+
|
847
|
+
it 'extracts the hosts' do
|
848
|
+
expect(hosts[0][:host]).to eq('host1')
|
849
|
+
expect(hosts[0][:protocol]).to eq('http')
|
850
|
+
expect(hosts[0][:port]).to be(9200)
|
851
|
+
expect(hosts[1][:host]).to eq('host2')
|
852
|
+
expect(hosts[1][:protocol]).to eq('http')
|
853
|
+
expect(hosts[1][:port]).to be(9200)
|
854
|
+
end
|
855
|
+
end
|
856
|
+
|
857
|
+
context 'when ports are also specified' do
|
858
|
+
|
859
|
+
let(:host) do
|
860
|
+
['host1:1000', 'host2:2000']
|
861
|
+
end
|
862
|
+
|
863
|
+
it 'extracts the hosts' do
|
864
|
+
expect(hosts[0][:host]).to eq('host1')
|
865
|
+
expect(hosts[0][:protocol]).to eq('http')
|
866
|
+
expect(hosts[0][:port]).to be(1000)
|
867
|
+
expect(hosts[1][:host]).to eq('host2')
|
868
|
+
expect(hosts[1][:protocol]).to eq('http')
|
869
|
+
expect(hosts[1][:port]).to be(2000)
|
870
|
+
end
|
871
|
+
end
|
872
|
+
end
|
873
|
+
|
874
|
+
context 'when the hosts is an instance of URI' do
|
875
|
+
|
876
|
+
let(:host) do
|
877
|
+
URI.parse('https://USERNAME:PASSWORD@myhost:4430')
|
878
|
+
end
|
879
|
+
|
880
|
+
it 'extracts the host' do
|
881
|
+
expect(hosts[0][:host]).to eq('myhost')
|
882
|
+
expect(hosts[0][:scheme]).to eq('https')
|
883
|
+
expect(hosts[0][:port]).to be(4430)
|
884
|
+
expect(hosts[0][:user]).to eq('USERNAME')
|
885
|
+
expect(hosts[0][:password]).to eq('PASSWORD')
|
886
|
+
end
|
887
|
+
end
|
888
|
+
|
889
|
+
context 'when the hosts is invalid' do
|
890
|
+
|
891
|
+
let(:host) do
|
892
|
+
123
|
893
|
+
end
|
894
|
+
|
895
|
+
it 'extracts the host' do
|
896
|
+
expect {
|
897
|
+
hosts
|
898
|
+
}.to raise_exception(ArgumentError)
|
899
|
+
end
|
900
|
+
end
|
901
|
+
end
|
902
|
+
|
903
|
+
context 'when hosts are specified with the \'host\' key' do
|
904
|
+
|
905
|
+
let(:client) do
|
906
|
+
described_class.new(host: ['host1', 'host2', 'host3', 'host4'], randomize_hosts: true)
|
907
|
+
end
|
908
|
+
|
909
|
+
let(:hosts) do
|
910
|
+
client.transport.hosts
|
911
|
+
end
|
912
|
+
|
913
|
+
it 'sets the hosts in random order' do
|
914
|
+
expect(hosts.all? { |host| client.transport.hosts.include?(host) }).to be(true)
|
915
|
+
end
|
916
|
+
end
|
917
|
+
|
918
|
+
context 'when hosts are specified with the \'host\' key as a String' do
|
919
|
+
|
920
|
+
let(:client) do
|
921
|
+
described_class.new('host' => ['host1', 'host2', 'host3', 'host4'], 'randomize_hosts' => true)
|
922
|
+
end
|
923
|
+
|
924
|
+
let(:hosts) do
|
925
|
+
client.transport.hosts
|
926
|
+
end
|
927
|
+
|
928
|
+
it 'sets the hosts in random order' do
|
929
|
+
expect(hosts.all? { |host| client.transport.hosts.include?(host) }).to be(true)
|
930
|
+
end
|
931
|
+
end
|
932
|
+
|
933
|
+
context 'when hosts are specified with the \'hosts\' key' do
|
934
|
+
|
935
|
+
let(:client) do
|
936
|
+
described_class.new(hosts: host)
|
937
|
+
end
|
938
|
+
|
939
|
+
let(:hosts) do
|
940
|
+
client.transport.hosts
|
941
|
+
end
|
942
|
+
|
943
|
+
it_behaves_like 'a client that extracts hosts'
|
944
|
+
end
|
945
|
+
|
946
|
+
context 'when hosts are specified with the \'hosts\' key as a String' do
|
947
|
+
|
948
|
+
let(:client) do
|
949
|
+
described_class.new('hosts' => host)
|
950
|
+
end
|
951
|
+
|
952
|
+
let(:hosts) do
|
953
|
+
client.transport.hosts
|
954
|
+
end
|
955
|
+
|
956
|
+
it_behaves_like 'a client that extracts hosts'
|
957
|
+
end
|
958
|
+
|
959
|
+
context 'when hosts are specified with the \'url\' key' do
|
960
|
+
|
961
|
+
let(:client) do
|
962
|
+
described_class.new(url: host)
|
963
|
+
end
|
964
|
+
|
965
|
+
let(:hosts) do
|
966
|
+
client.transport.hosts
|
967
|
+
end
|
968
|
+
|
969
|
+
it_behaves_like 'a client that extracts hosts'
|
970
|
+
end
|
971
|
+
|
972
|
+
context 'when hosts are specified with the \'url\' key as a String' do
|
973
|
+
|
974
|
+
let(:client) do
|
975
|
+
described_class.new('url' => host)
|
976
|
+
end
|
977
|
+
|
978
|
+
let(:hosts) do
|
979
|
+
client.transport.hosts
|
980
|
+
end
|
981
|
+
|
982
|
+
it_behaves_like 'a client that extracts hosts'
|
983
|
+
end
|
984
|
+
|
985
|
+
context 'when hosts are specified with the \'urls\' key' do
|
986
|
+
|
987
|
+
let(:client) do
|
988
|
+
described_class.new(urls: host)
|
989
|
+
end
|
990
|
+
|
991
|
+
let(:hosts) do
|
992
|
+
client.transport.hosts
|
993
|
+
end
|
994
|
+
|
995
|
+
it_behaves_like 'a client that extracts hosts'
|
996
|
+
end
|
997
|
+
|
998
|
+
context 'when hosts are specified with the \'urls\' key as a String' do
|
999
|
+
|
1000
|
+
let(:client) do
|
1001
|
+
described_class.new('urls' => host)
|
1002
|
+
end
|
1003
|
+
|
1004
|
+
let(:hosts) do
|
1005
|
+
client.transport.hosts
|
1006
|
+
end
|
1007
|
+
|
1008
|
+
it_behaves_like 'a client that extracts hosts'
|
1009
|
+
end
|
1010
|
+
|
1011
|
+
context 'when the URL is set in the OPENSEARCH_URL environment variable' do
|
1012
|
+
|
1013
|
+
context 'when there is only one host specified' do
|
1014
|
+
|
1015
|
+
around do |example|
|
1016
|
+
before_url = ENV['OPENSEARCH_URL']
|
1017
|
+
ENV['OPENSEARCH_URL'] = 'example.com'
|
1018
|
+
example.run
|
1019
|
+
ENV['OPENSEARCH_URL'] = before_url
|
1020
|
+
end
|
1021
|
+
|
1022
|
+
it 'sets the host' do
|
1023
|
+
expect(client.transport.hosts[0][:host]).to eq('example.com')
|
1024
|
+
expect(client.transport.hosts.size).to eq(1)
|
1025
|
+
end
|
1026
|
+
end
|
1027
|
+
|
1028
|
+
context 'when mutliple hosts are specified as a comma-separated String list' do
|
1029
|
+
|
1030
|
+
around do |example|
|
1031
|
+
before_url = ENV['OPENSEARCH_URL']
|
1032
|
+
ENV['OPENSEARCH_URL'] = 'example.com, other.com'
|
1033
|
+
example.run
|
1034
|
+
ENV['OPENSEARCH_URL'] = before_url
|
1035
|
+
end
|
1036
|
+
|
1037
|
+
it 'sets the hosts' do
|
1038
|
+
expect(client.transport.hosts[0][:host]).to eq('example.com')
|
1039
|
+
expect(client.transport.hosts[1][:host]).to eq('other.com')
|
1040
|
+
expect(client.transport.hosts.size).to eq(2)
|
1041
|
+
end
|
1042
|
+
end
|
1043
|
+
end
|
1044
|
+
|
1045
|
+
context 'when options are defined' do
|
1046
|
+
|
1047
|
+
context 'when scheme is specified' do
|
1048
|
+
|
1049
|
+
let(:client) do
|
1050
|
+
described_class.new(scheme: 'https')
|
1051
|
+
end
|
1052
|
+
|
1053
|
+
it 'sets the scheme' do
|
1054
|
+
expect(client.transport.connections[0].full_url('')).to match(/https/)
|
1055
|
+
end
|
1056
|
+
end
|
1057
|
+
|
1058
|
+
context 'when scheme is specified as a String key' do
|
1059
|
+
|
1060
|
+
let(:client) do
|
1061
|
+
described_class.new('scheme' => 'https')
|
1062
|
+
end
|
1063
|
+
|
1064
|
+
it 'sets the scheme' do
|
1065
|
+
expect(client.transport.connections[0].full_url('')).to match(/https/)
|
1066
|
+
end
|
1067
|
+
end
|
1068
|
+
|
1069
|
+
context 'when user and password are specified' do
|
1070
|
+
|
1071
|
+
let(:client) do
|
1072
|
+
described_class.new(user: 'USERNAME', password: 'PASSWORD')
|
1073
|
+
end
|
1074
|
+
|
1075
|
+
it 'sets the user and password' do
|
1076
|
+
expect(client.transport.connections[0].full_url('')).to match(/USERNAME/)
|
1077
|
+
expect(client.transport.connections[0].full_url('')).to match(/PASSWORD/)
|
1078
|
+
end
|
1079
|
+
|
1080
|
+
context 'when the connections are reloaded' do
|
1081
|
+
|
1082
|
+
before do
|
1083
|
+
allow(client.transport.sniffer).to receive(:hosts).and_return([{ host: 'foobar', port: 4567, id: 'foobar4567' }])
|
1084
|
+
client.transport.reload_connections!
|
1085
|
+
end
|
1086
|
+
|
1087
|
+
it 'sets keeps user and password' do
|
1088
|
+
expect(client.transport.connections[0].full_url('')).to match(/USERNAME/)
|
1089
|
+
expect(client.transport.connections[0].full_url('')).to match(/PASSWORD/)
|
1090
|
+
expect(client.transport.connections[0].full_url('')).to match(/foobar/)
|
1091
|
+
end
|
1092
|
+
end
|
1093
|
+
end
|
1094
|
+
|
1095
|
+
context 'when user and password are specified as String keys' do
|
1096
|
+
|
1097
|
+
let(:client) do
|
1098
|
+
described_class.new('user' => 'USERNAME', 'password' => 'PASSWORD')
|
1099
|
+
end
|
1100
|
+
|
1101
|
+
it 'sets the user and password' do
|
1102
|
+
expect(client.transport.connections[0].full_url('')).to match(/USERNAME/)
|
1103
|
+
expect(client.transport.connections[0].full_url('')).to match(/PASSWORD/)
|
1104
|
+
end
|
1105
|
+
|
1106
|
+
context 'when the connections are reloaded' do
|
1107
|
+
|
1108
|
+
before do
|
1109
|
+
allow(client.transport.sniffer).to receive(:hosts).and_return([{ host: 'foobar', port: 4567, id: 'foobar4567' }])
|
1110
|
+
client.transport.reload_connections!
|
1111
|
+
end
|
1112
|
+
|
1113
|
+
it 'sets keeps user and password' do
|
1114
|
+
expect(client.transport.connections[0].full_url('')).to match(/USERNAME/)
|
1115
|
+
expect(client.transport.connections[0].full_url('')).to match(/PASSWORD/)
|
1116
|
+
expect(client.transport.connections[0].full_url('')).to match(/foobar/)
|
1117
|
+
end
|
1118
|
+
end
|
1119
|
+
end
|
1120
|
+
|
1121
|
+
context 'when port is specified' do
|
1122
|
+
|
1123
|
+
let(:client) do
|
1124
|
+
described_class.new(host: 'node1', port: 1234)
|
1125
|
+
end
|
1126
|
+
|
1127
|
+
it 'sets the port' do
|
1128
|
+
expect(client.transport.connections[0].full_url('')).to match(/1234/)
|
1129
|
+
end
|
1130
|
+
end
|
1131
|
+
|
1132
|
+
context 'when the log option is true' do
|
1133
|
+
|
1134
|
+
let(:client) do
|
1135
|
+
described_class.new(log: true)
|
1136
|
+
end
|
1137
|
+
|
1138
|
+
it 'has a default logger for transport' do
|
1139
|
+
expect(client.transport.logger.info).to eq(described_class::DEFAULT_LOGGER.call.info)
|
1140
|
+
end
|
1141
|
+
end
|
1142
|
+
|
1143
|
+
context 'when the trace option is true' do
|
1144
|
+
|
1145
|
+
let(:client) do
|
1146
|
+
described_class.new(trace: true)
|
1147
|
+
end
|
1148
|
+
|
1149
|
+
it 'has a default logger for transport' do
|
1150
|
+
expect(client.transport.tracer.info).to eq(described_class::DEFAULT_TRACER.call.info)
|
1151
|
+
end
|
1152
|
+
end
|
1153
|
+
|
1154
|
+
context 'when a custom transport class is specified' do
|
1155
|
+
|
1156
|
+
let(:transport_class) do
|
1157
|
+
Class.new { def initialize(*); end }
|
1158
|
+
end
|
1159
|
+
|
1160
|
+
let(:client) do
|
1161
|
+
described_class.new(transport_class: transport_class)
|
1162
|
+
end
|
1163
|
+
|
1164
|
+
it 'allows the custom transport class to be defined' do
|
1165
|
+
expect(client.transport).to be_a(transport_class)
|
1166
|
+
end
|
1167
|
+
end
|
1168
|
+
|
1169
|
+
context 'when a custom transport instance is specified' do
|
1170
|
+
|
1171
|
+
let(:transport_instance) do
|
1172
|
+
Class.new { def initialize(*); end }.new
|
1173
|
+
end
|
1174
|
+
|
1175
|
+
let(:client) do
|
1176
|
+
described_class.new(transport: transport_instance)
|
1177
|
+
end
|
1178
|
+
|
1179
|
+
it 'allows the custom transport class to be defined' do
|
1180
|
+
expect(client.transport).to be(transport_instance)
|
1181
|
+
end
|
1182
|
+
end
|
1183
|
+
|
1184
|
+
context 'when \'transport_options\' are defined' do
|
1185
|
+
|
1186
|
+
let(:client) do
|
1187
|
+
described_class.new(transport_options: { request: { timeout: 1 } })
|
1188
|
+
end
|
1189
|
+
|
1190
|
+
it 'sets the options on the transport' do
|
1191
|
+
expect(client.transport.options[:transport_options][:request]).to eq(timeout: 1)
|
1192
|
+
end
|
1193
|
+
end
|
1194
|
+
|
1195
|
+
context 'when \'request_timeout\' is defined' do
|
1196
|
+
|
1197
|
+
let(:client) do
|
1198
|
+
described_class.new(request_timeout: 120)
|
1199
|
+
end
|
1200
|
+
|
1201
|
+
it 'sets the options on the transport' do
|
1202
|
+
expect(client.transport.options[:transport_options][:request]).to eq(timeout: 120)
|
1203
|
+
end
|
1204
|
+
end
|
1205
|
+
|
1206
|
+
context 'when \'request_timeout\' is defined as a String key' do
|
1207
|
+
|
1208
|
+
let(:client) do
|
1209
|
+
described_class.new('request_timeout' => 120)
|
1210
|
+
end
|
1211
|
+
|
1212
|
+
it 'sets the options on the transport' do
|
1213
|
+
expect(client.transport.options[:transport_options][:request]).to eq(timeout: 120)
|
1214
|
+
end
|
1215
|
+
end
|
1216
|
+
end
|
1217
|
+
|
1218
|
+
describe '#perform_request' do
|
1219
|
+
|
1220
|
+
let(:transport_instance) do
|
1221
|
+
Class.new { def initialize(*); end }.new
|
1222
|
+
end
|
1223
|
+
|
1224
|
+
let(:client) do
|
1225
|
+
described_class.new(transport: transport_instance)
|
1226
|
+
end
|
1227
|
+
|
1228
|
+
it 'delegates performing requests to the transport' do
|
1229
|
+
expect(transport_instance).to receive(:perform_request).and_return(true)
|
1230
|
+
expect(client.perform_request('GET', '/')).to be(true)
|
1231
|
+
end
|
1232
|
+
|
1233
|
+
context 'when the \'send_get_body_as\' option is specified' do
|
1234
|
+
|
1235
|
+
let(:client) do
|
1236
|
+
described_class.new(transport: transport_instance, :send_get_body_as => 'POST')
|
1237
|
+
end
|
1238
|
+
|
1239
|
+
before do
|
1240
|
+
expect(transport_instance).to receive(:perform_request).with('POST', '/', {},
|
1241
|
+
'{"foo":"bar"}',
|
1242
|
+
'{"Content-Type":"application/x-ndjson"}').and_return(true)
|
1243
|
+
end
|
1244
|
+
|
1245
|
+
let(:request) do
|
1246
|
+
client.perform_request('POST', '/', {}, '{"foo":"bar"}', '{"Content-Type":"application/x-ndjson"}')
|
1247
|
+
end
|
1248
|
+
|
1249
|
+
it 'sets the option' do
|
1250
|
+
expect(request).to be(true)
|
1251
|
+
end
|
1252
|
+
end
|
1253
|
+
|
1254
|
+
context 'when using the API Compatibility Header' do
|
1255
|
+
it 'sets the API compatibility headers' do
|
1256
|
+
ENV['ELASTIC_CLIENT_APIVERSIONING'] = 'true'
|
1257
|
+
client = described_class.new(host: hosts)
|
1258
|
+
headers = client.transport.connections.first.connection.headers
|
1259
|
+
|
1260
|
+
expect(headers['Content-Type']).to eq('application/vnd.opensearch+json; compatible-with=7')
|
1261
|
+
expect(headers['Accept']).to eq('application/vnd.opensearch+json;compatible-with=7')
|
1262
|
+
|
1263
|
+
response = client.perform_request('GET', '/')
|
1264
|
+
expect(response.headers['content-type']).to eq('application/json; charset=UTF-8')
|
1265
|
+
|
1266
|
+
ENV.delete('ELASTIC_CLIENT_APIVERSIONING')
|
1267
|
+
end
|
1268
|
+
|
1269
|
+
it 'does not use API compatibility headers' do
|
1270
|
+
val = ENV.delete('ELASTIC_CLIENT_APIVERSIONING')
|
1271
|
+
client = described_class.new(host: hosts)
|
1272
|
+
expect(client.transport.connections.first.connection.headers['Content-Type']).to eq('application/json')
|
1273
|
+
ENV['ELASTIC_CLIENT_APIVERSIONING'] = val
|
1274
|
+
end
|
1275
|
+
|
1276
|
+
it 'does not use API compatibility headers when it is set to unsupported values' do
|
1277
|
+
val = ENV.delete('ELASTIC_CLIENT_APIVERSIONING')
|
1278
|
+
|
1279
|
+
ENV['ELASTIC_CLIENT_APIVERSIONING'] = 'test'
|
1280
|
+
client = described_class.new(host: hosts)
|
1281
|
+
expect(client.transport.connections.first.connection.headers['Content-Type']).to eq('application/json')
|
1282
|
+
|
1283
|
+
ENV['ELASTIC_CLIENT_APIVERSIONING'] = 'false'
|
1284
|
+
client = described_class.new(host: hosts)
|
1285
|
+
expect(client.transport.connections.first.connection.headers['Content-Type']).to eq('application/json')
|
1286
|
+
|
1287
|
+
ENV['ELASTIC_CLIENT_APIVERSIONING'] = '3'
|
1288
|
+
client = described_class.new(host: hosts)
|
1289
|
+
expect(client.transport.connections.first.connection.headers['Content-Type']).to eq('application/json')
|
1290
|
+
ENV['ELASTIC_CLIENT_APIVERSIONING'] = val
|
1291
|
+
end
|
1292
|
+
end
|
1293
|
+
|
1294
|
+
context 'when OpenSearch response includes a warning header' do
|
1295
|
+
let(:client) do
|
1296
|
+
OpenSearch::Transport::Client.new(hosts: hosts)
|
1297
|
+
end
|
1298
|
+
|
1299
|
+
let(:warning) { 'OpenSearch warning: "deprecation warning"' }
|
1300
|
+
|
1301
|
+
it 'prints a warning' do
|
1302
|
+
allow_any_instance_of(OpenSearch::Transport::Transport::Response).to receive(:headers) do
|
1303
|
+
{ 'warning' => warning }
|
1304
|
+
end
|
1305
|
+
|
1306
|
+
begin
|
1307
|
+
stderr = $stderr
|
1308
|
+
fake_stderr = StringIO.new
|
1309
|
+
$stderr = fake_stderr
|
1310
|
+
|
1311
|
+
client.perform_request('GET', '/')
|
1312
|
+
fake_stderr.rewind
|
1313
|
+
expect(fake_stderr.string).to eq("warning: #{warning}\n")
|
1314
|
+
ensure
|
1315
|
+
$stderr = stderr
|
1316
|
+
end
|
1317
|
+
end
|
1318
|
+
end
|
1319
|
+
|
1320
|
+
context 'when a header is set on an endpoint request' do
|
1321
|
+
let(:client) { described_class.new(host: hosts) }
|
1322
|
+
let(:headers) { { 'user-agent' => 'my ruby app' } }
|
1323
|
+
|
1324
|
+
it 'performs the request with the header' do
|
1325
|
+
allow(client).to receive(:perform_request) { OpenStruct.new(body: '') }
|
1326
|
+
expect { client.perform_request('GET', '_search', {}, nil, headers) }.not_to raise_error
|
1327
|
+
expect(client).to have_received(:perform_request)
|
1328
|
+
.with('GET', '_search', {}, nil, headers)
|
1329
|
+
end
|
1330
|
+
end
|
1331
|
+
|
1332
|
+
context 'when a header is set on an endpoint request and on initialization' do
|
1333
|
+
let!(:client) do
|
1334
|
+
described_class.new(
|
1335
|
+
host: hosts,
|
1336
|
+
transport_options: { headers: instance_headers }
|
1337
|
+
)
|
1338
|
+
end
|
1339
|
+
let(:instance_headers) { { set_in_instantiation: 'header value' } }
|
1340
|
+
let(:param_headers) { {'user-agent' => 'My Ruby Tests', 'set-on-method-call' => 'header value'} }
|
1341
|
+
|
1342
|
+
it 'performs the request with the header' do
|
1343
|
+
expected_headers = client.transport.connections.connections.first.connection.headers.merge(param_headers)
|
1344
|
+
|
1345
|
+
expect_any_instance_of(Faraday::Connection)
|
1346
|
+
.to receive(:run_request)
|
1347
|
+
.with(:get, "http://#{hosts[0]}/_search", nil, expected_headers) { OpenStruct.new(body: '')}
|
1348
|
+
|
1349
|
+
client.perform_request('GET', '_search', {}, nil, param_headers)
|
1350
|
+
end
|
1351
|
+
end
|
1352
|
+
end
|
1353
|
+
|
1354
|
+
context 'when the client connects to OpenSearch' do
|
1355
|
+
let(:logger) do
|
1356
|
+
Logger.new(STDERR).tap do |logger|
|
1357
|
+
logger.formatter = proc do |severity, datetime, progname, msg|
|
1358
|
+
color = case severity
|
1359
|
+
when /INFO/ then :green
|
1360
|
+
when /ERROR|WARN|FATAL/ then :red
|
1361
|
+
when /DEBUG/ then :cyan
|
1362
|
+
else :white
|
1363
|
+
end
|
1364
|
+
ANSI.ansi(severity[0] + ' ', color, :faint) + ANSI.ansi(msg, :white, :faint) + "\n"
|
1365
|
+
end
|
1366
|
+
end unless ENV['QUIET']
|
1367
|
+
end
|
1368
|
+
|
1369
|
+
let(:port) do
|
1370
|
+
TEST_PORT
|
1371
|
+
end
|
1372
|
+
|
1373
|
+
let(:transport_options) do
|
1374
|
+
{}
|
1375
|
+
end
|
1376
|
+
|
1377
|
+
let(:options) do
|
1378
|
+
{}
|
1379
|
+
end
|
1380
|
+
|
1381
|
+
let(:client) do
|
1382
|
+
described_class.new({ host: hosts, logger: logger }.merge!(transport_options: transport_options).merge!(options))
|
1383
|
+
end
|
1384
|
+
|
1385
|
+
context 'when a request is made' do
|
1386
|
+
let!(:response) do
|
1387
|
+
client.perform_request('GET', '_cluster/health')
|
1388
|
+
end
|
1389
|
+
|
1390
|
+
it 'connects to the cluster' do
|
1391
|
+
expect(response.body['number_of_nodes']).to be >= (1)
|
1392
|
+
end
|
1393
|
+
end
|
1394
|
+
|
1395
|
+
describe '#initialize' do
|
1396
|
+
context 'when options are specified' do
|
1397
|
+
let(:transport_options) do
|
1398
|
+
{ headers: { accept: 'application/yaml', content_type: 'application/yaml' } }
|
1399
|
+
end
|
1400
|
+
|
1401
|
+
let(:response) do
|
1402
|
+
client.perform_request('GET', '_cluster/health')
|
1403
|
+
end
|
1404
|
+
|
1405
|
+
it 'applies the options to the client' do
|
1406
|
+
expect(response.body).to match(/---\n/)
|
1407
|
+
expect(response.headers['content-type']).to eq('application/yaml')
|
1408
|
+
end
|
1409
|
+
end
|
1410
|
+
|
1411
|
+
context 'when a block is provided' do
|
1412
|
+
let(:client) do
|
1413
|
+
described_class.new(host: OPENSEARCH_HOSTS.first, logger: logger) do |client|
|
1414
|
+
client.headers['Accept'] = 'application/yaml'
|
1415
|
+
end
|
1416
|
+
end
|
1417
|
+
|
1418
|
+
let(:response) do
|
1419
|
+
client.perform_request('GET', '_cluster/health')
|
1420
|
+
end
|
1421
|
+
|
1422
|
+
it 'executes the block' do
|
1423
|
+
expect(response.body).to match(/---\n/)
|
1424
|
+
expect(response.headers['content-type']).to eq('application/yaml')
|
1425
|
+
end
|
1426
|
+
|
1427
|
+
context 'when the Faraday adapter is set in the block' do
|
1428
|
+
let(:client) do
|
1429
|
+
described_class.new(host: OPENSEARCH_HOSTS.first, logger: logger) do |client|
|
1430
|
+
client.adapter(:net_http_persistent)
|
1431
|
+
end
|
1432
|
+
end
|
1433
|
+
|
1434
|
+
let(:handler_name) do
|
1435
|
+
client.transport.connections.first.connection.builder.adapter.name
|
1436
|
+
end
|
1437
|
+
|
1438
|
+
let(:response) do
|
1439
|
+
client.perform_request('GET', '_cluster/health')
|
1440
|
+
end
|
1441
|
+
|
1442
|
+
it 'sets the adapter' do
|
1443
|
+
expect(handler_name).to eq('Faraday::Adapter::NetHttpPersistent')
|
1444
|
+
end
|
1445
|
+
|
1446
|
+
it 'uses the adapter to connect' do
|
1447
|
+
expect(response.status).to eq(200)
|
1448
|
+
end
|
1449
|
+
end
|
1450
|
+
end
|
1451
|
+
end
|
1452
|
+
|
1453
|
+
describe '#options' do
|
1454
|
+
|
1455
|
+
context 'when retry_on_failure is true' do
|
1456
|
+
|
1457
|
+
context 'when a node is unreachable' do
|
1458
|
+
|
1459
|
+
let(:hosts) do
|
1460
|
+
[OPENSEARCH_HOSTS.first, "foobar1", "foobar2"]
|
1461
|
+
end
|
1462
|
+
|
1463
|
+
let(:options) do
|
1464
|
+
{ retry_on_failure: true }
|
1465
|
+
end
|
1466
|
+
|
1467
|
+
let(:responses) do
|
1468
|
+
5.times.collect do
|
1469
|
+
client.perform_request('GET', '_nodes/_local')
|
1470
|
+
end
|
1471
|
+
end
|
1472
|
+
|
1473
|
+
it 'retries on failure' do
|
1474
|
+
expect(responses.all? { true }).to be(true)
|
1475
|
+
end
|
1476
|
+
end
|
1477
|
+
end
|
1478
|
+
|
1479
|
+
context 'when retry_on_failure is an integer' do
|
1480
|
+
|
1481
|
+
let(:hosts) do
|
1482
|
+
[OPENSEARCH_HOSTS.first, 'foobar1', 'foobar2', 'foobar3']
|
1483
|
+
end
|
1484
|
+
|
1485
|
+
let(:options) do
|
1486
|
+
{ retry_on_failure: 1 }
|
1487
|
+
end
|
1488
|
+
|
1489
|
+
it 'retries only the specified number of times' do
|
1490
|
+
expect(client.perform_request('GET', '_nodes/_local'))
|
1491
|
+
expect {
|
1492
|
+
client.perform_request('GET', '_nodes/_local')
|
1493
|
+
}.to raise_exception(Faraday::ConnectionFailed)
|
1494
|
+
end
|
1495
|
+
end
|
1496
|
+
|
1497
|
+
context 'when reload_on_failure is true' do
|
1498
|
+
|
1499
|
+
let(:hosts) do
|
1500
|
+
[OPENSEARCH_HOSTS.first, 'foobar1', 'foobar2']
|
1501
|
+
end
|
1502
|
+
|
1503
|
+
let(:options) do
|
1504
|
+
{ reload_on_failure: true }
|
1505
|
+
end
|
1506
|
+
|
1507
|
+
let(:responses) do
|
1508
|
+
5.times.collect do
|
1509
|
+
client.perform_request('GET', '_nodes/_local')
|
1510
|
+
end
|
1511
|
+
end
|
1512
|
+
|
1513
|
+
it 'reloads the connections' do
|
1514
|
+
expect(client.transport.connections.size).to eq(3)
|
1515
|
+
expect(responses.all? { true }).to be(true)
|
1516
|
+
expect(client.transport.connections.size).to be >= (1)
|
1517
|
+
end
|
1518
|
+
end
|
1519
|
+
|
1520
|
+
context 'when retry_on_status is specified' do
|
1521
|
+
|
1522
|
+
let(:options) do
|
1523
|
+
{ retry_on_status: 400 }
|
1524
|
+
end
|
1525
|
+
|
1526
|
+
let(:logger) do
|
1527
|
+
double('logger', :debug? => false, :warn? => true, :fatal? => false, :error? => false)
|
1528
|
+
end
|
1529
|
+
|
1530
|
+
before do
|
1531
|
+
expect(logger).to receive(:warn).exactly(4).times
|
1532
|
+
end
|
1533
|
+
|
1534
|
+
it 'retries when the status matches' do
|
1535
|
+
expect {
|
1536
|
+
client.perform_request('PUT', '_foobar')
|
1537
|
+
}.to raise_exception(OpenSearch::Transport::Transport::Errors::BadRequest)
|
1538
|
+
end
|
1539
|
+
end
|
1540
|
+
|
1541
|
+
context 'when the \'compression\' option is set to true' do
|
1542
|
+
|
1543
|
+
context 'when using Faraday as the transport' do
|
1544
|
+
|
1545
|
+
context 'when using the Net::HTTP adapter' do
|
1546
|
+
|
1547
|
+
let(:client) do
|
1548
|
+
described_class.new(hosts: OPENSEARCH_HOSTS, compression: true, adapter: :net_http)
|
1549
|
+
end
|
1550
|
+
|
1551
|
+
it 'compresses the request and decompresses the response' do
|
1552
|
+
expect(client.perform_request('GET', '/').body).to be_a(Hash)
|
1553
|
+
end
|
1554
|
+
|
1555
|
+
it 'sets the Accept-Encoding header' do
|
1556
|
+
expect(client.transport.connections[0].connection.headers['Accept-Encoding'])
|
1557
|
+
end
|
1558
|
+
|
1559
|
+
it 'preserves the other headers' do
|
1560
|
+
expect(client.transport.connections[0].connection.headers['User-Agent'])
|
1561
|
+
end
|
1562
|
+
end
|
1563
|
+
|
1564
|
+
context 'when using the HTTPClient adapter' do
|
1565
|
+
|
1566
|
+
let(:client) do
|
1567
|
+
described_class.new(hosts: OPENSEARCH_HOSTS, compression: true, adapter: :httpclient)
|
1568
|
+
end
|
1569
|
+
|
1570
|
+
it 'compresses the request and decompresses the response' do
|
1571
|
+
expect(client.perform_request('GET', '/').body).to be_a(Hash)
|
1572
|
+
end
|
1573
|
+
|
1574
|
+
it 'sets the Accept-Encoding header' do
|
1575
|
+
expect(client.transport.connections[0].connection.headers['Accept-Encoding'])
|
1576
|
+
end
|
1577
|
+
|
1578
|
+
it 'preserves the other headers' do
|
1579
|
+
expect(client.transport.connections[0].connection.headers['User-Agent'])
|
1580
|
+
end
|
1581
|
+
end
|
1582
|
+
|
1583
|
+
context 'when using the Patron adapter', unless: jruby? do
|
1584
|
+
|
1585
|
+
let(:client) do
|
1586
|
+
described_class.new(hosts: OPENSEARCH_HOSTS, compression: true, adapter: :patron)
|
1587
|
+
end
|
1588
|
+
|
1589
|
+
it 'compresses the request and decompresses the response' do
|
1590
|
+
expect(client.perform_request('GET', '/').body).to be_a(Hash)
|
1591
|
+
end
|
1592
|
+
|
1593
|
+
it 'sets the Accept-Encoding header' do
|
1594
|
+
expect(client.transport.connections[0].connection.headers['Accept-Encoding'])
|
1595
|
+
end
|
1596
|
+
|
1597
|
+
it 'preserves the other headers' do
|
1598
|
+
expect(client.transport.connections[0].connection.headers['User-Agent'])
|
1599
|
+
end
|
1600
|
+
end
|
1601
|
+
|
1602
|
+
context 'when using the Net::HTTP::Persistent adapter' do
|
1603
|
+
|
1604
|
+
let(:client) do
|
1605
|
+
described_class.new(hosts: OPENSEARCH_HOSTS, compression: true, adapter: :net_http_persistent)
|
1606
|
+
end
|
1607
|
+
|
1608
|
+
it 'compresses the request and decompresses the response' do
|
1609
|
+
expect(client.perform_request('GET', '/').body).to be_a(Hash)
|
1610
|
+
end
|
1611
|
+
|
1612
|
+
it 'sets the Accept-Encoding header' do
|
1613
|
+
expect(client.transport.connections[0].connection.headers['Accept-Encoding'])
|
1614
|
+
end
|
1615
|
+
|
1616
|
+
it 'preserves the other headers' do
|
1617
|
+
expect(client.transport.connections[0].connection.headers['User-Agent'])
|
1618
|
+
end
|
1619
|
+
end
|
1620
|
+
|
1621
|
+
context 'when using the Typhoeus adapter' do
|
1622
|
+
|
1623
|
+
let(:client) do
|
1624
|
+
described_class.new(hosts: OPENSEARCH_HOSTS, compression: true, adapter: :typhoeus)
|
1625
|
+
end
|
1626
|
+
|
1627
|
+
it 'compresses the request and decompresses the response' do
|
1628
|
+
expect(client.perform_request('GET', '/').body).to be_a(Hash)
|
1629
|
+
end
|
1630
|
+
|
1631
|
+
it 'sets the Accept-Encoding header' do
|
1632
|
+
expect(client.transport.connections[0].connection.headers['Accept-Encoding'])
|
1633
|
+
end
|
1634
|
+
|
1635
|
+
it 'preserves the other headers' do
|
1636
|
+
expect(client.transport.connections[0].connection.headers['User-Agent'])
|
1637
|
+
end
|
1638
|
+
end unless jruby?
|
1639
|
+
end
|
1640
|
+
end
|
1641
|
+
|
1642
|
+
context 'when using Curb as the transport', unless: jruby? do
|
1643
|
+
let(:client) do
|
1644
|
+
described_class.new(
|
1645
|
+
hosts: OPENSEARCH_HOSTS,
|
1646
|
+
compression: true,
|
1647
|
+
transport_class: OpenSearch::Transport::Transport::HTTP::Curb
|
1648
|
+
)
|
1649
|
+
end
|
1650
|
+
|
1651
|
+
it 'compresses the request and decompresses the response' do
|
1652
|
+
expect(client.perform_request('GET', '/').body).to be_a(Hash)
|
1653
|
+
end
|
1654
|
+
|
1655
|
+
it 'sets the Accept-Encoding header' do
|
1656
|
+
expect(client.transport.connections[0].connection.headers['Accept-Encoding'])
|
1657
|
+
end
|
1658
|
+
|
1659
|
+
it 'preserves the other headers' do
|
1660
|
+
expect(client.transport.connections[0].connection.headers['User-Agent'])
|
1661
|
+
end
|
1662
|
+
end
|
1663
|
+
|
1664
|
+
context 'when using Manticore as the transport', if: jruby? do
|
1665
|
+
let(:client) do
|
1666
|
+
described_class.new(hosts: OPENSEARCH_HOSTS,
|
1667
|
+
compression: true,
|
1668
|
+
transport_class: OpenSearch::Transport::Transport::HTTP::Manticore)
|
1669
|
+
end
|
1670
|
+
|
1671
|
+
it 'compresses the request and decompresses the response' do
|
1672
|
+
expect(client.perform_request('GET', '/').body).to be_a(Hash)
|
1673
|
+
end
|
1674
|
+
end
|
1675
|
+
end
|
1676
|
+
|
1677
|
+
describe '#perform_request' do
|
1678
|
+
context 'when a request is made' do
|
1679
|
+
before do
|
1680
|
+
client.perform_request('DELETE', '_all')
|
1681
|
+
client.perform_request('DELETE', 'myindex') rescue
|
1682
|
+
client.perform_request('PUT', 'myindex', {}, { settings: { number_of_shards: 2, number_of_replicas: 0 } })
|
1683
|
+
client.perform_request('PUT', 'myindex/mydoc/1', { routing: 'XYZ', timeout: '1s' }, { foo: 'bar' })
|
1684
|
+
client.perform_request('GET', '_cluster/health?wait_for_status=green&timeout=2s', {})
|
1685
|
+
end
|
1686
|
+
|
1687
|
+
let(:response) do
|
1688
|
+
client.perform_request('GET', 'myindex/mydoc/1?routing=XYZ')
|
1689
|
+
end
|
1690
|
+
|
1691
|
+
it 'handles paths and URL paramters' do
|
1692
|
+
expect(response.status).to eq(200)
|
1693
|
+
end
|
1694
|
+
|
1695
|
+
it 'returns response body' do
|
1696
|
+
expect(response.body['_source']).to eq('foo' => 'bar')
|
1697
|
+
end
|
1698
|
+
end
|
1699
|
+
|
1700
|
+
context 'when an invalid url is specified' do
|
1701
|
+
it 'raises an exception' do
|
1702
|
+
expect {
|
1703
|
+
client.perform_request('GET', 'myindex/mydoc/1?routing=FOOBARBAZ')
|
1704
|
+
}.to raise_exception(OpenSearch::Transport::Transport::Errors::NotFound)
|
1705
|
+
end
|
1706
|
+
end
|
1707
|
+
|
1708
|
+
context 'when the \'ignore\' parameter is specified' do
|
1709
|
+
let(:response) do
|
1710
|
+
client.perform_request('PUT', '_foobar', ignore: 400)
|
1711
|
+
end
|
1712
|
+
|
1713
|
+
it 'exposes the status in the response' do
|
1714
|
+
expect(response.status).to eq(400)
|
1715
|
+
end
|
1716
|
+
|
1717
|
+
it 'exposes the body of the response' do
|
1718
|
+
expect(response.body).to be_a(Hash)
|
1719
|
+
expect(response.body.inspect).to match(/invalid_index_name_exception/)
|
1720
|
+
end
|
1721
|
+
end
|
1722
|
+
|
1723
|
+
context 'when request headers are specified' do
|
1724
|
+
|
1725
|
+
let(:response) do
|
1726
|
+
client.perform_request('GET', '/', {}, nil, { 'Content-Type' => 'application/yaml' })
|
1727
|
+
end
|
1728
|
+
|
1729
|
+
it 'passes them to the transport' do
|
1730
|
+
expect(response.body).to match(/---/)
|
1731
|
+
end
|
1732
|
+
end
|
1733
|
+
|
1734
|
+
describe 'selector' do
|
1735
|
+
|
1736
|
+
context 'when the round-robin selector is used' do
|
1737
|
+
|
1738
|
+
let(:nodes) do
|
1739
|
+
3.times.collect do
|
1740
|
+
client.perform_request('GET', '_nodes/_local').body['nodes'].to_a[0][1]['name']
|
1741
|
+
end
|
1742
|
+
end
|
1743
|
+
|
1744
|
+
let(:node_names) do
|
1745
|
+
client.perform_request('GET', '_nodes/stats').body('nodes').collect do |name, stats|
|
1746
|
+
stats['name']
|
1747
|
+
end
|
1748
|
+
end
|
1749
|
+
|
1750
|
+
let(:expected_names) do
|
1751
|
+
3.times.collect do |i|
|
1752
|
+
node_names[i % node_names.size]
|
1753
|
+
end
|
1754
|
+
end
|
1755
|
+
|
1756
|
+
# it 'rotates nodes' do
|
1757
|
+
# pending 'Better way to detect rotating nodes'
|
1758
|
+
# expect(nodes).to eq(expected_names)
|
1759
|
+
# end
|
1760
|
+
end
|
1761
|
+
end
|
1762
|
+
|
1763
|
+
context 'when patron is used as an adapter', unless: jruby? do
|
1764
|
+
before do
|
1765
|
+
require 'patron'
|
1766
|
+
end
|
1767
|
+
|
1768
|
+
let(:options) do
|
1769
|
+
{ adapter: :patron }
|
1770
|
+
end
|
1771
|
+
|
1772
|
+
let(:adapter) do
|
1773
|
+
client.transport.connections.first.connection.builder.adapter
|
1774
|
+
end
|
1775
|
+
|
1776
|
+
it 'uses the patron connection handler' do
|
1777
|
+
expect(adapter).to eq('Faraday::Adapter::Patron')
|
1778
|
+
end
|
1779
|
+
|
1780
|
+
it 'keeps connections open' do
|
1781
|
+
response = client.perform_request('GET', '_nodes/stats/http')
|
1782
|
+
connections_before = response.body['nodes'].values.find { |n| n['name'] == node_names.first }['http']['total_opened']
|
1783
|
+
client.transport.reload_connections!
|
1784
|
+
response = client.perform_request('GET', '_nodes/stats/http')
|
1785
|
+
connections_after = response.body['nodes'].values.find { |n| n['name'] == node_names.first }['http']['total_opened']
|
1786
|
+
expect(connections_after).to be >= (connections_before)
|
1787
|
+
end
|
1788
|
+
end
|
1789
|
+
|
1790
|
+
context 'when typhoeus is used as an adapter', unless: jruby? do
|
1791
|
+
before do
|
1792
|
+
require 'typhoeus'
|
1793
|
+
end
|
1794
|
+
|
1795
|
+
let(:options) do
|
1796
|
+
{ adapter: :typhoeus }
|
1797
|
+
end
|
1798
|
+
|
1799
|
+
let(:adapter) do
|
1800
|
+
client.transport.connections.first.connection.builder.adapter
|
1801
|
+
end
|
1802
|
+
|
1803
|
+
it 'uses the patron connection handler' do
|
1804
|
+
expect(adapter).to eq('Faraday::Adapter::Typhoeus')
|
1805
|
+
end
|
1806
|
+
|
1807
|
+
it 'keeps connections open' do
|
1808
|
+
response = client.perform_request('GET', '_nodes/stats/http')
|
1809
|
+
connections_before = response.body['nodes'].values.find { |n| n['name'] == node_names.first }['http']['total_opened']
|
1810
|
+
client.transport.reload_connections!
|
1811
|
+
response = client.perform_request('GET', '_nodes/stats/http')
|
1812
|
+
connections_after = response.body['nodes'].values.find { |n| n['name'] == node_names.first }['http']['total_opened']
|
1813
|
+
expect(connections_after).to be >= (connections_before)
|
1814
|
+
end
|
1815
|
+
end
|
1816
|
+
end
|
1817
|
+
end
|
1818
|
+
end
|