vcr 2.0.0.beta2 → 2.0.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. data/.gitignore +1 -0
  2. data/.travis.yml +0 -2
  3. data/CHANGELOG.md +22 -1
  4. data/CONTRIBUTING.md +46 -0
  5. data/Gemfile +1 -9
  6. data/README.md +8 -2
  7. data/Rakefile +12 -1
  8. data/cucumber.yml +8 -9
  9. data/features/.nav +10 -4
  10. data/features/cassettes/format.feature +1 -1
  11. data/features/cassettes/no_cassette.feature +8 -11
  12. data/features/configuration/allow_http_connections_when_no_cassette.feature +4 -4
  13. data/features/configuration/filter_sensitive_data.feature +3 -0
  14. data/features/configuration/hook_into.feature +4 -8
  15. data/features/configuration/ignore_request.feature +191 -0
  16. data/features/getting_started.md +38 -21
  17. data/features/hooks/after_http_request.feature +44 -0
  18. data/features/hooks/around_http_request.feature +56 -0
  19. data/features/hooks/before_http_request.feature +44 -0
  20. data/features/hooks/before_playback.feature +181 -0
  21. data/features/hooks/before_record.feature +172 -0
  22. data/features/middleware/faraday.feature +7 -3
  23. data/features/record_modes/none.feature +2 -1
  24. data/features/record_modes/once.feature +2 -1
  25. data/features/request_matching/body.feature +2 -2
  26. data/features/request_matching/custom_matcher.feature +2 -2
  27. data/features/request_matching/headers.feature +2 -2
  28. data/features/request_matching/host.feature +2 -2
  29. data/features/request_matching/identical_request_sequence.feature +2 -2
  30. data/features/request_matching/method.feature +2 -2
  31. data/features/request_matching/path.feature +2 -2
  32. data/features/request_matching/playback_repeats.feature +2 -1
  33. data/features/request_matching/uri.feature +2 -2
  34. data/features/support/env.rb +21 -12
  35. data/features/test_frameworks/cucumber.feature +9 -4
  36. data/features/test_frameworks/{rspec.feature → rspec_macro.feature} +7 -7
  37. data/features/test_frameworks/rspec_metadata.feature +90 -0
  38. data/lib/vcr.rb +1 -1
  39. data/lib/vcr/cassette.rb +3 -3
  40. data/lib/vcr/cassette/http_interaction_list.rb +13 -9
  41. data/lib/vcr/cassette/migrator.rb +1 -1
  42. data/lib/vcr/configuration.rb +37 -0
  43. data/lib/vcr/errors.rb +172 -6
  44. data/lib/vcr/library_hooks.rb +4 -6
  45. data/lib/vcr/library_hooks/excon.rb +23 -11
  46. data/lib/vcr/library_hooks/fakeweb.rb +85 -24
  47. data/lib/vcr/library_hooks/faraday.rb +30 -2
  48. data/lib/vcr/library_hooks/typhoeus.rb +25 -3
  49. data/lib/vcr/library_hooks/webmock.rb +25 -36
  50. data/lib/vcr/middleware/faraday.rb +23 -5
  51. data/lib/vcr/request_handler.rb +12 -1
  52. data/lib/vcr/request_ignorer.rb +12 -1
  53. data/lib/vcr/request_matcher_registry.rb +1 -9
  54. data/lib/vcr/structs.rb +32 -2
  55. data/lib/vcr/test_frameworks/rspec.rb +28 -0
  56. data/lib/vcr/util/hooks.rb +12 -4
  57. data/lib/vcr/util/version_checker.rb +2 -0
  58. data/lib/vcr/version.rb +1 -1
  59. data/spec/fixtures/cassette_spec/example.yml +1 -1
  60. data/spec/fixtures/{fake_example.com_responses.yml → fake_example_responses.yml} +0 -0
  61. data/spec/monkey_patches.rb +1 -1
  62. data/spec/spec_helper.rb +3 -1
  63. data/spec/support/http_library_adapters.rb +4 -3
  64. data/spec/support/shared_example_groups/hook_into_http_library.rb +194 -12
  65. data/spec/support/shared_example_groups/request_hooks.rb +58 -0
  66. data/spec/support/shared_example_groups/version_checking.rb +5 -0
  67. data/spec/support/sinatra_app.rb +17 -9
  68. data/spec/support/vcr_stub_helpers.rb +17 -0
  69. data/spec/vcr/cassette/http_interaction_list_spec.rb +28 -29
  70. data/spec/vcr/cassette/migrator_spec.rb +6 -7
  71. data/spec/vcr/cassette_spec.rb +5 -5
  72. data/spec/vcr/configuration_spec.rb +51 -32
  73. data/spec/vcr/deprecations_spec.rb +0 -8
  74. data/spec/vcr/errors_spec.rb +129 -0
  75. data/spec/vcr/library_hooks/excon_spec.rb +21 -4
  76. data/spec/vcr/library_hooks/fakeweb_spec.rb +71 -3
  77. data/spec/vcr/library_hooks/faraday_spec.rb +45 -0
  78. data/spec/vcr/library_hooks/typhoeus_spec.rb +31 -1
  79. data/spec/vcr/library_hooks/webmock_spec.rb +26 -3
  80. data/spec/vcr/middleware/faraday_spec.rb +84 -1
  81. data/spec/vcr/request_ignorer_spec.rb +16 -0
  82. data/spec/vcr/request_matcher_registry_spec.rb +0 -26
  83. data/spec/vcr/structs_spec.rb +61 -1
  84. data/spec/vcr/test_frameworks/rspec_spec.rb +32 -0
  85. data/spec/vcr/util/hooks_spec.rb +73 -63
  86. data/spec/vcr_spec.rb +2 -2
  87. data/vcr.gemspec +5 -5
  88. metadata +51 -31
  89. data/features/configuration/hooks.feature +0 -270
  90. data/features/configuration/ignore_hosts.feature +0 -61
  91. data/features/configuration/ignore_localhost.feature +0 -97
