elasticsearch-transport 7.1.0 → 7.13.3

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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +13 -9
  3. data/{LICENSE.txt → LICENSE} +0 -0
  4. data/README.md +175 -76
  5. data/Rakefile +1 -1
  6. data/elasticsearch-transport.gemspec +42 -60
  7. data/lib/elasticsearch/transport/client.rb +154 -57
  8. data/lib/elasticsearch/transport/meta_header.rb +135 -0
  9. data/lib/elasticsearch/transport/redacted.rb +1 -1
  10. data/lib/elasticsearch/transport/transport/base.rb +93 -18
  11. data/lib/elasticsearch/transport/transport/connections/collection.rb +3 -6
  12. data/lib/elasticsearch/transport/transport/connections/connection.rb +8 -6
  13. data/lib/elasticsearch/transport/transport/connections/selector.rb +18 -6
  14. data/lib/elasticsearch/transport/transport/errors.rb +1 -1
  15. data/lib/elasticsearch/transport/transport/http/curb.rb +26 -9
  16. data/lib/elasticsearch/transport/transport/http/faraday.rb +27 -5
  17. data/lib/elasticsearch/transport/transport/http/manticore.rb +25 -10
  18. data/lib/elasticsearch/transport/transport/loggable.rb +1 -1
  19. data/lib/elasticsearch/transport/transport/response.rb +1 -2
  20. data/lib/elasticsearch/transport/transport/serializer/multi_json.rb +1 -1
  21. data/lib/elasticsearch/transport/transport/sniffer.rb +20 -12
  22. data/lib/elasticsearch/transport/version.rb +2 -2
  23. data/lib/elasticsearch/transport.rb +1 -1
  24. data/lib/elasticsearch-transport.rb +1 -1
  25. data/spec/elasticsearch/connections/collection_spec.rb +266 -0
  26. data/spec/elasticsearch/connections/selector_spec.rb +174 -0
  27. data/spec/elasticsearch/transport/base_spec.rb +197 -13
  28. data/spec/elasticsearch/transport/client_spec.rb +945 -118
  29. data/spec/elasticsearch/transport/meta_header_spec.rb +265 -0
  30. data/spec/elasticsearch/transport/sniffer_spec.rb +1 -14
  31. data/spec/spec_helper.rb +25 -1
  32. data/test/integration/transport_test.rb +15 -2
  33. data/test/profile/client_benchmark_test.rb +1 -1
  34. data/test/test_helper.rb +1 -1
  35. data/test/unit/connection_test.rb +8 -3
  36. data/test/unit/response_test.rb +2 -2
  37. data/test/unit/serializer_test.rb +1 -1
  38. data/test/unit/transport_base_test.rb +2 -2
  39. data/test/unit/transport_curb_test.rb +2 -2
  40. data/test/unit/transport_faraday_test.rb +3 -3
  41. data/test/unit/transport_manticore_test.rb +30 -14
  42. metadata +87 -60
  43. data/test/unit/connection_collection_test.rb +0 -147
  44. data/test/unit/connection_selector_test.rb +0 -81
