1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
|
# frozen_string_literal: true
begin
require 'excon'
rescue LoadError
# excon not found
end
if defined?(Excon)
WebMock::VersionChecker.new('Excon', Excon::VERSION, '0.27.5').check_version!
module WebMock
module HttpLibAdapters
class ExconAdapter < HttpLibAdapter
PARAMS_TO_DELETE = [:expects, :idempotent,
:instrumentor_name, :instrumentor,
:response_block,
:__construction_args, :stack,
:connection, :response]
adapter_for :excon
instance_exec do
@original_excon_mock_default = nil
@stub = nil
end
def self.enable!
self.add_excon_stub
end
def self.disable!
self.remove_excon_stub
end
def self.add_excon_stub
if not @stub
@original_excon_mock_default = ::Excon.defaults[:mock]
::Excon.defaults[:mock] = true
@stub = ::Excon.stub({}) do |params|
self.handle_request(params)
end
end
end
def self.remove_excon_stub
::Excon.defaults[:mock] = @original_excon_mock_default
@original_excon_mock_default = nil
Excon.stubs.delete(@stub)
@stub = nil
end
def self.handle_request(params)
mock_request = self.build_request params.dup
WebMock::RequestRegistry.instance.requested_signatures.put(mock_request)
if mock_response = WebMock::StubRegistry.instance.response_for_request(mock_request)
self.perform_callbacks(mock_request, mock_response, real_request: false)
response = self.real_response(mock_response)
response
elsif WebMock.net_connect_allowed?(mock_request.uri)
conn = new_excon_connection(params)
real_response = conn.request(request_params_from(params.merge(mock: false)))
ExconAdapter.perform_callbacks(mock_request, ExconAdapter.mock_response(real_response), real_request: true)
real_response.data
else
raise WebMock::NetConnectNotAllowedError.new(mock_request)
end
end
def self.new_excon_connection(params)
# Ensure the connection is constructed with the exact same args
# that the orginal connection was constructed with.
args = params.fetch(:__construction_args)
::Excon::Connection.new(connection_params_from args.merge(mock: false))
end
def self.connection_params_from(hash)
hash = hash.dup
PARAMS_TO_DELETE.each { |key| hash.delete(key) }
hash
end
def self.request_params_from(hash)
hash = hash.dup
if defined?(Excon::VALID_REQUEST_KEYS)
hash.reject! {|key,_| !Excon::VALID_REQUEST_KEYS.include?(key) }
end
PARAMS_TO_DELETE.each { |key| hash.delete(key) }
hash
end
def self.to_query(hash)
string = "".dup
for key, values in hash
if values.nil?
string << key.to_s << '&'
else
for value in [*values]
string << key.to_s << '=' << CGI.escape(value.to_s) << '&'
end
end
end
string.chop! # remove trailing '&'
end
def self.build_request(params)
params = params.dup
params.delete(:user)
params.delete(:password)
method = (params.delete(:method) || :get).to_s.downcase.to_sym
params[:query] = to_query(params[:query]) if params[:query].is_a?(Hash)
uri = Addressable::URI.new(params).to_s
WebMock::RequestSignature.new method, uri, body: body_from(params), headers: params[:headers]
end
def self.body_from(params)
body = params[:body]
return body unless body.respond_to?(:read)
contents = body.read
body.rewind if body.respond_to?(:rewind)
contents
end
def self.real_response(mock)
raise Excon::Errors::Timeout if mock.should_timeout
mock.raise_error_if_any
{
body: mock.body,
status: mock.status[0].to_i,
reason_phrase: mock.status[1],
headers: mock.headers || {}
}
end
def self.mock_response(real)
mock = WebMock::Response.new
mock.status = [real.status, real.reason_phrase]
mock.headers = real.headers
mock.body = real.body.dup
mock
end
def self.perform_callbacks(request, response, options = {})
return unless WebMock::CallbackRegistry.any_callbacks?
WebMock::CallbackRegistry.invoke_callbacks(options.merge(lib: :excon), request, response)
end
end
end
end
Excon::Connection.class_eval do
def self.new(args = {})
args.delete(:__construction_args)
super(args).tap do |instance|
instance.data[:__construction_args] = args
end
end
end
# Suppresses Excon connection argument validation warning
Excon::VALID_CONNECTION_KEYS << :__construction_args
end
|