Skip to content

Commit

Permalink
Fix WebMock/Net::HTTP integration.
Browse files Browse the repository at this point in the history
Rather than using a Net::HTTP monkey patch to record new requests, use WebMock's callback.  This prevents the monkey patches from colliding each other and ensures that VCR & WebMock work properly with Open URI.

Closes #14.
  • Loading branch information
myronmarston committed Sep 27, 2010
1 parent cbb493e commit aec21b4
Show file tree
Hide file tree
Showing 10 changed files with 74 additions and 13 deletions.
11 changes: 11 additions & 0 deletions features/net_http.feature
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,14 @@ Feature: Net::HTTP
Given we do not have a "temp/block_with_a_return" cassette
When I make a returning block Net::HTTP get request to "http://example.com" while using the "temp/block_with_a_return" cassette
Then the "temp/block_with_a_return" library file should have a response for "http://example.com" that matches /You have reached this web page by typing.*example\.com/

Scenario: Record a request made with open uri
Given we do not have a "temp/open_uri" cassette
When I make an open uri Net::HTTP get request to "http://example.com" while using the "temp/open_uri" cassette
Then the "temp/open_uri" library file should have a response for "http://example.com" that matches /You have reached this web page by typing.*example\.com/

@copy_not_the_real_response_to_temp
Scenario: Replay a response for an open uri request
Given the "temp/not_the_real_response" library file has a response for "http://example.com" that matches /This is not the real response from example\.com/
When I make an open uri Net::HTTP get request to "http://example.com" while using the "temp/not_the_real_response" cassette
Then the response for "http://example.com" should match /This is not the real response from example\.com/
14 changes: 13 additions & 1 deletion features/step_definitions/net_http_steps.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require 'open-uri'

module NetHTTPHelpers
def perform_net_http_get_with_returning_block(uri, path)
Net::HTTP.new(uri.host, uri.port).request(Net::HTTP::Get.new(path, {})) do |response|
Expand Down Expand Up @@ -34,4 +36,14 @@ def result_body.body; self; end # make the string a fake response (so response.b
capture_response(url) do |uri, path|
perform_net_http_get_with_returning_block(uri, path)
end
end
end

When /^I make an open uri Net::HTTP get request to "([^"]*)"$/ do |url|
capture_response(url) do |uri, path|
result = open(url)
# #open returns a StringIO rather than a Net::HTTPResponse, so we add #body to make it conform to the same interface
def result.body; read; end
result
end
end

3 changes: 1 addition & 2 deletions lib/vcr/http_stubbing_adapters/webmock.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
require 'webmock'
require 'vcr/extensions/net_http'

module VCR
module HttpStubbingAdapters
Expand Down Expand Up @@ -93,7 +92,7 @@ def checkpoints
end
end

WebMock.after_request(:except => [:net_http], :real_requests_only => true) do |request, response|
WebMock.after_request(:real_requests_only => true) do |request, response|
http_interaction = VCR::HTTPInteraction.new(
VCR::Request.new(
request.method,
Expand Down
4 changes: 1 addition & 3 deletions spec/extensions/net_http_response_spec.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
require 'spec_helper'

describe VCR::Net::HTTPResponse do
# Disable the VCR/FakeWeb/WebMock Net::HTTP monkey patches so we don't have collisions with these specs
before(:all) { MonkeyPatches.disable! }
after(:all) { MonkeyPatches.enable! }
without_monkey_patches :all

def self.it_allows_the_body_to_be_read(expected_regex)
it 'allows the body to be read using #body' do
Expand Down
2 changes: 2 additions & 0 deletions spec/extensions/net_http_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
require 'spec_helper'

describe "Net::HTTP Extensions" do
without_webmock_callbacks

let(:uri) { URI.parse('http://example.com') }

it 'checks if the request is stubbed using a VCR::Request' do
Expand Down
2 changes: 2 additions & 0 deletions spec/http_stubbing_adapters/fakeweb_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
require 'spec_helper'

describe VCR::HttpStubbingAdapters::FakeWeb do
without_webmock_callbacks

it_should_behave_like 'an http stubbing adapter', ['net/http'], [:method, :uri, :host, :path]

describe '#should_unwind_response?' do
Expand Down
2 changes: 2 additions & 0 deletions spec/http_stubbing_adapters/webmock_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
require 'spec_helper'

describe VCR::HttpStubbingAdapters::WebMock do
without_monkey_patches :vcr

it_should_behave_like 'an http stubbing adapter',
%w[net/http patron httpclient em-http-request],
[:method, :uri, :host, :path, :body, :headers]
Expand Down
31 changes: 25 additions & 6 deletions spec/monkey_patches.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
module MonkeyPatches
extend self

module RSpecMacros
def without_monkey_patches(scope)
before(:each) { MonkeyPatches.disable!(scope) }
after(:each) { MonkeyPatches.enable!(scope) }
end
end

NET_HTTP_SINGLETON = class << Net::HTTP; self; end

MONKEY_PATCHES = [
Expand All @@ -10,15 +17,27 @@ module MonkeyPatches
[NET_HTTP_SINGLETON, :socket_type]
]

def enable!
MONKEY_PATCHES.each do |mp|
realias mp.first, mp.last, :with_monkeypatches
def enable!(scope)
case scope
when :all
MONKEY_PATCHES.each do |mp|
realias mp.first, mp.last, :with_monkeypatches
end
when :vcr
realias Net::HTTP, :request, :with_vcr
else raise ArgumentError.new("Unexpected scope: #{scope}")
end
end

def disable!
MONKEY_PATCHES.each do |mp|
realias mp.first, mp.last, :without_monkeypatches
def disable!(scope)
case scope
when :all
MONKEY_PATCHES.each do |mp|
realias mp.first, mp.last, :without_monkeypatches
end
when :vcr
realias Net::HTTP, :request, :without_vcr
else raise ArgumentError.new("Unexpected scope: #{scope}")
end
end

Expand Down
4 changes: 3 additions & 1 deletion spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
require 'httpclient'
require 'em-http-request' unless RUBY_PLATFORM =~ /java/
require 'vcr'
require 'vcr/http_stubbing_adapters/fakeweb'
require 'vcr/http_stubbing_adapters/webmock'
require 'vcr/http_stubbing_adapters/fakeweb'
require 'rspec'

# Ruby 1.9.1 has a different yaml serialization format.
Expand All @@ -22,6 +22,8 @@
RSpec.configure do |config|
config.extend TempCassetteLibraryDir
config.extend DisableWarnings
config.extend MonkeyPatches::RSpecMacros
config.extend WebMockMacros

config.color_enabled = true
config.debug = RUBY_PLATFORM != 'java'
Expand Down
14 changes: 14 additions & 0 deletions spec/support/webmock_macros.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module WebMockMacros
def without_webmock_callbacks
before(:all) do
@original_webmock_callbacks = ::WebMock::CallbackRegistry.callbacks
::WebMock::CallbackRegistry.reset
end

after(:all) do
@original_webmock_callbacks.each do |cb|
::WebMock::CallbackRegistry.add_callback(cb[:options], cb[:block])
end
end
end
end

0 comments on commit aec21b4

Please sign in to comment.