@@ -42,7 +42,7 @@ module VCR
42
42
 
43
43
  hash = {
44
44
  "http_interactions" => http_interactions,
45
- "recorded_with" => "VCR 1.11.3" # assume the last 1.x release
45
+ "recorded_with" => "VCR #{VCR.version}"
46
46
  }
47
47
 
48
48
  def hash.each
@@ -9,6 +9,8 @@ module VCR
9
9
  define_hook :before_record
10
10
  define_hook :before_playback
11
11
  define_hook :after_library_hooks_loaded
12
+ define_hook :before_http_request
13
+ define_hook :after_http_request, :prepend
12
14
 
13
15
  def initialize
14
16
  @allow_http_connections_when_no_cassette = nil
@@ -48,6 +50,10 @@ module VCR
48
50
  VCR.request_ignorer.ignore_localhost = value
49
51
  end
50
52
 
53
+ def ignore_request(&block)
54
+ VCR.request_ignorer.ignore_request(&block)
55
+ end
56
+
51
57
  attr_writer :allow_http_connections_when_no_cassette
52
58
  def allow_http_connections_when_no_cassette?
53
59
  !!@allow_http_connections_when_no_cassette
@@ -62,11 +68,28 @@ module VCR
62
68
  interaction.filter!(placeholder, call_block(block, interaction))
63
69
  end
64
70
  end
71
+ alias define_cassette_placeholder filter_sensitive_data
65
72
 
66
73
  def cassette_serializers
67
74
  VCR.cassette_serializers
68
75
  end
69
76
 
77
+ def around_http_request(&block)
78
+ require 'fiber'
79
+ rescue LoadError
80
+ raise Errors::NotSupportedError.new \
81
+ "VCR::Configuration#around_http_request requires fibers, " +
82
+ "which are not available on your ruby intepreter."
83
+ else
84
+ fiber, hook_decaration = nil, caller.first
85
+ before_http_request { |request| fiber = start_new_fiber_for(request, block) }
86
+ after_http_request { |request| resume_fiber(fiber, hook_decaration) }
87
+ end
88
+
89
+ def configure_rspec_metadata!
90
+ VCR::RSpec::Metadata.configure!
91
+ end
92
+
70
93
  private
