vcr 1.1.0 → 1.1.1
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.
- data/.document +5 -0
- data/.gitignore +27 -0
- data/CHANGELOG.md +13 -0
- data/Gemfile +24 -0
- data/Gemfile.lock +119 -0
- data/README.md +3 -6
- data/Rakefile +70 -0
- data/benchmarks/http_stubbing_libraries.rb +59 -0
- data/features/fixtures/vcr_cassettes/1.9.1/cucumber_tags/regex_cassette.yml +43 -0
- data/features/fixtures/vcr_cassettes/1.9.1/cucumber_tags/replay_cassette1.yml +43 -0
- data/features/fixtures/vcr_cassettes/1.9.1/cucumber_tags/replay_cassette2.yml +63 -0
- data/features/fixtures/vcr_cassettes/1.9.1/cucumber_tags/replay_cassette3.yml +85 -0
- data/features/fixtures/vcr_cassettes/1.9.1/erb_cassette.yml +36 -0
- data/features/fixtures/vcr_cassettes/1.9.1/match_requests_on.yml +35 -0
- data/features/fixtures/vcr_cassettes/1.9.1/nested_replay_cassette.yml +32 -0
- data/features/fixtures/vcr_cassettes/1.9.1/not_the_real_response.yml +43 -0
- data/features/fixtures/vcr_cassettes/1.9.1/replay_localhost_cassette.yml +32 -0
- data/features/fixtures/vcr_cassettes/not_1.9.1/cucumber_tags/regex_cassette.yml +43 -0
- data/features/fixtures/vcr_cassettes/not_1.9.1/cucumber_tags/replay_cassette1.yml +43 -0
- data/features/fixtures/vcr_cassettes/not_1.9.1/cucumber_tags/replay_cassette2.yml +47 -0
- data/features/fixtures/vcr_cassettes/not_1.9.1/cucumber_tags/replay_cassette3.yml +85 -0
- data/features/fixtures/vcr_cassettes/not_1.9.1/erb_cassette.yml +36 -0
- data/features/fixtures/vcr_cassettes/not_1.9.1/match_requests_on.yml +35 -0
- data/features/fixtures/vcr_cassettes/not_1.9.1/nested_replay_cassette.yml +24 -0
- data/features/fixtures/vcr_cassettes/not_1.9.1/not_the_real_response.yml +43 -0
- data/features/fixtures/vcr_cassettes/not_1.9.1/replay_localhost_cassette.yml +32 -0
- data/features/http_client.feature +16 -0
- data/features/net_http.feature +27 -0
- data/features/record_response.feature +66 -0
- data/features/replay_recorded_response.feature +96 -0
- data/features/step_definitions/http_client_steps.rb +7 -0
- data/features/step_definitions/net_http_steps.rb +37 -0
- data/features/step_definitions/vcr_steps.rb +240 -0
- data/features/support/env.rb +104 -0
- data/features/webmock.feature +26 -0
- data/lib/vcr.rb +2 -2
- data/lib/vcr/extensions/net_http.rb +0 -8
- data/lib/vcr/http_stubbing_adapters/common.rb +39 -0
- data/lib/vcr/http_stubbing_adapters/fakeweb.rb +74 -70
- data/lib/vcr/http_stubbing_adapters/webmock.rb +61 -62
- data/lib/vcr/version.rb +1 -1
- data/spec/cassette_spec.rb +280 -0
- data/spec/config_spec.rb +76 -0
- data/spec/cucumber_tags_spec.rb +55 -0
- data/spec/deprecations_spec.rb +52 -0
- data/spec/extensions/net_http_response_spec.rb +85 -0
- data/spec/extensions/net_http_spec.rb +77 -0
- data/spec/fixtures/1.9.1/0_3_1_cassette.yml +29 -0
- data/spec/fixtures/1.9.1/cassette_spec/erb_with_no_vars.yml +32 -0
- data/spec/fixtures/1.9.1/cassette_spec/erb_with_vars.yml +32 -0
- data/spec/fixtures/1.9.1/cassette_spec/example.yml +110 -0
- data/spec/fixtures/1.9.1/cassette_spec/with_localhost_requests.yml +86 -0
- data/spec/fixtures/1.9.1/example_net_http.yml +14 -0
- data/spec/fixtures/1.9.1/example_net_http_request.yml +12 -0
- data/spec/fixtures/1.9.1/example_net_http_response.yml +25 -0
- data/spec/fixtures/1.9.1/fake_example.com_responses.yml +106 -0
- data/spec/fixtures/1.9.1/match_requests_on.yml +185 -0
- data/spec/fixtures/not_1.9.1/0_3_1_cassette.yml +29 -0
- data/spec/fixtures/not_1.9.1/cassette_spec/erb_with_no_vars.yml +32 -0
- data/spec/fixtures/not_1.9.1/cassette_spec/erb_with_vars.yml +32 -0
- data/spec/fixtures/not_1.9.1/cassette_spec/example.yml +110 -0
- data/spec/fixtures/not_1.9.1/cassette_spec/with_localhost_requests.yml +86 -0
- data/spec/fixtures/not_1.9.1/example_net_http.yml +14 -0
- data/spec/fixtures/not_1.9.1/example_net_http_request.yml +12 -0
- data/spec/fixtures/not_1.9.1/example_net_http_response.yml +25 -0
- data/spec/fixtures/not_1.9.1/fake_example.com_responses.yml +106 -0
- data/spec/fixtures/not_1.9.1/match_requests_on.yml +185 -0
- data/spec/http_stubbing_adapters/fakeweb_spec.rb +35 -0
- data/spec/http_stubbing_adapters/webmock_spec.rb +35 -0
- data/spec/request_matcher_spec.rb +194 -0
- data/spec/spec_helper.rb +40 -0
- data/spec/structs_spec.rb +121 -0
- data/spec/support/disable_warnings.rb +12 -0
- data/spec/support/http_library_adapters.rb +272 -0
- data/spec/support/http_stubbing_adapter.rb +100 -0
- data/spec/support/pending_on_heroku.rb +14 -0
- data/spec/support/temp_cassette_library_dir.rb +16 -0
- data/spec/support/vcr_localhost_server.rb +53 -0
- data/spec/vcr_spec.rb +198 -0
- data/spec/version_spec.rb +11 -0
- data/vcr.gemspec +43 -0
- metadata +134 -73
- data/lib/vcr/http_stubbing_adapters/base.rb +0 -36
- data/lib/vcr/version.rbc +0 -572
@@ -0,0 +1,37 @@
|
|
1
|
+
module NetHTTPHelpers
|
2
|
+
def perform_net_http_get_with_returning_block(uri, path)
|
3
|
+
Net::HTTP.new(uri.host, uri.port).request(Net::HTTP::Get.new(path, {})) do |response|
|
4
|
+
return response
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
World(NetHTTPHelpers)
|
9
|
+
|
10
|
+
When /^I make an asynchronous Net::HTTP get request to "([^\"]*)"$/ do |url|
|
11
|
+
capture_response(url) do |uri, path|
|
12
|
+
result = Net::HTTP.new(uri.host, uri.port).request_get(path) { |r| r.read_body { } }
|
13
|
+
result.body.should be_a(Net::ReadAdapter)
|
14
|
+
result
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
When /^I make a replayed asynchronous Net::HTTP get request to "([^\"]*)"$/ do |url|
|
19
|
+
capture_response(url) do |uri, path|
|
20
|
+
result_body = ''
|
21
|
+
result = Net::HTTP.new(uri.host, uri.port).request_get(path) { |r| r.read_body { |fragment| result_body << fragment } }
|
22
|
+
result.body.should == result_body
|
23
|
+
result
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
When /^I make a recursive Net::HTTP post request to "([^\"]*)"$/ do |url|
|
28
|
+
capture_response(url) do |uri, path|
|
29
|
+
Net::HTTP.new(uri.host, uri.port).post(path, nil)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
When /^I make a returning block Net::HTTP get request to "([^\"]*)"$/ do |url|
|
34
|
+
capture_response(url) do |uri, path|
|
35
|
+
perform_net_http_get_with_returning_block(uri, path)
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,240 @@
|
|
1
|
+
require 'tmpdir'
|
2
|
+
|
3
|
+
RSpec::Matchers.define :have_expected_response do |regex_str, request_attributes|
|
4
|
+
def matched_responses(responses, request_attributes)
|
5
|
+
url, request_body, request_headers = request_attributes[:url], request_attributes[:request_body], request_attributes[:request_headers]
|
6
|
+
|
7
|
+
selector = case url
|
8
|
+
when String then lambda { |r| URI.parse(r.uri) == URI.parse(url) }
|
9
|
+
when Regexp then lambda { |r| r.uri == url }
|
10
|
+
else raise ArgumentError.new("Unexpected url: #{url.class.to_s}: #{url.inspect}")
|
11
|
+
end
|
12
|
+
|
13
|
+
matched = responses.select(&selector)
|
14
|
+
|
15
|
+
if request_body
|
16
|
+
matched = matched.select { |r| r.request.body == request_body }
|
17
|
+
end
|
18
|
+
|
19
|
+
(request_headers || {}).each do |r_key, r_val|
|
20
|
+
matched = matched.select do |r|
|
21
|
+
r.request.headers.any? { |k, v| k.downcase == r_key.downcase && v == [r_val] }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
matched
|
26
|
+
end
|
27
|
+
|
28
|
+
match do |responses|
|
29
|
+
regex = /#{regex_str}/i
|
30
|
+
matched_responses(responses, request_attributes).detect { |r| r.response.body =~ regex }
|
31
|
+
end
|
32
|
+
|
33
|
+
failure_message_for_should do |responses|
|
34
|
+
url = request_attributes[:url]
|
35
|
+
responses = matched_responses(responses, request_attributes)
|
36
|
+
response_bodies = responses.map { |r| r.response.body }
|
37
|
+
"expected a response for #{url.inspect} to match /#{regex_str}/. Responses for #{url.inspect}:\n\n #{response_bodies.join("\n\n")}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
RSpec::Matchers.define :be_tagged_with do |tag|
|
42
|
+
match do |scenario|
|
43
|
+
scenario.source_tag_names.include?(tag)
|
44
|
+
end
|
45
|
+
|
46
|
+
failure_message_for_should do |scenario|
|
47
|
+
"expected scenario to be tagged with #{tag}. Tags: #{scenario.source_tag_names.inspect}"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
RSpec::Matchers.define :have_normalized_headers do
|
52
|
+
match do |object|
|
53
|
+
headers = object.headers
|
54
|
+
headers.is_a?(Hash) &&
|
55
|
+
headers.keys.map { |k| k.downcase } == headers.keys &&
|
56
|
+
headers.values.all? { |val| val.is_a?(Array) }
|
57
|
+
end
|
58
|
+
|
59
|
+
failure_message_for_should do |object|
|
60
|
+
"expected headers to be normalized to have lower cased keys and arrays as values. Actual headers: #{object.headers.inspect}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
module VCRHelpers
|
65
|
+
def static_rack_server(response_string)
|
66
|
+
orig_ignore_localhost = VCR.http_stubbing_adapter.ignore_localhost?
|
67
|
+
VCR.http_stubbing_adapter.ignore_localhost = true
|
68
|
+
|
69
|
+
begin
|
70
|
+
VCR::LocalhostServer::STATIC_SERVERS[response_string]
|
71
|
+
ensure
|
72
|
+
VCR.http_stubbing_adapter.ignore_localhost = orig_ignore_localhost
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def recorded_interactions_for(cassette_name)
|
77
|
+
yaml_file = File.join(VCR::Config.cassette_library_dir, "#{cassette_name}.yml")
|
78
|
+
yaml = File.open(yaml_file, 'r') { |f| f.read }
|
79
|
+
interactions = YAML.load(yaml)
|
80
|
+
end
|
81
|
+
|
82
|
+
def capture_response(url)
|
83
|
+
@http_requests ||= Hash.new([])
|
84
|
+
uri = URI.parse(url)
|
85
|
+
path = uri.path.to_s == '' ? '/' : uri.path
|
86
|
+
begin
|
87
|
+
result = yield uri, path
|
88
|
+
rescue => e
|
89
|
+
result = e
|
90
|
+
end
|
91
|
+
@http_requests[url] += [result]
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
World(VCRHelpers)
|
96
|
+
|
97
|
+
Given /^we do not have a "([^\"]*)" cassette$/ do |cassette_name|
|
98
|
+
fixture_file = File.join(VCR::Config.cassette_library_dir, "#{cassette_name}.yml")
|
99
|
+
File.exist?(fixture_file).should be_false
|
100
|
+
end
|
101
|
+
|
102
|
+
Given /^we have a "([^\"]*)" library file with (a|no) previously recorded response for "([^\"]*)"$/ do |file_name, a_or_no, url|
|
103
|
+
fixture_file = File.join(VCR::Config.cassette_library_dir, "#{file_name}.yml")
|
104
|
+
File.exist?(fixture_file).should be_true
|
105
|
+
responses = File.open(fixture_file, 'r') { |f| YAML.load(f.read) }
|
106
|
+
should_method = a_or_no == 'a' ? :should : :should_not
|
107
|
+
responses.map{ |r| URI.parse(r.uri) }.send(should_method, include(URI.parse(url)))
|
108
|
+
end
|
109
|
+
|
110
|
+
Given /^the "([^\"]*)" library file has a response for "([^\"]*)" that matches \/(.+)\/$/ do |cassette_name, url, regex_str|
|
111
|
+
Given %{we have a "#{cassette_name}" library file with a previously recorded response for "#{url}"}
|
112
|
+
Then %{the "#{cassette_name}" library file should have a response for "#{url}" that matches /#{regex_str}/}
|
113
|
+
end
|
114
|
+
|
115
|
+
Given /^the "([^\"]*)" library file has a response for \/(\S+)\/ that matches \/(.+)\/$/ do |cassette_name, url_regex, body_regex|
|
116
|
+
recorded_interactions_for(cassette_name).should have_expected_response(body_regex, :url => /#{url_regex}/)
|
117
|
+
end
|
118
|
+
|
119
|
+
Given /^the "([^"]*)" library file has a response for "([^"]*)" with the request body "([^"]*)" that matches \/(.+)\/$/ do |cassette_name, url, request_body, response_regex|
|
120
|
+
recorded_interactions_for(cassette_name).should have_expected_response(response_regex, :url => url, :request_body => request_body)
|
121
|
+
end
|
122
|
+
|
123
|
+
Given /^the "([^"]*)" library file has a response for "([^"]*)" with the request header "([^"]*)=([^"]*)" that matches \/(.+)\/$/ do |cassette_name, url, header_key, header_value, response_regex|
|
124
|
+
recorded_interactions_for(cassette_name).should have_expected_response(response_regex, :url => url, :request_headers => { header_key => header_value })
|
125
|
+
end
|
126
|
+
|
127
|
+
Given /^this scenario is tagged with the vcr cassette tag: "([^\"]+)"$/ do |tag|
|
128
|
+
VCR.current_cucumber_scenario.should be_tagged_with(tag)
|
129
|
+
VCR::CucumberTags.tags.should include(tag)
|
130
|
+
end
|
131
|
+
|
132
|
+
Given /^the previous scenario was tagged with the vcr cassette tag: "([^\"]*)"$/ do |tag|
|
133
|
+
last_scenario = VCR.completed_cucumber_scenarios.last
|
134
|
+
last_scenario.should_not be_nil
|
135
|
+
last_scenario.should be_tagged_with(tag)
|
136
|
+
VCR::CucumberTags.tags.should include(tag)
|
137
|
+
end
|
138
|
+
|
139
|
+
When /^I make (?:an )?HTTP get request to "([^\"]*)"$/ do |url|
|
140
|
+
capture_response(url) do |uri, path|
|
141
|
+
make_http_request(:get, url)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
When /^I make an HTTP post request to "([^"]*)" with request body "([^"]*)"$/ do |url, request_body|
|
146
|
+
capture_response(url) do |uri, path|
|
147
|
+
make_http_request(:post, url, request_body)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
When /^I make an HTTP post request to "([^"]*)" with request header "([^"]*)=([^"]*)"$/ do |url, header_key, header_val|
|
152
|
+
capture_response(url) do |uri, path|
|
153
|
+
make_http_request(:post, url, '', { header_key => header_val })
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
When /^I make (.*) requests? to "([^\"]*)"(?: and "([^\"]*)")? within the "([^\"]*)" cassette(?: using cassette options: (.*))?$/ do |http_request_type, url1, url2, cassette_name, options|
|
158
|
+
options = options.to_s == '' ? { :record => :new_episodes } : eval(options)
|
159
|
+
urls = [url1, url2].select { |u| u.to_s.size > 0 }
|
160
|
+
VCR.use_cassette(cassette_name, options) do
|
161
|
+
urls.each do |url|
|
162
|
+
When %{I make #{http_request_type} request to "#{url}"}
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
When /^I make an HTTP post request to "([^"]*)" with request body "([^"]*)" within the "([^"]*)" cassette(?: using cassette options: (.*))?$/ do |url, request_body, cassette_name, options|
|
168
|
+
options = options.to_s == '' ? { :record => :new_episodes } : eval(options)
|
169
|
+
VCR.use_cassette(cassette_name, options) do
|
170
|
+
When %{I make an HTTP post request to "#{url}" with request body "#{request_body}"}
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
When /^I make an HTTP post request to "([^"]*)" with request header "([^"]*)=([^"]*)" within the "([^"]*)" cassette(?: using cassette options: (.*))?$/ do |url, header_key, header_value, cassette_name, options|
|
175
|
+
options = options.to_s == '' ? { :record => :new_episodes } : eval(options)
|
176
|
+
VCR.use_cassette(cassette_name, options) do
|
177
|
+
When %{I make an HTTP post request to "#{url}" with request header "#{header_key}=#{header_value}"}
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
Then /^the "([^\"]*)" library file should have a response for "([^\"]*)" that matches \/(.+)\/$/ do |cassette_name, url, regex_str|
|
182
|
+
interactions = recorded_interactions_for(cassette_name)
|
183
|
+
interactions.should have_expected_response(regex_str, :url => url)
|
184
|
+
end
|
185
|
+
|
186
|
+
Then /^the "([^\"]*)" library file should have exactly (\d+) response$/ do |cassette_name, response_count|
|
187
|
+
interactions = recorded_interactions_for(cassette_name)
|
188
|
+
interactions.should have(response_count.to_i).responses
|
189
|
+
end
|
190
|
+
|
191
|
+
Then /^the "([^"]*)" library file should have normalized headers for all recorded interactions$/ do |cassette_name|
|
192
|
+
interactions = recorded_interactions_for(cassette_name)
|
193
|
+
interactions.each do |i|
|
194
|
+
i.request.should have_normalized_headers
|
195
|
+
i.response.should have_normalized_headers
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
Then /^I can test the scenario cassette's recorded responses in the next scenario, after the cassette has been ejected$/ do
|
200
|
+
# do nothing...
|
201
|
+
end
|
202
|
+
|
203
|
+
Then /^the HTTP get request to "([^\"]*)" should result in an error that mentions VCR$/ do |url|
|
204
|
+
result = @http_requests[url][0]
|
205
|
+
result.should be_a(StandardError)
|
206
|
+
result.message.should =~ /VCR/
|
207
|
+
end
|
208
|
+
|
209
|
+
Then /^(?:the )?response(?: (\d+))? for "([^\"]*)" should match \/(.+)\/$/ do |response_num, url, regex_str|
|
210
|
+
response_num = response_num.to_i || 0
|
211
|
+
response_num -= 1 if response_num > 0 # translate to 0-based array index.
|
212
|
+
regex = /#{regex_str}/i
|
213
|
+
get_body_string(@http_requests[url][response_num]).should =~ regex
|
214
|
+
end
|
215
|
+
|
216
|
+
Then /^there should not be a "([^\"]*)" library file$/ do |cassette_name|
|
217
|
+
yaml_file = File.join(VCR::Config.cassette_library_dir, "#{cassette_name}.yml")
|
218
|
+
File.exist?(yaml_file).should be_false
|
219
|
+
end
|
220
|
+
|
221
|
+
Given /^the ignore_localhost config setting is set to (true|false)$/ do |value|
|
222
|
+
VCR::Config.ignore_localhost = eval(value)
|
223
|
+
end
|
224
|
+
|
225
|
+
Given /^a rack app is running on localhost that returns "([^"]+)" for all requests$/ do |response_string|
|
226
|
+
@rack_server = static_rack_server(response_string)
|
227
|
+
end
|
228
|
+
|
229
|
+
When /^I make an HTTP get request to the localhost rack app within the "([^\"]*)" cassette$/ do |cassette|
|
230
|
+
When %{I make an HTTP get request to "http://localhost:#{@rack_server.port}/" within the "#{cassette}" cassette}
|
231
|
+
end
|
232
|
+
|
233
|
+
Then /^the response for the localhost rack app should match \/(.*)\/$/ do |regex|
|
234
|
+
Then %{the response for "http://localhost:#{@rack_server.port}/" should match /#{regex}/}
|
235
|
+
end
|
236
|
+
|
237
|
+
Given /^the "([^\"]*)" library file has a response for localhost that matches \/(.*)\/$/ do |cassette, regex|
|
238
|
+
port = static_rack_server('localhost response').port
|
239
|
+
Given %{the "#{cassette}" library file has a response for "http://localhost:#{port}/" that matches /#{regex}/}
|
240
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../spec/support')
|
2
|
+
|
3
|
+
if ENV['HTTP_STUBBING_ADAPTER'].to_s == ''
|
4
|
+
ENV['HTTP_STUBBING_ADAPTER'] = 'fakeweb'
|
5
|
+
warn "Using FakeWeb for VCR's cucumber features since the adapter was not specified. Set HTTP_STUBBING_ADAPTER to specify."
|
6
|
+
end
|
7
|
+
|
8
|
+
if ENV['HTTP_LIB'].to_s == ''
|
9
|
+
ENV['HTTP_LIB'] = 'net/http'
|
10
|
+
warn "Using Net::HTTP for VCR's cucumber features since the HTTP library was not specified. Set HTTP_LIB to specify."
|
11
|
+
end
|
12
|
+
|
13
|
+
# The HTTP library must be loaded before VCR since WebMock looks for the presence of the HTTB library class constant
|
14
|
+
# to decide whether or not to hook into it.
|
15
|
+
require ENV['HTTP_LIB']
|
16
|
+
require 'http_library_adapters'
|
17
|
+
World(HTTP_LIBRARY_ADAPTERS[ENV['HTTP_LIB']])
|
18
|
+
|
19
|
+
puts "\n\n---------------- Running features using #{ENV['HTTP_STUBBING_ADAPTER']} and #{ENV['HTTP_LIB']} -----------------\n"
|
20
|
+
|
21
|
+
require 'vcr'
|
22
|
+
require 'vcr_localhost_server'
|
23
|
+
|
24
|
+
require 'rubygems'
|
25
|
+
require 'bundler'
|
26
|
+
Bundler.setup
|
27
|
+
|
28
|
+
begin
|
29
|
+
require 'ruby-debug'
|
30
|
+
Debugger.start
|
31
|
+
Debugger.settings[:autoeval] = true if Debugger.respond_to?(:settings)
|
32
|
+
rescue LoadError
|
33
|
+
# ruby-debug wasn't available so neither can the debugging be
|
34
|
+
end unless RUBY_VERSION > '1.9.1' # ruby-debug doesn't work on 1.9.2 yet
|
35
|
+
|
36
|
+
# Ruby 1.9.1 has a different yaml serialization format.
|
37
|
+
YAML_SERIALIZATION_VERSION = RUBY_VERSION == '1.9.1' ? '1.9.1' : 'not_1.9.1'
|
38
|
+
|
39
|
+
VCR.config do |c|
|
40
|
+
c.cassette_library_dir = File.join(File.dirname(__FILE__), '..', 'fixtures', 'vcr_cassettes', YAML_SERIALIZATION_VERSION)
|
41
|
+
c.http_stubbing_library = ENV['HTTP_STUBBING_ADAPTER'].to_sym
|
42
|
+
end
|
43
|
+
|
44
|
+
VCR.module_eval do
|
45
|
+
def self.completed_cucumber_scenarios
|
46
|
+
@completed_cucumber_scenarios ||= []
|
47
|
+
end
|
48
|
+
|
49
|
+
class << self
|
50
|
+
attr_accessor :current_cucumber_scenario
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
After do |scenario|
|
55
|
+
if raised_error = (@http_requests || {}).values.flatten.detect { |result| result.is_a?(Exception) && result.message !~ /VCR/ }
|
56
|
+
raise raised_error
|
57
|
+
end
|
58
|
+
VCR.completed_cucumber_scenarios << scenario
|
59
|
+
end
|
60
|
+
|
61
|
+
Before do |scenario|
|
62
|
+
VCR::Config.ignore_localhost = false
|
63
|
+
|
64
|
+
VCR.current_cucumber_scenario = scenario
|
65
|
+
temp_dir = File.join(VCR::Config.cassette_library_dir, 'temp')
|
66
|
+
FileUtils.rm_rf(temp_dir) if File.exist?(temp_dir)
|
67
|
+
end
|
68
|
+
|
69
|
+
Before('@copy_not_the_real_response_to_temp') do
|
70
|
+
orig_file = File.join(VCR::Config.cassette_library_dir, 'not_the_real_response.yml')
|
71
|
+
temp_file = File.join(VCR::Config.cassette_library_dir, 'temp', 'not_the_real_response.yml')
|
72
|
+
FileUtils.mkdir_p(File.join(VCR::Config.cassette_library_dir, 'temp'))
|
73
|
+
FileUtils.cp orig_file, temp_file
|
74
|
+
end
|
75
|
+
|
76
|
+
Before('@create_replay_localhost_cassette') do
|
77
|
+
orig_file = File.join(VCR::Config.cassette_library_dir, 'replay_localhost_cassette.yml')
|
78
|
+
temp_file = File.join(VCR::Config.cassette_library_dir, 'temp', 'replay_localhost_cassette.yml')
|
79
|
+
FileUtils.mkdir_p(File.join(VCR::Config.cassette_library_dir, 'temp'))
|
80
|
+
|
81
|
+
# the port varies each time, so create a temp cassette with the correct port.
|
82
|
+
port = static_rack_server('localhost response').port
|
83
|
+
|
84
|
+
interactions = YAML.load(File.read(orig_file))
|
85
|
+
interactions.each do |i|
|
86
|
+
uri = URI.parse(i.request.uri)
|
87
|
+
uri.port = port
|
88
|
+
i.request.uri = uri.to_s
|
89
|
+
end
|
90
|
+
|
91
|
+
File.open(temp_file, 'w') { |f| f.write interactions.to_yaml }
|
92
|
+
end
|
93
|
+
|
94
|
+
at_exit do
|
95
|
+
%w(record_cassette1 record_cassette2).each do |tag|
|
96
|
+
file = File.join(VCR::Config.cassette_library_dir, 'cucumber_tags', "#{tag}.yml")
|
97
|
+
FileUtils.rm_rf(file) if File.exist?(file)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
VCR.cucumber_tags do |t|
|
102
|
+
t.tags '@record_cassette1', '@record_cassette2', :record => :new_episodes
|
103
|
+
t.tags '@replay_cassette1', '@replay_cassette2', '@replay_cassette3', '@regex_cassette', :record => :none
|
104
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
@webmock
|
2
|
+
Feature: Replay recorded response
|
3
|
+
In order to have deterministic, fast tests that do not depend on an internet connection
|
4
|
+
As a TDD/BDD developer who uses WebMock
|
5
|
+
I want to replay responses for requests I have previously recorded
|
6
|
+
|
7
|
+
Scenario: Use the :match_requests_on option to differentiate requests by request body (for "foo=bar")
|
8
|
+
Given the "match_requests_on" library file has a response for "http://example.com/" with the request body "foo=bar" that matches /foo=bar response/
|
9
|
+
When I make an HTTP post request to "http://example.com/" with request body "foo=bar" within the "match_requests_on" cassette using cassette options: { :match_requests_on => [:uri, :body], :record => :none }
|
10
|
+
Then the response for "http://example.com/" should match /foo=bar response/
|
11
|
+
|
12
|
+
Scenario: Use the :match_requests_on option to differentiate requests by request body (for "bar=bazz")
|
13
|
+
Given the "match_requests_on" library file has a response for "http://example.com/" with the request body "bar=bazz" that matches /bar=bazz response/
|
14
|
+
When I make an HTTP post request to "http://example.com/" with request body "bar=bazz" within the "match_requests_on" cassette using cassette options: { :match_requests_on => [:uri, :body], :record => :none }
|
15
|
+
Then the response for "http://example.com/" should match /bar=bazz response/
|
16
|
+
|
17
|
+
Scenario: Use the :match_requests_on option to differentiate requests by request header (for "X-HTTP-USER=joe")
|
18
|
+
Given the "match_requests_on" library file has a response for "http://example.com/" with the request header "X-HTTP-USER=joe" that matches /joe response/
|
19
|
+
When I make an HTTP post request to "http://example.com/" with request header "X-HTTP-USER=joe" within the "match_requests_on" cassette using cassette options: { :match_requests_on => [:uri, :headers], :record => :none }
|
20
|
+
Then the response for "http://example.com/" should match /joe response/
|
21
|
+
|
22
|
+
Scenario: Use the :match_requests_on option to differentiate requests by request header (for "X-HTTP-USER=bob")
|
23
|
+
Given the "match_requests_on" library file has a response for "http://example.com/" with the request header "X-HTTP-USER=bob" that matches /bob response/
|
24
|
+
When I make an HTTP post request to "http://example.com/" with request header "X-HTTP-USER=bob" within the "match_requests_on" cassette using cassette options: { :match_requests_on => [:uri, :headers], :record => :none }
|
25
|
+
Then the response for "http://example.com/" should match /bob response/
|
26
|
+
|
data/lib/vcr.rb
CHANGED
@@ -8,7 +8,7 @@ require 'vcr/version'
|
|
8
8
|
|
9
9
|
require 'vcr/extensions/net_http_response'
|
10
10
|
|
11
|
-
require 'vcr/http_stubbing_adapters/
|
11
|
+
require 'vcr/http_stubbing_adapters/common'
|
12
12
|
|
13
13
|
module VCR
|
14
14
|
extend self
|
@@ -77,4 +77,4 @@ module VCR
|
|
77
77
|
def cassettes
|
78
78
|
@cassettes ||= []
|
79
79
|
end
|
80
|
-
end
|
80
|
+
end
|
@@ -5,14 +5,6 @@ module Net
|
|
5
5
|
alias_method :request_without_vcr, :request
|
6
6
|
|
7
7
|
def request(request, body = nil, &block)
|
8
|
-
uri = URI.parse(VCR.http_stubbing_adapter.request_uri(self, request))
|
9
|
-
|
10
|
-
if VCR::LOCALHOST_ALIASES.include?(uri.host) && VCR.http_stubbing_adapter.ignore_localhost?
|
11
|
-
VCR.http_stubbing_adapter.with_http_connections_allowed_set_to(true) do
|
12
|
-
return request_without_vcr(request, body, &block)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
8
|
vcr_request = VCR::Request.from_net_http_request(self, request)
|
17
9
|
response = request_without_vcr(request, body)
|
18
10
|
|