Permalink
Browse files

Added #allow_real_http cassette option, that allows real http request…

…s for URLs that return true for the given lambda.
  • Loading branch information...
1 parent 6a98933 commit 2ed9c3c318305ee39fa054997da1b67c1413a408 @myronmarston committed Mar 9, 2010
@@ -64,3 +64,9 @@ Feature: Record response
When I make a recursive HTTP post request to "http://example.com" within the "temp/recursive_post" unregistered cassette
Then the "temp/recursive_post" cache file should have a response for "http://example.com" that matches /You have reached this web page by typing.*example\.com/
And the "temp/recursive_post" cache file should have exactly 1 response
+
+ Scenario: Make an allowed HTTP request in a cassette with record mode set to :none
+ Given we do not have a "temp/record_none_cassette" cassette
+ When I make an HTTP get request to "http://example.com" within the "temp/record_none_cassette" none cassette, allowing requests matching /example.com/
+ Then the response for "http://example.com" should match /You have reached this web page by typing.*example\.com/
+ And there should not be a "temp/record_none_cassette" cache file
@@ -67,11 +67,11 @@ def recorded_responses_for(cassette_name)
@http_requests[url] += [result]
end
-When /^I make(?: an)?(.*)? HTTP (get|post) requests? to "([^\"]*)"(?: and "([^\"]*)")? within the "([^\"]*)" ?(#{VCR::Cassette::VALID_RECORD_MODES.join('|')})? cassette$/ do |request_type, method, url1, url2, cassette_name, record_mode|
- record_mode ||= :unregistered
- record_mode = record_mode.to_sym
+When /^I make(?: an)?(.*)? HTTP (get|post) requests? to "([^\"]*)"(?: and "([^\"]*)")? within the "([^\"]*)" ?(#{VCR::Cassette::VALID_RECORD_MODES.join('|')})? cassette(?:, allowing requests matching \/([^\/]+)\/)?$/ do |request_type, method, url1, url2, cassette_name, record_mode, allowed|
+ options = { :record => (record_mode ? record_mode.to_sym : :unregistered) }
+ options[:allow_real_http] = lambda { |uri| uri.to_s =~ /#{allowed}/ } if allowed.to_s.size > 0
urls = [url1, url2].select { |u| u.to_s.size > 0 }
- VCR.with_cassette(cassette_name, :record => record_mode) do
+ VCR.with_cassette(cassette_name, options) do
urls.each do |url|
When %{I make an#{request_type} HTTP #{method} request to "#{url}"}
end
View
@@ -10,6 +10,7 @@ class Cassette
def initialize(name, options = {})
@name = name
@record_mode = options[:record] || VCR::Config.default_cassette_options[:record]
+ @allow_real_http_lambda = allow_real_http_lambda_for(options[:allow_real_http] || VCR::Config.default_cassette_options[:allow_real_http])
self.class.raise_error_unless_valid_record_mode(record_mode)
set_fakeweb_allow_net_connect
load_recorded_responses
@@ -39,6 +40,10 @@ def self.raise_error_unless_valid_record_mode(record_mode)
end
end
+ def allow_real_http_requests_to?(uri)
+ @allow_real_http_lambda ? @allow_real_http_lambda.call(uri) : false
+ end
+
private
def new_recorded_responses
@@ -93,5 +98,13 @@ def deregister_original_recorded_responses
FakeWeb.remove_from_registry(rr.method, rr.uri)
end
end
+
+ def allow_real_http_lambda_for(allow_option)
+ if allow_option == :localhost
+ lambda { |uri| uri.host == 'localhost' }
+ else
+ allow_option
+ end
+ end
end
end
@@ -5,6 +5,16 @@ def self.remove_from_registry(method, url)
Registry.instance.remove(method, url)
end
+ def self.with_allow_net_connect_set_to(value)
+ original_value = FakeWeb.allow_net_connect?
+ begin
+ FakeWeb.allow_net_connect = value
+ yield
+ ensure
+ FakeWeb.allow_net_connect = original_value
+ end
+ end
+
class Registry #:nodoc:
def remove(method, url)
uri_map.delete_if do |uri, method_hash|
@@ -4,9 +4,14 @@ module Net
class HTTP
def request_with_vcr(request, body = nil, &block)
@__request_with_vcr_call_count = (@__request_with_vcr_call_count || 0) + 1
- response = request_without_vcr(request, body, &block)
- __store_response_with_vcr__(response, request) if @__request_with_vcr_call_count == 1
- response
+ uri = URI.parse(__vcr_uri__(request))
+ if (cassette = VCR.current_cassette) && cassette.allow_real_http_requests_to?(uri)
+ FakeWeb.with_allow_net_connect_set_to(true) { request_without_vcr(request, body, &block) }
+ else
+ response = request_without_vcr(request, body, &block)
+ __store_response_with_vcr__(response, request) if @__request_with_vcr_call_count == 1
+ response
+ end
ensure
@__request_with_vcr_call_count -= 1
end
@@ -15,22 +20,26 @@ def request_with_vcr(request, body = nil, &block)
private
- def __store_response_with_vcr__(response, request)
- if cassette = VCR.current_cassette
- # Copied from: http://github.com/chrisk/fakeweb/blob/fakeweb-1.2.8/lib/fake_web/ext/net_http.rb#L39-52
- protocol = use_ssl? ? "https" : "http"
+ def __vcr_uri__(request)
+ # Copied from: http://github.com/chrisk/fakeweb/blob/fakeweb-1.2.8/lib/fake_web/ext/net_http.rb#L39-52
+ protocol = use_ssl? ? "https" : "http"
- path = request.path
- path = URI.parse(request.path).request_uri if request.path =~ /^http/
+ path = request.path
+ path = URI.parse(request.path).request_uri if request.path =~ /^http/
- if request["authorization"] =~ /^Basic /
- userinfo = FakeWeb::Utility.decode_userinfo_from_header(request["authorization"])
- userinfo = FakeWeb::Utility.encode_unsafe_chars_in_userinfo(userinfo) + "@"
- else
- userinfo = ""
- end
+ if request["authorization"] =~ /^Basic /
+ userinfo = FakeWeb::Utility.decode_userinfo_from_header(request["authorization"])
+ userinfo = FakeWeb::Utility.encode_unsafe_chars_in_userinfo(userinfo) + "@"
+ else
+ userinfo = ""
+ end
- uri = "#{protocol}://#{userinfo}#{self.address}:#{self.port}#{path}"
+ "#{protocol}://#{userinfo}#{self.address}:#{self.port}#{path}"
+ end
+
+ def __store_response_with_vcr__(response, request)
+ if cassette = VCR.current_cassette
+ uri = __vcr_uri__(request)
method = request.method.downcase.to_sym
unless FakeWeb.registered_uri?(method, uri)
View
@@ -103,6 +103,44 @@
end
end
+ describe '#allow_real_http_requests_to?' do
+ it 'delegates to the :allow_real_http lambda' do
+ [true, false].each do |value|
+ yielded_uri = nil
+ c = VCR::Cassette.new('example', :allow_real_http => lambda { |uri| yielded_uri = uri; value })
+ c.allow_real_http_requests_to?(:the_uri).should == value
+ yielded_uri.should == :the_uri
+ end
+ end
+
+ it 'returns true for localhost requests when the :allow_real_http option is set to :localhost' do
+ c = VCR::Cassette.new('example', :allow_real_http => :localhost)
+ c.allow_real_http_requests_to?(URI('http://localhost')).should be_true
+ c.allow_real_http_requests_to?(URI('http://example.com')).should be_false
+ end
+
+ it 'returns false when no option is set' do
+ c = VCR::Cassette.new('example')
+ c.allow_real_http_requests_to?(URI('http://localhost')).should be_false
+ c.allow_real_http_requests_to?(URI('http://example.com')).should be_false
+ end
+
+ it 'delegates to the default :allow_real_http lambda' do
+ [true, false].each do |value|
+ yielded_uri = nil
+ VCR::Config.default_cassette_options.merge!(:allow_real_http => lambda { |uri| yielded_uri = uri; value })
+ c = VCR::Cassette.new('example')
+ c.allow_real_http_requests_to?(:the_uri).should == value
+ yielded_uri.should == :the_uri
+ end
+
+ VCR::Config.default_cassette_options.merge!(:allow_real_http => :localhost)
+ c = VCR::Cassette.new('example')
+ c.allow_real_http_requests_to?(URI('http://localhost')).should be_true
+ c.allow_real_http_requests_to?(URI('http://example.com')).should be_false
+ end
+ end
+
describe '#destroy!' do
temp_dir File.expand_path(File.dirname(__FILE__) + '/fixtures/cassette_spec_destroy'), :assign_to_cache_dir => true
@@ -30,4 +30,34 @@
'The fakeweb error message. You can use VCR to automatically record this request and replay it later with fakeweb. For more details, see the VCR README at: http://github.com/myronmarston/vcr'
end
end
+
+ describe "#with_allow_net_connect_set_to" do
+ it 'sets allow_net_connect for the duration of the block to the provided value' do
+ [true, false].each do |expected|
+ yielded_value = :not_set
+ FakeWeb.with_allow_net_connect_set_to(expected) { yielded_value = FakeWeb.allow_net_connect? }
+ yielded_value.should == expected
+ end
+ end
+
+ it 'returns the value returned by the block' do
+ FakeWeb.with_allow_net_connect_set_to(true) { :return_value }.should == :return_value
+ end
+
+ it 'reverts allow_net_connect when the block completes' do
+ [true, false].each do |expected|
+ FakeWeb.allow_net_connect = expected
+ FakeWeb.with_allow_net_connect_set_to(true) { }
+ FakeWeb.allow_net_connect?.should == expected
+ end
+ end
+
+ it 'reverts allow_net_connect when the block completes, even if an error is raised' do
+ [true, false].each do |expected|
+ FakeWeb.allow_net_connect = expected
+ lambda { FakeWeb.with_allow_net_connect_set_to(true) { raise RuntimeError } }.should raise_error(RuntimeError)
+ FakeWeb.allow_net_connect?.should == expected
+ end
+ end
+ end
end
@@ -3,32 +3,55 @@
describe "Net::HTTP Extensions" do
before(:each) do
VCR.stub!(:current_cassette).and_return(@current_cassette = mock)
+ @uri = URI.parse('http://example.com')
end
- describe 'a request that is not registered with FakeWeb' do
- it 'calls #store_recorded_response! on the current cassette' do
- recorded_response = VCR::RecordedResponse.new(:get, 'http://example.com:80/', :example_response)
- VCR::RecordedResponse.should_receive(:new).with(:get, 'http://example.com:80/', an_instance_of(Net::HTTPOK)).and_return(recorded_response)
- @current_cassette.should_receive(:store_recorded_response!).with(recorded_response)
- Net::HTTP.get(URI.parse('http://example.com'))
+ it 'works when there is no current cassette' do
+ VCR.stub!(:current_cassette).and_return(nil)
+ lambda { Net::HTTP.get(@uri) }.should_not raise_error
+ end
+
+ context 'when current_cassette.allow_real_http_requests_to? returns false' do
+ before(:each) do
+ @current_cassette.should_receive(:allow_real_http_requests_to?).at_least(:once).with(@uri).and_return(false)
end
- it 'calls #store_recorded_response! only once, even when Net::HTTP internally recursively calls #request' do
- @current_cassette.should_receive(:store_recorded_response!).once
- Net::HTTP.new('example.com', 80).post('/', nil)
+ describe 'a request that is not registered with FakeWeb' do
+ it 'calls #store_recorded_response! on the current cassette' do
+ recorded_response = VCR::RecordedResponse.new(:get, 'http://example.com:80/', :example_response)
+ VCR::RecordedResponse.should_receive(:new).with(:get, 'http://example.com:80/', an_instance_of(Net::HTTPOK)).and_return(recorded_response)
+ @current_cassette.should_receive(:store_recorded_response!).with(recorded_response)
+ Net::HTTP.get(@uri)
+ end
+
+ it 'calls #store_recorded_response! only once, even when Net::HTTP internally recursively calls #request' do
+ @current_cassette.should_receive(:store_recorded_response!).once
+ Net::HTTP.new('example.com', 80).post('/', nil)
+ end
end
- it 'does not have an error if there is no current cassette' do
- VCR.stub!(:current_cassette).and_return(nil)
- lambda { Net::HTTP.get(URI.parse('http://example.com')) }.should_not raise_error
+ describe 'a request that is registered with FakeWeb' do
+ it 'does not call #store_recorded_response! on the current cassette' do
+ FakeWeb.register_uri(:get, 'http://example.com', :body => 'example.com response')
+ @current_cassette.should_not_receive(:store_recorded_response!)
+ Net::HTTP.get(@uri)
+ end
end
end
- describe 'a request that is registered with FakeWeb' do
+ context 'when current_cassette.allow_real_http_requests_to? returns true' do
+ before(:each) do
+ @current_cassette.should_receive(:allow_real_http_requests_to?).with(@uri).and_return(true)
+ end
+
it 'does not call #store_recorded_response! on the current cassette' do
- FakeWeb.register_uri(:get, 'http://example.com', :body => 'example.com response')
- @current_cassette.should_not_receive(:store_recorded_response!)
- Net::HTTP.get(URI.parse('http://example.com'))
+ @current_cassette.should_receive(:store_recorded_response!).never
+ Net::HTTP.get(@uri)
+ end
+
+ it 'uses FakeWeb.with_allow_net_connect_set_to(true) to make the request' do
+ FakeWeb.should_receive(:with_allow_net_connect_set_to).with(true).and_yield
+ Net::HTTP.get(@uri)
end
end
end

0 comments on commit 2ed9c3c

Please sign in to comment.