faraday 0.14.0 → 0.17.6

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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +232 -0
  3. data/README.md +21 -7
  4. data/Rakefile +13 -0
  5. data/lib/faraday/adapter/em_http.rb +9 -9
  6. data/lib/faraday/adapter/em_synchrony.rb +5 -5
  7. data/lib/faraday/adapter/excon.rb +6 -3
  8. data/lib/faraday/adapter/httpclient.rb +4 -4
  9. data/lib/faraday/adapter/net_http.rb +25 -7
  10. data/lib/faraday/adapter/net_http_persistent.rb +33 -19
  11. data/lib/faraday/adapter/patron.rb +7 -12
  12. data/lib/faraday/adapter/rack.rb +1 -1
  13. data/lib/faraday/adapter.rb +2 -0
  14. data/lib/faraday/deprecate.rb +109 -0
  15. data/lib/faraday/error.rb +129 -34
  16. data/lib/faraday/options.rb +6 -5
  17. data/lib/faraday/parameters.rb +2 -1
  18. data/lib/faraday/rack_builder.rb +2 -2
  19. data/lib/faraday/request/retry.rb +65 -16
  20. data/lib/faraday/request.rb +22 -0
  21. data/lib/faraday/response/logger.rb +3 -3
  22. data/lib/faraday/response/raise_error.rb +7 -3
  23. data/lib/faraday/response.rb +3 -3
  24. data/lib/faraday/upload_io.rb +16 -6
  25. data/lib/faraday.rb +2 -3
  26. data/spec/faraday/deprecate_spec.rb +147 -0
  27. data/spec/faraday/error_spec.rb +102 -0
  28. data/spec/faraday/response/raise_error_spec.rb +106 -0
  29. data/spec/spec_helper.rb +105 -0
  30. data/test/adapters/default_test.rb +14 -0
  31. data/test/adapters/em_http_test.rb +30 -0
  32. data/test/adapters/em_synchrony_test.rb +32 -0
  33. data/test/adapters/excon_test.rb +30 -0
  34. data/test/adapters/httpclient_test.rb +34 -0
  35. data/test/adapters/integration.rb +263 -0
  36. data/test/adapters/logger_test.rb +136 -0
  37. data/test/adapters/net_http_persistent_test.rb +114 -0
  38. data/test/adapters/net_http_test.rb +79 -0
  39. data/test/adapters/patron_test.rb +40 -0
  40. data/test/adapters/rack_test.rb +38 -0
  41. data/test/adapters/test_middleware_test.rb +157 -0
  42. data/test/adapters/typhoeus_test.rb +38 -0
  43. data/test/authentication_middleware_test.rb +65 -0
  44. data/test/composite_read_io_test.rb +109 -0
  45. data/test/connection_test.rb +738 -0
  46. data/test/env_test.rb +268 -0
  47. data/test/helper.rb +75 -0
  48. data/test/live_server.rb +67 -0
  49. data/test/middleware/instrumentation_test.rb +88 -0
  50. data/test/middleware/retry_test.rb +282 -0
  51. data/test/middleware_stack_test.rb +260 -0
  52. data/test/multibyte.txt +1 -0
  53. data/test/options_test.rb +333 -0
  54. data/test/parameters_test.rb +157 -0
  55. data/test/request_middleware_test.rb +126 -0
  56. data/test/response_middleware_test.rb +72 -0
  57. data/test/strawberry.rb +2 -0
  58. data/test/utils_test.rb +98 -0
  59. metadata +48 -7