71
94
 
72
95
  def load_library_hook(hook)
@@ -76,6 +99,20 @@ module VCR
76
99
  raise e unless e.message.include?(file) # in case FakeWeb/WebMock/etc itself is not available
77
100
  raise ArgumentError.new("#{hook.inspect} is not a supported VCR HTTP library hook.")
78
101
  end
102
+
103
+ def resume_fiber(fiber, hook_declaration)
104
+ fiber.resume
105
+ rescue FiberError
106
+ raise Errors::AroundHTTPRequestHookError.new \
107
+ "Your around_http_request hook declared at #{hook_declaration}" +
108
+ " must call #proceed on the yielded request but did not."
109
+ end
110
+
111
+ def start_new_fiber_for(request, block)
112
+ Fiber.new(&block).tap do |fiber|
113
+ fiber.resume(request.fiber_aware)
114
+ end
115
+ end
79
116
  end
80
117
  end
81
118
 
data/lib/vcr/errors.rb CHANGED
@@ -7,15 +7,181 @@ module VCR
7
7
  class LibraryVersionTooLowError < Error; end
8
8
  class UnregisteredMatcherError < Error; end
9
9
  class InvalidCassetteFormatError < Error; end
10
+ class AroundHTTPRequestHookError < Error; end
11
+ class NotSupportedError < Error; end
12
+
13
+ class UnhandledHTTPRequestError < Error
14
+ attr_reader :request
10
15
 
11
- class HTTPConnectionNotAllowedError < Error
12
16
  def initialize(request)
