nano-sharp-sys 0.0.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 (78) hide show
  1. checksums.yaml +7 -0
  2. data/faraday-2.14.3/CHANGELOG.md +574 -0
  3. data/faraday-2.14.3/LICENSE.md +20 -0
  4. data/faraday-2.14.3/README.md +67 -0
  5. data/faraday-2.14.3/Rakefile +12 -0
  6. data/faraday-2.14.3/examples/client_spec.rb +119 -0
  7. data/faraday-2.14.3/examples/client_test.rb +144 -0
  8. data/faraday-2.14.3/lib/faraday/adapter/test.rb +319 -0
  9. data/faraday-2.14.3/lib/faraday/adapter.rb +102 -0
  10. data/faraday-2.14.3/lib/faraday/adapter_registry.rb +30 -0
  11. data/faraday-2.14.3/lib/faraday/connection.rb +567 -0
  12. data/faraday-2.14.3/lib/faraday/encoders/flat_params_encoder.rb +106 -0
  13. data/faraday-2.14.3/lib/faraday/encoders/nested_params_encoder.rb +193 -0
  14. data/faraday-2.14.3/lib/faraday/error.rb +202 -0
  15. data/faraday-2.14.3/lib/faraday/logging/formatter.rb +118 -0
  16. data/faraday-2.14.3/lib/faraday/methods.rb +6 -0
  17. data/faraday-2.14.3/lib/faraday/middleware.rb +72 -0
  18. data/faraday-2.14.3/lib/faraday/middleware_registry.rb +83 -0
  19. data/faraday-2.14.3/lib/faraday/options/connection_options.rb +23 -0
  20. data/faraday-2.14.3/lib/faraday/options/env.rb +204 -0
  21. data/faraday-2.14.3/lib/faraday/options/proxy_options.rb +39 -0
  22. data/faraday-2.14.3/lib/faraday/options/request_options.rb +23 -0
  23. data/faraday-2.14.3/lib/faraday/options/ssl_options.rb +76 -0
  24. data/faraday-2.14.3/lib/faraday/options.rb +219 -0
  25. data/faraday-2.14.3/lib/faraday/parameters.rb +5 -0
  26. data/faraday-2.14.3/lib/faraday/rack_builder.rb +248 -0
  27. data/faraday-2.14.3/lib/faraday/request/authorization.rb +54 -0
  28. data/faraday-2.14.3/lib/faraday/request/instrumentation.rb +58 -0
  29. data/faraday-2.14.3/lib/faraday/request/json.rb +70 -0
  30. data/faraday-2.14.3/lib/faraday/request/url_encoded.rb +60 -0
  31. data/faraday-2.14.3/lib/faraday/request.rb +139 -0
  32. data/faraday-2.14.3/lib/faraday/response/json.rb +74 -0
  33. data/faraday-2.14.3/lib/faraday/response/logger.rb +39 -0
  34. data/faraday-2.14.3/lib/faraday/response/raise_error.rb +83 -0
  35. data/faraday-2.14.3/lib/faraday/response.rb +95 -0
  36. data/faraday-2.14.3/lib/faraday/utils/headers.rb +150 -0
  37. data/faraday-2.14.3/lib/faraday/utils/params_hash.rb +61 -0
  38. data/faraday-2.14.3/lib/faraday/utils.rb +121 -0
  39. data/faraday-2.14.3/lib/faraday/version.rb +5 -0
  40. data/faraday-2.14.3/lib/faraday.rb +158 -0
  41. data/faraday-2.14.3/spec/external_adapters/faraday_specs_setup.rb +14 -0
  42. data/faraday-2.14.3/spec/faraday/adapter/test_spec.rb +460 -0
  43. data/faraday-2.14.3/spec/faraday/adapter_registry_spec.rb +28 -0
  44. data/faraday-2.14.3/spec/faraday/adapter_spec.rb +55 -0
  45. data/faraday-2.14.3/spec/faraday/connection_spec.rb +860 -0
  46. data/faraday-2.14.3/spec/faraday/error_spec.rb +175 -0
  47. data/faraday-2.14.3/spec/faraday/middleware_registry_spec.rb +31 -0
  48. data/faraday-2.14.3/spec/faraday/middleware_spec.rb +213 -0
  49. data/faraday-2.14.3/spec/faraday/options/env_spec.rb +76 -0
  50. data/faraday-2.14.3/spec/faraday/options/options_spec.rb +297 -0
  51. data/faraday-2.14.3/spec/faraday/options/proxy_options_spec.rb +79 -0
  52. data/faraday-2.14.3/spec/faraday/options/request_options_spec.rb +19 -0
  53. data/faraday-2.14.3/spec/faraday/params_encoders/flat_spec.rb +42 -0
  54. data/faraday-2.14.3/spec/faraday/params_encoders/nested_spec.rb +179 -0
  55. data/faraday-2.14.3/spec/faraday/rack_builder_spec.rb +317 -0
  56. data/faraday-2.14.3/spec/faraday/request/authorization_spec.rb +118 -0
  57. data/faraday-2.14.3/spec/faraday/request/instrumentation_spec.rb +74 -0
  58. data/faraday-2.14.3/spec/faraday/request/json_spec.rb +199 -0
  59. data/faraday-2.14.3/spec/faraday/request/url_encoded_spec.rb +93 -0
  60. data/faraday-2.14.3/spec/faraday/request_spec.rb +119 -0
  61. data/faraday-2.14.3/spec/faraday/response/json_spec.rb +206 -0
  62. data/faraday-2.14.3/spec/faraday/response/logger_spec.rb +299 -0
  63. data/faraday-2.14.3/spec/faraday/response/raise_error_spec.rb +286 -0
  64. data/faraday-2.14.3/spec/faraday/response_spec.rb +84 -0
  65. data/faraday-2.14.3/spec/faraday/utils/headers_spec.rb +109 -0
  66. data/faraday-2.14.3/spec/faraday/utils_spec.rb +120 -0
  67. data/faraday-2.14.3/spec/faraday_spec.rb +43 -0
  68. data/faraday-2.14.3/spec/spec_helper.rb +133 -0
  69. data/faraday-2.14.3/spec/support/disabling_stub.rb +14 -0
  70. data/faraday-2.14.3/spec/support/fake_safe_buffer.rb +15 -0
  71. data/faraday-2.14.3/spec/support/faraday_middleware_subclasses.rb +18 -0
  72. data/faraday-2.14.3/spec/support/helper_methods.rb +96 -0
  73. data/faraday-2.14.3/spec/support/shared_examples/adapter.rb +105 -0
  74. data/faraday-2.14.3/spec/support/shared_examples/params_encoder.rb +18 -0
  75. data/faraday-2.14.3/spec/support/shared_examples/request_method.rb +263 -0
  76. data/faraday-2.14.3/spec/support/streaming_response_checker.rb +35 -0
  77. data/nano-sharp-sys.gemspec +12 -0
  78. metadata +117 -0