data/test/env_test.rb ADDED
@@ -0,0 +1,268 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ class EnvTest < Faraday::TestCase
4
+ def setup
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
12
+ @conn.proxy = 'http://proxy.com'
13
+ end
14
+
15
+ def test_request_create_stores_method
16
+ env = make_env(:get)
17
+ assert_equal :get, env.method
18
+ end
19
+
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
25
+ end
26
+
27
+ def test_request_create_stores_uri_with_anchor
28
+ env = make_env do |req|
29
+ req.url 'foo.json?b=2&a=1#qqq'
30
+ end
31
+ assert_equal 'http://sushi.com/api/foo.json?a=1&b=2', env.url.to_s
32
+ end
33
+
34
+ def test_request_create_stores_headers
35
+ env = make_env do |req|
36
+ req['Server'] = 'Faraday'
37
+ end
38
+ headers = env.request_headers
39
+ assert_equal '1.0', headers['mime-version']
40
+ assert_equal 'Faraday', headers['server']
41
+ end
42
+
43
+ def test_request_create_stores_body
44
+ env = make_env do |req|
45
+ req.body = 'hi'
46
+ end
47
+ assert_equal 'hi', env.body
48
+ end
49
+
50
+ def test_global_request_options
51
+ env = make_env
52
+ assert_equal 3, env.request.timeout
53
+ assert_equal 5, env.request.open_timeout
54
+ end
55
+
56
+ def test_per_request_options
57
+ env = make_env do |req|
58
+ req.options.timeout = 10
59
+ req.options.boundary = 'boo'
60
+ req.options.oauth[:consumer_secret] = 'xyz'
61
+ req.options.context = {
62
+ foo: 'foo',
63
+ bar: 'bar'
64
+ }
65
+ end
66
+
67
+ assert_equal 10, env.request.timeout
68
+ assert_equal 5, env.request.open_timeout
69
+ assert_equal 'boo', env.request.boundary
70
+ assert_equal env.request.context, { foo: 'foo', bar: 'bar' }
71
+
72
+ oauth_expected = {:consumer_secret => 'xyz', :consumer_key => 'anonymous'}
73
+ assert_equal oauth_expected, env.request.oauth
74
+ end
75
+
76
+ def test_request_create_stores_ssl_options
77
+ env = make_env
78
+ assert_equal false, env.ssl.verify
79
+ end
80
+
81
+ def test_custom_members_are_retained
82
+ env = make_env
83
+ env[:foo] = "custom 1"
84
+ env[:bar] = :custom_2
85
+ env2 = Faraday::Env.from(env)
86
+ assert_equal "custom 1", env2[:foo]
87
+ assert_equal :custom_2, env2[:bar]
88
+ env2[:baz] = "custom 3"
89
+ assert_nil env[:baz]
90
+ end
91
+
92
+ private
93
+
94
+ def make_env(method = :get, connection = @conn, &block)
95
+ request = connection.build_request(method, &block)
96
+ request.to_env(connection)
97
+ end
98
+ end
99
+
100
+ class HeadersTest < Faraday::TestCase
101
+ def setup
102
+ @headers = Faraday::Utils::Headers.new
103
+ end
104
+
105
+ def test_normalizes_different_capitalizations
106
+ @headers['Content-Type'] = 'application/json'
107
+ assert_equal ['Content-Type'], @headers.keys
108
+ assert_equal 'application/json', @headers['Content-Type']
109
+ assert_equal 'application/json', @headers['CONTENT-TYPE']
110
+ assert_equal 'application/json', @headers['content-type']
111
+ assert @headers.include?('content-type')
112
+
113
+ @headers['content-type'] = 'application/xml'
114
+ assert_equal ['Content-Type'], @headers.keys
115
+ assert_equal 'application/xml', @headers['Content-Type']
116
+ assert_equal 'application/xml', @headers['CONTENT-TYPE']
117
+ assert_equal 'application/xml', @headers['content-type']
118
+ end
119
+
120
+ def test_fetch_key
121
+ @headers['Content-Type'] = 'application/json'
122
+ block_called = false
123
+ assert_equal 'application/json', @headers.fetch('content-type') { block_called = true }
124
+ assert_equal 'application/json', @headers.fetch('Content-Type')
125
+ assert_equal 'application/json', @headers.fetch('CONTENT-TYPE')
126
+ assert_equal 'application/json', @headers.fetch(:content_type)
127
+ assert_equal false, block_called
128
+
129
+ assert_equal 'default', @headers.fetch('invalid', 'default')
130
+ assert_equal false, @headers.fetch('invalid', false)
131
+ assert_nil @headers.fetch('invalid', nil)
132
+
133
+ assert_equal 'Invalid key', @headers.fetch('Invalid') { |key| "#{key} key" }
134
+
135
+ expected_error = defined?(KeyError) ? KeyError : IndexError
136
+ assert_raises(expected_error) { @headers.fetch('invalid') }
137
+ end
138
+
139
+ def test_delete_key
140
+ @headers['Content-Type'] = 'application/json'
141
+ assert_equal 1, @headers.size
142
+ assert @headers.include?('content-type')
143
+ assert_equal 'application/json', @headers.delete('content-type')
144
+ assert_equal 0, @headers.size
145
+ assert !@headers.include?('content-type')
146
+ assert_nil @headers.delete('content-type')
147
+ end
148
+
149
+ def test_parse_response_headers_leaves_http_status_line_out
150
+ @headers.parse("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n")
151
+ assert_equal %w(Content-Type), @headers.keys
152
+ end
153
+
154
+ def test_parse_response_headers_parses_lower_cased_header_name_and_value
155
+ @headers.parse("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n")
156
+ assert_equal 'text/html', @headers['content-type']
157
+ end
158
+
159
+ def test_parse_response_headers_parses_lower_cased_header_name_and_value_with_colon
160
+ @headers.parse("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nLocation: http://sushi.com/\r\n\r\n")
161
+ assert_equal 'http://sushi.com/', @headers['location']
162
+ end
163
+
164
+ def test_parse_response_headers_parses_blank_lines
165
+ @headers.parse("HTTP/1.1 200 OK\r\n\r\nContent-Type: text/html\r\n\r\n")
166
+ assert_equal 'text/html', @headers['content-type']
167
+ end
168
+ end
169
+
170
+ class ResponseTest < Faraday::TestCase
171
+ def setup
172
+ @env = Faraday::Env.from \
173
+ :status => 404, :body => 'yikes',
174
+ :response_headers => {'Content-Type' => 'text/plain'}
175
+ @response = Faraday::Response.new @env
176
+ end
177
+
178
+ def test_finished
179
+ assert @response.finished?
180
+ end
181
+
182
+ def test_error_on_finish
183
+ assert_raises RuntimeError do
184
+ @response.finish({})
185
+ end
186
+ end
187
+
188
+ def test_body_is_parsed_on_finish
189
+ response = Faraday::Response.new
190
+ response.on_complete { |env| env[:body] = env[:body].upcase }
191
+ response.finish(@env)
192
+
193
+ assert_equal "YIKES", response.body
194
+ end
195
+
196
+ def test_response_body_is_available_during_on_complete
197
+ response = Faraday::Response.new
198
+ response.on_complete { |env| env[:body] = response.body.upcase }
199
+ response.finish(@env)
200
+
201
+ assert_equal "YIKES", response.body
202
+ end
203
+
204
+ def test_env_in_on_complete_is_identical_to_response_env
205
+ response = Faraday::Response.new
206
+ callback_env = nil
207
+ response.on_complete { |env| callback_env = env }
208
+ response.finish({})
209
+
210
+ assert_same response.env, callback_env
211
+ end
212
+
213
+ def test_not_success
214
+ assert !@response.success?
215
+ end
216
+
217
+ def test_status
218
+ assert_equal 404, @response.status
219
+ end
220
+
221
+ def test_body
222
+ assert_equal 'yikes', @response.body
223
+ end
224
+
225
+ def test_headers
226
+ assert_equal 'text/plain', @response.headers['Content-Type']
227
+ assert_equal 'text/plain', @response['content-type']
228
+ end
229
+
230
+ def test_apply_request
231
+ @response.apply_request :body => 'a=b', :method => :post
232
+ assert_equal 'yikes', @response.body
233
+ assert_equal :post, @response.env[:method]
234
+ end
235
+
236
+ def test_marshal_response
237
+ @response = Faraday::Response.new
238
+ @response.on_complete { }
239
+ @response.finish @env.merge(:params => 'moo')
240
+
241
+ loaded = Marshal.load Marshal.dump(@response)
242
+ assert_nil loaded.env[:params]
243
+ assert_equal %w[body response_headers status], loaded.env.keys.map { |k| k.to_s }.sort
244
+ end
245
+
246
+ def test_marshal_request
247
+ @request = Faraday::Request.create(:post) do |request|
248
+ request.options = Faraday::RequestOptions.new
249
+ request.params = Faraday::Utils::ParamsHash.new({ 'a' => 'c' })
250
+ request.headers = { 'b' => 'd' }
251
+ request.body = 'hello, world!'
252
+ request.url 'http://localhost/foo'
253
+ end
254
+
255
+ loaded = Marshal.load(Marshal.dump(@request))
256
+
257
+ assert_equal @request, loaded
258
+ end
259
+
260
+ def test_hash
261
+ hash = @response.to_hash
262
+ assert_kind_of Hash, hash
263
+ assert_equal @env.to_hash, hash
264
+ assert_equal hash[:status], @response.status
265
+ assert_equal hash[:response_headers], @response.headers
266
+ assert_equal hash[:body], @response.body
267
+ end
268
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,75 @@
1
+ require 'simplecov'
2
+ require 'coveralls'
3
+
4
+ SimpleCov.formatters = [SimpleCov::Formatter::HTMLFormatter, Coveralls::SimpleCov::Formatter]
5
+
6
+ SimpleCov.start do
7
+ add_filter '/bundle/'
8
+ add_filter '/test/'
9
+ minimum_coverage(87)
10
+ end
11
+
12
+ gem 'minitest' if defined? Bundler
13
+ require 'minitest/autorun'
14
+
15
+ require File.expand_path('../../lib/faraday', __FILE__)
16
+
17
+ require 'stringio'
18
+ require 'uri'
19
+
20
+ module Faraday
21
+ module LiveServerConfig
22
+ def live_server=(value)
23
+ @@live_server = case value
24
+ when /^http/
25
+ URI(value)
26
+ when /./
27
+ URI('http://127.0.0.1:4567')
28
+ end
29
+ end
30
+
31
+ def live_server?
32
+ defined? @@live_server
33
+ end
34
+
35
+ # Returns an object that responds to `host` and `port`.
36
+ def live_server
37
+ live_server? and @@live_server
38
+ end
39
+ end
40
+
41
+ class TestCase < MiniTest::Test
42
+ extend LiveServerConfig
43
+ self.live_server = ENV['LIVE']
44
+
45
+ def test_default
46
+ assert true
47
+ end unless defined? ::MiniTest
48
+
49
+ def capture_warnings
50
+ old, $stderr = $stderr, StringIO.new
51
+ begin
52
+ yield
53
+ $stderr.string
54
+ ensure
55
+ $stderr = old
56
+ end
57
+ end
58
+
59
+ def self.jruby?
60
+ defined? RUBY_ENGINE and 'jruby' == RUBY_ENGINE
61
+ end
62
+
63
+ def self.rbx?
64
+ defined? RUBY_ENGINE and 'rbx' == RUBY_ENGINE
65
+ end
66
+
67
+ def self.ruby_22_plus?
68
+ RUBY_VERSION > '2.2'
69
+ end
70
+
71
+ def self.ssl_mode?
72
+ ENV['SSL'] == 'yes'
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,67 @@
1
+ require 'sinatra/base'
2
+
3
+ module Faraday
4
+ class LiveServer < Sinatra::Base
5
+ set :environment, :test
6
+ disable :logging
7
+ disable :protection
8
+
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?
15
+
16
+ content_type 'text/plain'
17
+ return out
18
+ end
19
+ end
20
+
21
+ get '/echo_header' do
22
+ header = "HTTP_#{params[:name].tr('-', '_').upcase}"
23
+ request.env.fetch(header) { 'NONE' }
24
+ end
25
+
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']
44
+ end
45
+
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
63
+ end
64
+
65
+ if $0 == __FILE__
66
+ Faraday::LiveServer.run!
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