Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Fix double block call and add global stub hook #139

Merged
merged 3 commits into from

2 participants

@myronmarston
Collaborator

Do one of you want to code review this before I merge this in?

myronmarston added some commits
@myronmarston myronmarston Lock to a curb version that doesn't have double-request problems.
Curb 0.7.16 causes 16 tests to fail.  Curb 0.7.15 doesn't.  This
should be fixed at some point, but for now to get the build green
so I can work on other things, I'm locking to 0.7.15.

See issue #136 for more info.
99f0a75
@myronmarston myronmarston Ensure stub.with block is only called once per request.
Previously it was called 2 or even 3 times for one request,
which made it difficult to put any behavior in the hook
besides returning true or false as you had to keep track of the request
to see if the hook was being called again for the same request.
8786b65
@myronmarston myronmarston Add WebMock.globally_stub_request.
This allows easier integration with WebMock by another library like VCR so it can register a global hook to handle every request.
2fe6808
@bblimke
Owner

Looks good to me. Wow, I can't believe stub with block was called twice in so many places.

@myronmarston myronmarston merged commit 2fe6808 into from
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Nov 18, 2011
  1. @myronmarston

    Lock to a curb version that doesn't have double-request problems.

    myronmarston authored
    Curb 0.7.16 causes 16 tests to fail.  Curb 0.7.15 doesn't.  This
    should be fixed at some point, but for now to get the build green
    so I can work on other things, I'm locking to 0.7.15.
    
    See issue #136 for more info.
  2. @myronmarston

    Ensure stub.with block is only called once per request.

    myronmarston authored
    Previously it was called 2 or even 3 times for one request,
    which made it difficult to put any behavior in the hook
    besides returning true or false as you had to keep track of the request
    to see if the hook was being called again for the same request.
  3. @myronmarston

    Add WebMock.globally_stub_request.

    myronmarston authored
    This allows easier integration with WebMock by another library like VCR so it can register a global hook to handle every request.