13
- super \
14
- "Real HTTP connections are disabled. " +
15
- "Request: #{request.method.to_s.upcase} #{request.uri}. " +
16
- "You can use VCR to automatically record this request and replay it later. " +
17
- "For more details, visit the VCR documentation at: http://relishapp.com/myronmarston/vcr/v/#{VCR.version.gsub('.', '-')}"
17
+ @request = request
18
+ super construct_message
19
+ end
20
+
21
+ private
22
+
23
+ def relish_version_slug
24
+ @relish_version_slug ||= VCR.version.gsub(/\W/, '-')
25
+ end
26
+
27
+ def construct_message
28
+ ["", "", "=" * 80,
29
+ "An HTTP request has been made that VCR does not know how to handle:",
30
+ " #{request_description}\n",
31
+ cassette_description,
32
+ formatted_suggestions,
33
+ "=" * 80, "", ""].join("\n")
34
+ end
35
+
36
+ def request_description
37
+ "#{request.method.to_s.upcase} #{request.uri}"
38
+ end
39
+
40
+ def cassette_description
41
+ if cassette = VCR.current_cassette
42
+ ["VCR is currently using the following cassette:",
43
+ " - #{cassette.file}",
44
+ " - :record => #{cassette.record_mode.inspect}",
45
+ " - :match_requests_on => #{cassette.match_requests_on.inspect}\n",
46
+ "Under the current configuration VCR can not find a suitable HTTP interaction",
47
+ "to replay and is prevented from recording new requests. There are a few ways",
48
+ "you can deal with this:\n"].join("\n")
49
+ else
50
+ ["There is currently no cassette in use. There are a few ways",
51
+ "you can configure VCR to handle this request:\n"].join("\n")
52
+ end
53
+ end
54
+
55
+ def formatted_suggestions
56
+ formatted_points, formatted_foot_notes = [], []
57
+
58
+ suggestions.each_with_index do |suggestion, index|
59
+ bullet_point, foot_note = suggestion.first, suggestion.last
60
+ formatted_points << format_bullet_point(bullet_point, index)
61
+ formatted_foot_notes << format_foot_note(foot_note, index)
62
+ end
63
+
64
+ [
65
+ formatted_points.join("\n"),
66
+ formatted_foot_notes.join("\n")
67
+ ].join("\n\n")
68
+ end
69
+
70
+ def format_bullet_point(lines, index)
71
+ lines.first.insert(0, " * ")
72
+ lines.last << " [#{index + 1}]."
73
+ lines.join("\n ")
74
+ end
75
+
76
+ def format_foot_note(url, index)
77
+ "[#{index + 1}] #{url % relish_version_slug}"
78
+ end
79
+
80
+ ALL_SUGGESTIONS = {
81
+ :use_new_episodes => [
82
+ ["You can use the :new_episodes record mode to allow VCR to",
83
+ "record this new request to the existing cassette"],
84
+ "https://www.relishapp.com/myronmarston/vcr/v/%s/docs/record-modes/new-episodes"
85
+ ],
86
+
87
+ :delete_cassette_for_once => [
88
+ ["The current record mode (:once) does not allow new requests to be recorded",
89
+ "to a previously recorded cassette. You can delete the cassette file and re-run",
90
+ "your tests to allow the cassette to be recorded with this request"],
91
+ "https://www.relishapp.com/myronmarston/vcr/v/%s/docs/record-modes/once"
92
+ ],
93
+
94
+ :deal_with_none => [
95
+ ["The current record mode (:none) does not allow requests to be recorded. You",
96
+ "can temporarily change the record mode to :once, delete the cassette file ",
97
+ "and re-run your tests to allow the cassette to be recorded with this request"],
98
+ "https://www.relishapp.com/myronmarston/vcr/v/%s/docs/record-modes/none"
99
+ ],
100
+
101
+ :use_a_cassette => [
102
+ ["If you want VCR to record this request and play it back during future test",
103
+ "runs, you should wrap your test (or this portion of your test) in a",
104
+ "`VCR.use_cassette` block"],
105
+ "https://www.relishapp.com/myronmarston/vcr/v/%s/docs/getting-started"
106
+ ],
107
+
108
+ :allow_http_connections_when_no_cassette => [
109
+ ["If you only want VCR to handle requests made while a cassette is in use,",
110
+ "configure `allow_http_connections_when_no_cassette = true`. VCR will",
111
+ "ignore this request since it is made when there is no cassette"],
112
+ "https://www.relishapp.com/myronmarston/vcr/v/%s/docs/configuration/allow-http-connections-when-no-cassette"
113
+ ],
114
+
115
+ :ignore_request => [
116
+ ["If you want VCR to ignore this request (and others like it), you can",
117
+ "set an `ignore_request` callback"],
118
+ "https://www.relishapp.com/myronmarston/vcr/v/%s/docs/configuration/ignore-request"
119
+ ],
120
+
121
+ :allow_playback_repeats => [
122
+ ["The cassette contains an HTTP interaction that matches this request,",
123
+ "but it has already been played back. If you wish to allow a single HTTP",
124
+ "interaction to be played back multiple times, set the `:allow_playback_repeats`",
125
+ "cassette option"],
126
+ "https://www.relishapp.com/myronmarston/vcr/v/%s/docs/request-matching/playback-repeats"
127
+ ],
128
+
129
+ :match_requests_on => [
130
+ ["The cassette contains %s not been",
131
+ "played back. If your request is non-deterministic, you may need to",
132
+ "change your :match_requests_on cassette option to be more lenient",
133
+ "or use a custom request matcher to allow it to match"],
134
+ "https://www.relishapp.com/myronmarston/vcr/v/%s/docs/request-matching"
135
+ ]
136
+ }
137
+
138
+ def suggestion_for(key)
139
+ bullet_point_lines, url = ALL_SUGGESTIONS[key]
140
+ bullet_point_lines = bullet_point_lines.map(&:dup)
141
+ url = url.dup
142
+ [bullet_point_lines, url]
143
+ end
144
+
145
+ def suggestions
146
+ return no_cassette_suggestions unless cassette = VCR.current_cassette
147
+
148
+ [:use_new_episodes, :ignore_request].tap do |suggestions|
149
+ suggestions.push(*record_mode_suggestion)
150
+ suggestions << :allow_playback_repeats if cassette.http_interactions.has_used_interaction_matching?(request)
151
+ suggestions.map! { |k| suggestion_for(k) }
152
+ suggestions.push(*match_requests_on_suggestion)
153
+ end
154
+ end
155
+
156
+ def no_cassette_suggestions
157
+ [:use_a_cassette, :allow_http_connections_when_no_cassette, :ignore_request].map do |key|
158
+ suggestion_for(key)
159
+ end
160
+ end
161
+
162
+ def record_mode_suggestion
163
+ case VCR.current_cassette.record_mode
164
+ when :none then [:deal_with_none]
165
+ when :once then [:delete_cassette_for_once]
166
+ else []
167
+ end
18
168
  end
