Skip to content

Commit

Permalink
Added support for Excon
Browse files Browse the repository at this point in the history
  • Loading branch information
dim committed Feb 3, 2012
1 parent ad9ea7f commit e2369ac
Show file tree
Hide file tree
Showing 9 changed files with 140 additions and 5 deletions.
1 change: 1 addition & 0 deletions lib/webmock.rb
Expand Up @@ -14,6 +14,7 @@
require 'webmock/http_lib_adapters/curb_adapter'
require 'webmock/http_lib_adapters/em_http_request_adapter'
require 'webmock/http_lib_adapters/typhoeus_hydra_adapter'
require 'webmock/http_lib_adapters/excon_adapter'

require 'webmock/errors'

Expand Down
77 changes: 77 additions & 0 deletions lib/webmock/http_lib_adapters/excon_adapter.rb
@@ -0,0 +1,77 @@
begin
require 'excon'
rescue LoadError
# excon not found
end

if defined?(Excon)

module WebMock
module HttpLibAdapters

class ExconAdapter < HttpLibAdapter
adapter_for :excon

def self.enable!
Excon.send(:remove_const, :Connection)
Excon.send(:const_set, :Connection, ExconConnection)
end

def self.disable!
Excon.send(:remove_const, :Connection)
Excon.send(:const_set, :Connection, ExconConnection.superclass)
end

def self.build_request(params)
uri = Addressable::URI.new(params).to_s
method = (params[:method] || :get).to_s.downcase.to_sym
WebMock::RequestSignature.new method, uri, :body => params[:body], :headers => params[:headers]
end

def self.real_response(mock)
raise Excon::Errors::Timeout if mock.should_timeout
mock.raise_error_if_any
Excon::Response.new \
:body => mock.body,
:status => mock.status[0].to_i,
:headers => mock.headers
end

def self.mock_response(real)
mock = WebMock::Response.new
mock.status = real.status
mock.headers = real.headers
mock.body = real.body
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

class ExconConnection < ::Excon::Connection

def request_kernel(params, &block)
mock_request = ExconAdapter.build_request params.dup
WebMock::RequestRegistry.instance.requested_signatures.put(mock_request)

if mock_response = WebMock::StubRegistry.instance.response_for_request(mock_request)
ExconAdapter.perform_callbacks(mock_request, mock_response, :real_request => false)
ExconAdapter.real_response(mock_response)
elsif WebMock.net_connect_allowed?(mock_request.uri)
real_response = super
ExconAdapter.perform_callbacks(mock_request, ExconAdapter.mock_response(real_response), :real_request => true)
real_response
else
raise WebMock::NetConnectNotAllowedError.new(mock_request)
end
end

end
end
end

end
9 changes: 9 additions & 0 deletions spec/acceptance/excon/excon_spec.rb
@@ -0,0 +1,9 @@
require 'spec_helper'
require 'acceptance/webmock_shared'
require 'acceptance/excon/excon_spec_helper'

describe "Excon" do
include ExconSpecHelper
include_context "with WebMock"
end

37 changes: 37 additions & 0 deletions spec/acceptance/excon/excon_spec_helper.rb
@@ -0,0 +1,37 @@
require 'ostruct'

module ExconSpecHelper

def http_request(method, uri, options = {}, &block)
uri = Addressable::URI.heuristic_parse(uri)
uri = uri.omit(:userinfo).to_s.gsub(' ', '+')

options = options.merge(:method => method) # Dup and merge
response = Excon.new(uri).request(options, &block)

headers = WebMock::Util::Headers.normalize_headers(response.headers)
headers = headers.inject({}) do |res, (name, value)|
res[name] = value.is_a?(Array) ? value.flatten.join(', ') : value
res
end

OpenStruct.new \
:body => response.body,
:headers => headers,
:status => response.status.to_s,
:message => ""
end

def client_timeout_exception_class
Excon::Errors::Timeout
end

