avdi-faraday 0.8.1

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 (60) hide show
  1. data/Gemfile +27 -0
  2. data/LICENSE.md +20 -0
  3. data/README.md +250 -0
  4. data/Rakefile +87 -0
  5. data/config.ru +6 -0
  6. data/faraday.gemspec +86 -0
  7. data/lib/faraday.rb +276 -0
  8. data/lib/faraday/adapter.rb +71 -0
  9. data/lib/faraday/adapter/em_http.rb +217 -0
  10. data/lib/faraday/adapter/em_synchrony.rb +89 -0
  11. data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +66 -0
  12. data/lib/faraday/adapter/excon.rb +59 -0
  13. data/lib/faraday/adapter/httpclient.rb +92 -0
  14. data/lib/faraday/adapter/net_http.rb +116 -0
  15. data/lib/faraday/adapter/net_http_persistent.rb +37 -0
  16. data/lib/faraday/adapter/patron.rb +65 -0
  17. data/lib/faraday/adapter/rack.rb +57 -0
  18. data/lib/faraday/adapter/test.rb +162 -0
  19. data/lib/faraday/adapter/typhoeus.rb +107 -0
  20. data/lib/faraday/builder.rb +184 -0
  21. data/lib/faraday/connection.rb +468 -0
  22. data/lib/faraday/error.rb +40 -0
  23. data/lib/faraday/middleware.rb +41 -0
  24. data/lib/faraday/request.rb +101 -0
  25. data/lib/faraday/request/authorization.rb +40 -0
  26. data/lib/faraday/request/basic_authentication.rb +13 -0
  27. data/lib/faraday/request/multipart.rb +62 -0
  28. data/lib/faraday/request/retry.rb +67 -0
  29. data/lib/faraday/request/token_authentication.rb +15 -0
  30. data/lib/faraday/request/url_encoded.rb +35 -0
  31. data/lib/faraday/response.rb +99 -0
  32. data/lib/faraday/response/logger.rb +34 -0
  33. data/lib/faraday/response/raise_error.rb +16 -0
  34. data/lib/faraday/upload_io.rb +23 -0
  35. data/lib/faraday/utils.rb +274 -0
  36. data/script/test +91 -0
  37. data/test/adapters/default_test.rb +14 -0
  38. data/test/adapters/em_http_test.rb +19 -0
  39. data/test/adapters/em_synchrony_test.rb +20 -0
  40. data/test/adapters/excon_test.rb +15 -0
  41. data/test/adapters/httpclient_test.rb +16 -0
  42. data/test/adapters/integration.rb +193 -0
  43. data/test/adapters/logger_test.rb +37 -0
  44. data/test/adapters/net_http_persistent_test.rb +11 -0
  45. data/test/adapters/net_http_test.rb +49 -0
  46. data/test/adapters/patron_test.rb +17 -0
  47. data/test/adapters/rack_test.rb +26 -0
  48. data/test/adapters/test_middleware_test.rb +70 -0
  49. data/test/adapters/typhoeus_test.rb +20 -0
  50. data/test/authentication_middleware_test.rb +65 -0
  51. data/test/connection_test.rb +375 -0
  52. data/test/env_test.rb +183 -0
  53. data/test/helper.rb +75 -0
  54. data/test/live_server.rb +57 -0
  55. data/test/middleware/retry_test.rb +62 -0
  56. data/test/middleware_stack_test.rb +203 -0
  57. data/test/middleware_test.rb +12 -0
  58. data/test/request_middleware_test.rb +108 -0
  59. data/test/response_middleware_test.rb +74 -0
  60. metadata +182 -0
