Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Added support for Excon #158

Merged
merged 2 commits into from

3 participants

Dimitrij Denissenko Bartosz Blimke Myron Marston
Dimitrij Denissenko
dim commented

Had to add a few pending specs, as Excon is (currently) simply ignoring userinfo in URLs. Not sure if that's the best approach. D

Bartosz Blimke bblimke merged commit e6a9e81 into from
Bartosz Blimke
Owner

Thank you! That's a big one. Great to have one more library supported by WebMock.

Have you considered using Excon internal stubbing?

Dimitrij Denissenko
dim commented

I did, but not sure how that would work in combination with WebMock's internals (registry, etc). We are using exconn + net/http in many of our projects, hence I wanted to create a single, consistent way of stubbing our connections.

Bartosz Blimke
Owner

Thanks. It will go in Webmock 1.8.0 release within couple of days.

Bartosz Blimke
Owner

@myronmarston could you please check if this will cause any conflicts with Excon support in VCR, before I release 1.8.0?

Myron Marston
Collaborator

Yep, thanks for the heads up! I will try to get to it later this weekend.

Myron Marston
Collaborator

All my VCR tests pass, so this is good to go :).

Bartosz Blimke
Owner

Excellent! I'm planning to release 1.8.0 tomorrow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Feb 3, 2012
  1. Dimitrij Denissenko

    Added support for Excon

    dim authored
  2. Dimitrij Denissenko
This page is out of date. Refresh to see the latest.
1  lib/webmock.rb
View
@@ -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'
94 lib/webmock/http_lib_adapters/excon_adapter.rb
View
@@ -0,0 +1,94 @@
+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.to_query(hash)
+ string = ""
+ 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
+ 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 => 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
15 spec/acceptance/excon/excon_spec.rb
View
@@ -0,0 +1,15 @@
+require 'spec_helper'
+require 'acceptance/webmock_shared'
+require 'acceptance/excon/excon_spec_helper'
+
+describe "Excon" do
+ include ExconSpecHelper
+ include_context "with WebMock"
+
+ it 'should allow Excon requests to use query hash paramters' do
+ stub_request(:get, "http://example.com/resource/?a=1&b=2").to_return(:body => "abc")
+ Excon.get('http://example.com', :path => "resource/", :query => {:a => 1, :b => 2}).body.should == "abc"
+ end
+
+end
+
37 spec/acceptance/excon/excon_spec_helper.rb
View
@@ -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  spec/acceptance/shared/callbacks.rb
View
@@ -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
1  spec/acceptance/shared/request_expectations.rb
View
@@ -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
12 spec/acceptance/shared/returning_declared_responses.rb
View
@@ -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
@@ -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
@@ -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
@@ -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
4 spec/acceptance/shared/stubbing_requests.rb
View
@@ -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"
1  webmock.gemspec
View
@@ -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')
Something went wrong with that request. Please try again.