Skip to content

Commit

Permalink
Respect the params_encoder in Faraday::Adapter::Test (#1316)
Browse files Browse the repository at this point in the history
  • Loading branch information
yykamei authored and iMacTia committed Aug 30, 2021
1 parent dd1552f commit 0f9626c
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 45 deletions.
13 changes: 13 additions & 0 deletions examples/client_spec.rb
Expand Up @@ -81,4 +81,17 @@ def sushi(jname, params: {})
stubs.verify_stubbed_calls
end
end

context 'When the Faraday connection is configured with FlatParamsEncoder' do
let(:conn) { Faraday.new(request: { params_encoder: Faraday::FlatParamsEncoder }) { |b| b.adapter(:test, stubs) } }

it 'handles the same multiple URL parameters' do
stubs.get('/ebi?a=x&a=y&a=z') { [200, { 'Content-Type' => 'application/json' }, '{"name": "shrimp"}'] }

# uncomment to raise Stubs::NotFound
# expect(client.sushi('ebi', params: { a: %w[x y] })).to eq('shrimp')
expect(client.sushi('ebi', params: { a: %w[x y z] })).to eq('shrimp')
stubs.verify_stubbed_calls
end
end
end
43 changes: 41 additions & 2 deletions examples/client_test.rb
Expand Up @@ -13,8 +13,8 @@ def initialize(conn)
@conn = conn
end

def sushi(jname)
res = @conn.get("/#{jname}")
def sushi(jname, params: {})
res = @conn.get("/#{jname}", params)
data = JSON.parse(res.body)
data['name']
end
Expand Down Expand Up @@ -70,6 +70,45 @@ def test_sushi_exception
stubs.verify_stubbed_calls
end

def test_strict_mode
stubs = Faraday::Adapter::Test::Stubs.new(strict_mode: true)
stubs.get('/ebi?abc=123') do
[
200,
{ 'Content-Type': 'application/javascript' },
'{"name": "shrimp"}'
]
end

cli = client(stubs)
assert_equal 'shrimp', cli.sushi('ebi', params: { abc: 123 })

# uncomment to raise Stubs::NotFound
# assert_equal 'shrimp', cli.sushi('ebi', params: { abc: 123, foo: 'Kappa' })
stubs.verify_stubbed_calls
end

def test_non_default_params_encoder
stubs = Faraday::Adapter::Test::Stubs.new(strict_mode: true)
stubs.get('/ebi?a=x&a=y&a=z') do
[
200,
{ 'Content-Type': 'application/javascript' },
'{"name": "shrimp"}'
]
end
conn = Faraday.new(request: { params_encoder: Faraday::FlatParamsEncoder }) do |builder|
builder.adapter :test, stubs
end

cli = Client.new(conn)
assert_equal 'shrimp', cli.sushi('ebi', params: { a: %w[x y z] })

# uncomment to raise Stubs::NotFound
# assert_equal 'shrimp', cli.sushi('ebi', params: { a: %w[x y] })
stubs.verify_stubbed_calls
end

def client(stubs)
conn = Faraday.new do |builder|
builder.adapter :test, stubs
Expand Down
73 changes: 30 additions & 43 deletions lib/faraday/adapter/test.rb
Expand Up @@ -62,18 +62,20 @@ def empty?
@stack.empty?
end

def match(request_method, host, path, headers, body)
# @param env [Faraday::Env]
def match(env)
request_method = env[:method]
return false unless @stack.key?(request_method)

stack = @stack[request_method]
consumed = (@consumed[request_method] ||= [])

stub, meta = matches?(stack, host, path, headers, body)
stub, meta = matches?(stack, env)
if stub
consumed << stack.delete(stub)
return stub, meta
end
matches?(consumed, host, path, headers, body)
matches?(consumed, env)
end

def get(path, headers = {}, &block)
Expand Down Expand Up @@ -142,51 +144,39 @@ def new_stub(request_method, path, headers = {}, body = nil, &block)
Faraday::Utils.URI(path).host
]
end

path, query = normalized_path.respond_to?(:split) ? normalized_path.split('?') : normalized_path
headers = Utils::Headers.new(headers)
stub = Stub.new(host, normalized_path, headers, body, @strict_mode, block)

stub = Stub.new(host, path, query, headers, body, @strict_mode, block)
(@stack[request_method] ||= []) << stub
end