@@ -0,0 +1,19 @@
1
+ require File.expand_path('../integration', __FILE__)
2
+
3
+ module Adapters
4
+ class EMHttpTest < Faraday::TestCase
5
+
6
+ def adapter() :em_http end
7
+
8
+ Integration.apply(self, :Parallel) do
9
+ # https://github.com/eventmachine/eventmachine/pull/289
10
+ undef :test_timeout
11
+
12
+ def test_binds_local_socket
13
+ host = '1.2.3.4'
14
+ conn = create_connection :request => { :bind => { :host => host } }
15
+ assert_equal host, conn.options[:bind][:host]
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ require File.expand_path('../integration', __FILE__)
2
+
3
+ module Adapters
4
+ class EMSynchronyTest < Faraday::TestCase
5
+
6
+ def adapter() :em_synchrony end
7
+
8
+ Integration.apply(self, :Parallel) do
9
+ # https://github.com/eventmachine/eventmachine/pull/289
10
+ undef :test_timeout
11
+
12
+ def test_binds_local_socket
13
+ host = '1.2.3.4'
14
+ conn = create_connection :request => { :bind => { :host => host } }
15
+ #put conn.get('/who-am-i').body
16
+ assert_equal host, conn.options[:bind][:host]
17
+ end
18
+ end
19
+ end unless RUBY_VERSION < '1.9' or (defined? RUBY_ENGINE and 'jruby' == RUBY_ENGINE)
20
+ end
@@ -0,0 +1,15 @@
1
+ require File.expand_path('../integration', __FILE__)
2
+
3
+ module Adapters
4
+ class ExconTest < Faraday::TestCase
5
+
6
+ def adapter() :excon end
7
+
8
+ Integration.apply(self, :NonParallel) do
9
+ # https://github.com/geemus/excon/issues/127
10
+ # TODO: remove after 0.14.1 or greater is out
11
+ undef :test_timeout
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ require File.expand_path('../integration', __FILE__)
2
+
3
+ module Adapters
4
+ class HttpclientTest < Faraday::TestCase
5
+
6
+ def adapter() :httpclient end
7
+
8
+ Integration.apply(self, :NonParallel) do
9
+ def test_binds_local_socket
10
+ host = '1.2.3.4'
11
+ conn = create_connection :request => { :bind => { :host => host } }
12
+ assert_equal host, conn.options[:bind][:host]
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,193 @@
1
+ require 'forwardable'
2
+ require File.expand_path("../../helper", __FILE__)
3
+
4
+ module Adapters
5
+ # Adapter integration tests. To use, implement two methods:
6
+ #
7
+ # `#adapter` required. returns a symbol for the adapter middleware name
8
+ # `#adapter_options` optional. extra arguments for building an adapter
9
+ module Integration
10
+ def self.apply(base, *extras)
11
+ if base.live_server?
12
+ ([:Common] + extras).each {|name| base.send(:include, self.const_get(name)) }
13
+ yield if block_given?
14
+ elsif !defined? @warned
15
+ warn "Warning: Not running integration tests against a live server."
16
+ warn "Start the server `ruby test/live_server.rb` and set the LIVE=1 env variable."
17
+ @warned = true
18
+ end
19
+ end
20
+
21
+ module Parallel
22
+ def test_in_parallel
23
+ resp1, resp2 = nil, nil
24
+
25
+ connection = create_connection
26
+ connection.in_parallel do
27
+ resp1 = connection.get('echo?a=1')
28
+ resp2 = connection.get('echo?b=2')
29
+ assert connection.in_parallel?
30
+ assert_nil resp1.body
31
+ assert_nil resp2.body
32
+ end
33
+ assert !connection.in_parallel?
34
+ assert_equal 'get ?{"a"=>"1"}', resp1.body
35
+ assert_equal 'get ?{"b"=>"2"}', resp2.body
36
+ end
37
+ end
38
+
39
+ module NonParallel
40
+ def test_no_parallel_support
41
+ connection = create_connection
42
+ response = nil
43
+
44
+ err = capture_warnings do
45
+ connection.in_parallel do
46
+ response = connection.get('echo').body
47
+ end
48
+ end
49
+ assert response
50
+ assert_match "no parallel-capable adapter on Faraday stack", err
51
+ assert_match __FILE__, err
52
+ end
53
+ end
54
+
55
+ module Compression
56
+ def test_GET_handles_compression
57
+ res = get('echo_header', :name => 'accept-encoding')
58
+ assert_match /gzip;.+\bdeflate\b/, res.body
59
+ end
60
+ end
61
+
62
+ module Common
63
+ extend Forwardable
64
+ def_delegators :create_connection, :get, :head, :put, :post, :patch, :delete, :run_request
65
+
66
+ def test_GET_retrieves_the_response_body
67
+ assert_equal 'get', get('echo').body
68
+ end
69
+
70
+ def test_GET_send_url_encoded_params
71
+ assert_equal %(get ?{"name"=>"zack"}), get('echo', :name => 'zack').body
72
+ end
73
+
74
+ def test_GET_retrieves_the_response_headers
75
+ response = get('echo')
76
+ assert_match(/text\/plain/, response.headers['Content-Type'], 'original case fail')
77
+ assert_match(/text\/plain/, response.headers['content-type'], 'lowercase fail')
78
+ end
79
+
80
+ def test_GET_handles_headers_with_multiple_values
81
+ assert_equal 'one, two', get('multi').headers['set-cookie']
82
+ end
83
+
84
+ def test_GET_with_body
85
+ response = get('echo') do |req|
86
+ req.body = {'bodyrock' => true}
87
+ end
88
+ assert_equal %(get {"bodyrock"=>"true"}), response.body
89
+ end
90
+
91
+ def test_GET_sends_user_agent
92
+ response = get('echo_header', {:name => 'user-agent'}, :user_agent => 'Agent Faraday')
93
+ assert_equal 'Agent Faraday', response.body
94
+ end
95
+
96
+ def test_POST_send_url_encoded_params
97
+ assert_equal %(post {"name"=>"zack"}), post('echo', :name => 'zack').body
98
+ end
99
+
100
+ def test_POST_send_url_encoded_nested_params
101
+ resp = post('echo', 'name' => {'first' => 'zack'})
102
+ assert_equal %(post {"name"=>{"first"=>"zack"}}), resp.body
103
+ end
104
+
105
+ def test_POST_retrieves_the_response_headers
106
+ assert_match(/text\/plain/, post('echo').headers['content-type'])
107
+ end
108
+
109
+ def test_POST_sends_files
110
+ resp = post('file') do |req|
111
+ req.body = {'uploaded_file' => Faraday::UploadIO.new(__FILE__, 'text/x-ruby')}
112
+ end
113
+ assert_equal "file integration.rb text/x-ruby", resp.body
114
+ end
115
+
116
+ def test_PUT_send_url_encoded_params
117
+ assert_equal %(put {"name"=>"zack"}), put('echo', :name => 'zack').body
118
+ end
119
+
120
+ def test_PUT_send_url_encoded_nested_params
121
+ resp = put('echo', 'name' => {'first' => 'zack'})
122
+ assert_equal %(put {"name"=>{"first"=>"zack"}}), resp.body
123
+ end
124
+
125
+ def test_PUT_retrieves_the_response_headers
126
+ assert_match(/text\/plain/, put('echo').headers['content-type'])
127
+ end
128
+
129
+ def test_PATCH_send_url_encoded_params
130
+ assert_equal %(patch {"name"=>"zack"}), patch('echo', :name => 'zack').body
131
+ end
132
+
133
+ def test_OPTIONS
134
+ resp = run_request(:options, 'echo', nil, {})
135
+ assert_equal 'options', resp.body
136
+ end
137
+
138
+ def test_HEAD_retrieves_no_response_body
139
+ # FIXME: some adapters return empty string, some nil
140
+ assert_equal '', head('echo').body.to_s
141
+ end
142
+
143
+ def test_HEAD_retrieves_the_response_headers
144
+ assert_match(/text\/plain/, head('echo').headers['content-type'])
145
+ end
146
+
147
+ def test_DELETE_retrieves_the_response_headers
148
+ assert_match(/text\/plain/, delete('echo').headers['content-type'])
149
+ end
150
+
151
+ def test_DELETE_retrieves_the_body
152
+ assert_equal %(delete), delete('echo').body
153
+ end
154
+
155
+ def test_timeout
156
+ conn = create_connection(:request => {:timeout => 1, :open_timeout => 1})
157
+ assert_raise Faraday::Error::TimeoutError do
158
+ conn.get '/slow'
159
+ end
160
+ end
161
+
162
+ def adapter
163
+ raise NotImplementedError.new("Need to override #adapter")
164
+ end
165
+
166
+ # extra options to pass when building the adapter
167
+ def adapter_options
168
+ []
169
+ end
170
+
171
+ def create_connection(options = {})
172
+ if adapter == :default
173
+ builder_block = nil
174
+ else
175
+ builder_block = Proc.new do |b|
176
+ b.request :multipart
177
+ b.request :url_encoded
178
+ b.adapter adapter, *adapter_options
179
+ end
180
+ end
181
+
182
+ server = self.class.live_server
183
+ url = 'http://%s:%d' % [server.host, server.port]
184
+
185
+ Faraday::Connection.new(url, options, &builder_block).tap do |conn|
186
+ conn.headers['X-Faraday-Adapter'] = adapter.to_s
187
+ adapter_handler = conn.builder.handlers.last
188
+ conn.builder.insert_before adapter_handler, Faraday::Response::RaiseError
189
+ end
190
+ end
191
+ end
192
+ end
193
+ end
@@ -0,0 +1,37 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'helper'))
2
+ require 'stringio'
3
+ require 'logger'
4
+
5
+ module Adapters
6
+ class LoggerTest < Faraday::TestCase
7
+ def setup
8
+ @io = StringIO.new
9
+ @logger = Logger.new(@io)
10
+ @logger.level = Logger::DEBUG
11
+
12
+ @conn = Faraday.new do |b|
13
+ b.response :logger, @logger
14
+ b.adapter :test do |stubs|
15
+ stubs.get('/hello') { [200, {'Content-Type' => 'text/html'}, 'hello'] }
16
+ end
17
+ end
18
+ @resp = @conn.get '/hello', nil, :accept => 'text/html'
19
+ end
20
+
21
+ def test_still_returns_output
22
+ assert_equal 'hello', @resp.body
23
+ end
24
+
25
+ def test_logs_method_and_url
26
+ assert_match "get http:/hello", @io.string
27
+ end
28
+
29
+ def test_logs_request_headers
30
+ assert_match %(Accept: "text/html), @io.string
31
+ end
32
+
33
+ def test_logs_response_headers
34
+ assert_match %(Content-Type: "text/html), @io.string
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,11 @@
1
+ require File.expand_path('../integration', __FILE__)
2
+
3
+ module Adapters
4
+ class NetHttpPersistentTest < Faraday::TestCase
5
+
6
+ def adapter() :net_http_persistent end
7
+
8
+ Integration.apply(self, :NonParallel)
9
+
10
+ end
11
+ end
@@ -0,0 +1,49 @@
1
+ require File.expand_path('../integration', __FILE__)
2
+
3
+ module Adapters
4
+ class NetHttpTest < Faraday::TestCase
5
+
6
+ def adapter() :net_http end
7
+
8
+ behaviors = [:NonParallel]
9
+ behaviors << :Compression if RUBY_VERSION >= '1.9'
10
+
11
+ Integration.apply(self, *behaviors)
12
+
13
+ def test_connection_errors_get_wrapped
14
+ connection = Faraday.new('http://disney.com') do |b|
15
+ b.adapter :net_http
16
+ end
17
+
18
+ exceptions = [
19
+ EOFError,
20
+ Errno::ECONNABORTED,
21
+ Errno::ECONNREFUSED,
22
+ Errno::ECONNRESET,
23
+ Errno::EINVAL,
24
+ Net::HTTPBadResponse,
25
+ Net::HTTPHeaderSyntaxError,
26
+ Net::ProtocolError,
27
+ SocketError
28
+ ]
29
+
30
+ exceptions << OpenSSL::SSL::SSLError if defined?(OpenSSL)
31
+
32
+ exceptions.each do |exception_class|
33
+ stub_request(:get, 'disney.com/hello').to_raise(exception_class)
34
+
35
+ assert_raise(Faraday::Error::ConnectionFailed,
36
+ "Failed to wrap #{exception_class} exceptions") do
37
+ connection.get('/hello')
38
+ end
39
+ end
40
+ end
41
+
42
+ def test_configure_ssl
43
+ http = Net::HTTP.new 'disney.com', 443
44
+ # this should not raise an error
45
+ Faraday::Adapter::NetHttp.new.configure_ssl(http, :ssl => {:verify => true})
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,17 @@
1
+ require File.expand_path('../integration', __FILE__)
2
+
3
+ module Adapters
4
+ class Patron < Faraday::TestCase
5
+
6
+ def adapter() :patron end
7
+
8
+ Integration.apply(self, :NonParallel) do
9
+ # https://github.com/toland/patron/issues/34
10
+ undef :test_PATCH_send_url_encoded_params
11
+
12
+ # https://github.com/toland/patron/issues/52
13
+ undef :test_GET_with_body
14
+ end
15
+
16
+ end unless defined? RUBY_ENGINE and 'jruby' == RUBY_ENGINE
17
+ end
@@ -0,0 +1,26 @@
1
+ require File.expand_path("../integration", __FILE__)
2
+ require File.expand_path('../../live_server', __FILE__)
3
+
4
+ module Adapters
5
+ class RackTest < Faraday::TestCase
6
+
7
+ def adapter() :rack end
8
+
9
+ def adapter_options
10
+ [Faraday::LiveServer]
11
+ end
12
+
13
+ # no Integration.apply because this doesn't require a server as a separate process
14
+ include Integration::Common
15
+ include Integration::NonParallel
16
+
17
+ # not using shared test because error is swallowed by Sinatra
18
+ def test_timeout
19
+ conn = create_connection(:request => {:timeout => 1, :open_timeout => 1})
20
+ begin
21
+ conn.get '/slow'
22
+ rescue Faraday::Error::ClientError
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,70 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'helper'))
2
+
3
+ module Adapters
4
+ class TestMiddleware < Faraday::TestCase
5
+ def setup
6
+ @stubs = Faraday::Adapter::Test::Stubs.new
7
+ @conn = Faraday.new do |builder|
8
+ builder.adapter :test, @stubs
9
+ end
10
+ @stubs.get('/hello') { [200, {'Content-Type' => 'text/html'}, 'hello'] }
11
+ @resp = @conn.get('/hello')
12
+ end
13
+
14
+ def test_middleware_with_simple_path_sets_status
15
+ assert_equal 200, @resp.status
16
+ end
17
+
18
+ def test_middleware_with_simple_path_sets_headers
19
+ assert_equal 'text/html', @resp.headers['Content-Type']
20
+ end
21
+
22
+ def test_middleware_with_simple_path_sets_body
23
+ assert_equal 'hello', @resp.body
24
+ end
25
+
26
+ def test_middleware_can_be_called_several_times
27
+ assert_equal 'hello', @conn.get("/hello").body
28
+ end
29
+
30
+ def test_middleware_with_get_params
31
+ @stubs.get('/param?a=1') { [200, {}, 'a'] }
32
+ assert_equal 'a', @conn.get('/param?a=1').body
33
+ end
34
+
35
+ def test_middleware_ignores_unspecified_get_params
36
+ @stubs.get('/optional?a=1') { [200, {}, 'a'] }
37
+ assert_equal 'a', @conn.get('/optional?a=1&b=1').body
38
+ assert_equal 'a', @conn.get('/optional?a=1').body
39
+ assert_raise Faraday::Adapter::Test::Stubs::NotFound do
40
+ @conn.get('/optional')
41
+ end
42
+ end
43
+
44
+ def test_middleware_allow_different_outcomes_for_the_same_request
45
+ @stubs.get('/hello') { [200, {'Content-Type' => 'text/html'}, 'hello'] }
46
+ @stubs.get('/hello') { [200, {'Content-Type' => 'text/html'}, 'world'] }
47
+ assert_equal 'hello', @conn.get("/hello").body
48
+ assert_equal 'world', @conn.get("/hello").body
49
+ end
50
+
51
+ def test_yields_env_to_stubs
52
+ @stubs.get '/hello' do |env|
53
+ assert_equal '/hello', env[:url].path
54
+ assert_equal 'foo.com', env[:url].host
55
+ assert_equal '1', env[:params]['a']
56
+ assert_equal 'text/plain', env[:request_headers]['Accept']
57
+ [200, {}, 'a']
58
+ end
59
+
60
+ @conn.headers['Accept'] = 'text/plain'
61
+ assert_equal 'a', @conn.get('http://foo.com/hello?a=1').body
62
+ end
63
+
64
+ def test_raises_an_error_if_no_stub_is_found_for_request
65
+ assert_raise Faraday::Adapter::Test::Stubs::NotFound do
66
+ @conn.get('/invalid'){ [200, {}, []] }
67
+ end
68
+ end
69
+ end
70
+ end