faraday 0.17.0 → 0.17.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +216 -0
  3. data/Rakefile +13 -0
  4. data/lib/faraday.rb +1 -1
  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 +3 -3
  8. data/lib/faraday/adapter/httpclient.rb +4 -4
  9. data/lib/faraday/adapter/net_http.rb +2 -2
  10. data/lib/faraday/adapter/net_http_persistent.rb +3 -3
  11. data/lib/faraday/adapter/patron.rb +5 -5
  12. data/lib/faraday/adapter/rack.rb +1 -1
  13. data/lib/faraday/deprecate.rb +101 -0
  14. data/lib/faraday/error.rb +85 -32
  15. data/lib/faraday/options.rb +1 -1
  16. data/lib/faraday/request/retry.rb +6 -5
  17. data/lib/faraday/response.rb +3 -3
  18. data/lib/faraday/response/raise_error.rb +7 -3
  19. data/spec/faraday/deprecate_spec.rb +69 -0
  20. data/spec/faraday/error_spec.rb +102 -0
  21. data/spec/faraday/response/raise_error_spec.rb +95 -0
  22. data/spec/spec_helper.rb +104 -0
  23. data/test/adapters/default_test.rb +14 -0
  24. data/test/adapters/em_http_test.rb +30 -0
  25. data/test/adapters/em_synchrony_test.rb +32 -0
  26. data/test/adapters/excon_test.rb +30 -0
  27. data/test/adapters/httpclient_test.rb +34 -0
  28. data/test/adapters/integration.rb +263 -0
  29. data/test/adapters/logger_test.rb +136 -0
  30. data/test/adapters/net_http_persistent_test.rb +114 -0
  31. data/test/adapters/net_http_test.rb +79 -0
  32. data/test/adapters/patron_test.rb +40 -0
  33. data/test/adapters/rack_test.rb +38 -0
  34. data/test/adapters/test_middleware_test.rb +157 -0
  35. data/test/adapters/typhoeus_test.rb +38 -0
  36. data/test/authentication_middleware_test.rb +65 -0
  37. data/test/composite_read_io_test.rb +109 -0
  38. data/test/connection_test.rb +738 -0
  39. data/test/env_test.rb +268 -0
  40. data/test/helper.rb +75 -0
  41. data/test/live_server.rb +67 -0
  42. data/test/middleware/instrumentation_test.rb +88 -0
  43. data/test/middleware/retry_test.rb +282 -0
  44. data/test/middleware_stack_test.rb +260 -0
  45. data/test/multibyte.txt +1 -0
  46. data/test/options_test.rb +333 -0
  47. data/test/parameters_test.rb +157 -0
  48. data/test/request_middleware_test.rb +126 -0
  49. data/test/response_middleware_test.rb +72 -0
  50. data/test/strawberry.rb +2 -0
  51. data/test/utils_test.rb +98 -0
  52. metadata +47 -5
@@ -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
@@ -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