@@ -0,0 +1,266 @@
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::Collection do
21
+
22
+ describe '#initialize' do
23
+
24
+ let(:collection) do
25
+ described_class.new
26
+ end
27
+
28
+ it 'has an empty list of connections as a default' do
29
+ expect(collection.connections).to be_empty
30
+ end
31
+
32
+ it 'has a default selector class' do
33
+ expect(collection.selector).not_to be_nil
34
+ end
35
+
36
+ context 'when a selector class is specified' do
37
+
38
+ let(:collection) do
39
+ described_class.new(selector_class: Elasticsearch::Transport::Transport::Connections::Selector::Random)
40
+ end
41
+
42
+ it 'sets the selector' do
43
+ expect(collection.selector).to be_a(Elasticsearch::Transport::Transport::Connections::Selector::Random)
44
+ end
45
+ end
46
+ end
47
+
48
+ describe '#get_connection' do
49
+
50
+ let(:collection) do
51
+ described_class.new(selector_class: Elasticsearch::Transport::Transport::Connections::Selector::Random)
52
+ end
53
+
54
+ before do
55
+ expect(collection.selector).to receive(:select).and_return('OK')
56
+ end
57
+
58
+ it 'uses the selector to select a connection' do
59
+ expect(collection.get_connection).to eq('OK')
60
+ end
61
+ end
62
+
63
+ describe '#hosts' do
64
+
65
+ let(:collection) do
66
+ described_class.new(connections: [ double('connection', host: 'A'),
67
+ double('connection', host: 'B') ])
68
+ end
69
+
70
+ it 'returns a list of hosts' do
71
+ expect(collection.hosts).to eq([ 'A', 'B'])
72
+ end
73
+ end
74
+
75
+ describe 'enumerable' do
76
+
77
+ let(:collection) do
78
+ described_class.new(connections: [ double('connection', host: 'A', dead?: false),
79
+ double('connection', host: 'B', dead?: false) ])
80
+ end
81
+
82
+ describe '#map' do
83
+
84
+ it 'responds to the method' do
85
+ expect(collection.map { |c| c.host.downcase }).to eq(['a', 'b'])
86
+ end
87
+ end
88
+
89
+ describe '#[]' do
90
+
91
+ it 'responds to the method' do
92
+ expect(collection[0].host).to eq('A')
93
+ expect(collection[1].host).to eq('B')
94
+ end
95
+ end
96
+
97
+ describe '#size' do
98
+
99
+ it 'responds to the method' do
100
+ expect(collection.size).to eq(2)
101
+ end
102
+ end
103
+
104
+ context 'when a connection is marked as dead' do
105
+
106
+ let(:collection) do
107
+ described_class.new(connections: [ double('connection', host: 'A', dead?: true),
108
+ double('connection', host: 'B', dead?: false) ])
109
+ end
110
+
111
+ it 'does not enumerate the dead connections' do
112
+ expect(collection.size).to eq(1)
113
+ expect(collection.collect { |c| c.host }).to eq(['B'])
114
+ end
115
+
116
+ context '#alive' do
117
+
118
+ it 'enumerates the alive connections' do
119
+ expect(collection.alive.collect { |c| c.host }).to eq(['B'])
120
+ end
121
+ end
122
+
123
+ context '#dead' do
124
+
125
+ it 'enumerates the alive connections' do
126
+ expect(collection.dead.collect { |c| c.host }).to eq(['A'])
127
+ end
128
+ end
129
+ end
130
+ end
131
+
132
+ describe '#add' do
133
+
134
+ let(:collection) do
135
+ described_class.new(connections: [ double('connection', host: 'A', dead?: false),
136
+ double('connection', host: 'B', dead?: false) ])
137
+ end
138
+
139
+ context 'when an array is provided' do
140
+
141
+ before do
142
+ collection.add([double('connection', host: 'C', dead?: false),
143
+ double('connection', host: 'D', dead?: false)])
144
+ end
145
+
146
+ it 'adds the connections' do
147
+ expect(collection.size).to eq(4)
148
+ end
149
+ end
150
+
151
+ context 'when an element is provided' do
152
+
153
+ before do
154
+ collection.add(double('connection', host: 'C', dead?: false))
155
+ end
156
+
157
+ it 'adds the connection' do
158
+ expect(collection.size).to eq(3)
159
+ end
160
+ end
161
+ end
162
+
163
+ describe '#remove' do
164
+
165
+ let(:connections) do
166
+ [ double('connection', host: 'A', dead?: false),
167
+ double('connection', host: 'B', dead?: false) ]
168
+ end
169
+
170
+ let(:collection) do
171
+ described_class.new(connections: connections)
172
+ end
173
+
174
+ context 'when an array is provided' do
175
+
176
+ before do
177
+ collection.remove(connections)
178
+ end
179
+
180
+ it 'removes the connections' do
181
+ expect(collection.size).to eq(0)
182
+ end
183
+ end
184
+
185
+ context 'when an element is provided' do
186
+
187
+ let(:connections) do
188
+ [ double('connection', host: 'A', dead?: false),
189
+ double('connection', host: 'B', dead?: false) ]
190
+ end
191
+
192
+ before do
193
+ collection.remove(connections.first)
194
+ end
195
+
196
+ it 'removes the connection' do
197
+ expect(collection.size).to eq(1)
198
+ end
199
+ end
200
+ end
201
+
202
+ describe '#get_connection' do
203
+
204
+ context 'when all connections are dead' do
205
+
206
+ let(:connection_a) do
207
+ Elasticsearch::Transport::Transport::Connections::Connection.new(host: { host: 'A' })
208
+ end
209
+
210
+ let(:connection_b) do
211
+ Elasticsearch::Transport::Transport::Connections::Connection.new(host: { host: 'B' })
212
+ end
213
+
214
+ let(:collection) do
215
+ described_class.new(connections: [connection_a, connection_b])
216
+ end
217
+
218
+ before do
219
+ connection_a.dead!.dead!
220
+ connection_b.dead!
221
+ end
222
+
223
+ it 'returns the connection with the least failures' do
224
+ expect(collection.get_connection.host[:host]).to eq('B')
225
+ end
226
+ end
227
+
228
+ context 'when multiple threads are used' do
229
+
230
+ let(:connections) do
231
+ 20.times.collect do |i|
232
+ Elasticsearch::Transport::Transport::Connections::Connection.new(host: { host: i })
233
+ end
234
+ end
235
+
236
+ let(:collection) do
237
+ described_class.new(connections: connections)
238
+ end
239
+
240
+ it 'allows threads to select connections in parallel' do
241
+ expect(10.times.collect do
242
+ threads = []
243
+ 20.times do
244
+ threads << Thread.new do
245
+ collection.get_connection
246
+ end
247
+ end
248
+ threads.map { |t| t.join }
249
+ collection.get_connection.host[:host]
250
+ end).to eq((0..9).to_a)
251
+ end
252
+
253
+ it 'always returns a connection' do
254
+ threads = 20.times.map do
255
+ Thread.new do
256
+ 20.times.map do
257
+ collection.get_connection.dead!
258
+ end
259
+ end
260
+ end
261
+
262
+ expect(threads.flat_map(&:value).size).to eq(400)
263
+ end
264
+ end
265
+ end
266
+ end
@@ -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
@@ -6,7 +6,7 @@
6
6
  # not use this file except in compliance with the License.
