vcr 1.1.0 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|