169
+
170
+ def match_requests_on_suggestion
171
+ num_remaining_interactions = VCR.current_cassette.http_interactions.remaining_unused_interaction_count
172
+ return [] if num_remaining_interactions.zero?
173
+
174
+ interaction_description = if num_remaining_interactions == 1
175
+ "1 HTTP interaction that has"
176
+ else
177
+ "#{num_remaining_interactions} HTTP interactions that have"
178
+ end
179
+
180
+ description_lines, link = suggestion_for(:match_requests_on)
181
+ description_lines[0] = description_lines[0] % interaction_description
182
+ [[description_lines, link]]
183
+ end
184
+
19
185
  end
20
186
  end
21
187
  end
@@ -1,18 +1,16 @@
1
1
  module VCR
2
2
  class LibraryHooks
3
- def initialize
4
- @exclusive_hook = nil
5
- end
3
+ attr_accessor :exclusive_hook
6
4
 
7
5
  def disabled?(hook)
8
- ![nil, hook].include?(@exclusive_hook)
6
+ ![nil, hook].include?(exclusive_hook)
9
7
  end
10
8
 
11
9
  def exclusively_enabled(hook)
12
- @exclusive_hook = hook
10
+ self.exclusive_hook = hook
13
11
  yield
14
12
  ensure
15
- @exclusive_hook = nil
13
+ self.exclusive_hook = nil
16
14
  end
17
15
  end
18
16
  end
@@ -2,7 +2,7 @@ require 'vcr/util/version_checker'
2
2
  require 'vcr/request_handler'
3
3
  require 'excon'
4
4
 
5
- VCR::VersionChecker.new('Excon', Excon::VERSION, '0.6.5', '0.6').check_version!
5
+ VCR::VersionChecker.new('Excon', Excon::VERSION, '0.6.5', '0.7').check_version!
6
6
 
7
7
  module VCR
8
8
  class LibraryHooks
@@ -10,12 +10,20 @@ module VCR
10
10
  class RequestHandler < ::VCR::RequestHandler
11
11
  attr_reader :params
12
12
  def initialize(params)
13
+ @vcr_response = nil
13
14
  @params = params
14
15
  end
15
16
 
17
+ def handle
18
+ super
19
+ ensure
20
+ invoke_after_request_hook(@vcr_response)
21
+ end
22
+
16
23
  private
17
24
 
18
25
  def on_stubbed_request
26
+ @vcr_response = stubbed_response
19
27
  {
20
28
  :body => stubbed_response.body,
21
29
  :headers => normalized_headers(stubbed_response.headers || {}),
@@ -23,6 +31,10 @@ module VCR
23
31
  }
24
32
  end
25
33
 
34
+ def on_ignored_request
35
+ perform_real_request
36
+ end
37
+
26
38
  def response_from_excon_error(error)
27
39
  if error.respond_to?(:response)
28
40
  error.response
@@ -34,20 +46,18 @@ module VCR
34
46
  end
35
47
 
36
48
  def perform_real_request
