faraday 0.15.4 → 0.17.4

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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +232 -0
  3. data/README.md +15 -1
  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 +3 -3
  8. data/lib/faraday/adapter/httpclient.rb +4 -4
  9. data/lib/faraday/adapter/net_http.rb +3 -2
  10. data/lib/faraday/adapter/net_http_persistent.rb +4 -4
  11. data/lib/faraday/adapter/patron.rb +5 -5
  12. data/lib/faraday/adapter/rack.rb +1 -1
  13. data/lib/faraday/deprecate.rb +109 -0
  14. data/lib/faraday/error.rb +127 -35
  15. data/lib/faraday/options.rb +3 -3
  16. data/lib/faraday/rack_builder.rb +2 -2
  17. data/lib/faraday/request/retry.rb +8 -5
  18. data/lib/faraday/response/raise_error.rb +7 -3
  19. data/lib/faraday/response.rb +3 -3
  20. data/lib/faraday.rb +2 -3
  21. data/spec/faraday/deprecate_spec.rb +147 -0
  22. data/spec/faraday/error_spec.rb +102 -0
  23. data/spec/faraday/response/raise_error_spec.rb +106 -0
  24. data/spec/spec_helper.rb +105 -0
  25. data/test/adapters/default_test.rb +14 -0
  26. data/test/adapters/em_http_test.rb +30 -0
  27. data/test/adapters/em_synchrony_test.rb +32 -0
  28. data/test/adapters/excon_test.rb +30 -0
  29. data/test/adapters/httpclient_test.rb +34 -0
  30. data/test/adapters/integration.rb +263 -0
  31. data/test/adapters/logger_test.rb +136 -0
  32. data/test/adapters/net_http_persistent_test.rb +114 -0
  33. data/test/adapters/net_http_test.rb +79 -0
  34. data/test/adapters/patron_test.rb +40 -0
  35. data/test/adapters/rack_test.rb +38 -0
  36. data/test/adapters/test_middleware_test.rb +157 -0
  37. data/test/adapters/typhoeus_test.rb +38 -0
  38. data/test/authentication_middleware_test.rb +65 -0
  39. data/test/composite_read_io_test.rb +109 -0
  40. data/test/connection_test.rb +738 -0
  41. data/test/env_test.rb +268 -0
  42. data/test/helper.rb +75 -0
  43. data/test/live_server.rb +67 -0
  44. data/test/middleware/instrumentation_test.rb +88 -0
  45. data/test/middleware/retry_test.rb +282 -0
  46. data/test/middleware_stack_test.rb +260 -0
  47. data/test/multibyte.txt +1 -0
  48. data/test/options_test.rb +333 -0
  49. data/test/parameters_test.rb +157 -0
  50. data/test/request_middleware_test.rb +126 -0
  51. data/test/response_middleware_test.rb +72 -0
  52. data/test/strawberry.rb +2 -0
  53. data/test/utils_test.rb +98 -0
  54. metadata +48 -7
data/lib/faraday/error.rb CHANGED
@@ -1,22 +1,17 @@
1
- module Faraday
2
- class Error < StandardError; end
1
+ # frozen_string_literal: true
3
2
 
4
- class ClientError < Error
5
- attr_reader :response, :wrapped_exception
3
+ require 'faraday/deprecate'
6
4
 
7
- def initialize(ex, response = nil)
8
- @wrapped_exception = nil
9
- @response = response
5
+ # Faraday namespace.
6
+ module Faraday
7
+ # Faraday error base class.
8
+ class Error < StandardError
9
+ attr_reader :response, :wrapped_exception
10
10
 
11
- if ex.respond_to?(:backtrace)
12
- super(ex.message)
13
- @wrapped_exception = ex
14
- elsif ex.respond_to?(:each_key)
15
- super("the server responded with status #{ex[:status]}")
16
- @response = ex
17
- else
18
- super(ex.to_s)
19
- end
11
+ def initialize(exc, response = nil)
12
+ @wrapped_exception = nil unless defined?(@wrapped_exception)
13
+ @response = nil unless defined?(@response)
14
+ super(exc_msg_and_response!(exc, response))
20
15
  end