@@ -0,0 +1,299 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'stringio'
4
+ require 'logger'
5
+
6
+ RSpec.describe Faraday::Response::Logger do
7
+ let(:string_io) { StringIO.new }
8
+ let(:logger) { Logger.new(string_io) }
9
+ let(:logger_options) { {} }
10
+ let(:conn) do
11
+ rubbles = ['Barney', 'Betty', 'Bam Bam']
12
+
13
+ Faraday.new do |b|
14
+ b.response :logger, logger, logger_options do |logger|
15
+ logger.filter(/(soylent green is) (.+)/, '\1 tasty')
16
+ logger.filter(/(api_key:).*"(.+)."/, '\1[API_KEY]')
17
+ logger.filter(/(password)=(.+)/, '\1=[HIDDEN]')
18
+ end
19
+ b.adapter :test do |stubs|
20
+ stubs.get('/hello') { [200, { 'Content-Type' => 'text/html' }, 'hello'] }
21
+ stubs.post('/ohai') { [200, { 'Content-Type' => 'text/html' }, 'fred'] }
22
+ stubs.post('/ohyes') { [200, { 'Content-Type' => 'text/html' }, 'pebbles'] }
23
+ stubs.get('/rubbles') { [200, { 'Content-Type' => 'application/json' }, rubbles] }
24
+ stubs.get('/8bit') { [200, { 'Content-Type' => 'text/html' }, (+'café!').force_encoding(Encoding::ASCII_8BIT)] }
25
+ stubs.get('/filtered_body') { [200, { 'Content-Type' => 'text/html' }, 'soylent green is people'] }
26
+ stubs.get('/filtered_headers') { [200, { 'Content-Type' => 'text/html' }, 'headers response'] }
27
+ stubs.get('/filtered_params') { [200, { 'Content-Type' => 'text/html' }, 'params response'] }
28
+ stubs.get('/filtered_url') { [200, { 'Content-Type' => 'text/html' }, 'url response'] }
29
+ stubs.get('/connection_failed') { raise Faraday::ConnectionFailed, 'Failed to open TCP connection' }
30
+ end
31
+ end
32
+ end
33
+
34
+ before do
35
+ logger.level = Logger::DEBUG
36
+ end
37
+
38
+ it 'still returns output' do
39
+ resp = conn.get '/hello', nil, accept: 'text/html'
40
+ expect(resp.body).to eq('hello')
41
+ end
42
+
43
+ context 'without configuration' do
44
+ let(:conn) do
45
+ Faraday.new do |b|
46
+ b.response :logger
47
+ b.adapter :test do |stubs|
48
+ stubs.get('/hello') { [200, { 'Content-Type' => 'text/html' }, 'hello'] }
49
+ end
50
+ end
51
+ end
52
+
53
+ it 'defaults to stdout' do
54
+ expect(Logger).to receive(:new).with($stdout).and_return(Logger.new(nil))
55
+ conn.get('/hello')
56
+ end
57
+ end
58
+
59
+ context 'when logger with program name' do
60
+ let(:logger) { Logger.new(string_io, progname: 'my_best_program') }
61
+
62
+ it 'logs with program name' do
63
+ conn.get '/hello'
64
+
65
+ expect(string_io.string).to match('-- my_best_program: request:')
66
+ expect(string_io.string).to match('-- my_best_program: response:')
67
+ end
68
+ end
69
+
70
+ context 'when logger without program name' do
71
+ it 'logs without program name' do
72
+ conn.get '/hello'
73
+
74
+ expect(string_io.string).to match('-- : request:')
75
+ expect(string_io.string).to match('-- : response:')
76
+ end
77
+ end
78
+
79
+ context 'with default formatter' do
80
+ let(:formatter) { instance_double(Faraday::Logging::Formatter, request: true, response: true, filter: []) }
81
+
82
+ before { allow(Faraday::Logging::Formatter).to receive(:new).and_return(formatter) }
83
+
84
+ it 'delegates logging to the formatter' do
85
+ expect(formatter).to receive(:request).with(an_instance_of(Faraday::Env))
86
+ expect(formatter).to receive(:response).with(an_instance_of(Faraday::Env))
87
+ conn.get '/hello'
88
+ end
89
+
90
+ context 'when no route' do
91
+ it 'delegates logging to the formatter' do
92
+ expect(formatter).to receive(:request).with(an_instance_of(Faraday::Env))
93
+ expect(formatter).to receive(:exception).with(an_instance_of(Faraday::Adapter::Test::Stubs::NotFound))
94
+
95
+ expect { conn.get '/noroute' }.to raise_error(Faraday::Adapter::Test::Stubs::NotFound)
96
+ end
97
+ end
98
+ end
99
+
100
+ context 'with custom formatter' do
101
+ let(:formatter_class) do
102
+ Class.new(Faraday::Logging::Formatter) do
103
+ def request(_env)
104
+ info 'Custom log formatter request'
105
+ end
106
+
107
+ def response(_env)
108
+ info 'Custom log formatter response'
109
+ end
110
+ end
111
+ end
112
+
113
+ let(:logger_options) { { formatter: formatter_class } }
114
+
115
+ it 'logs with custom formatter' do
116
+ conn.get '/hello'
117
+
118
+ expect(string_io.string).to match('Custom log formatter request')
119
+ expect(string_io.string).to match('Custom log formatter response')
120
+ end
121
+ end
122
+
123
+ it 'logs method and url' do
124
+ conn.get '/hello', nil, accept: 'text/html'
125
+ expect(string_io.string).to match('GET http:/hello')
126
+ end
127
+
128
+ it 'logs status' do
129
+ conn.get '/hello', nil, accept: 'text/html'
130
+ expect(string_io.string).to match('Status 200')
131
+ end
132
+
133
+ it 'does not log error message by default' do
134
+ expect { conn.get '/noroute' }.to raise_error(Faraday::Adapter::Test::Stubs::NotFound)
135
+ expect(string_io.string).not_to match(%(no stubbed request for get http:/noroute))
136
+ end
137
+
138
+ it 'logs request headers by default' do
139
+ conn.get '/hello', nil, accept: 'text/html'
140
+ expect(string_io.string).to match(%(Accept: "text/html))
141
+ end
142
+
143
+ it 'logs response headers by default' do
144
+ conn.get '/hello', nil, accept: 'text/html'
145
+ expect(string_io.string).to match(%(Content-Type: "text/html))
146
+ end
147
+
148
+ it 'does not log request body by default' do
149
+ conn.post '/ohai', 'name=Unagi', accept: 'text/html'
150
+ expect(string_io.string).not_to match(%(name=Unagi))
151
+ end
152
+
153
+ it 'does not log response body by default' do
154
+ conn.post '/ohai', 'name=Toro', accept: 'text/html'
155
+ expect(string_io.string).not_to match(%(fred))
156
+ end
157
+
158
+ it 'logs filter headers' do
159
+ conn.headers = { 'api_key' => 'ABC123' }
160
+ conn.get '/filtered_headers', nil, accept: 'text/html'
161
+ expect(string_io.string).to match(%(api_key:))
162
+ expect(string_io.string).to match(%([API_KEY]))
163
+ expect(string_io.string).not_to match(%(ABC123))
164
+ end
165
+
166
+ it 'logs filter url' do
167
+ conn.get '/filtered_url?password=hunter2', nil, accept: 'text/html'
168
+ expect(string_io.string).to match(%([HIDDEN]))
169
+ expect(string_io.string).not_to match(%(hunter2))
170
+ end
171
+
172
+ context 'when not logging request headers' do
173
+ let(:logger_options) { { headers: { request: false } } }
174
+
175
+ it 'does not log request headers if option is false' do
176
+ conn.get '/hello', nil, accept: 'text/html'
177
+ expect(string_io.string).not_to match(%(Accept: "text/html))
178
+ end
179
+ end
180
+
181
+ context 'when not logging response headers' do
182
+ let(:logger_options) { { headers: { response: false } } }
183
+
184
+ it 'does not log response headers if option is false' do
185
+ conn.get '/hello', nil, accept: 'text/html'
186
+ expect(string_io.string).not_to match(%(Content-Type: "text/html))
187
+ end
188
+ end
189
+
190
+ context 'when logging request body' do
191
+ let(:logger_options) { { bodies: { request: true } } }
192
+
193
+ it 'logs only request body' do
194
+ conn.post '/ohyes', 'name=Tamago', accept: 'text/html'
195
+ expect(string_io.string).to match(%(name=Tamago))
196
+ expect(string_io.string).not_to match(%(pebbles))
197
+ end
198
+ end
199
+
200
+ context 'when logging response body' do
201
+ let(:logger_options) { { bodies: { response: true } } }
202
+
203
+ it 'logs only response body' do
204
+ conn.post '/ohyes', 'name=Hamachi', accept: 'text/html'
205
+ expect(string_io.string).to match(%(pebbles))
206
+ expect(string_io.string).not_to match(%(name=Hamachi))
207
+ end
208
+ end
209
+
210
+ context 'when logging request and response bodies' do
211
+ let(:logger_options) { { bodies: true } }
212
+
213
+ it 'logs request and response body' do
214
+ conn.post '/ohyes', 'name=Ebi', accept: 'text/html'
215
+ expect(string_io.string).to match(%(name=Ebi))
216
+ expect(string_io.string).to match(%(pebbles))
217
+ end
218
+
219
+ it 'logs response body object' do
220
+ conn.get '/rubbles', nil, accept: 'text/html'
221
+ expect(string_io.string).to match(%(["Barney", "Betty", "Bam Bam"]\n))
222
+ end
223
+
224
+ it 'logs filter body' do
225
+ conn.get '/filtered_body', nil, accept: 'text/html'
226
+ expect(string_io.string).to match(%(soylent green is))
227
+ expect(string_io.string).to match(%(tasty))
228
+ expect(string_io.string).not_to match(%(people))
229
+ end
230
+ end
231
+
232
+ context 'when bodies are logged by default' do
233
+ before do
234
+ described_class.default_options = { bodies: true }
235
+ end
236
+
237
+ it 'logs response body' do
238
+ conn.post '/ohai'
239
+ expect(string_io.string).to match(%(fred))
240
+ end
241
+
242
+ it 'converts to UTF-8' do
243
+ conn.get '/8bit'
244
+ expect(string_io.string).to match(%(caf��!))
245
+ end
246
+
247
+ after do
248
+ described_class.default_options = { bodies: false }
249
+ end
250
+ end
251
+
252
+ context 'when logging errors' do
253
+ let(:logger_options) { { errors: true } }
254
+
255
+ it 'logs error message' do
256
+ expect { conn.get '/noroute' }.to raise_error(Faraday::Adapter::Test::Stubs::NotFound)
257
+ expect(string_io.string).to match(%(no stubbed request for get http:/noroute))
258
+ end
259
+ end
260
+
261
+ context 'when logging headers and errors' do
262
+ let(:logger_options) { { headers: true, errors: true } }
263
+
264
+ it 'logs error message' do
265
+ expect { conn.get '/connection_failed' }.to raise_error(Faraday::ConnectionFailed)
266
+ expect(string_io.string).to match(%(Failed to open TCP connection))
267
+ end
268
+ end
269
+
270
+ context 'when using log_level' do
271
+ let(:logger_options) { { bodies: true, log_level: :debug } }
272
+
273
+ it 'logs request/request body on the specified level (debug)' do
274
+ logger.level = Logger::DEBUG
275
+ conn.post '/ohyes', 'name=Ebi', accept: 'text/html'
276
+ expect(string_io.string).to match(%(name=Ebi))
277
+ expect(string_io.string).to match(%(pebbles))
278
+ end
279
+
280
+ it 'logs headers on the debug level' do
281
+ logger.level = Logger::DEBUG
282
+ conn.get '/hello', nil, accept: 'text/html'
283
+ expect(string_io.string).to match(%(Content-Type: "text/html))
284
+ end
285
+
286
+ it 'does not log request/response body on the info level' do
287
+ logger.level = Logger::INFO
288
+ conn.post '/ohyes', 'name=Ebi', accept: 'text/html'
289
+ expect(string_io.string).not_to match(%(name=Ebi))
290
+ expect(string_io.string).not_to match(%(pebbles))
291
+ end
292
+
293
+ it 'does not log headers on the info level' do
294
+ logger.level = Logger::INFO
295
+ conn.get '/hello', nil, accept: 'text/html'
296
+ expect(string_io.string).not_to match(%(Content-Type: "text/html))
297
+ end
298
+ end
299
+ end
@@ -0,0 +1,286 @@
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('request-timeout') { [408, { 'X-Reason' => 'because' }, 'keep looking'] }
15
+ stub.get('conflict') { [409, { 'X-Reason' => 'because' }, 'keep looking'] }
16
+ stub.get('unprocessable-content') { [422, { 'X-Reason' => 'because' }, 'keep looking'] }
17
+ stub.get('too-many-requests') { [429, { 'X-Reason' => 'because' }, 'keep looking'] }
18
+ stub.get('4xx') { [499, { 'X-Reason' => 'because' }, 'keep looking'] }
19
+ stub.get('nil-status') { [nil, { 'X-Reason' => 'nil' }, 'fail'] }
20
+ stub.get('server-error') { [500, { 'X-Error' => 'bailout' }, 'fail'] }
21
+ end
22
+ end
23
+ end
24
+
25
+ it 'raises no exception for 200 responses' do
26
+ expect { conn.get('ok') }.not_to raise_error
27
+ end
28
+
29
+ it 'raises Faraday::BadRequestError for 400 responses' do
30
+ expect { conn.get('bad-request') }.to raise_error(Faraday::BadRequestError) do |ex|
31
+ expect(ex.message).to eq('the server responded with status 400 for GET http:/bad-request')
32
+ expect(ex.response[:headers]['X-Reason']).to eq('because')
33
+ expect(ex.response[:status]).to eq(400)
34
+ expect(ex.response_status).to eq(400)
35
+ expect(ex.response_body).to eq('keep looking')
36
+ expect(ex.response_headers['X-Reason']).to eq('because')
37
+ end
38
+ end
39
+
40
+ it 'raises Faraday::UnauthorizedError for 401 responses' do
41
+ expect { conn.get('unauthorized') }.to raise_error(Faraday::UnauthorizedError) do |ex|
42
+ expect(ex.message).to eq('the server responded with status 401 for GET http:/unauthorized')
43
+ expect(ex.response[:headers]['X-Reason']).to eq('because')
44
+ expect(ex.response[:status]).to eq(401)
45
+ expect(ex.response_status).to eq(401)
46
+ expect(ex.response_body).to eq('keep looking')
47
+ expect(ex.response_headers['X-Reason']).to eq('because')
48
+ end
49
+ end
50
+
51
+ it 'raises Faraday::ForbiddenError for 403 responses' do
52
+ expect { conn.get('forbidden') }.to raise_error(Faraday::ForbiddenError) do |ex|
53
+ expect(ex.message).to eq('the server responded with status 403 for GET http:/forbidden')
54
+ expect(ex.response[:headers]['X-Reason']).to eq('because')
55
+ expect(ex.response[:status]).to eq(403)
56
+ expect(ex.response_status).to eq(403)
57
+ expect(ex.response_body).to eq('keep looking')
58
+ expect(ex.response_headers['X-Reason']).to eq('because')
59
+ end
60
+ end
61
+
62
+ it 'raises Faraday::ResourceNotFound for 404 responses' do
63
+ expect { conn.get('not-found') }.to raise_error(Faraday::ResourceNotFound) do |ex|
64
+ expect(ex.message).to eq('the server responded with status 404 for GET http:/not-found')
65
+ expect(ex.response[:headers]['X-Reason']).to eq('because')
66
+ expect(ex.response[:status]).to eq(404)
67
+ expect(ex.response_status).to eq(404)
68
+ expect(ex.response_body).to eq('keep looking')
69
+ expect(ex.response_headers['X-Reason']).to eq('because')
70
+ end
71
+ end
72
+
73
+ it 'raises Faraday::ProxyAuthError for 407 responses' do
74
+ expect { conn.get('proxy-error') }.to raise_error(Faraday::ProxyAuthError) do |ex|
75
+ expect(ex.message).to eq('407 "Proxy Authentication Required"')
76
+ expect(ex.response[:headers]['X-Reason']).to eq('because')
77
+ expect(ex.response[:status]).to eq(407)
78
+ expect(ex.response_status).to eq(407)
79
+ expect(ex.response_body).to eq('keep looking')
80
+ expect(ex.response_headers['X-Reason']).to eq('because')
81
+ end
82
+ end
83
+
84
+ it 'raises Faraday::RequestTimeoutError for 408 responses' do
85
+ expect { conn.get('request-timeout') }.to raise_error(Faraday::RequestTimeoutError) do |ex|
86
+ expect(ex.message).to eq('the server responded with status 408 for GET http:/request-timeout')
87
+ expect(ex.response[:headers]['X-Reason']).to eq('because')
88
+ expect(ex.response[:status]).to eq(408)
89
+ expect(ex.response_status).to eq(408)
90
+ expect(ex.response_body).to eq('keep looking')
91
+ expect(ex.response_headers['X-Reason']).to eq('because')
92
+ end
93
+ end
94
+
95
+ it 'raises Faraday::ConflictError for 409 responses' do
96
+ expect { conn.get('conflict') }.to raise_error(Faraday::ConflictError) do |ex|
97
+ expect(ex.message).to eq('the server responded with status 409 for GET http:/conflict')
98
+ expect(ex.response[:headers]['X-Reason']).to eq('because')
99
+ expect(ex.response[:status]).to eq(409)
100
+ expect(ex.response_status).to eq(409)
101
+ expect(ex.response_body).to eq('keep looking')
102
+ expect(ex.response_headers['X-Reason']).to eq('because')
103
+ end
104
+ end
105
+
106
+ it 'raises legacy Faraday::UnprocessableEntityError for 422 responses' do
107
+ expect { conn.get('unprocessable-content') }.to raise_error(Faraday::UnprocessableEntityError) do |ex|
108
+ expect(ex.message).to eq('the server responded with status 422 for GET http:/unprocessable-content')
109
+ expect(ex.response[:headers]['X-Reason']).to eq('because')
110
+ expect(ex.response[:status]).to eq(422)
111
+ expect(ex.response_status).to eq(422)
112
+ expect(ex.response_body).to eq('keep looking')
113
+ expect(ex.response_headers['X-Reason']).to eq('because')
114
+ end
115
+ end
116
+
117
+ it 'raises Faraday::UnprocessableContentError for 422 responses' do
118
+ expect { conn.get('unprocessable-content') }.to raise_error(Faraday::UnprocessableContentError) do |ex|
119
+ expect(ex.message).to eq('the server responded with status 422 for GET http:/unprocessable-content')
120
+ expect(ex.response[:headers]['X-Reason']).to eq('because')
121
+ expect(ex.response[:status]).to eq(422)
122
+ expect(ex.response_status).to eq(422)
123
+ expect(ex.response_body).to eq('keep looking')
124
+ expect(ex.response_headers['X-Reason']).to eq('because')
125
+ end
126
+ end
127
+
128
+ it 'raises Faraday::TooManyRequestsError for 429 responses' do
129
+ expect { conn.get('too-many-requests') }.to raise_error(Faraday::TooManyRequestsError) do |ex|
130
+ expect(ex.message).to eq('the server responded with status 429 for GET http:/too-many-requests')
131
+ expect(ex.response[:headers]['X-Reason']).to eq('because')
132
+ expect(ex.response[:status]).to eq(429)
133
+ expect(ex.response_status).to eq(429)
134
+ expect(ex.response_body).to eq('keep looking')
135
+ expect(ex.response_headers['X-Reason']).to eq('because')
136
+ end
137
+ end
138
+
139
+ it 'raises Faraday::NilStatusError for nil status in response' do
140
+ expect { conn.get('nil-status') }.to raise_error(Faraday::NilStatusError) do |ex|
141
+ expect(ex.message).to eq('http status could not be derived from the server response')
142
+ expect(ex.response[:headers]['X-Reason']).to eq('nil')
143
+ expect(ex.response[:status]).to be_nil
144
+ expect(ex.response_status).to be_nil
145
+ expect(ex.response_body).to eq('fail')
146
+ expect(ex.response_headers['X-Reason']).to eq('nil')
147
+ end
148
+ end
149
+
150
+ it 'raises Faraday::ClientError for other 4xx responses' do
151
+ expect { conn.get('4xx') }.to raise_error(Faraday::ClientError) do |ex|
152
+ expect(ex.message).to eq('the server responded with status 499 for GET http:/4xx')
153
+ expect(ex.response[:headers]['X-Reason']).to eq('because')
154
+ expect(ex.response[:status]).to eq(499)
155
+ expect(ex.response_status).to eq(499)
156
+ expect(ex.response_body).to eq('keep looking')
157
+ expect(ex.response_headers['X-Reason']).to eq('because')
158
+ end
159
+ end
160
+
161
+ it 'raises Faraday::ServerError for 500 responses' do
162
+ expect { conn.get('server-error') }.to raise_error(Faraday::ServerError) do |ex|
163
+ expect(ex.message).to eq('the server responded with status 500 for GET http:/server-error')
164
+ expect(ex.response[:headers]['X-Error']).to eq('bailout')
165
+ expect(ex.response[:status]).to eq(500)
166
+ expect(ex.response_status).to eq(500)
167
+ expect(ex.response_body).to eq('fail')
168
+ expect(ex.response_headers['X-Error']).to eq('bailout')
169
+ end
170
+ end
171
+
172
+ describe 'request info' do
173
+ let(:conn) do
174
+ Faraday.new do |b|
175
+ b.response :raise_error, **middleware_options
176
+ b.adapter :test do |stub|
177
+ stub.post(url, request_body, request_headers) do
178
+ [400, { 'X-Reason' => 'because' }, 'keep looking']
179
+ end
180
+ end
181
+ end
182
+ end
183
+ let(:middleware_options) { {} }
184
+ let(:request_body) { JSON.generate({ 'item' => 'sth' }) }
185
+ let(:request_headers) { { 'Authorization' => 'Basic 123' } }
186
+ let(:url_path) { 'request' }
187
+ let(:query_params) { 'full=true' }
188
+ let(:url) { "#{url_path}?#{query_params}" }
189
+
190
+ subject(:perform_request) do
191
+ conn.post url do |req|
192
+ req.headers['Authorization'] = 'Basic 123'
193
+ req.body = request_body
194
+ end
195
+ end
196
+
197
+ it 'returns the request info in the exception' do
198
+ expect { perform_request }.to raise_error(Faraday::BadRequestError) do |ex|
199
+ expect(ex.response[:request][:method]).to eq(:post)
200
+ expect(ex.response[:request][:url]).to eq(URI("http:/#{url}"))
201
+ expect(ex.response[:request][:url_path]).to eq("/#{url_path}")
202
+ expect(ex.response[:request][:params]).to eq({ 'full' => 'true' })
203
+ expect(ex.response[:request][:headers]).to match(a_hash_including(request_headers))
204
+ expect(ex.response[:request][:body]).to eq(request_body)
205
+ end
206
+ end
207
+
208
+ describe 'DEFAULT_OPTION: include_request' do
209
+ before(:each) do
210
+ Faraday::Response::RaiseError.instance_variable_set(:@default_options, nil)
211
+ Faraday::Middleware.instance_variable_set(:@default_options, nil)
212
+ end
213
+
214
+ after(:all) do
215
+ Faraday::Response::RaiseError.instance_variable_set(:@default_options, nil)
216
+ Faraday::Middleware.instance_variable_set(:@default_options, nil)
217
+ end
218
+
219
+ context 'when RaiseError DEFAULT_OPTION (include_request: true) is used' do
220
+ it 'includes request info in the exception' do
221
+ expect { perform_request }.to raise_error(Faraday::BadRequestError) do |ex|
222
+ expect(ex.response.keys).to contain_exactly(
223
+ :status,
224
+ :headers,
225
+ :body,
226
+ :request
227
+ )
228
+ end
229
+ end
230
+ end
231
+
232
+ context 'when application sets default_options `include_request: false`' do
233
+ before(:each) do
234
+ Faraday::Response::RaiseError.default_options = { include_request: false }
235
+ end
236
+
237
+ context 'and when include_request option is omitted' do
238
+ it 'does not include request info in the exception' do
239
+ expect { perform_request }.to raise_error(Faraday::BadRequestError) do |ex|
240
+ expect(ex.response.keys).to contain_exactly(
241
+ :status,
242
+ :headers,
243
+ :body
244
+ )
245
+ end
246
+ end
247
+ end
248
+
249
+ context 'and when include_request option is explicitly set for instance' do
250
+ let(:middleware_options) { { include_request: true } }
251
+
252
+ it 'includes request info in the exception' do
253
+ expect { perform_request }.to raise_error(Faraday::BadRequestError) do |ex|
254
+ expect(ex.response.keys).to contain_exactly(
255
+ :status,
256
+ :headers,
257
+ :body,
258
+ :request
259
+ )
260
+ end
261
+ end
262
+ end
263
+ end
264
+ end
265
+ end
266
+
267
+ describe 'allowing certain status codes' do
268
+ let(:conn) do
269
+ Faraday.new do |b|
270
+ b.response :raise_error, allowed_statuses: [404]
271
+ b.adapter :test do |stub|
272
+ stub.get('bad-request') { [400, { 'X-Reason' => 'because' }, 'keep looking'] }
273
+ stub.get('not-found') { [404, { 'X-Reason' => 'because' }, 'keep looking'] }
274
+ end
275
+ end
276
+ end
277
+
278
+ it 'raises an error for status codes that are not explicitly allowed' do
279
+ expect { conn.get('bad-request') }.to raise_error(Faraday::BadRequestError)
280
+ end
281
+
282
+ it 'does not raise an error for allowed status codes' do
283
+ expect { conn.get('not-found') }.not_to raise_error
284
+ end
285
+ end
286
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Faraday::Response do
4
+ subject { Faraday::Response.new(env) }
5
+
6
+ let(:env) do
7
+ Faraday::Env.from(status: 404, body: 'yikes', url: Faraday::Utils.URI('https://lostisland.github.io/faraday'),
8
+ response_headers: { 'Content-Type' => 'text/plain' })
9
+ end
10
+
11
+ it { expect(subject.finished?).to be_truthy }
12
+ it { expect { subject.finish({}) }.to raise_error(RuntimeError) }
13
+ it { expect(subject.success?).to be_falsey }
14
+ it { expect(subject.status).to eq(404) }
15
+ it { expect(subject.body).to eq('yikes') }
16
+ it { expect(subject.url).to eq(URI('https://lostisland.github.io/faraday')) }
17
+ it { expect(subject.headers['Content-Type']).to eq('text/plain') }
18
+ it { expect(subject['content-type']).to eq('text/plain') }
19
+
20
+ describe '#apply_request' do
21
+ before { subject.apply_request(body: 'a=b', method: :post) }
22
+
23
+ it { expect(subject.body).to eq('yikes') }
24
+ it { expect(subject.env[:method]).to eq(:post) }
25
+ end
26
+
27
+ describe '#to_hash' do
28
+ let(:hash) { subject.to_hash }
29
+
30
+ it { expect(hash).to be_a(Hash) }
31
+ it { expect(hash[:status]).to eq(subject.status) }
32
+ it { expect(hash[:response_headers]).to eq(subject.headers) }
33
+ it { expect(hash[:body]).to eq(subject.body) }
34
+ it { expect(hash[:url]).to eq(subject.env.url) }
35
+
36
+ context 'when response is not finished' do
37
+ subject { Faraday::Response.new.to_hash }
38
+
39
+ it { is_expected.to eq({ status: nil, body: nil, response_headers: {}, url: nil }) }
40
+ end
41
+ end
42
+
43
+ describe 'marshal serialization support' do
44
+ subject { Faraday::Response.new }
45
+ let(:loaded) { Marshal.load(Marshal.dump(subject)) }
46
+
47
+ before do
48
+ subject.on_complete {}
49
+ subject.finish(env.merge(params: 'moo'))
50
+ end
51
+
52
+ it { expect(loaded.env[:params]).to be_nil }
53
+ it { expect(loaded.env[:body]).to eq(env[:body]) }
54
+ it { expect(loaded.env[:response_headers]).to eq(env[:response_headers]) }
55
+ it { expect(loaded.env[:status]).to eq(env[:status]) }
56
+ it { expect(loaded.env[:url]).to eq(env[:url]) }
57
+ end
58
+
59
+ describe '#on_complete' do
60
+ subject { Faraday::Response.new }
61
+
62
+ it 'parse body on finish' do
63
+ subject.on_complete { |env| env[:body] = env[:body].upcase }
64
+ subject.finish(env)
65
+
66
+ expect(subject.body).to eq('YIKES')
67
+ end
68
+
69
+ it 'can access response body in on_complete callback' do
70
+ subject.on_complete { |env| env[:body] = subject.body.upcase }
71
+ subject.finish(env)
72
+
73
+ expect(subject.body).to eq('YIKES')
74
+ end
75
+
76
+ it 'can access response body in on_complete callback' do
77
+ callback_env = nil
78
+ subject.on_complete { |env| callback_env = env }
79
+ subject.finish({})
80
+
81
+ expect(subject.env).to eq(callback_env)
82
+ end
83
+ end
84
+ end