This page is out of date. Refresh to see the latest.
View
3  lib/webmock/http_lib_adapters/curb_adapter.rb
@@ -56,8 +56,7 @@ def curb_or_webmock
request_signature = build_request_signature
WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
- if WebMock::StubRegistry.instance.registered_request?(request_signature)
- webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
+ if webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
build_curb_response(webmock_response)
WebMock::CallbackRegistry.invoke_callbacks(
{:lib => :curb}, request_signature, webmock_response)
View
3  lib/webmock/http_lib_adapters/em_http_request/em_http_request_0_x.rb
@@ -52,8 +52,7 @@ def send_request_with_webmock(&block)
WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
- if WebMock::StubRegistry.instance.registered_request?(request_signature)
- webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
+ if webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
WebMock::CallbackRegistry.invoke_callbacks(
{:lib => :em_http_request}, request_signature, webmock_response)
client = WebMockHttpClient.new(nil)
View
21 lib/webmock/http_lib_adapters/em_http_request/em_http_request_1_x.rb
@@ -51,7 +51,7 @@ class WebMockHttpConnection < HttpConnection
def webmock_activate_connection(client)
request_signature = client.request_signature
- if WebMock::StubRegistry.instance.registered_request?(request_signature)
+ if client.stubbed_webmock_response
conn = HttpStubConnection.new rand(10000)
post_init
@@ -95,13 +95,12 @@ def setup(response, uri, error = nil)
def send_request_with_webmock(head, body)
WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
- if WebMock::StubRegistry.instance.registered_request?(request_signature)
- webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
- on_error("WebMock timeout error") if webmock_response.should_timeout
- WebMock::CallbackRegistry.invoke_callbacks({:lib => :em_http_request}, request_signature, webmock_response)
+ if stubbed_webmock_response
+ on_error("WebMock timeout error") if stubbed_webmock_response.should_timeout
+ WebMock::CallbackRegistry.invoke_callbacks({:lib => :em_http_request}, request_signature, stubbed_webmock_response)
EM.next_tick {
- setup(make_raw_response(webmock_response), @uri,
- webmock_response.should_timeout ? "WebMock timeout error" : nil)
+ setup(make_raw_response(stubbed_webmock_response), @uri,
+ stubbed_webmock_response.should_timeout ? "WebMock timeout error" : nil)
}
self
elsif WebMock.net_connect_allowed?(request_signature.uri)
@@ -128,6 +127,14 @@ def request_signature
@request_signature ||= build_request_signature
end
+ def stubbed_webmock_response
+ unless defined?(@stubbed_webmock_response)
+ @stubbed_webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
+ end
+
+ @stubbed_webmock_response
+ end
+
private
def build_webmock_response
View
13 lib/webmock/http_lib_adapters/httpclient_adapter.rb
@@ -42,8 +42,8 @@ def do_get_with_webmock(req, proxy, conn, stream = false, &block)
WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
- if WebMock::StubRegistry.instance.registered_request?(request_signature)
- webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
+ if webmock_responses[request_signature]
+ webmock_response = webmock_responses.delete(request_signature)
response = build_httpclient_response(webmock_response, stream, &block)
@request_filter.each do |filter|
filter.filter_response(req, response)
@@ -76,8 +76,7 @@ def do_request_async_with_webmock(method, uri, query, body, extheader)
req = create_request(method, uri, query, body, extheader)
request_signature = build_request_signature(req)
- if WebMock::StubRegistry.instance.registered_request?(request_signature) ||
- WebMock.net_connect_allowed?(request_signature.uri)
+ if webmock_responses[request_signature] || WebMock.net_connect_allowed?(request_signature.uri)
do_request_async_without_webmock(method, uri, query, body, extheader)
else
raise WebMock::NetConnectNotAllowedError.new(request_signature)
@@ -158,4 +157,10 @@ def build_request_signature(req)
)
end
+ def webmock_responses
+ @webmock_responses ||= Hash.new do |hash, request_signature|
+ hash[request_signature] = WebMock::StubRegistry.instance.response_for_request(request_signature)
+ end
+ end
+
end
View
3  lib/webmock/http_lib_adapters/net_http.rb
@@ -68,9 +68,8 @@ def request_with_webmock(request, body = nil, &block)
WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
- if WebMock::StubRegistry.instance.registered_request?(request_signature)
+ if webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
@socket = Net::HTTP.socket_type.new
- webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
WebMock::CallbackRegistry.invoke_callbacks(
{:lib => :net_http}, request_signature, webmock_response)
build_net_http_response(webmock_response, &block)
View
4 lib/webmock/http_lib_adapters/patron_adapter.rb
@@ -19,9 +19,7 @@ def handle_request_with_webmock(req)
WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
- if WebMock::StubRegistry.instance.registered_request?(request_signature)
- webmock_response =
- WebMock::StubRegistry.instance.response_for_request(request_signature)
+ if webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
WebMock::HttpLibAdapters::PatronAdapter.
handle_file_name(req, webmock_response)
res = WebMock::HttpLibAdapters::PatronAdapter.
View
4 lib/webmock/http_lib_adapters/typhoeus_hydra_adapter.rb
@@ -140,9 +140,7 @@ def queue_with_webmock(request)
::WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
- if ::WebMock::StubRegistry.instance.registered_request?(request_signature)
- webmock_response =
- ::WebMock::StubRegistry.instance.response_for_request(request_signature)
+ if webmock_response = ::WebMock::StubRegistry.instance.response_for_request(request_signature)
::WebMock::HttpLibAdapters::TyphoeusAdapter.
stub_typhoeus(request_signature, webmock_response, self)
webmock_response.raise_error_if_any
View
19 lib/webmock/stub_registry.rb
@@ -4,13 +4,30 @@ class StubRegistry
include Singleton
attr_accessor :request_stubs
+ attr_accessor :global_stub
def initialize
reset!
end
def reset!
- self.request_stubs = []
+ self.request_stubs = global_stub ? [global_stub] : []
+ end
+
+ def global_stub_block=(block)
+ self.global_stub = ::WebMock::RequestStub.new(:any, /.*/)
+
+ # This hash contains the responses returned by the block,
+ # keyed by the exact request (using the object_id).
+ # That way, there's no race condition in case #to_return
+ # doesn't run immediately after stub.with.
+ responses = {}
+
+ self.global_stub.with { |request|
+ responses[request.object_id] = block.call(request)
+ }.to_return(lambda { |request| responses.delete(request.object_id) })
+
+ register_request_stub(self.global_stub)
end
def register_request_stub(stub)
View
4 lib/webmock/webmock.rb
@@ -88,6 +88,10 @@ def self.print_executed_requests
puts WebMock::RequestExecutionVerifier.executed_requests_message
end
+ def self.globally_stub_request(&block)
+ WebMock::StubRegistry.instance.global_stub_block = block
+ end
+
%w(
allow_net_connect!
disable_net_connect!
View
57 spec/acceptance/shared/stubbing_requests.rb
@@ -287,6 +287,56 @@
end
end
+ describe "when stubbing request with a global hook" do
+ after(:each) do
+ WebMock::StubRegistry.instance.global_stub = nil
+ end
+
+ it 'returns the response returned by the hook' do
+ WebMock.globally_stub_request do |request|
+ { :body => "global stub body" }
+ end
+
+ http_request(:get, "http://www.example.com/").body.should == "global stub body"
+ end
+
+ it 'does not get cleared when a user calls WebMock.reset!' do
+ WebMock.globally_stub_request do |request|
+ { :body => "global stub body" }
+ end
+ WebMock.reset!
+ http_request(:get, "http://www.example.com/").body.should == "global stub body"
+ end
+
+ it "does not stub the request if the hook does not return anything" do
+ WebMock.globally_stub_request { |r| }
+ lambda {
+ http_request(:get, "http://www.example.com/")
+ }.should raise_error(WebMock::NetConnectNotAllowedError, %r(Real HTTP connections are disabled. Unregistered request: GET http://www.example.com/))
+ end
+
+ it "passes the request to the block" do
+ passed_request = nil
+ WebMock.globally_stub_request do |request|
+ passed_request = request
+ { :body => "global stub body" }
+ end
+
+ http_request(:get, "http://www.example.com:456/bar")
+ passed_request.uri.to_s.should == "http://www.example.com:456/bar"
+ end
+
+ it "should call the block only once per request" do
+ call_count = 0
+ WebMock.globally_stub_request do |request|
+ call_count += 1
+ { :body => "global stub body" }
+ end
+ http_request(:get, "http://www.example.com/")
+ call_count.should == 1
+ end
+ end
+
describe "when stubbing request with a block evaluated on request" do
it "should match if block returns true" do
stub_request(:get, "www.example.com").with { |request| true }
@@ -309,6 +359,13 @@
http_request(:post, "http://www.example.com/", :body => "jander")
}.should raise_error(WebMock::NetConnectNotAllowedError, %r(Real HTTP connections are disabled. Unregistered request: POST http://www.example.com/ with body 'jander'))
end
+
+ it "should call the block only once per request" do
+ call_count = 0
+ stub_request(:get, "www.example.com").with { |request| call_count += 1; true }
+ http_request(:get, "http://www.example.com/").status.should == "200"
+ call_count.should == 1
+ end
end
end
end
View
2  webmock.gemspec
@@ -21,7 +21,7 @@ Gem::Specification.new do |s|
s.add_development_dependency 'httpclient', '>= 2.1.5.2'
s.add_development_dependency 'patron', '>= 0.4.15'
s.add_development_dependency 'em-http-request', '~> 0.3.0'
- s.add_development_dependency 'curb', '>= 0.7.8'
+ s.add_development_dependency 'curb', '0.7.15'
s.add_development_dependency 'typhoeus', '>= 0.2.4'
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.