37
- connection = ::Excon.new(uri)
38
-
39
- response = begin
40
- connection.request(params.merge(:mock => false))
41
- rescue ::Excon::Errors::Error => e
42
- yield response_from_excon_error(e) if block_given?
43
- raise e
49
+ begin
50
+ response = ::Excon.new(uri).request(params.merge(:mock => false))
51
+ rescue ::Excon::Errors::Error => excon_error
52
+ response = response_from_excon_error(excon_error)
44
53
  end
45
54
 
55
+ @vcr_response = vcr_response_from(response)
46
56
  yield response if block_given?
57
+ raise excon_error if excon_error
47
58
 
48
59
  response.attributes
49
60
  end
50
- alias on_ignored_request perform_real_request
51
61
 
52
62
  def on_recordable_request
53
63
  perform_real_request do |response|
@@ -60,6 +70,8 @@ module VCR
60
70
  @uri ||= "#{params[:scheme]}://#{params[:host]}:#{params[:port]}#{params[:path]}#{query}"
61
71
  end
62
72
 
73
+ # based on:
74
+ # https://github.com/geemus/excon/blob/v0.7.8/lib/excon/connection.rb#L117-132
63
75
  def query
64
76
  @query ||= case params[:query]
65
77
  when String
@@ -84,7 +96,7 @@ module VCR
84
96
  def http_interaction_for(response)
85
97
  VCR::HTTPInteraction.new \
86
98
  vcr_request,
87
- vcr_response(response)
99
+ vcr_response_from(response)
88
100
  end
89
101
 
90
102
  def vcr_request
@@ -100,7 +112,7 @@ module VCR
100
112
  end
101
113
  end
102
114
 
103
- def vcr_response(response)
115
+ def vcr_response_from(response)
104
116
  VCR::Response.new \
105
117
  VCR::ResponseStatus.new(response.status, nil),
106
118
  response.headers,
@@ -3,6 +3,7 @@ require 'fakeweb'
3
3
  require 'net/http'
4
4
  require 'vcr/extensions/net_http_response'
5
5
  require 'vcr/request_handler'
6
+ require 'set'
6
7
 
7
8
  VCR::VersionChecker.new('FakeWeb', FakeWeb::VERSION, '1.3.0', '1.3').check_version!
8
9
 
@@ -10,39 +11,84 @@ module VCR
10
11
  class LibraryHooks
11
12
  module FakeWeb
12
13
  class RequestHandler < ::VCR::RequestHandler
13
- attr_reader :net_http, :request, :request_body, :block
14
- def initialize(net_http, request, request_body = nil, &block)
15
- @net_http, @request, @request_body, @block =
16
- net_http, request, request_body, block
14
+ attr_reader :net_http, :request, :request_body, :response_block
15
+ def initialize(net_http, request, request_body = nil, &response_block)
16
+ @net_http, @request, @request_body, @response_block =
17
+ net_http, request, request_body, response_block
18
+ @vcr_response, @recursing = nil, false
17
19
  end
18
20
 
19
- private
21
+ def handle
22
+ super
23
+ ensure
24
+ invoke_after_request_hook(@vcr_response) unless @recursing
25
+ end
20
26
 
21
- def perform_and_record_request
22
- # Net::HTTP calls #request recursively in certain circumstances.
23
- # We only want to record hte request when the request is started, as
24
- # that is the final time through #request.
25
- return perform_request unless net_http.started?
27
+ class << self
28
+ def already_seen_requests
29
+ @already_seen_requests ||= Set.new
30
+ end
31
+ end
26
32
 
27
- perform_request do |response|
28
- VCR.record_http_interaction VCR::HTTPInteraction.new(vcr_request, vcr_response_from(response))
29
- response.extend VCR::Net::HTTPResponse # "unwind" the response
30
- block.call(response) if block
33
+ private
34
+
35
+ def invoke_before_request_hook
36
+ unless self.class.already_seen_requests.include?(request.object_id)
37
+ super
38
+ # we use the object_id so that if there is bug that causes
39
+ # us not to fully cleanup, we'll only be leaking the memory
40
+ # of one integer, not the whole request object.
41
+ self.class.already_seen_requests << request.object_id
31
42
  end