7
7
  # You may obtain a copy of the License at
8
8
  #
9
- # http://www.apache.org/licenses/LICENSE-2.0
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
10
  #
11
11
  # Unless required by applicable law or agreed to in writing,
12
12
  # software distributed under the License is distributed on an
@@ -18,11 +18,8 @@
18
18
  require 'spec_helper'
19
19
 
20
20
  describe Elasticsearch::Transport::Transport::Base do
21
-
22
21
  context 'when a host is printed in a logged message' do
23
-
24
22
  shared_examples_for 'a redacted string' do
25
-
26
23
  let(:client) do
27
24
  Elasticsearch::Transport::Client.new(arguments)
28
25
  end
@@ -33,6 +30,7 @@ describe Elasticsearch::Transport::Transport::Base do
33
30
 
34
31
  it 'does not include the password in the logged string' do
35
32
  expect(logger).not_to receive(:error).with(/secret_password/)
33
+
36
34
  expect {
37
35
  client.cluster.stats
38
36
  }.to raise_exception(Faraday::ConnectionFailed)
@@ -47,35 +45,221 @@ describe Elasticsearch::Transport::Transport::Base do
47
45
  end
48
46
 
49
47
  context 'when the user and password are provided as separate arguments' do
50
-
51
48
  let(:arguments) do
52
- { hosts: 'fake',
49
+ {
50
+ hosts: 'fake',
53
51
  logger: logger,
54
52
  password: 'secret_password',
55
- user: 'test' }
53
+ user: 'test'
54
+ }
56
55
  end