def matches?(stack, host, path, headers, body)
# @param stack [Hash]
# @param env [Faraday::Env]
def matches?(stack, env)
stack.each do |stub|
match_result, meta = stub.matches?(host, path, headers, body)
match_result, meta = stub.matches?(env)
return stub, meta if match_result
end
nil
end
end

# Stub request
# rubocop:disable Style/StructInheritance
class Stub < Struct.new(:host, :path, :params, :headers, :body, :strict_mode, :block)
# rubocop:enable Style/StructInheritance
def initialize(host, full, headers, body, strict_mode, block) # rubocop:disable Metrics/ParameterLists
path, query = full.respond_to?(:split) ? full.split('?') : full
params =
if query
Faraday::Utils.parse_nested_query(query)
else
{}
end
class Stub < Struct.new(:host, :path, :query, :headers, :body, :strict_mode, :block) # rubocop:disable Style/StructInheritance
# @param env [Faraday::Env]
def matches?(env)
request_host = env[:url].host
request_path = Faraday::Utils.normalize_path(env[:url].path)
request_headers = env.request_headers
request_body = env[:body]

super(host, path, params, headers, body, strict_mode, block)
end

def matches?(request_host, request_uri, request_headers, request_body)
request_path, request_query = request_uri.split('?')
request_params =
if request_query
Faraday::Utils.parse_nested_query(request_query)
else
{}
end
# meta is a hash used as carrier
# that will be yielded to consumer block
meta = {}
[(host.nil? || host == request_host) &&
path_match?(request_path, meta) &&
params_match?(request_params) &&
params_match?(env) &&
(body.to_s.size.zero? || request_body == body) &&
headers_match?(request_headers), meta]
end
Expand All @@ -199,7 +189,11 @@ def path_match?(request_path, meta)
end
end

def params_match?(request_params)
# @param env [Faraday::Env]
def params_match?(env)
request_params = env[:params]
params = env.params_encoder.decode(query) || {}

if strict_mode
return Set.new(params) == Set.new(request_params)
end
Expand Down Expand Up @@ -239,26 +233,19 @@ def configure
yield(stubs)
end

# @param env [Faraday::Env]
def call(env)
super
host = env[:url].host
normalized_path = Faraday::Utils.normalize_path(env[:url])
params_encoder = env.request.params_encoder ||
Faraday::Utils.default_params_encoder

stub, meta = stubs.match(env[:method], host, normalized_path,
env.request_headers, env[:body])
env.request.params_encoder ||= Faraday::Utils.default_params_encoder
env[:params] = env.params_encoder.decode(env[:url].query) || {}
stub, meta = stubs.match(env)

unless stub
raise Stubs::NotFound, "no stubbed request for #{env[:method]} "\
"#{normalized_path} #{env[:body]}"
"#{env[:url]} #{env[:body]}"
end

env[:params] = if (query = env[:url].query)
params_encoder.decode(query)
else
{}
end
block_arity = stub.block.arity
status, headers, body =
if block_arity >= 0
Expand Down
32 changes: 32 additions & 0 deletions spec/faraday/adapter/test_spec.rb
Expand Up @@ -258,6 +258,38 @@ def make_request
end
end

describe 'for request with non default params encoder' do
let(:connection) do
Faraday.new(request: { params_encoder: Faraday::FlatParamsEncoder }) do |builder|
builder.adapter :test, stubs
end
end
let(:stubs) do
described_class::Stubs.new do |stubs|
stubs.get('/path?a=x&a=y&a=z') { [200, {}, 'a'] }
end
end

context 'when all flat param values are correctly set' do
subject(:request) { connection.get('/path?a=x&a=y&a=z') }

it { expect(request.status).to eq 200 }
end

shared_examples 'raise NotFound when params do not satisfy the flat param values' do |params|
subject(:request) { connection.get('/path', params) }

context "with #{params.inspect}" do
it { expect { request }.to raise_error described_class::Stubs::NotFound }
end
end

it_behaves_like 'raise NotFound when params do not satisfy the flat param values', { a: %w[x] }
it_behaves_like 'raise NotFound when params do not satisfy the flat param values', { a: %w[x y] }
it_behaves_like 'raise NotFound when params do not satisfy the flat param values', { a: %w[x z y] } # NOTE: The order of the value is also compared.
it_behaves_like 'raise NotFound when params do not satisfy the flat param values', { b: %w[x y z] }
end

describe 'strict_mode' do
let(:stubs) do
described_class::Stubs.new(strict_mode: true) do |stubs|
Expand Down

0 comments on commit 0f9626c

Please sign in to comment.