faraday 0.9.1 → 1.8.0
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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +360 -0
- data/LICENSE.md +1 -1
- data/README.md +28 -195
- data/Rakefile +4 -68
- data/examples/client_spec.rb +97 -0
- data/examples/client_test.rb +118 -0
- data/lib/faraday/adapter/test.rb +158 -58
- data/lib/faraday/adapter/typhoeus.rb +7 -115
- data/lib/faraday/adapter.rb +79 -20
- data/lib/faraday/adapter_registry.rb +30 -0
- data/lib/faraday/autoload.rb +39 -36
- data/lib/faraday/connection.rb +378 -168
- data/lib/faraday/dependency_loader.rb +37 -0
- data/lib/faraday/encoders/flat_params_encoder.rb +105 -0
- data/lib/faraday/encoders/nested_params_encoder.rb +176 -0
- data/lib/faraday/error.rb +128 -29
- data/lib/faraday/file_part.rb +128 -0
- data/lib/faraday/logging/formatter.rb +105 -0
- data/lib/faraday/methods.rb +6 -0
- data/lib/faraday/middleware.rb +19 -25
- data/lib/faraday/middleware_registry.rb +129 -0
- data/lib/faraday/options/connection_options.rb +22 -0
- data/lib/faraday/options/env.rb +181 -0
- data/lib/faraday/options/proxy_options.rb +32 -0
- data/lib/faraday/options/request_options.rb +22 -0
- data/lib/faraday/options/ssl_options.rb +59 -0
- data/lib/faraday/options.rb +61 -193
- data/lib/faraday/param_part.rb +53 -0
- data/lib/faraday/parameters.rb +4 -180
- data/lib/faraday/rack_builder.rb +84 -47
- data/lib/faraday/request/authorization.rb +51 -31
- data/lib/faraday/request/basic_authentication.rb +14 -7
- data/lib/faraday/request/instrumentation.rb +45 -27
- data/lib/faraday/request/multipart.rb +88 -45
- data/lib/faraday/request/retry.rb +212 -121
- data/lib/faraday/request/token_authentication.rb +15 -10
- data/lib/faraday/request/url_encoded.rb +43 -23
- data/lib/faraday/request.rb +96 -32
- data/lib/faraday/response/logger.rb +22 -48
- data/lib/faraday/response/raise_error.rb +49 -14
- data/lib/faraday/response.rb +33 -25
- data/lib/faraday/utils/headers.rb +139 -0
- data/lib/faraday/utils/params_hash.rb +61 -0
- data/lib/faraday/utils.rb +38 -218
- data/lib/faraday/version.rb +5 -0
- data/lib/faraday.rb +130 -213
- data/spec/external_adapters/faraday_specs_setup.rb +14 -0
- data/spec/faraday/adapter/em_http_spec.rb +49 -0
- data/spec/faraday/adapter/em_synchrony_spec.rb +18 -0
- data/spec/faraday/adapter/excon_spec.rb +49 -0
- data/spec/faraday/adapter/httpclient_spec.rb +73 -0
- data/spec/faraday/adapter/net_http_spec.rb +64 -0
- data/spec/faraday/adapter/patron_spec.rb +18 -0
- data/spec/faraday/adapter/rack_spec.rb +8 -0
- data/spec/faraday/adapter/test_spec.rb +377 -0
- data/spec/faraday/adapter/typhoeus_spec.rb +7 -0
- data/spec/faraday/adapter_registry_spec.rb +28 -0
- data/spec/faraday/adapter_spec.rb +55 -0
- data/spec/faraday/composite_read_io_spec.rb +80 -0
- data/spec/faraday/connection_spec.rb +736 -0
- data/spec/faraday/error_spec.rb +60 -0
- data/spec/faraday/middleware_spec.rb +52 -0
- data/spec/faraday/options/env_spec.rb +70 -0
- data/spec/faraday/options/options_spec.rb +297 -0
- data/spec/faraday/options/proxy_options_spec.rb +44 -0
- data/spec/faraday/options/request_options_spec.rb +19 -0
- data/spec/faraday/params_encoders/flat_spec.rb +42 -0
- data/spec/faraday/params_encoders/nested_spec.rb +142 -0
- data/spec/faraday/rack_builder_spec.rb +345 -0
- data/spec/faraday/request/authorization_spec.rb +96 -0
- data/spec/faraday/request/instrumentation_spec.rb +76 -0
- data/spec/faraday/request/multipart_spec.rb +302 -0
- data/spec/faraday/request/retry_spec.rb +242 -0
- data/spec/faraday/request/url_encoded_spec.rb +83 -0
- data/spec/faraday/request_spec.rb +120 -0
- data/spec/faraday/response/logger_spec.rb +220 -0
- data/spec/faraday/response/middleware_spec.rb +68 -0
- data/spec/faraday/response/raise_error_spec.rb +169 -0
- data/spec/faraday/response_spec.rb +75 -0
- data/spec/faraday/utils/headers_spec.rb +82 -0
- data/spec/faraday/utils_spec.rb +56 -0
- data/spec/faraday_spec.rb +37 -0
- data/spec/spec_helper.rb +132 -0
- data/spec/support/disabling_stub.rb +14 -0
- data/spec/support/fake_safe_buffer.rb +15 -0
- data/spec/support/helper_methods.rb +133 -0
- data/spec/support/shared_examples/adapter.rb +105 -0
- data/spec/support/shared_examples/params_encoder.rb +18 -0
- data/spec/support/shared_examples/request_method.rb +262 -0
- data/spec/support/streaming_response_checker.rb +35 -0
- data/spec/support/webmock_rack_app.rb +68 -0
- metadata +199 -98
- data/.document +0 -6
- data/CONTRIBUTING.md +0 -36
- data/Gemfile +0 -25
- data/faraday.gemspec +0 -34
- data/lib/faraday/adapter/em_http.rb +0 -237
- data/lib/faraday/adapter/em_http_ssl_patch.rb +0 -56
- data/lib/faraday/adapter/em_synchrony/parallel_manager.rb +0 -66
- data/lib/faraday/adapter/em_synchrony.rb +0 -92
- data/lib/faraday/adapter/excon.rb +0 -80
- data/lib/faraday/adapter/httpclient.rb +0 -106
- data/lib/faraday/adapter/net_http.rb +0 -130
- data/lib/faraday/adapter/net_http_persistent.rb +0 -48
- data/lib/faraday/adapter/patron.rb +0 -72
- data/lib/faraday/adapter/rack.rb +0 -58
- data/lib/faraday/upload_io.rb +0 -67
- data/script/cached-bundle +0 -46
- data/script/console +0 -7
- data/script/generate_certs +0 -42
- data/script/package +0 -7
- data/script/proxy-server +0 -42
- data/script/release +0 -17
- data/script/s3-put +0 -71
- data/script/server +0 -36
- data/script/test +0 -172
- data/test/adapters/default_test.rb +0 -14
- data/test/adapters/em_http_test.rb +0 -20
- data/test/adapters/em_synchrony_test.rb +0 -20
- data/test/adapters/excon_test.rb +0 -20
- data/test/adapters/httpclient_test.rb +0 -21
- data/test/adapters/integration.rb +0 -254
- data/test/adapters/logger_test.rb +0 -82
- data/test/adapters/net_http_persistent_test.rb +0 -20
- data/test/adapters/net_http_test.rb +0 -14
- data/test/adapters/patron_test.rb +0 -20
- data/test/adapters/rack_test.rb +0 -31
- data/test/adapters/test_middleware_test.rb +0 -114
- data/test/adapters/typhoeus_test.rb +0 -28
- data/test/authentication_middleware_test.rb +0 -65
- data/test/composite_read_io_test.rb +0 -111
- data/test/connection_test.rb +0 -522
- data/test/env_test.rb +0 -218
- data/test/helper.rb +0 -81
- data/test/live_server.rb +0 -67
- data/test/middleware/instrumentation_test.rb +0 -88
- data/test/middleware/retry_test.rb +0 -177
- data/test/middleware_stack_test.rb +0 -173
- data/test/multibyte.txt +0 -1
- data/test/options_test.rb +0 -252
- data/test/parameters_test.rb +0 -64
- data/test/request_middleware_test.rb +0 -142
- data/test/response_middleware_test.rb +0 -72
- data/test/strawberry.rb +0 -2
- data/test/utils_test.rb +0 -58
data/Rakefile
CHANGED
@@ -1,71 +1,7 @@
|
|
1
|
-
|
2
|
-
require 'fileutils'
|
3
|
-
require 'openssl'
|
4
|
-
require 'rake/testtask'
|
5
|
-
require 'bundler'
|
6
|
-
Bundler::GemHelper.install_tasks
|
1
|
+
# frozen_string_literal: true
|
7
2
|
|
8
|
-
|
3
|
+
require 'rspec/core/rake_task'
|
9
4
|
|
10
|
-
|
5
|
+
RSpec::Core::RakeTask.new(:spec)
|
11
6
|
|
12
|
-
|
13
|
-
@name ||= Dir['*.gemspec'].first.split('.').first
|
14
|
-
end
|
15
|
-
|
16
|
-
def version
|
17
|
-
line = File.read("lib/#{name}.rb")[/^\s*VERSION\s*=\s*.*/]
|
18
|
-
line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
|
19
|
-
end
|
20
|
-
|
21
|
-
def gemspec_file
|
22
|
-
"#{name}.gemspec"
|
23
|
-
end
|
24
|
-
|
25
|
-
def gem_file
|
26
|
-
"#{name}-#{version}.gem"
|
27
|
-
end
|
28
|
-
|
29
|
-
def replace_header(head, header_name)
|
30
|
-
head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
|
31
|
-
end
|
32
|
-
|
33
|
-
# Adapted from WEBrick::Utils. Skips cert extensions so it
|
34
|
-
# can be used as a CA bundle
|
35
|
-
def create_self_signed_cert(bits, cn, comment)
|
36
|
-
rsa = OpenSSL::PKey::RSA.new(bits)
|
37
|
-
cert = OpenSSL::X509::Certificate.new
|
38
|
-
cert.version = 2
|
39
|
-
cert.serial = 1
|
40
|
-
name = OpenSSL::X509::Name.new(cn)
|
41
|
-
cert.subject = name
|
42
|
-
cert.issuer = name
|
43
|
-
cert.not_before = Time.now
|
44
|
-
cert.not_after = Time.now + (365*24*60*60)
|
45
|
-
cert.public_key = rsa.public_key
|
46
|
-
cert.sign(rsa, OpenSSL::Digest::SHA1.new)
|
47
|
-
return [cert, rsa]
|
48
|
-
end
|
49
|
-
|
50
|
-
## standard tasks
|
51
|
-
|
52
|
-
desc "Run all tests"
|
53
|
-
task :test do
|
54
|
-
exec 'script/test'
|
55
|
-
end
|
56
|
-
|
57
|
-
desc "Generate certificates for SSL tests"
|
58
|
-
task :'test:generate_certs' do
|
59
|
-
cert, key = create_self_signed_cert(1024, [['CN', 'localhost']], 'Faraday Test CA')
|
60
|
-
FileUtils.mkdir_p 'tmp'
|
61
|
-
File.open('tmp/faraday-cert.key', 'w') {|f| f.puts(key) }
|
62
|
-
File.open('tmp/faraday-cert.crt', 'w') {|f| f.puts(cert.to_s) }
|
63
|
-
end
|
64
|
-
|
65
|
-
file 'tmp/faraday-cert.key' => :'test:generate_certs'
|
66
|
-
file 'tmp/faraday-cert.crt' => :'test:generate_certs'
|
67
|
-
|
68
|
-
desc "Open an irb session preloaded with this library"
|
69
|
-
task :console do
|
70
|
-
sh "irb -rubygems -r ./lib/#{name}.rb"
|
71
|
-
end
|
7
|
+
task default: :spec
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Requires Ruby with rspec and faraday gems.
|
4
|
+
# rspec client_spec.rb
|
5
|
+
|
6
|
+
require 'faraday'
|
7
|
+
require 'json'
|
8
|
+
|
9
|
+
# Example API client
|
10
|
+
class Client
|
11
|
+
def initialize(conn)
|
12
|
+
@conn = conn
|
13
|
+
end
|
14
|
+
|
15
|
+
def sushi(jname, params: {})
|
16
|
+
res = @conn.get("/#{jname}", params)
|
17
|
+
data = JSON.parse(res.body)
|
18
|
+
data['name']
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
RSpec.describe Client do
|
23
|
+
let(:stubs) { Faraday::Adapter::Test::Stubs.new }
|
24
|
+
let(:conn) { Faraday.new { |b| b.adapter(:test, stubs) } }
|
25
|
+
let(:client) { Client.new(conn) }
|
26
|
+
|
27
|
+
it 'parses name' do
|
28
|
+
stubs.get('/ebi') do |env|
|
29
|
+
# optional: you can inspect the Faraday::Env
|
30
|
+
expect(env.url.path).to eq('/ebi')
|
31
|
+
[
|
32
|
+
200,
|
33
|
+
{ 'Content-Type': 'application/javascript' },
|
34
|
+
'{"name": "shrimp"}'
|
35
|
+
]
|
36
|
+
end
|
37
|
+
|
38
|
+
# uncomment to trigger stubs.verify_stubbed_calls failure
|
39
|
+
# stubs.get('/unused') { [404, {}, ''] }
|
40
|
+
|
41
|
+
expect(client.sushi('ebi')).to eq('shrimp')
|
42
|
+
stubs.verify_stubbed_calls
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'handles 404' do
|
46
|
+
stubs.get('/ebi') do
|
47
|
+
[
|
48
|
+
404,
|
49
|
+
{ 'Content-Type': 'application/javascript' },
|
50
|
+
'{}'
|
51
|
+
]
|
52
|
+
end
|
53
|
+
expect(client.sushi('ebi')).to be_nil
|
54
|
+
stubs.verify_stubbed_calls
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'handles exception' do
|
58
|
+
stubs.get('/ebi') do
|
59
|
+
raise Faraday::ConnectionFailed, nil
|
60
|
+
end
|
61
|
+
|
62
|
+
expect { client.sushi('ebi') }.to raise_error(Faraday::ConnectionFailed)
|
63
|
+
stubs.verify_stubbed_calls
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'When the test stub is run in strict_mode' do
|
67
|
+
let(:stubs) { Faraday::Adapter::Test::Stubs.new(strict_mode: true) }
|
68
|
+
|
69
|
+
it 'verifies the all parameter values are identical' do
|
70
|
+
stubs.get('/ebi?abc=123') do
|
71
|
+
[
|
72
|
+
200,
|
73
|
+
{ 'Content-Type': 'application/javascript' },
|
74
|
+
'{"name": "shrimp"}'
|
75
|
+
]
|
76
|
+
end
|
77
|
+
|
78
|
+
# uncomment to raise Stubs::NotFound
|
79
|
+
# expect(client.sushi('ebi', params: { abc: 123, foo: 'Kappa' })).to eq('shrimp')
|
80
|
+
expect(client.sushi('ebi', params: { abc: 123 })).to eq('shrimp')
|
81
|
+
stubs.verify_stubbed_calls
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'When the Faraday connection is configured with FlatParamsEncoder' do
|
86
|
+
let(:conn) { Faraday.new(request: { params_encoder: Faraday::FlatParamsEncoder }) { |b| b.adapter(:test, stubs) } }
|
87
|
+
|
88
|
+
it 'handles the same multiple URL parameters' do
|
89
|
+
stubs.get('/ebi?a=x&a=y&a=z') { [200, { 'Content-Type' => 'application/json' }, '{"name": "shrimp"}'] }
|
90
|
+
|
91
|
+
# uncomment to raise Stubs::NotFound
|
92
|
+
# expect(client.sushi('ebi', params: { a: %w[x y] })).to eq('shrimp')
|
93
|
+
expect(client.sushi('ebi', params: { a: %w[x y z] })).to eq('shrimp')
|
94
|
+
stubs.verify_stubbed_calls
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Requires Ruby with test-unit and faraday gems.
|
4
|
+
# ruby client_test.rb
|
5
|
+
|
6
|
+
require 'faraday'
|
7
|
+
require 'json'
|
8
|
+
require 'test/unit'
|
9
|
+
|
10
|
+
# Example API client
|
11
|
+
class Client
|
12
|
+
def initialize(conn)
|
13
|
+
@conn = conn
|
14
|
+
end
|
15
|
+
|
16
|
+
def sushi(jname, params: {})
|
17
|
+
res = @conn.get("/#{jname}", params)
|
18
|
+
data = JSON.parse(res.body)
|
19
|
+
data['name']
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Example API client test
|
24
|
+
class ClientTest < Test::Unit::TestCase
|
25
|
+
def test_sushi_name
|
26
|
+
stubs = Faraday::Adapter::Test::Stubs.new
|
27
|
+
stubs.get('/ebi') do |env|
|
28
|
+
# optional: you can inspect the Faraday::Env
|
29
|
+
assert_equal '/ebi', env.url.path
|
30
|
+
[
|
31
|
+
200,
|
32
|
+
{ 'Content-Type': 'application/javascript' },
|
33
|
+
'{"name": "shrimp"}'
|
34
|
+
]
|
35
|
+
end
|
36
|
+
|
37
|
+
# uncomment to trigger stubs.verify_stubbed_calls failure
|
38
|
+
# stubs.get('/unused') { [404, {}, ''] }
|
39
|
+
|
40
|
+
cli = client(stubs)
|
41
|
+
assert_equal 'shrimp', cli.sushi('ebi')
|
42
|
+
stubs.verify_stubbed_calls
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_sushi_404
|
46
|
+
stubs = Faraday::Adapter::Test::Stubs.new
|
47
|
+
stubs.get('/ebi') do
|
48
|
+
[
|
49
|
+
404,
|
50
|
+
{ 'Content-Type': 'application/javascript' },
|
51
|
+
'{}'
|
52
|
+
]
|
53
|
+
end
|
54
|
+
|
55
|
+
cli = client(stubs)
|
56
|
+
assert_nil cli.sushi('ebi')
|
57
|
+
stubs.verify_stubbed_calls
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_sushi_exception
|
61
|
+
stubs = Faraday::Adapter::Test::Stubs.new
|
62
|
+
stubs.get('/ebi') do
|
63
|
+
raise Faraday::ConnectionFailed, nil
|
64
|
+
end
|
65
|
+
|
66
|
+
cli = client(stubs)
|
67
|
+
assert_raise Faraday::ConnectionFailed do
|
68
|
+
cli.sushi('ebi')
|
69
|
+
end
|
70
|
+
stubs.verify_stubbed_calls
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_strict_mode
|
74
|
+
stubs = Faraday::Adapter::Test::Stubs.new(strict_mode: true)
|
75
|
+
stubs.get('/ebi?abc=123') do
|
76
|
+
[
|
77
|
+
200,
|
78
|
+
{ 'Content-Type': 'application/javascript' },
|
79
|
+
'{"name": "shrimp"}'
|
80
|
+
]
|
81
|
+
end
|
82
|
+
|
83
|
+
cli = client(stubs)
|
84
|
+
assert_equal 'shrimp', cli.sushi('ebi', params: { abc: 123 })
|
85
|
+
|
86
|
+
# uncomment to raise Stubs::NotFound
|
87
|
+
# assert_equal 'shrimp', cli.sushi('ebi', params: { abc: 123, foo: 'Kappa' })
|
88
|
+
stubs.verify_stubbed_calls
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_non_default_params_encoder
|
92
|
+
stubs = Faraday::Adapter::Test::Stubs.new(strict_mode: true)
|
93
|
+
stubs.get('/ebi?a=x&a=y&a=z') do
|
94
|
+
[
|
95
|
+
200,
|
96
|
+
{ 'Content-Type': 'application/javascript' },
|
97
|
+
'{"name": "shrimp"}'
|
98
|
+
]
|
99
|
+
end
|
100
|
+
conn = Faraday.new(request: { params_encoder: Faraday::FlatParamsEncoder }) do |builder|
|
101
|
+
builder.adapter :test, stubs
|
102
|
+
end
|
103
|
+
|
104
|
+
cli = Client.new(conn)
|
105
|
+
assert_equal 'shrimp', cli.sushi('ebi', params: { a: %w[x y z] })
|
106
|
+
|
107
|
+
# uncomment to raise Stubs::NotFound
|
108
|
+
# assert_equal 'shrimp', cli.sushi('ebi', params: { a: %w[x y] })
|
109
|
+
stubs.verify_stubbed_calls
|
110
|
+
end
|
111
|
+
|
112
|
+
def client(stubs)
|
113
|
+
conn = Faraday.new do |builder|
|
114
|
+
builder.adapter :test, stubs
|
115
|
+
end
|
116
|
+
Client.new(conn)
|
117
|
+
end
|
118
|
+
end
|
data/lib/faraday/adapter/test.rb
CHANGED
@@ -1,26 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Faraday
|
2
4
|
class Adapter
|
3
|
-
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
5
|
+
# @example
|
6
|
+
# test = Faraday::Connection.new do
|
7
|
+
# use Faraday::Adapter::Test do |stub|
|
8
|
+
# # Define matcher to match the request
|
9
|
+
# stub.get '/resource.json' do
|
10
|
+
# # return static content
|
11
|
+
# [200, {'Content-Type' => 'application/json'}, 'hi world']
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# # response with content generated based on request
|
15
|
+
# stub.get '/showget' do |env|
|
16
|
+
# [200, {'Content-Type' => 'text/plain'}, env[:method].to_s]
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# # A regular expression can be used as matching filter
|
20
|
+
# stub.get /\A\/items\/(\d+)\z/ do |env, meta|
|
21
|
+
# # in case regular expression is used, an instance of MatchData
|
22
|
+
# # can be received
|
23
|
+
# [200,
|
24
|
+
# {'Content-Type' => 'text/plain'},
|
25
|
+
# "showing item: #{meta[:match_data][1]}"
|
26
|
+
# ]
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# # You can set strict_mode to exactly match the stubbed requests.
|
30
|
+
# stub.strict_mode = true
|
7
31
|
# end
|
8
32
|
# end
|
9
|
-
# end
|
10
33
|
#
|
11
|
-
#
|
12
|
-
#
|
34
|
+
# resp = test.get '/resource.json'
|
35
|
+
# resp.body # => 'hi world'
|
13
36
|
#
|
37
|
+
# resp = test.get '/showget'
|
38
|
+
# resp.body # => 'get'
|
39
|
+
#
|
40
|
+
# resp = test.get '/items/1'
|
41
|
+
# resp.body # => 'showing item: 1'
|
42
|
+
#
|
43
|
+
# resp = test.get '/items/2'
|
44
|
+
# resp.body # => 'showing item: 2'
|
14
45
|
class Test < Faraday::Adapter
|
15
46
|
attr_accessor :stubs
|
16
47
|
|
48
|
+
# A stack of Stubs
|
17
49
|
class Stubs
|
18
50
|
class NotFound < StandardError
|
19
51
|
end
|
20
52
|
|
21
|
-
def initialize
|
22
|
-
# {:
|
23
|
-
@stack
|
53
|
+
def initialize(strict_mode: false)
|
54
|
+
# { get: [Stub, Stub] }
|
55
|
+
@stack = {}
|
56
|
+
@consumed = {}
|
57
|
+
@strict_mode = strict_mode
|
24
58
|
yield(self) if block_given?
|
25
59
|
end
|
26
60
|
|
@@ -28,17 +62,20 @@ module Faraday
|
|
28
62
|
@stack.empty?
|
29
63
|
end
|
30
64
|
|
31
|
-
|
32
|
-
|
65
|
+
# @param env [Faraday::Env]
|
66
|
+
def match(env)
|
67
|
+
request_method = env[:method]
|
68
|
+
return false unless @stack.key?(request_method)
|
69
|
+
|
33
70
|
stack = @stack[request_method]
|
34
71
|
consumed = (@consumed[request_method] ||= [])
|
35
72
|
|
36
|
-
|
73
|
+
stub, meta = matches?(stack, env)
|
74
|
+
if stub
|
37
75
|
consumed << stack.delete(stub)
|
38
|
-
stub
|
39
|
-
else
|
40
|
-
matches?(consumed, path, headers, body)
|
76
|
+
return stub, meta
|
41
77
|
end
|
78
|
+
matches?(consumed, env)
|
42
79
|
end
|
43
80
|
|
44
81
|
def get(path, headers = {}, &block)
|
@@ -49,15 +86,15 @@ module Faraday
|
|
49
86
|
new_stub(:head, path, headers, &block)
|
50
87
|
end
|
51
88
|
|
52
|
-
def post(path, body=nil, headers = {}, &block)
|
89
|
+
def post(path, body = nil, headers = {}, &block)
|
53
90
|
new_stub(:post, path, headers, body, &block)
|
54
91
|
end
|
55
92
|
|
56
|
-
def put(path, body=nil, headers = {}, &block)
|
93
|
+
def put(path, body = nil, headers = {}, &block)
|
57
94
|
new_stub(:put, path, headers, body, &block)
|
58
95
|
end
|
59
96
|
|
60
|
-
def patch(path, body=nil, headers = {}, &block)
|
97
|
+
def patch(path, body = nil, headers = {}, &block)
|
61
98
|
new_stub(:patch, path, headers, body, &block)
|
62
99
|
end
|
63
100
|
|
@@ -73,54 +110,109 @@ module Faraday
|
|
73
110
|
def verify_stubbed_calls
|
74
111
|
failed_stubs = []
|
75
112
|
@stack.each do |method, stubs|
|
76
|
-
|
77
|
-
|
113
|
+
next if stubs.empty?
|
114
|
+
|
115
|
+
failed_stubs.concat(
|
116
|
+
stubs.map do |stub|
|
78
117
|
"Expected #{method} #{stub}."
|
79
|
-
|
118
|
+
end
|
119
|
+
)
|
120
|
+
end
|
121
|
+
raise failed_stubs.join(' ') unless failed_stubs.empty?
|
122
|
+
end
|
123
|
+
|
124
|
+
# Set strict_mode. If the value is true, this adapter tries to find matched requests strictly,
|
125
|
+
# which means that all of a path, parameters, and headers must be the same as an actual request.
|
126
|
+
def strict_mode=(value)
|
127
|
+
@strict_mode = value
|
128
|
+
@stack.each do |_method, stubs|
|
129
|
+
stubs.each do |stub|
|
130
|
+
stub.strict_mode = value
|
80
131
|
end
|
81
132
|
end
|
82
|
-
raise failed_stubs.join(" ") unless failed_stubs.size == 0
|
83
133
|
end
|
84
134
|
|
85
135
|
protected
|
86
136
|
|
87
|
-
def new_stub(request_method, path, headers = {}, body=nil, &block)
|
88
|
-
normalized_path =
|
89
|
-
|
137
|
+
def new_stub(request_method, path, headers = {}, body = nil, &block)
|
138
|
+
normalized_path, host =
|
139
|
+
if path.is_a?(Regexp)
|
140
|
+
path
|
141
|
+
else
|
142
|
+
[
|
143
|
+
Faraday::Utils.normalize_path(path),
|
144
|
+
Faraday::Utils.URI(path).host
|
145
|
+
]
|
146
|
+
end
|
147
|
+
path, query = normalized_path.respond_to?(:split) ? normalized_path.split('?') : normalized_path
|
148
|
+
headers = Utils::Headers.new(headers)
|
149
|
+
|
150
|
+
stub = Stub.new(host, path, query, headers, body, @strict_mode, block)
|
151
|
+
(@stack[request_method] ||= []) << stub
|
90
152
|
end
|
91
153
|
|
92
|
-
|
93
|
-
|
154
|
+
# @param stack [Hash]
|
155
|
+
# @param env [Faraday::Env]
|
156
|
+
def matches?(stack, env)
|
157
|
+
stack.each do |stub|
|
158
|
+
match_result, meta = stub.matches?(env)
|
159
|
+
return stub, meta if match_result
|
160
|
+
end
|
161
|
+
nil
|
94
162
|
end
|
95
163
|
end
|
96
164
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
params_match?(request_params) &&
|
165
|
+
# Stub request
|
166
|
+
class Stub < Struct.new(:host, :path, :query, :headers, :body, :strict_mode, :block) # rubocop:disable Style/StructInheritance
|
167
|
+
# @param env [Faraday::Env]
|
168
|
+
def matches?(env)
|
169
|
+
request_host = env[:url].host
|
170
|
+
request_path = Faraday::Utils.normalize_path(env[:url].path)
|
171
|
+
request_headers = env.request_headers
|
172
|
+
request_body = env[:body]
|
173
|
+
|
174
|
+
# meta is a hash used as carrier
|
175
|
+
# that will be yielded to consumer block
|
176
|
+
meta = {}
|
177
|
+
[(host.nil? || host == request_host) &&
|
178
|
+
path_match?(request_path, meta) &&
|
179
|
+
params_match?(env) &&
|
113
180
|
(body.to_s.size.zero? || request_body == body) &&
|
114
|
-
headers_match?(request_headers)
|
181
|
+
headers_match?(request_headers), meta]
|
115
182
|
end
|
116
183
|
|
117
|
-
def
|
184
|
+
def path_match?(request_path, meta)
|
185
|
+
if path.is_a?(Regexp)
|
186
|
+
!!(meta[:match_data] = path.match(request_path))
|
187
|
+
else
|
188
|
+
path == request_path
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
# @param env [Faraday::Env]
|
193
|
+
def params_match?(env)
|
194
|
+
request_params = env[:params]
|
195
|
+
params = env.params_encoder.decode(query) || {}
|
196
|
+
|
197
|
+
if strict_mode
|
198
|
+
return Set.new(params) == Set.new(request_params)
|
199
|
+
end
|
200
|
+
|
118
201
|
params.keys.all? do |key|
|
119
202
|
request_params[key] == params[key]
|
120
203
|
end
|
121
204
|
end
|
122
205
|
|
123
206
|
def headers_match?(request_headers)
|
207
|
+
if strict_mode
|
208
|
+
headers_with_user_agent = headers.dup.tap do |hs|
|
209
|
+
# NOTE: Set User-Agent in case it's not set when creating Stubs.
|
210
|
+
# Users would not want to set Faraday's User-Agent explicitly.
|
211
|
+
hs[:user_agent] ||= Connection::USER_AGENT
|
212
|
+
end
|
213
|
+
return Set.new(headers_with_user_agent) == Set.new(request_headers)
|
214
|
+
end
|
215
|
+
|
124
216
|
headers.keys.all? do |key|
|
125
217
|
request_headers[key] == headers[key]
|
126
218
|
end
|
@@ -131,7 +223,7 @@ module Faraday
|
|
131
223
|
end
|
132
224
|
end
|
133
225
|
|
134
|
-
def initialize(app, stubs=nil, &block)
|
226
|
+
def initialize(app, stubs = nil, &block)
|
135
227
|
super(app)
|
136
228
|
@stubs = stubs || Stubs.new
|
137
229
|
configure(&block) if block
|
@@ -141,20 +233,28 @@ module Faraday
|
|
141
233
|
yield(stubs)
|
142
234
|
end
|
143
235
|
|
236
|
+
# @param env [Faraday::Env]
|
144
237
|
def call(env)
|
145
238
|
super
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
save_response(env, status, body, headers)
|
155
|
-
else
|
156
|
-
raise Stubs::NotFound, "no stubbed request for #{env[:method]} #{normalized_path} #{env[:body]}"
|
239
|
+
|
240
|
+
env.request.params_encoder ||= Faraday::Utils.default_params_encoder
|
241
|
+
env[:params] = env.params_encoder.decode(env[:url].query) || {}
|
242
|
+
stub, meta = stubs.match(env)
|
243
|
+
|
244
|
+
unless stub
|
245
|
+
raise Stubs::NotFound, "no stubbed request for #{env[:method]} "\
|
246
|
+
"#{env[:url]} #{env[:body]}"
|
157
247
|
end
|
248
|
+
|
249
|
+
block_arity = stub.block.arity
|
250
|
+
status, headers, body =
|
251
|
+
if block_arity >= 0
|
252
|
+
stub.block.call(*[env, meta].take(block_arity))
|
253
|
+
else
|
254
|
+
stub.block.call(env, meta)
|
255
|
+
end
|
256
|
+
save_response(env, status, body, headers)
|
257
|
+
|
158
258
|
@app.call(env)
|
159
259
|
end
|
160
260
|
end
|