21
16
 
22
17
  def backtrace
@@ -29,38 +24,135 @@ module Faraday
29
24
 
30
25
  def inspect
31
26
  inner = ''
32
- if @wrapped_exception
33
- inner << " wrapped=#{@wrapped_exception.inspect}"
34
- end
35
- if @response
36
- inner << " response=#{@response.inspect}"
37
- end
38
- if inner.empty?
39
- inner << " #{super}"
40
- end
27
+ inner += " wrapped=#{@wrapped_exception.inspect}" if @wrapped_exception
28
+ inner += " response=#{@response.inspect}" if @response
29
+ inner += " #{super}" if inner.empty?
41
30
  %(#<#{self.class}#{inner}>)
42
31
  end
32
+
33
+ protected
34
+
35
+ # Pulls out potential parent exception and response hash, storing them in
36
+ # instance variables.
37
+ # exc - Either an Exception, a string message, or a response hash.
38
+ # response - Hash
39
+ # :status - Optional integer HTTP response status
40
+ # :headers - String key/value hash of HTTP response header
41
+ # values.
42
+ # :body - Optional string HTTP response body.
43
+ #
44
+ # If a subclass has to call this, then it should pass a string message
45
+ # to `super`. See NilStatusError.
46
+ def exc_msg_and_response!(exc, response = nil)
47
+ if @response.nil? && @wrapped_exception.nil?
48
+ @wrapped_exception, msg, @response = exc_msg_and_response(exc, response)
49
+ return msg
50
+ end
51
+
52
+ exc.to_s
53
+ end
54
+
55
+ # Pulls out potential parent exception and response hash.
56
+ def exc_msg_and_response(exc, response = nil)
57
+ return [exc, exc.message, response] if exc.respond_to?(:backtrace)
58
+
59
+ return [nil, "the server responded with status #{exc[:status]}", exc] \
60
+ if exc.respond_to?(:each_key)
61
+
62
+ [nil, exc.to_s, response]
63
+ end
64
+ end
65
+
66
+ # Faraday client error class. Represents 4xx status responses.
67
+ class ClientError < Error
68
+ end
69
+
70
+ # Raised by Faraday::Response::RaiseError in case of a 400 response.
71
+ class BadRequestError < ClientError
43
72
  end
44
73
 
45
- class ConnectionFailed < ClientError; end
46
- class ResourceNotFound < ClientError; end
47
- class ParsingError < ClientError; end
74
+ # Raised by Faraday::Response::RaiseError in case of a 401 response.
75
+ class UnauthorizedError < ClientError
76
+ end
77
+
78
+ # Raised by Faraday::Response::RaiseError in case of a 403 response.
79
+ class ForbiddenError < ClientError
80
+ end
48
81
 
82
+ # Raised by Faraday::Response::RaiseError in case of a 404 response.
83
+ class ResourceNotFound < ClientError
84
+ end
85
+
86
+ # Raised by Faraday::Response::RaiseError in case of a 407 response.
87
+ class ProxyAuthError < ClientError
88
+ end
89
+
90
+ # Raised by Faraday::Response::RaiseError in case of a 409 response.
91
+ class ConflictError < ClientError
92
+ end
93
+
94
+ # Raised by Faraday::Response::RaiseError in case of a 422 response.
95
+ class UnprocessableEntityError < ClientError
96
+ end
97
+
98
+ # Faraday server error class. Represents 5xx status responses.
99
+ class ServerError < Error
100
+ end
101
+
102
+ # A unified client error for timeouts.
49
103
  class TimeoutError < ClientError
50
- def initialize(ex = nil)
51
- super(ex || "timeout")
104
+ def initialize(exc = 'timeout', response = nil)
105
+ super(exc, response)
52
106
  end
53
107
  end
54
108
 
55
- class SSLError < ClientError
109
+ # Raised by Faraday::Response::RaiseError in case of a nil status in response.
110
+ class NilStatusError < ServerError
111
+ def initialize(exc, response = nil)
112
+ exc_msg_and_response!(exc, response)
113
+ @response = unwrap_resp!(@response)
114
+ super('http status could not be derived from the server response')
115
+ end
116
+
117
+ private
118
+
119
+ extend Faraday::Deprecate
120
+
121
+ def unwrap_resp(resp)
122
+ if inner = (resp.keys.size == 1 && resp[:response])
123
+ return unwrap_resp(inner)
124
+ end
125
+
126
+ resp
127
+ end
128
+
129
+ alias_method :unwrap_resp!, :unwrap_resp
130
+ deprecate('unwrap_resp', nil, '1.0')
56
131
  end
57
132
 
58
- class RetriableResponse < ClientError; end
133
+ # A unified error for failed connections.
134
+ class ConnectionFailed < ClientError
135
+ end
59
136
 
60
- [:ClientError, :ConnectionFailed, :ResourceNotFound,
61
- :ParsingError, :TimeoutError, :SSLError, :RetriableResponse].each do |const|
62
- Error.const_set(const, Faraday.const_get(const))
137
+ # A unified client error for SSL errors.
138
+ class SSLError < ClientError
139
+ end
140
+
141
+ # Raised by FaradayMiddleware::ResponseMiddleware
142
+ class ParsingError < ClientError
63
143
  end
64
144
 
145
+ # Exception used to control the Retry middleware.
146
+ #
147
+ # @see Faraday::Request::Retry
148
+ class RetriableResponse < ClientError
149
+ end
65
150
 
151
+ [:ClientError, :ConnectionFailed, :ResourceNotFound,
152
+ :ParsingError, :TimeoutError, :SSLError, :RetriableResponse].each do |const|
153
+ Error.const_set(
154
+ const,
155
+ DeprecatedClass.proxy_class(Faraday.const_get(const))
156
+ )
157
+ end
66
158
  end
@@ -72,7 +72,7 @@ module Faraday
72
72
  if args.size > 0
73
73
  send(key_setter, args.first)
74
74
  elsif block_given?
75
- send(key_setter, Proc.new.call(key))
75
+ send(key_setter, yield(key))
76
76
  else
77
77
  raise self.class.fetch_error_class, "key not found: #{key.inspect}"
78
78
  end
@@ -162,8 +162,8 @@ module Faraday
162
162
  @attribute_options ||= {}
163
163
  end
164
164
 
165
- def self.memoized(key)
166
- memoized_attributes[key.to_sym] = Proc.new
165
+ def self.memoized(key, &block)
166
+ memoized_attributes[key.to_sym] = block
167
167
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
168
168
  def #{key}() self[:#{key}]; end
169
169
  RUBY
@@ -49,10 +49,10 @@ module Faraday
49
49
  end
50
50
  end
51
51
 
52
- def initialize(handlers = [])
52
+ def initialize(handlers = [], &block)
53
53
  @handlers = handlers
54
54
  if block_given?
55
- build(&Proc.new)
55
+ build(&block)
56
56
  elsif @handlers.empty?
57
57
  # default stack, if nothing else is configured
58
58
  self.request :url_encoded
@@ -1,3 +1,5 @@
1
+ require 'date'
2
+
1
3
  module Faraday
2
4
  # Catches exceptions and retries each request a limited number of times.
3
5
  #
@@ -19,8 +21,9 @@ module Faraday
19
21
  # interval that is random between 0.1 and 0.15
20
22
  #
21
23
  class Request::Retry < Faraday::Middleware
22
-
23
- DEFAULT_EXCEPTIONS = [Errno::ETIMEDOUT, 'Timeout::Error', Error::TimeoutError, Faraday::Error::RetriableResponse].freeze
24
+ DEFAULT_EXCEPTIONS = [Errno::ETIMEDOUT, 'Timeout::Error',
25
+ Faraday::TimeoutError, Faraday::RetriableResponse
26
+ ].freeze
24
27
  IDEMPOTENT_METHODS = [:delete, :get, :head, :options, :put]
25
28
 
26
29
  class Options < Faraday::Options.new(:max, :interval, :max_interval, :interval_randomness,
@@ -93,7 +96,7 @@ module Faraday
93
96
  # exceptions - The list of exceptions to handle. Exceptions can be
94
97
  # given as Class, Module, or String. (default:
95
98
  # [Errno::ETIMEDOUT, 'Timeout::Error',
96
- # Error::TimeoutError, Faraday::Error::RetriableResponse])
99
+ # Faraday::TimeoutError, Faraday::RetriableResponse])
97
100
  # methods - A list of HTTP methods to retry without calling retry_if. Pass
98
101
  # an empty Array to call retry_if for all exceptions.
99
102
  # (defaults to the idempotent HTTP methods in IDEMPOTENT_METHODS)
@@ -126,7 +129,7 @@ module Faraday
126
129
  begin
127
130
  env[:body] = request_body # after failure env[:body] is set to the response body
128
131
  @app.call(env).tap do |resp|
129
- raise Faraday::Error::RetriableResponse.new(nil, resp) if @options.retry_statuses.include?(resp.status)
132
+ raise Faraday::RetriableResponse.new(nil, resp) if @options.retry_statuses.include?(resp.status)
130
133
  end
131
134
  rescue @errmatch => exception
132
135
  if retries > 0 && retry_request?(env, exception)
@@ -139,7 +142,7 @@ module Faraday
139
142
  end
140
143
  end
141
144
 
142
- if exception.is_a?(Faraday::Error::RetriableResponse)
145
+ if exception.is_a?(Faraday::RetriableResponse)
143
146
  exception.response
144
147
  else
145
148
  raise
@@ -5,12 +5,16 @@ module Faraday
5
5
  def on_complete(env)
6
6
  case env[:status]
7
7
  when 404
8
- raise Faraday::Error::ResourceNotFound, response_values(env)
8
+ raise Faraday::ResourceNotFound, response_values(env)
9
9
  when 407
10
10
  # mimic the behavior that we get with proxy requests with HTTPS
11
- raise Faraday::Error::ConnectionFailed, %{407 "Proxy Authentication Required "}
11
+ raise Faraday::ConnectionFailed.new(
12
+ %{407 "Proxy Authentication Required "},
13
+ response_values(env))
12
14
  when ClientErrorStatuses
13
- raise Faraday::Error::ClientError, response_values(env)
15
+ raise Faraday::ClientError, response_values(env)
16
+ when nil
17
+ raise Faraday::NilStatusError, response_values(env)
14
18
  end
15
19
  end
16
20
 
@@ -54,9 +54,9 @@ module Faraday
54
54
  !!env
55
55
  end
56
56
 
57
- def on_complete
58
- if not finished?
59
- @on_complete_callbacks << Proc.new
57
+ def on_complete(&block)
58
+ if !finished?
59
+ @on_complete_callbacks << block
60
60
  else
61
61
  yield(env)
62
62
  end
data/lib/faraday.rb CHANGED
@@ -14,7 +14,7 @@ require 'forwardable'
14
14
  # conn.get '/'
15
15
  #
16
16
  module Faraday
17
- VERSION = "0.15.4"
17
+ VERSION = "0.17.4"
18
18
 
19
19
  class << self
20
20
  # Public: Gets or sets the root path that Faraday is being loaded from.
@@ -64,8 +64,7 @@ module Faraday
64
64
  # :params => {:page => 1}
65
65
  #
66
66
  # Returns a Faraday::Connection.
67
- def new(url = nil, options = nil)
68
- block = block_given? ? Proc.new : nil
67
+ def new(url = nil, options = nil, &block)
69
68
  options = options ? default_connection_options.merge(options) : default_connection_options
70
69
  Faraday::Connection.new(url, options, &block)
71
70
  end
@@ -0,0 +1,147 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Faraday::DeprecatedClass do
4
+ class SampleClass < StandardError
5
+ attr_accessor :foo
6
+
7
+ def initialize(foo = nil)
8
+ @foo = foo || :foo
9
+ end
10
+ end
11
+
12
+ SampleDeprecatedClass = Faraday::DeprecatedClass.proxy_class(SampleClass)
13
+
14
+ it 'does not raise error for deprecated classes but prints an error message' do
15
+ error_message, foobar = with_warn_squelching { SampleDeprecatedClass.new(:foo_bar) }
16
+ expect(foobar).to be_a(SampleClass)
17
+ expect(foobar.foo).to eq(:foo_bar)
18
+ expect(error_message).to match(
19
+ Regexp.new(
20
+ 'NOTE: SampleDeprecatedClass.new is deprecated; '\
21
+ 'use SampleClass.new instead. It will be removed in or after version 1.0'
22
+ )
23
+ )
24
+ end
25
+
26
+ it 'does not raise an error for inherited error-namespaced classes but prints an error message' do
27
+ error_message, = with_warn_squelching { Class.new(SampleDeprecatedClass) }
28
+
29
+ expect(error_message).to match(
30
+ Regexp.new(
31
+ 'NOTE: Inheriting SampleDeprecatedClass is deprecated; '\
32
+ 'use SampleClass instead. It will be removed in or after version 1.0'
33
+ )
34
+ )
35
+ end
36
+
37
+ it 'allows backward-compatible class to be subclassed' do
38
+ expect {
39
+ with_warn_squelching { Class.new(SampleDeprecatedClass) }
40
+ }.not_to raise_error
41
+ end
42
+
43
+ it 'allows rescuing of a current error with a deprecated error' do
44
+ expect { raise SampleClass, nil }.to raise_error(SampleDeprecatedClass)
45
+ end
46
+
47
+ it 'allows rescuing of a current error with a current error' do
48
+ expect { raise SampleClass, nil }.to raise_error(SampleClass)
49
+ end
50
+
51
+ it 'allows rescuing of a deprecated error with a deprecated error' do
52
+ expect { raise SampleDeprecatedClass, nil }.to raise_error(SampleDeprecatedClass)
53
+ end
54
+
55
+ it 'allows rescuing of a deprecated error with a current error' do
56
+ expect { raise SampleDeprecatedClass, nil }.to raise_error(SampleClass)
57
+ end
58
+
59
+ describe 'match behavior' do
60
+ class SampleDeprecatedClassA < SampleDeprecatedClass; end
61
+ class SampleDeprecatedClassB < SampleDeprecatedClass; end
62
+
63
+ class SampleDeprecatedClassAX < SampleDeprecatedClassA; end
64
+
65
+ class SampleClassA < SampleClass; end
66
+
67
+ describe 'undeprecated class' do
68
+ it 'is === to instance of deprecated class' do
69
+ expect(SampleClass === SampleDeprecatedClass.new).to be true
70
+ end
71
+
72
+ it 'is === to instance of subclass of deprecated class' do
73
+ expect(SampleClass === SampleDeprecatedClassA.new).to be true
74
+ end
75
+
76
+ it 'is === to instance of subclass of subclass of deprecated class' do
77
+ expect(SampleClass === SampleDeprecatedClassAX.new).to be true
78
+ end
79
+ end
80
+
81
+ describe 'subclass of undeprecated class' do
82
+ it 'is not === to instance of undeprecated class' do
83
+ expect(SampleClassA === SampleClass.new).to be false
84
+ end
85
+
86
+ it 'is not === to instance of deprecated class' do
87
+ expect(SampleClassA === SampleDeprecatedClass.new).to be false
88
+ end
89
+ end
90
+
91
+ describe 'deprecated class' do
92
+ it 'is === to instance of undeprecated class' do
93
+ expect(SampleDeprecatedClass === SampleClass.new).to be true
94
+ end
95
+
96
+ it 'is === to instance of subclass of undeprecated class' do
97
+ expect(SampleDeprecatedClass === SampleClassA.new).to be true
98
+ end
99
+
100
+ it 'is === to instance of subclass of deprecated class' do
101
+ expect(SampleDeprecatedClass === SampleDeprecatedClassA.new).to be true
102
+ end
103
+
104
+ it 'is === to instance of subclass of subclass of deprecated class' do
105
+ expect(SampleDeprecatedClass === SampleDeprecatedClassAX.new).to be true
106
+ end
107
+ end
108
+
109
+ describe 'subclass of deprecated class' do
110
+ it 'is not === to instance of subclass of undeprecated class' do
111
+ expect(SampleDeprecatedClassA === SampleClass.new).to be false
112
+ end
113
+
114
+ it 'is not === to instance of another subclass of deprecated class' do
115
+ expect(SampleDeprecatedClassA === SampleDeprecatedClassB.new).to be false
116
+ end
117
+
118
+ it 'is === to instance of its subclass' do
119
+ expect(SampleDeprecatedClassA === SampleDeprecatedClassAX.new).to be true
120
+ end
121
+
122
+ it 'is === to instance of deprecated class' do
123
+ expect(SampleDeprecatedClass === SampleDeprecatedClassB.new).to be true
124
+ end
125
+ end
126
+
127
+ describe 'subclass of subclass of deprecated class' do
128
+ it 'is not === to instance of subclass of another subclass of deprecated class' do
129
+ expect(SampleDeprecatedClassAX === SampleDeprecatedClassB.new).to be false
130
+ end
131
+
132
+ it 'is not === to instance of its superclass' do
133
+ expect(SampleDeprecatedClassA === SampleDeprecatedClass.new).to be false
134
+ end
135
+ end
136
+ end
137
+
138
+ def with_warn_squelching
139
+ stderr_catcher = StringIO.new
140
+ original_stderr = $stderr
141
+ $stderr = stderr_catcher
142
+ result = yield if block_given?
143
+ [stderr_catcher.tap(&:rewind).string, result]
144
+ ensure
145
+ $stderr = original_stderr
146
+ end
147
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Faraday::ClientError do
4
+ describe '.initialize' do
5
+ subject { described_class.new(exception, response) }
6
+ let(:response) { nil }
7
+
8
+ context 'with exception only' do
9
+ let(:exception) { RuntimeError.new('test') }
10
+
11
+ it { expect(subject.wrapped_exception).to eq(exception) }
12
+ it { expect(subject.response).to be_nil }
13
+ it { expect(subject.message).to eq(exception.message) }
14
+ it { expect(subject.backtrace).to eq(exception.backtrace) }
15
+ it { expect(subject.inspect).to eq('#<Faraday::ClientError wrapped=#<RuntimeError: test>>') }
16
+ end
17
+
18
+ context 'with response hash' do
19
+ let(:exception) { { status: 400 } }
20
+
21
+ it { expect(subject.wrapped_exception).to be_nil }
22
+ it { expect(subject.response).to eq(exception) }
23
+ it { expect(subject.message).to eq('the server responded with status 400') }
24
+ it { expect(subject.inspect).to eq('#<Faraday::ClientError response={:status=>400}>') }
25
+ end
26
+
27
+ context 'with string' do
28
+ let(:exception) { 'custom message' }
29
+
30
+ it { expect(subject.wrapped_exception).to be_nil }
31
+ it { expect(subject.response).to be_nil }
32
+ it { expect(subject.message).to eq('custom message') }
33
+ it { expect(subject.inspect).to eq('#<Faraday::ClientError #<Faraday::ClientError: custom message>>') }
34
+ end
35
+
36
+ context 'with anything else #to_s' do
37
+ let(:exception) { %w[error1 error2] }
38
+
39
+ it { expect(subject.wrapped_exception).to be_nil }
40
+ it { expect(subject.response).to be_nil }
41
+ it { expect(subject.message).to eq('["error1", "error2"]') }
42
+ it { expect(subject.inspect).to eq('#<Faraday::ClientError #<Faraday::ClientError: ["error1", "error2"]>>') }
43
+ end
44
+
45
+ context 'maintains backward-compatibility until 1.0' do
46
+ it 'does not raise an error for error-namespaced classes but prints an error message' do
47
+ error_message, error = with_warn_squelching { Faraday::Error::ClientError.new('foo') }
48
+
49
+ expect(error).to be_a Faraday::ClientError
50
+ expect(error_message).to match(
51
+ Regexp.new(
52
+ 'NOTE: Faraday::Error::ClientError.new is deprecated; '\
53
+ 'use Faraday::ClientError.new instead. It will be removed in or after version 1.0'
54
+ )
55
+ )
56
+ end
57
+
58
+ it 'does not raise an error for inherited error-namespaced classes but prints an error message' do
59
+ error_message, = with_warn_squelching { Class.new(Faraday::Error::ClientError) }
60
+
61
+ expect(error_message).to match(
62
+ Regexp.new(
63
+ 'NOTE: Inheriting Faraday::Error::ClientError is deprecated; '\
64
+ 'use Faraday::ClientError instead. It will be removed in or after version 1.0'
65
+ )
66
+ )
67
+ end
68
+
69
+ it 'allows backward-compatible class to be subclassed' do
70
+ expect {
71
+ with_warn_squelching { Class.new(Faraday::Error::ClientError) }
72
+ }.not_to raise_error
73
+ end
74
+
75
+ it 'allows rescuing of a current error with a deprecated error' do
76
+ expect { raise Faraday::ClientError, nil }.to raise_error(Faraday::Error::ClientError)
77
+ end
78
+
79
+ it 'allows rescuing of a current error with a current error' do
80
+ expect { raise Faraday::ClientError, nil }.to raise_error(Faraday::ClientError)
81
+ end
82
+
83
+ it 'allows rescuing of a deprecated error with a deprecated error' do
84
+ expect { raise Faraday::Error::ClientError, nil }.to raise_error(Faraday::Error::ClientError)
85
+ end
86
+
87
+ it 'allows rescuing of a deprecated error with a current error' do
88
+ expect { raise Faraday::Error::ClientError, nil }.to raise_error(Faraday::ClientError)
89
+ end
90
+ end
91
+
92
+ def with_warn_squelching
93
+ stderr_catcher = StringIO.new
94
+ original_stderr = $stderr
95
+ $stderr = stderr_catcher
96
+ result = yield if block_given?
97
+ [stderr_catcher.tap(&:rewind).string, result]
98
+ ensure
99
+ $stderr = original_stderr
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Faraday::Response::RaiseError do
4
+ let(:conn) do
5
+ Faraday.new do |b|
6
+ b.response :raise_error
7
+ b.adapter :test do |stub|
8
+ stub.get('ok') { [200, { 'Content-Type' => 'text/html' }, '<body></body>'] }
9
+ stub.get('bad-request') { [400, { 'X-Reason' => 'because' }, 'keep looking'] }
10
+ stub.get('unauthorized') { [401, { 'X-Reason' => 'because' }, 'keep looking'] }
11
+ stub.get('forbidden') { [403, { 'X-Reason' => 'because' }, 'keep looking'] }
12
+ stub.get('not-found') { [404, { 'X-Reason' => 'because' }, 'keep looking'] }
13
+ stub.get('proxy-error') { [407, { 'X-Reason' => 'because' }, 'keep looking'] }
14
+ stub.get('conflict') { [409, { 'X-Reason' => 'because' }, 'keep looking'] }
15
+ stub.get('unprocessable-entity') { [422, { 'X-Reason' => 'because' }, 'keep looking'] }
16
+ stub.get('4xx') { [499, { 'X-Reason' => 'because' }, 'keep looking'] }
17
+ stub.get('nil-status') { [nil, { 'X-Reason' => 'nil' }, 'fail'] }
18
+ stub.get('server-error') { [500, { 'X-Error' => 'bailout' }, 'fail'] }
19
+ end
20
+ end
21
+ end
22
+
23
+ it 'raises no exception for 200 responses' do
24
+ expect { conn.get('ok') }.not_to raise_error
25
+ end
26
+
27
+ it 'raises Faraday::ClientError for 400 responses' do
28
+ expect { conn.get('bad-request') }.to raise_error(Faraday::ClientError) do |ex|
29
+ expect(ex.message).to eq('the server responded with status 400')
30
+ expect(ex.response[:headers]['X-Reason']).to eq('because')
31
+ expect(ex.response[:status]).to eq(400)
32
+ end
33
+ end
34
+
35
+ it 'raises Faraday::ClientError for 401 responses' do
36
+ expect { conn.get('unauthorized') }.to raise_error(Faraday::ClientError) do |ex|
37
+ expect(ex.message).to eq('the server responded with status 401')
38
+ expect(ex.response[:headers]['X-Reason']).to eq('because')
39
+ expect(ex.response[:status]).to eq(401)
40
+ end
41
+ end
42
+
43
+ it 'raises Faraday::ClientError for 403 responses' do
44
+ expect { conn.get('forbidden') }.to raise_error(Faraday::ClientError) do |ex|
45
+ expect(ex.message).to eq('the server responded with status 403')
46
+ expect(ex.response[:headers]['X-Reason']).to eq('because')
47
+ expect(ex.response[:status]).to eq(403)
48
+ end
49
+ end
50
+
51
+ it 'raises Faraday::ResourceNotFound for 404 responses' do
52
+ expect { conn.get('not-found') }.to raise_error(Faraday::ResourceNotFound) do |ex|
53
+ expect(ex.message).to eq('the server responded with status 404')
54
+ expect(ex.response[:headers]['X-Reason']).to eq('because')
55
+ expect(ex.response[:status]).to eq(404)
56
+ end
57
+ end
58
+
59
+ it 'raises Faraday::ConnectionFailed for 407 responses' do
60
+ expect { conn.get('proxy-error') }.to raise_error(Faraday::ConnectionFailed) do |ex|
61
+ expect(ex.message).to eq('407 "Proxy Authentication Required "')
62
+ expect(ex.response[:headers]['X-Reason']).to eq('because')
63
+ expect(ex.response[:status]).to eq(407)
64
+ end
65
+ end
66
+
67
+ it 'raises Faraday::ClientError for 409 responses' do
68
+ expect { conn.get('conflict') }.to raise_error(Faraday::ClientError) do |ex|
69
+ expect(ex.message).to eq('the server responded with status 409')
70
+ expect(ex.response[:headers]['X-Reason']).to eq('because')
71
+ expect(ex.response[:status]).to eq(409)
72
+ end
73
+ end
74
+
75
+ it 'raises Faraday::ClientError for 422 responses' do
76
+ expect { conn.get('unprocessable-entity') }.to raise_error(Faraday::ClientError) do |ex|
77
+ expect(ex.message).to eq('the server responded with status 422')
78
+ expect(ex.response[:headers]['X-Reason']).to eq('because')
79
+ expect(ex.response[:status]).to eq(422)
80
+ end
81
+ end
82
+
83
+ it 'raises Faraday::NilStatusError for nil status in response' do
84
+ expect { conn.get('nil-status') }.to raise_error(Faraday::NilStatusError) do |ex|
85
+ expect(ex.message).to eq('http status could not be derived from the server response')
86
+ expect(ex.response[:headers]['X-Reason']).to eq('nil')
87
+ expect(ex.response[:status]).to be_nil
88
+ end
89
+ end
90
+
91
+ it 'raises Faraday::ClientError for other 4xx responses' do
92
+ expect { conn.get('4xx') }.to raise_error(Faraday::ClientError) do |ex|
93
+ expect(ex.message).to eq('the server responded with status 499')
94
+ expect(ex.response[:headers]['X-Reason']).to eq('because')
95
+ expect(ex.response[:status]).to eq(499)
96
+ end
97
+ end
98
+
99
+ it 'raises Faraday::ClientError for 500 responses' do
100
+ expect { conn.get('server-error') }.to raise_error(Faraday::ClientError) do |ex|
101
+ expect(ex.message).to eq('the server responded with status 500')
102
+ expect(ex.response[:headers]['X-Error']).to eq('bailout')
103
+ expect(ex.response[:status]).to eq(500)
104
+ end
105
+ end
106
+ end