def connection_refused_exception_class
Excon::Errors::SocketError
end

def http_library
:excon
end

end
3 changes: 2 additions & 1 deletion spec/acceptance/shared/callbacks.rb
Expand Up @@ -87,7 +87,8 @@

it "should pass real response to callback with status and message" do
# not supported by em-http-request, it always returns "unknown" for http_reason
unless http_library == :em_http_request
# not supported by excon, it only returns a status code
unless [:em_http_request, :excon].include?(http_library)
@response.status[0].should == 302
@response.status[1].should == "Found"
end
Expand Down
1 change: 1 addition & 0 deletions spec/acceptance/shared/request_expectations.rb
Expand Up @@ -412,6 +412,7 @@

describe "with authentication" do
before(:each) do
pending "Excon does not accept basic auth user-info in URLs" if http_library == :excon
stub_request(:any, "http://user:pass@www.example.com")
stub_request(:any, "http://user:pazz@www.example.com")
end
Expand Down
12 changes: 8 additions & 4 deletions spec/acceptance/shared/returning_declared_responses.rb
Expand Up @@ -76,7 +76,8 @@ class MyException < StandardError; end;
stub_request(:get, "www.example.com").to_return(:status => [500, "Internal Server Error"])
response = http_request(:get, "http://www.example.com/")
# not supported by em-http-request, it always returns "unknown" for http_reason
unless http_library == :em_http_request
# not supported by excon, it only returns a status code
unless [:em_http_request, :excon].include?(http_library)
response.message.should == "Internal Server Error"
end
end
Expand All @@ -90,7 +91,8 @@ class MyException < StandardError; end;
stub_request(:get, "www.example.com")
response = http_request(:get, "http://www.example.com/")
# not supported by em-http-request, it always returns "unknown" for http_reason
unless http_library == :em_http_request
# not supported by excon, it only returns a status code
unless [:em_http_request, :excon].include?(http_library)
response.message.should == ""
end
end
Expand Down Expand Up @@ -188,7 +190,8 @@ def call(request)

it "should return recorded status message" do
# not supported by em-http-request, it always returns "unknown" for http_reason
unless http_library == :em_http_request
# not supported by excon, it only returns a status code
unless [:em_http_request, :excon].include?(http_library)
@response.message.should == "OK"
end
end
Expand Down Expand Up @@ -225,7 +228,8 @@ def call(request)

it "should return recorded status message" do
# not supported by em-http-request, it always returns "unknown" for http_reason
unless http_library == :em_http_request
# not supported by excon, it only returns a status code
unless [:em_http_request, :excon].include?(http_library)
@response.message.should == "OK"
end
end
Expand Down
4 changes: 4 additions & 0 deletions spec/acceptance/shared/stubbing_requests.rb
Expand Up @@ -260,6 +260,10 @@
end

describe "when stubbing request with basic authentication" do
before do
pending "Excon does not accept basic auth user-info in URLs" if http_library == :excon
end

it "should match if credentials are the same" do
stub_request(:get, "user:pass@www.example.com")
http_request(:get, "http://user:pass@www.example.com/").status.should == "200"
Expand Down
1 change: 1 addition & 0 deletions webmock.gemspec
Expand Up @@ -24,6 +24,7 @@ Gem::Specification.new do |s|
s.add_development_dependency 'em-synchrony', '>= 1.0.0' if RUBY_VERSION >= "1.9"
s.add_development_dependency 'curb', '>= 0.8.0'
s.add_development_dependency 'typhoeus', '>= 0.3.0' unless RUBY_PLATFORM =~ /java/
s.add_development_dependency 'excon', '>= 0.9.5'
s.add_development_dependency 'minitest', '>= 2.2.2'
s.add_development_dependency 'rdoc', ((RUBY_VERSION == '1.8.6') ? '<= 3.5.0' : '>3.5.0')

Expand Down

0 comments on commit e2369ac

Please sign in to comment.