32
43
  end
33
- alias on_recordable_request perform_and_record_request
34
44
 
35
- def perform_stubbed_request
45
+ def invoke_after_request_hook(vcr_response)
46
+ self.class.already_seen_requests.delete(request.object_id)
47
+ super
48
+ end
49
+
50
+ def on_recordable_request
51
+ perform_request(net_http.started?, :record_interaction)
52
+ end
53
+
54
+ def on_stubbed_request
36
55
  with_exclusive_fakeweb_stub(stubbed_response) do
37
- perform_request
56
+ # force it to be considered started since it doesn't
57
+ # recurse in this case like the others.
58
+ perform_request(:started)
38
59
  end
39
60
  end
40
- alias on_stubbed_request perform_stubbed_request
41
61
 
42
- def perform_request(&record_block)
43
- net_http.request_without_vcr(request, request_body, &(record_block || block))
62
+ def on_ignored_request
63
+ perform_request(net_http.started?)
64
+ end
65
+
66
+ # overriden to prevent it from invoking the after_http_request hook,
67
+ # since we invoke the hook in an ensure block above.
68
+ def on_connection_not_allowed
69
+ raise VCR::Errors::UnhandledHTTPRequestError.new(vcr_request)
70
+ end
71
+
72
+ def perform_request(started, record_interaction = false)
73
+ # Net::HTTP calls #request recursively in certain circumstances.
74
+ # We only want to record the request when the request is started, as
75
+ # that is the final time through #request.
76
+ unless started
77
+ @recursing = true
78
+ return net_http.request_without_vcr(request, request_body, &response_block)
79
+ end
80
+
81
+ net_http.request_without_vcr(request, request_body) do |response|
82
+ @vcr_response = vcr_response_from(response)
83
+
84
+ if record_interaction
85
+ VCR.record_http_interaction VCR::HTTPInteraction.new(vcr_request, @vcr_response)
86
+ end
87
+
88
+ response.extend VCR::Net::HTTPResponse # "unwind" the response
89
+ response_block.call(response) if response_block
90
+ end
44
91
  end
45
- alias on_ignored_request perform_request
46
92
 
47
93
  def uri
48
94
  @uri ||= ::FakeWeb::Utility.request_uri_as_string(net_http, request)
@@ -91,9 +137,13 @@ module Net
91
137
  class HTTP
92
138
  unless method_defined?(:request_with_vcr)
93
139
  def request_with_vcr(*args, &block)
94
- VCR::LibraryHooks::FakeWeb::RequestHandler.new(
95
- self, *args, &block
96
- ).handle
140
+ if VCR.turned_on?
141
+ VCR::LibraryHooks::FakeWeb::RequestHandler.new(
142
+ self, *args, &block
143
+ ).handle
144
+ else
145
+ request_without_vcr(*args, &block)
146
+ end
97
147
  end
98
148
 
99
149
  alias request_without_vcr request
@@ -102,6 +152,17 @@ module Net
102
152
  end
103
153
  end
104
154
 
155
+ class << FakeWeb
156
+ # ensure HTTP requests are always allowed; VCR takes care of disallowing
157
+ # them at the appropriate times in its hook
158
+ def allow_net_connect_with_vcr?(*args)
159
+ VCR.turned_on? ? true : allow_net_connect_without_vcr?
160
+ end
161
+
162
+ alias allow_net_connect_without_vcr? allow_net_connect?
163
+ alias allow_net_connect? allow_net_connect_with_vcr?
164
+ end unless FakeWeb.respond_to?(:allow_net_connect_with_vcr?)
165
+
105
166
  VCR.configuration.after_library_hooks_loaded do
106
167
  if defined?(WebMock)
107
168
  raise ArgumentError.new("You have configured VCR to hook into both :fakeweb and :webmock. You cannot use both.")