faraday 0.6.0 → 0.9.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
- data/.document +6 -0
- data/CHANGELOG.md +15 -0
- data/CONTRIBUTING.md +36 -0
- data/Gemfile +25 -15
- data/{LICENSE → LICENSE.md} +1 -1
- data/README.md +187 -137
- data/Rakefile +38 -101
- data/faraday.gemspec +26 -81
- data/lib/faraday/adapter/em_http.rb +237 -0
- data/lib/faraday/adapter/em_http_ssl_patch.rb +56 -0
- data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +66 -0
- data/lib/faraday/adapter/em_synchrony.rb +65 -38
- data/lib/faraday/adapter/excon.rb +60 -9
- data/lib/faraday/adapter/httpclient.rb +106 -0
- data/lib/faraday/adapter/net_http.rb +89 -38
- data/lib/faraday/adapter/net_http_persistent.rb +47 -0
- data/lib/faraday/adapter/patron.rb +46 -9
- data/lib/faraday/adapter/rack.rb +58 -0
- data/lib/faraday/adapter/test.rb +68 -28
- data/lib/faraday/adapter/typhoeus.rb +94 -16
- data/lib/faraday/adapter.rb +33 -25
- data/lib/faraday/autoload.rb +85 -0
- data/lib/faraday/connection.rb +342 -134
- data/lib/faraday/error.rb +44 -29
- data/lib/faraday/middleware.rb +18 -10
- data/lib/faraday/options.rb +350 -0
- data/lib/faraday/parameters.rb +193 -0
- data/lib/faraday/rack_builder.rb +212 -0
- data/lib/faraday/request/authorization.rb +42 -0
- data/lib/faraday/request/basic_authentication.rb +13 -0
- data/lib/faraday/request/instrumentation.rb +36 -0
- data/lib/faraday/request/multipart.rb +15 -15
- data/lib/faraday/request/retry.rb +118 -0
- data/lib/faraday/request/token_authentication.rb +15 -0
- data/lib/faraday/request/url_encoded.rb +8 -9
- data/lib/faraday/request.rb +46 -45
- data/lib/faraday/response/logger.rb +4 -4
- data/lib/faraday/response/raise_error.rb +8 -3
- data/lib/faraday/response.rb +20 -25
- data/lib/faraday/upload_io.rb +51 -7
- data/lib/faraday/utils.rb +240 -44
- data/lib/faraday.rb +218 -38
- data/script/console +7 -0
- data/script/generate_certs +42 -0
- data/script/package +7 -0
- data/script/proxy-server +42 -0
- data/script/release +17 -0
- data/script/server +36 -0
- data/script/test +172 -0
- data/test/adapters/default_test.rb +14 -0
- data/test/adapters/em_http_test.rb +20 -0
- data/test/adapters/em_synchrony_test.rb +20 -0
- data/test/adapters/excon_test.rb +20 -0
- data/test/adapters/httpclient_test.rb +21 -0
- data/test/adapters/integration.rb +254 -0
- data/test/adapters/logger_test.rb +3 -3
- data/test/adapters/net_http_persistent_test.rb +20 -0
- data/test/adapters/net_http_test.rb +6 -25
- data/test/adapters/patron_test.rb +20 -0
- data/test/adapters/rack_test.rb +31 -0
- data/test/adapters/test_middleware_test.rb +74 -3
- data/test/adapters/typhoeus_test.rb +28 -0
- data/test/authentication_middleware_test.rb +65 -0
- data/test/composite_read_io_test.rb +111 -0
- data/test/connection_test.rb +381 -104
- data/test/env_test.rb +116 -40
- data/test/helper.rb +61 -25
- data/test/live_server.rb +55 -29
- data/test/middleware/instrumentation_test.rb +88 -0
- data/test/middleware/retry_test.rb +109 -0
- data/test/middleware_stack_test.rb +87 -5
- data/test/multibyte.txt +1 -0
- data/test/options_test.rb +252 -0
- data/test/request_middleware_test.rb +78 -21
- data/test/response_middleware_test.rb +32 -7
- data/test/strawberry.rb +2 -0
- data/test/utils_test.rb +58 -0
- metadata +116 -117
- data/lib/faraday/adapter/action_dispatch.rb +0 -30
- data/lib/faraday/builder.rb +0 -137
- data/lib/faraday/request/json.rb +0 -31
- data/test/adapters/live_test.rb +0 -186
data/test/env_test.rb
CHANGED
|
@@ -1,56 +1,80 @@
|
|
|
1
|
-
require File.expand_path(
|
|
1
|
+
require File.expand_path('../helper', __FILE__)
|
|
2
2
|
|
|
3
3
|
class EnvTest < Faraday::TestCase
|
|
4
4
|
def setup
|
|
5
|
-
@conn = Faraday.new :url => 'http://sushi.com/api',
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
@conn = Faraday.new :url => 'http://sushi.com/api',
|
|
6
|
+
:headers => {'Mime-Version' => '1.0'},
|
|
7
|
+
:request => {:oauth => {:consumer_key => 'anonymous'}}
|
|
8
|
+
|
|
9
|
+
@conn.options.timeout = 3
|
|
10
|
+
@conn.options.open_timeout = 5
|
|
11
|
+
@conn.ssl.verify = false
|
|
9
12
|
@conn.proxy 'http://proxy.com'
|
|
10
|
-
@input = { :body => 'abc' }
|
|
11
|
-
@env = env_for @conn do |req|
|
|
12
|
-
req.url 'foo.json', 'a' => 1
|
|
13
|
-
req['Server'] = 'Faraday'
|
|
14
|
-
req.body = @input[:body]
|
|
15
|
-
end
|
|
16
13
|
end
|
|
17
14
|
|
|
18
15
|
def test_request_create_stores_method
|
|
19
|
-
|
|
16
|
+
env = make_env(:get)
|
|
17
|
+
assert_equal :get, env.method
|
|
20
18
|
end
|
|
21
19
|
|
|
22
|
-
def
|
|
23
|
-
|
|
20
|
+
def test_request_create_stores_uri
|
|
21
|
+
env = make_env do |req|
|
|
22
|
+
req.url 'foo.json', 'a' => 1
|
|
23
|
+
end
|
|
24
|
+
assert_equal 'http://sushi.com/api/foo.json?a=1', env.url.to_s
|
|
24
25
|
end
|
|
25
26
|
|
|
26
27
|
def test_request_create_stores_headers
|
|
27
|
-
|
|
28
|
+
env = make_env do |req|
|
|
29
|
+
req['Server'] = 'Faraday'
|
|
30
|
+
end
|
|
31
|
+
headers = env.request_headers
|
|
28
32
|
assert_equal '1.0', headers['mime-version']
|
|
29
33
|
assert_equal 'Faraday', headers['server']
|
|
30
34
|
end
|
|
31
35
|
|
|
32
36
|
def test_request_create_stores_body
|
|
33
|
-
|
|
37
|
+
env = make_env do |req|
|
|
38
|
+
req.body = 'hi'
|
|
39
|
+
end
|
|
40
|
+
assert_equal 'hi', env.body
|
|
34
41
|
end
|
|
35
42
|
|
|
36
|
-
def
|
|
37
|
-
|
|
38
|
-
assert_equal
|
|
43
|
+
def test_global_request_options
|
|
44
|
+
env = make_env
|
|
45
|
+
assert_equal 3, env.request.timeout
|
|
46
|
+
assert_equal 5, env.request.open_timeout
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def test_per_request_options
|
|
50
|
+
env = make_env do |req|
|
|
51
|
+
req.options.timeout = 10
|
|
52
|
+
req.options.boundary = 'boo'
|
|
53
|
+
req.options.oauth[:consumer_secret] = 'xyz'
|
|
54
|
+
end
|
|
55
|
+
assert_equal 10, env.request.timeout
|
|
56
|
+
assert_equal 5, env.request.open_timeout
|
|
57
|
+
assert_equal 'boo', env.request.boundary
|
|
58
|
+
|
|
59
|
+
oauth_expected = {:consumer_secret => 'xyz', :consumer_key => 'anonymous'}
|
|
60
|
+
assert_equal oauth_expected, env.request.oauth
|
|
39
61
|
end
|
|
40
62
|
|
|
41
63
|
def test_request_create_stores_ssl_options
|
|
42
|
-
|
|
64
|
+
env = make_env
|
|
65
|
+
assert_equal false, env.ssl.verify
|
|
43
66
|
end
|
|
44
67
|
|
|
45
68
|
def test_request_create_stores_proxy_options
|
|
46
|
-
|
|
69
|
+
env = make_env
|
|
70
|
+
assert_equal 'proxy.com', env.request.proxy.host
|
|
47
71
|
end
|
|
48
72
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
73
|
+
private
|
|
74
|
+
|
|
75
|
+
def make_env(method = :get, connection = @conn, &block)
|
|
76
|
+
request = connection.build_request(method, &block)
|
|
77
|
+
request.to_env(connection)
|
|
54
78
|
end
|
|
55
79
|
end
|
|
56
80
|
|
|
@@ -59,6 +83,50 @@ class HeadersTest < Faraday::TestCase
|
|
|
59
83
|
@headers = Faraday::Utils::Headers.new
|
|
60
84
|
end
|
|
61
85
|
|
|
86
|
+
def test_normalizes_different_capitalizations
|
|
87
|
+
@headers['Content-Type'] = 'application/json'
|
|
88
|
+
assert_equal ['Content-Type'], @headers.keys
|
|
89
|
+
assert_equal 'application/json', @headers['Content-Type']
|
|
90
|
+
assert_equal 'application/json', @headers['CONTENT-TYPE']
|
|
91
|
+
assert_equal 'application/json', @headers['content-type']
|
|
92
|
+
assert @headers.include?('content-type')
|
|
93
|
+
|
|
94
|
+
@headers['content-type'] = 'application/xml'
|
|
95
|
+
assert_equal ['Content-Type'], @headers.keys
|
|
96
|
+
assert_equal 'application/xml', @headers['Content-Type']
|
|
97
|
+
assert_equal 'application/xml', @headers['CONTENT-TYPE']
|
|
98
|
+
assert_equal 'application/xml', @headers['content-type']
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def test_fetch_key
|
|
102
|
+
@headers['Content-Type'] = 'application/json'
|
|
103
|
+
block_called = false
|
|
104
|
+
assert_equal 'application/json', @headers.fetch('content-type') { block_called = true }
|
|
105
|
+
assert_equal 'application/json', @headers.fetch('Content-Type')
|
|
106
|
+
assert_equal 'application/json', @headers.fetch('CONTENT-TYPE')
|
|
107
|
+
assert_equal 'application/json', @headers.fetch(:content_type)
|
|
108
|
+
assert_equal false, block_called
|
|
109
|
+
|
|
110
|
+
assert_equal 'default', @headers.fetch('invalid', 'default')
|
|
111
|
+
assert_equal false, @headers.fetch('invalid', false)
|
|
112
|
+
assert_nil @headers.fetch('invalid', nil)
|
|
113
|
+
|
|
114
|
+
assert_equal 'Invalid key', @headers.fetch('Invalid') { |key| "#{key} key" }
|
|
115
|
+
|
|
116
|
+
expected_error = defined?(KeyError) ? KeyError : IndexError
|
|
117
|
+
assert_raises(expected_error) { @headers.fetch('invalid') }
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def test_delete_key
|
|
121
|
+
@headers['Content-Type'] = 'application/json'
|
|
122
|
+
assert_equal 1, @headers.size
|
|
123
|
+
assert @headers.include?('content-type')
|
|
124
|
+
assert_equal 'application/json', @headers.delete('content-type')
|
|
125
|
+
assert_equal 0, @headers.size
|
|
126
|
+
assert !@headers.include?('content-type')
|
|
127
|
+
assert_equal nil, @headers.delete('content-type')
|
|
128
|
+
end
|
|
129
|
+
|
|
62
130
|
def test_parse_response_headers_leaves_http_status_line_out
|
|
63
131
|
@headers.parse("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n")
|
|
64
132
|
assert_equal %w(Content-Type), @headers.keys
|
|
@@ -82,53 +150,61 @@ end
|
|
|
82
150
|
|
|
83
151
|
class ResponseTest < Faraday::TestCase
|
|
84
152
|
def setup
|
|
85
|
-
@env =
|
|
153
|
+
@env = Faraday::Env.from \
|
|
86
154
|
:status => 404, :body => 'yikes',
|
|
87
|
-
:response_headers =>
|
|
88
|
-
}
|
|
155
|
+
:response_headers => {'Content-Type' => 'text/plain'}
|
|
89
156
|
@response = Faraday::Response.new @env
|
|
90
157
|
end
|
|
91
|
-
|
|
158
|
+
|
|
92
159
|
def test_finished
|
|
93
160
|
assert @response.finished?
|
|
94
161
|
end
|
|
95
|
-
|
|
162
|
+
|
|
96
163
|
def test_error_on_finish
|
|
97
164
|
assert_raises RuntimeError do
|
|
98
165
|
@response.finish({})
|
|
99
166
|
end
|
|
100
167
|
end
|
|
101
|
-
|
|
168
|
+
|
|
102
169
|
def test_not_success
|
|
103
170
|
assert !@response.success?
|
|
104
171
|
end
|
|
105
|
-
|
|
172
|
+
|
|
106
173
|
def test_status
|
|
107
174
|
assert_equal 404, @response.status
|
|
108
175
|
end
|
|
109
|
-
|
|
176
|
+
|
|
110
177
|
def test_body
|
|
111
178
|
assert_equal 'yikes', @response.body
|
|
112
179
|
end
|
|
113
|
-
|
|
180
|
+
|
|
114
181
|
def test_headers
|
|
115
182
|
assert_equal 'text/plain', @response.headers['Content-Type']
|
|
116
183
|
assert_equal 'text/plain', @response['content-type']
|
|
117
184
|
end
|
|
118
|
-
|
|
185
|
+
|
|
119
186
|
def test_apply_request
|
|
120
187
|
@response.apply_request :body => 'a=b', :method => :post
|
|
121
188
|
assert_equal 'yikes', @response.body
|
|
122
189
|
assert_equal :post, @response.env[:method]
|
|
123
190
|
end
|
|
124
|
-
|
|
191
|
+
|
|
125
192
|
def test_marshal
|
|
126
193
|
@response = Faraday::Response.new
|
|
127
194
|
@response.on_complete { }
|
|
128
|
-
@response.finish @env.merge(:
|
|
129
|
-
|
|
195
|
+
@response.finish @env.merge(:params => 'moo')
|
|
196
|
+
|
|
130
197
|
loaded = Marshal.load Marshal.dump(@response)
|
|
131
|
-
assert_nil loaded.env[:
|
|
198
|
+
assert_nil loaded.env[:params]
|
|
132
199
|
assert_equal %w[body response_headers status], loaded.env.keys.map { |k| k.to_s }.sort
|
|
133
200
|
end
|
|
201
|
+
|
|
202
|
+
def test_hash
|
|
203
|
+
hash = @response.to_hash
|
|
204
|
+
assert_kind_of Hash, hash
|
|
205
|
+
assert_equal @env.to_hash, hash
|
|
206
|
+
assert_equal hash[:status], @response.status
|
|
207
|
+
assert_equal hash[:response_headers], @response.headers
|
|
208
|
+
assert_equal hash[:body], @response.body
|
|
209
|
+
end
|
|
134
210
|
end
|
data/test/helper.rb
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
|
-
require '
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
require 'rubygems' # rubygems/version doesn't work by itself
|
|
2
|
+
require 'rubygems/version' # for simplecov-html
|
|
3
|
+
require 'simplecov'
|
|
4
|
+
require 'coveralls'
|
|
5
|
+
|
|
6
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
|
7
|
+
SimpleCov::Formatter::HTMLFormatter,
|
|
8
|
+
Coveralls::SimpleCov::Formatter
|
|
9
|
+
]
|
|
10
|
+
SimpleCov.start do
|
|
11
|
+
add_filter '/bundle/'
|
|
6
12
|
end
|
|
7
13
|
|
|
8
|
-
|
|
9
|
-
|
|
14
|
+
gem 'minitest' if defined? Bundler
|
|
15
|
+
require 'minitest/autorun'
|
|
10
16
|
|
|
11
17
|
if ENV['LEFTRIGHT']
|
|
12
18
|
begin
|
|
@@ -16,30 +22,60 @@ if ENV['LEFTRIGHT']
|
|
|
16
22
|
end
|
|
17
23
|
end
|
|
18
24
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
require 'faraday'
|
|
24
|
-
|
|
25
|
-
begin
|
|
26
|
-
require 'ruby-debug'
|
|
27
|
-
rescue LoadError
|
|
28
|
-
# ignore
|
|
29
|
-
else
|
|
30
|
-
Debugger.start
|
|
31
|
-
end
|
|
25
|
+
require File.expand_path('../../lib/faraday', __FILE__)
|
|
26
|
+
|
|
27
|
+
require 'stringio'
|
|
28
|
+
require 'uri'
|
|
32
29
|
|
|
33
30
|
module Faraday
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
when
|
|
38
|
-
|
|
31
|
+
module LiveServerConfig
|
|
32
|
+
def live_server=(value)
|
|
33
|
+
@@live_server = case value
|
|
34
|
+
when /^http/
|
|
35
|
+
URI(value)
|
|
36
|
+
when /./
|
|
37
|
+
URI('http://127.0.0.1:4567')
|
|
38
|
+
end
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
+
def live_server?
|
|
42
|
+
defined? @@live_server
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Returns an object that responds to `host` and `port`.
|
|
46
|
+
def live_server
|
|
47
|
+
live_server? and @@live_server
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
class TestCase < MiniTest::Test
|
|
52
|
+
extend LiveServerConfig
|
|
53
|
+
self.live_server = ENV['LIVE']
|
|
54
|
+
|
|
41
55
|
def test_default
|
|
42
56
|
assert true
|
|
43
57
|
end unless defined? ::MiniTest
|
|
58
|
+
|
|
59
|
+
def capture_warnings
|
|
60
|
+
old, $stderr = $stderr, StringIO.new
|
|
61
|
+
begin
|
|
62
|
+
yield
|
|
63
|
+
$stderr.string
|
|
64
|
+
ensure
|
|
65
|
+
$stderr = old
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def self.jruby?
|
|
70
|
+
defined? RUBY_ENGINE and 'jruby' == RUBY_ENGINE
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def self.rbx?
|
|
74
|
+
defined? RUBY_ENGINE and 'rbx' == RUBY_ENGINE
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def self.ssl_mode?
|
|
78
|
+
ENV['SSL'] == 'yes'
|
|
79
|
+
end
|
|
44
80
|
end
|
|
45
81
|
end
|
data/test/live_server.rb
CHANGED
|
@@ -1,41 +1,67 @@
|
|
|
1
|
-
require 'sinatra'
|
|
2
|
-
set :logging, false
|
|
1
|
+
require 'sinatra/base'
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
module Faraday
|
|
4
|
+
class LiveServer < Sinatra::Base
|
|
5
|
+
set :environment, :test
|
|
6
|
+
disable :logging
|
|
7
|
+
disable :protection
|
|
7
8
|
|
|
8
|
-
get
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
[:get, :post, :put, :patch, :delete, :options].each do |method|
|
|
10
|
+
send(method, '/echo') do
|
|
11
|
+
kind = request.request_method.downcase
|
|
12
|
+
out = kind.dup
|
|
13
|
+
out << ' ?' << request.GET.inspect if request.GET.any?
|
|
14
|
+
out << ' ' << request.POST.inspect if request.POST.any?
|
|
12
15
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
params[:uploaded_file][:filename],
|
|
17
|
-
params[:uploaded_file][:type]]
|
|
18
|
-
else
|
|
19
|
-
status 400
|
|
16
|
+
content_type 'text/plain'
|
|
17
|
+
return out
|
|
18
|
+
end
|
|
20
19
|
end
|
|
21
|
-
end
|
|
22
20
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
get '/echo_header' do
|
|
22
|
+
header = "HTTP_#{params[:name].tr('-', '_').upcase}"
|
|
23
|
+
request.env.fetch(header) { 'NONE' }
|
|
26
24
|
end
|
|
27
|
-
end
|
|
28
25
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
post '/file' do
|
|
27
|
+
if params[:uploaded_file].respond_to? :each_key
|
|
28
|
+
"file %s %s %d" % [
|
|
29
|
+
params[:uploaded_file][:filename],
|
|
30
|
+
params[:uploaded_file][:type],
|
|
31
|
+
params[:uploaded_file][:tempfile].size
|
|
32
|
+
]
|
|
33
|
+
else
|
|
34
|
+
status 400
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
get '/multi' do
|
|
39
|
+
[200, { 'Set-Cookie' => 'one, two' }, '']
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
get '/who-am-i' do
|
|
43
|
+
request.env['REMOTE_ADDR']
|
|
32
44
|
end
|
|
33
|
-
end
|
|
34
45
|
|
|
35
|
-
|
|
36
|
-
|
|
46
|
+
get '/slow' do
|
|
47
|
+
sleep 10
|
|
48
|
+
[200, {}, 'ok']
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
get '/204' do
|
|
52
|
+
status 204 # no content
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
get '/ssl' do
|
|
56
|
+
request.secure?.to_s
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
error do |e|
|
|
60
|
+
"#{e.class}\n#{e.to_s}\n#{e.backtrace.join("\n")}"
|
|
61
|
+
end
|
|
62
|
+
end
|
|
37
63
|
end
|
|
38
64
|
|
|
39
|
-
|
|
40
|
-
|
|
65
|
+
if $0 == __FILE__
|
|
66
|
+
Faraday::LiveServer.run!
|
|
41
67
|
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
require File.expand_path("../../helper", __FILE__)
|
|
2
|
+
|
|
3
|
+
module Middleware
|
|
4
|
+
class InstrumentationTest < Faraday::TestCase
|
|
5
|
+
def setup
|
|
6
|
+
@instrumenter = FakeInstrumenter.new
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def test_default_name
|
|
10
|
+
assert_equal 'request.faraday', options.name
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def test_default_instrumenter
|
|
14
|
+
begin
|
|
15
|
+
instrumenter = options.instrumenter
|
|
16
|
+
rescue NameError => err
|
|
17
|
+
assert_match 'ActiveSupport', err.to_s
|
|
18
|
+
else
|
|
19
|
+
assert_equal ActiveSupport::Notifications, instrumenter
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def test_name
|
|
24
|
+
assert_equal 'booya', options(:name => 'booya').name
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def test_instrumenter
|
|
28
|
+
assert_equal :boom, options(:instrumenter => :boom).instrumenter
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def test_instrumentation_with_default_name
|
|
32
|
+
assert_equal 0, @instrumenter.instrumentations.size
|
|
33
|
+
|
|
34
|
+
faraday = conn
|
|
35
|
+
res = faraday.get '/'
|
|
36
|
+
assert_equal 'ok', res.body
|
|
37
|
+
|
|
38
|
+
assert_equal 1, @instrumenter.instrumentations.size
|
|
39
|
+
name, env = @instrumenter.instrumentations.first
|
|
40
|
+
assert_equal 'request.faraday', name
|
|
41
|
+
assert_equal '/', env[:url].path
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def test_instrumentation
|
|
45
|
+
assert_equal 0, @instrumenter.instrumentations.size
|
|
46
|
+
|
|
47
|
+
faraday = conn :name => 'booya'
|
|
48
|
+
res = faraday.get '/'
|
|
49
|
+
assert_equal 'ok', res.body
|
|
50
|
+
|
|
51
|
+
assert_equal 1, @instrumenter.instrumentations.size
|
|
52
|
+
name, env = @instrumenter.instrumentations.first
|
|
53
|
+
assert_equal 'booya', name
|
|
54
|
+
assert_equal '/', env[:url].path
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
class FakeInstrumenter
|
|
58
|
+
attr_reader :instrumentations
|
|
59
|
+
|
|
60
|
+
def initialize
|
|
61
|
+
@instrumentations = []
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def instrument(name, env)
|
|
65
|
+
@instrumentations << [name, env]
|
|
66
|
+
yield
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def options(hash = nil)
|
|
71
|
+
Faraday::Request::Instrumentation::Options.from hash
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def conn(hash = nil)
|
|
75
|
+
hash ||= {}
|
|
76
|
+
hash[:instrumenter] = @instrumenter
|
|
77
|
+
|
|
78
|
+
Faraday.new do |f|
|
|
79
|
+
f.request :instrumentation, hash
|
|
80
|
+
f.adapter :test do |stub|
|
|
81
|
+
stub.get '/' do
|
|
82
|
+
[200, {}, 'ok']
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
require File.expand_path("../../helper", __FILE__)
|
|
2
|
+
|
|
3
|
+
module Middleware
|
|
4
|
+
class RetryTest < Faraday::TestCase
|
|
5
|
+
def setup
|
|
6
|
+
@times_called = 0
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def conn(*retry_args)
|
|
10
|
+
Faraday.new do |b|
|
|
11
|
+
b.request :retry, *retry_args
|
|
12
|
+
b.adapter :test do |stub|
|
|
13
|
+
stub.post('/unstable') {
|
|
14
|
+
@times_called += 1
|
|
15
|
+
@explode.call @times_called
|
|
16
|
+
}
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def test_unhandled_error
|
|
22
|
+
@explode = lambda {|n| raise "boom!" }
|
|
23
|
+
assert_raises(RuntimeError) { conn.post("/unstable") }
|
|
24
|
+
assert_equal 1, @times_called
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def test_handled_error
|
|
28
|
+
@explode = lambda {|n| raise Errno::ETIMEDOUT }
|
|
29
|
+
assert_raises(Errno::ETIMEDOUT) { conn.post("/unstable") }
|
|
30
|
+
assert_equal 3, @times_called
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def test_legacy_max_retries
|
|
34
|
+
@explode = lambda {|n| raise Errno::ETIMEDOUT }
|
|
35
|
+
assert_raises(Errno::ETIMEDOUT) { conn(1).post("/unstable") }
|
|
36
|
+
assert_equal 2, @times_called
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def test_new_max_retries
|
|
40
|
+
@explode = lambda {|n| raise Errno::ETIMEDOUT }
|
|
41
|
+
assert_raises(Errno::ETIMEDOUT) { conn(:max => 3).post("/unstable") }
|
|
42
|
+
assert_equal 4, @times_called
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def test_interval
|
|
46
|
+
@explode = lambda {|n| raise Errno::ETIMEDOUT }
|
|
47
|
+
started = Time.now
|
|
48
|
+
assert_raises(Errno::ETIMEDOUT) {
|
|
49
|
+
conn(:max => 2, :interval => 0.1).post("/unstable")
|
|
50
|
+
}
|
|
51
|
+
assert_in_delta 0.2, Time.now - started, 0.04
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def test_calls_sleep_amount
|
|
55
|
+
explode_app = MiniTest::Mock.new
|
|
56
|
+
explode_app.expect(:call, nil, [{:body=>nil}])
|
|
57
|
+
def explode_app.call(env)
|
|
58
|
+
raise Errno::ETIMEDOUT
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
retry_middleware = Faraday::Request::Retry.new(explode_app)
|
|
62
|
+
class << retry_middleware
|
|
63
|
+
attr_accessor :sleep_amount_retries
|
|
64
|
+
|
|
65
|
+
def sleep_amount(retries)
|
|
66
|
+
self.sleep_amount_retries.delete(retries)
|
|
67
|
+
0
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
retry_middleware.sleep_amount_retries = [2, 1]
|
|
71
|
+
|
|
72
|
+
assert_raises(Errno::ETIMEDOUT) {
|
|
73
|
+
retry_middleware.call({})
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
assert_empty retry_middleware.sleep_amount_retries
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def test_exponential_backoff
|
|
80
|
+
middleware = Faraday::Request::Retry.new(nil, :max => 5, :interval => 0.1, :backoff_factor => 2)
|
|
81
|
+
assert_equal middleware.sleep_amount(5), 0.1
|
|
82
|
+
assert_equal middleware.sleep_amount(4), 0.2
|
|
83
|
+
assert_equal middleware.sleep_amount(3), 0.4
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def test_random_additional_interval_amount
|
|
87
|
+
middleware = Faraday::Request::Retry.new(nil, :max => 2, :interval => 0.1, :interval_randomness => 1.0)
|
|
88
|
+
sleep_amount = middleware.sleep_amount(2)
|
|
89
|
+
assert_operator sleep_amount, :>=, 0.1
|
|
90
|
+
assert_operator sleep_amount, :<=, 0.2
|
|
91
|
+
middleware = Faraday::Request::Retry.new(nil, :max => 2, :interval => 0.1, :interval_randomness => 0.5)
|
|
92
|
+
sleep_amount = middleware.sleep_amount(2)
|
|
93
|
+
assert_operator sleep_amount, :>=, 0.1
|
|
94
|
+
assert_operator sleep_amount, :<=, 0.15
|
|
95
|
+
middleware = Faraday::Request::Retry.new(nil, :max => 2, :interval => 0.1, :interval_randomness => 0.25)
|
|
96
|
+
sleep_amount = middleware.sleep_amount(2)
|
|
97
|
+
assert_operator sleep_amount, :>=, 0.1
|
|
98
|
+
assert_operator sleep_amount, :<=, 0.125
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def test_custom_exceptions
|
|
102
|
+
@explode = lambda {|n| raise "boom!" }
|
|
103
|
+
assert_raises(RuntimeError) {
|
|
104
|
+
conn(:exceptions => StandardError).post("/unstable")
|
|
105
|
+
}
|
|
106
|
+
assert_equal 3, @times_called
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|