elasticsearch-transport 7.1.0 → 7.13.3

Sign up to get free protection for your applications and to get access to all the features.
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