faraday 0.15.4 → 0.17.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) 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/request.rb +2 -0
  19. data/lib/faraday/response/raise_error.rb +7 -3
  20. data/lib/faraday/response.rb +3 -3
  21. data/lib/faraday/upload_io.rb +16 -6
  22. data/lib/faraday.rb +2 -3
  23. data/spec/faraday/deprecate_spec.rb +147 -0
  24. data/spec/faraday/error_spec.rb +102 -0
  25. data/spec/faraday/response/raise_error_spec.rb +106 -0
  26. data/spec/spec_helper.rb +105 -0
  27. data/test/adapters/default_test.rb +14 -0
  28. data/test/adapters/em_http_test.rb +30 -0
  29. data/test/adapters/em_synchrony_test.rb +32 -0
  30. data/test/adapters/excon_test.rb +30 -0
  31. data/test/adapters/httpclient_test.rb +34 -0
  32. data/test/adapters/integration.rb +263 -0
  33. data/test/adapters/logger_test.rb +136 -0
  34. data/test/adapters/net_http_persistent_test.rb +114 -0
  35. data/test/adapters/net_http_test.rb +79 -0
  36. data/test/adapters/patron_test.rb +40 -0
  37. data/test/adapters/rack_test.rb +38 -0
  38. data/test/adapters/test_middleware_test.rb +157 -0
  39. data/test/adapters/typhoeus_test.rb +38 -0
  40. data/test/authentication_middleware_test.rb +65 -0
  41. data/test/composite_read_io_test.rb +109 -0
  42. data/test/connection_test.rb +738 -0
  43. data/test/env_test.rb +268 -0
  44. data/test/helper.rb +75 -0
  45. data/test/live_server.rb +67 -0
  46. data/test/middleware/instrumentation_test.rb +88 -0
  47. data/test/middleware/retry_test.rb +282 -0
  48. data/test/middleware_stack_test.rb +260 -0
  49. data/test/multibyte.txt +1 -0
  50. data/test/options_test.rb +333 -0
  51. data/test/parameters_test.rb +157 -0
  52. data/test/request_middleware_test.rb +126 -0
  53. data/test/response_middleware_test.rb +72 -0
  54. data/test/strawberry.rb +2 -0
  55. data/test/utils_test.rb +98 -0
  56. 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
@@ -12,6 +12,8 @@ module Faraday
12
12
  class Request < Struct.new(:method, :path, :params, :headers, :body, :options)
13
13
  extend MiddlewareRegistry
14
14
 
15
+ alias_method :http_method, :method
16
+
15
17
  register_middleware File.expand_path('../request', __FILE__),
16
18
  :url_encoded => [:UrlEncoded, 'url_encoded'],
17
19
  :multipart => [:Multipart, 'multipart'],
@@ -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
@@ -1,10 +1,15 @@
1
1
  begin
2
- require 'composite_io'
3
- require 'parts'
2
+ require 'multipart/post'
4
3
  require 'stringio'
5
4
  rescue LoadError
6
- $stderr.puts "Install the multipart-post gem."
7
- raise
5
+ begin
6
+ require 'composite_io'
7
+ require 'parts'
8
+ require 'stringio'
9
+ rescue LoadError
10
+ $stderr.puts "Install the multipart-post gem."
11
+ raise
12
+ end
8
13
  end
9
14
 
10
15
  module Faraday
@@ -62,6 +67,11 @@ module Faraday
62
67
  end
63
68
  end
64
69
 
65
- UploadIO = ::UploadIO
66
- Parts = ::Parts
70
+ if defined?(::Multipart::Post::UploadIO)
71
+ UploadIO = ::Multipart::Post::UploadIO
72
+ Parts = ::Multipart::Post::Parts
73
+ else
74
+ UploadIO = ::UploadIO
75
+ Parts = ::Parts
76
+ end
67
77
  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.6"
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