57
56
 
58
57
  it_behaves_like 'a redacted string'
59
58
  end
60
59
 
61
60
  context 'when the user and password are provided in the string URI' do
62
-
63
61
  let(:arguments) do
64
- { hosts: 'http://test:secret_password@fake.com',
65
- logger: logger }
62
+ {
63
+ hosts: 'https://test:secret_password@fake_local_elasticsearch',
64
+ logger: logger
65
+ }
66
66
  end
67
67
 
68
68
  it_behaves_like 'a redacted string'
69
69
  end
70
70
 
71
71
  context 'when the user and password are provided in the URI object' do
72
-
73
72
  let(:arguments) do
74
- { hosts: URI.parse('http://test:secret_password@fake.com'),
75
- logger: logger }
73
+ {
74
+ hosts: URI.parse('https://test:secret_password@fake_local_elasticsearch'),
75
+ logger: logger
76
+ }
76
77
  end
77
78
 
78
79
  it_behaves_like 'a redacted string'
79
80
  end
80
81
  end
82
+
83
+ context 'when reload_on_failure is true and and hosts are unreachable' do
84
+ let(:client) do
85
+ Elasticsearch::Transport::Client.new(arguments)
86
+ end
87
+
88
+ let(:arguments) do
89
+ {
90
+ hosts: ['http://unavailable:9200', 'http://unavailable:9201'],
91
+ reload_on_failure: true,
92
+ sniffer_timeout: 5
93
+ }
94
+ end
95
+
96
+ it 'raises an exception' do
97
+ expect { client.info }.to raise_exception(Faraday::ConnectionFailed)
98
+ end
99
+ end
100
+
101
+ context 'when the client has `retry_on_failure` set to an integer' do
102
+ let(:client) do
103
+ Elasticsearch::Transport::Client.new(arguments)
104
+ end
105
+
106
+ let(:arguments) do
107
+ {
108
+ hosts: ['http://unavailable:9200', 'http://unavailable:9201'],
109
+ retry_on_failure: 2
110
+ }
111
+ end
112
+
113
+ context 'when `perform_request` is called without a `retry_on_failure` option value' do
114
+ before do
115
+ expect(client.transport).to receive(:get_connection).exactly(3).times.and_call_original
116
+ end
117
+
118
+ it 'uses the client `retry_on_failure` value' do
119
+ expect {
120
+ client.transport.perform_request('GET', '/info')
121
+ }.to raise_exception(Faraday::ConnectionFailed)
122
+ end
123
+ end
124
+
125
+ context 'when `perform_request` is called with a `retry_on_status` option value' do
126
+ before do
127
+ expect(client.transport).to receive(:__raise_transport_error).exactly(6).times.and_call_original
128
+ end
129
+
130
+ let(:arguments) do
131
+ {
132
+ hosts: ['http://localhost:9250'],
133
+ retry_on_status: ['404']
134
+ }
135
+ end
136
+
137
+ it 'retries on 404 status the specified number of max_retries' do
138
+ expect do
139
+ client.transport.perform_request('GET', 'myindex/mydoc/1?routing=FOOBARBAZ', {}, nil, nil, retry_on_failure: 5)
140
+ end.to raise_exception(Elasticsearch::Transport::Transport::Errors::NotFound)
141
+ end
142
+ end
143
+
144
+ context 'when `perform_request` is called with a `retry_on_failure` option value' do
145
+ before do
146
+ expect(client.transport).to receive(:get_connection).exactly(6).times.and_call_original
147
+ end
148
+
149
+ it 'uses the option `retry_on_failure` value' do
150
+ expect do
151
+ client.transport.perform_request('GET', '/info', {}, nil, nil, retry_on_failure: 5)
152
+ end.to raise_exception(Faraday::ConnectionFailed)
153
+ end
154
+ end
155
+ end
156
+
157
+ context 'when the client has `retry_on_failure` set to true' do
158
+ let(:client) do
159
+ Elasticsearch::Transport::Client.new(arguments)
160
+ end
161
+
162
+ let(:arguments) do
163
+ {
164
+ hosts: ['http://unavailable:9200', 'http://unavailable:9201'],
165
+ retry_on_failure: true
166
+ }
167
+ end
168
+
169
+ context 'when `perform_request` is called without a `retry_on_failure` option value' do
170
+ before do
171
+ expect(client.transport).to receive(:get_connection).exactly(4).times.and_call_original
172
+ end
173
+
174
+ it 'uses the default `MAX_RETRIES` value' do
175
+ expect {
176
+ client.transport.perform_request('GET', '/info')
177
+ }.to raise_exception(Faraday::ConnectionFailed)
178
+ end
179
+ end
180
+
181
+ context 'when `perform_request` is called with a `retry_on_failure` option value' do
182
+ before do
183
+ expect(client.transport).to receive(:get_connection).exactly(6).times.and_call_original
184
+ end
185
+
186
+ it 'uses the option `retry_on_failure` value' do
187
+ expect {
188
+ client.transport.perform_request('GET', '/info', {}, nil, nil, retry_on_failure: 5)
189
+ }.to raise_exception(Faraday::ConnectionFailed)
190
+ end
191
+ end
192
+ end
193
+
194
+ context 'when the client has `retry_on_failure` set to false' do
195
+ let(:client) do
196
+ Elasticsearch::Transport::Client.new(arguments)
197
+ end
198
+
199
+ let(:arguments) do
200
+ {
201
+ hosts: ['http://unavailable:9200', 'http://unavailable:9201'],
202
+ retry_on_failure: false
203
+ }
204
+ end
205
+
206
+ context 'when `perform_request` is called without a `retry_on_failure` option value' do
207
+ before do
208
+ expect(client.transport).to receive(:get_connection).once.and_call_original
209
+ end
210
+
211
+ it 'does not retry' do
212
+ expect {
213
+ client.transport.perform_request('GET', '/info')
214
+ }.to raise_exception(Faraday::ConnectionFailed)
215
+ end
216
+ end
217
+
218
+ context 'when `perform_request` is called with a `retry_on_failure` option value' do
219
+
220
+ before do
221
+ expect(client.transport).to receive(:get_connection).exactly(6).times.and_call_original
222
+ end
223
+
224
+ it 'uses the option `retry_on_failure` value' do
225
+ expect {
226
+ client.transport.perform_request('GET', '/info', {}, nil, nil, retry_on_failure: 5)
227
+ }.to raise_exception(Faraday::ConnectionFailed)
228
+ end
229
+ end
230
+ end
231
+
232
+ context 'when the client has no `retry_on_failure` set' do
233
+ let(:client) do
234
+ Elasticsearch::Transport::Client.new(arguments)
235
+ end
236
+
237
+ let(:arguments) do
238
+ { hosts: ['http://unavailable:9200', 'http://unavailable:9201'] }
239
+ end
240
+
241
+ context 'when `perform_request` is called without a `retry_on_failure` option value' do
242
+ before do
243
+ expect(client.transport).to receive(:get_connection).exactly(1).times.and_call_original
244
+ end
245
+
246
+ it 'does not retry' do
247
+ expect do
248
+ client.transport.perform_request('GET', '/info')
249
+ end.to raise_exception(Faraday::ConnectionFailed)
250
+ end
251
+ end
252
+
253
+ context 'when `perform_request` is called with a `retry_on_failure` option value' do
254
+ before do
255
+ expect(client.transport).to receive(:get_connection).exactly(6).times.and_call_original
256
+ end
257
+
258
+ it 'uses the option `retry_on_failure` value' do
259
+ expect do
260
+ client.transport.perform_request('GET', '/info', {}, nil, nil, retry_on_failure: 5)
261
+ end.to raise_exception(Faraday::ConnectionFailed)
262
+ end
263
+ end
264
+ end
81
265
  end