From e0993a2b03194486e1f1182d9ab586352c515fa6 Mon Sep 17 00:00:00 2001 From: Myron Marston Date: Thu, 4 Mar 2010 08:23:06 -0800 Subject: [PATCH] Got things to work for when a cassette records multiple requests made to the same URL with the same HTTP verb, but different responses. We have to register an array of responses with fakeweb. --- .../1.8.6/cucumber_tags/replay_cassette3.yml | 85 ++++++++++ .../1.8.7/cucumber_tags/replay_cassette3.yml | 85 ++++++++++ .../1.9.1/cucumber_tags/replay_cassette3.yml | 85 ++++++++++ features/replay_recorded_response.feature | 12 +- features/step_definitions/vcr_steps.rb | 17 +- features/support/env.rb | 2 +- lib/vcr/cassette.rb | 10 +- spec/cassette_spec.rb | 20 ++- spec/fixtures/1.8.6/cassette_spec/example.yml | 158 +++++++++++------- spec/fixtures/1.8.7/cassette_spec/example.yml | 158 +++++++++++------- spec/fixtures/1.9.1/cassette_spec/example.yml | 30 ++++ 11 files changed, 515 insertions(+), 147 deletions(-) create mode 100644 features/fixtures/vcr_cassettes/1.8.6/cucumber_tags/replay_cassette3.yml create mode 100644 features/fixtures/vcr_cassettes/1.8.7/cucumber_tags/replay_cassette3.yml create mode 100644 features/fixtures/vcr_cassettes/1.9.1/cucumber_tags/replay_cassette3.yml diff --git a/features/fixtures/vcr_cassettes/1.8.6/cucumber_tags/replay_cassette3.yml b/features/fixtures/vcr_cassettes/1.8.6/cucumber_tags/replay_cassette3.yml new file mode 100644 index 00000000..9bdd10d7 --- /dev/null +++ b/features/fixtures/vcr_cassettes/1.8.6/cucumber_tags/replay_cassette3.yml @@ -0,0 +1,85 @@ +--- +- !ruby/struct:VCR::RecordedResponse + method: :get + uri: http://example.com:80/ + response: !ruby/object:Net::HTTPOK + body: | + + + Example Web Page + + +

+ This is not the real response from example.com +

+ + + + + body_exist: true + code: "200" + header: + etag: + - "\"24ec5-1b6-4059a80bfd280\"" + last-modified: + - Tue, 15 Nov 2005 13:24:10 GMT + connection: + - Keep-Alive + content-type: + - text/html; charset=UTF-8 + date: + - Thu, 25 Feb 2010 15:22:32 GMT + server: + - Apache/2.2.3 (CentOS) + content-length: + - "438" + age: + - "2643" + accept-ranges: + - bytes + http_version: "1.1" + message: OK + read: true + socket: +- !ruby/struct:VCR::RecordedResponse + method: :get + uri: http://example.com:80/ + response: !ruby/object:Net::HTTPOK + body: | + + + Example Web Page + + +

+ This is another fake response from example.com +

+ + + + + body_exist: true + code: "200" + header: + etag: + - "\"24ec5-1b6-4059a80bfd280\"" + last-modified: + - Tue, 15 Nov 2005 13:24:10 GMT + connection: + - Keep-Alive + content-type: + - text/html; charset=UTF-8 + date: + - Thu, 25 Feb 2010 15:22:32 GMT + server: + - Apache/2.2.3 (CentOS) + content-length: + - "438" + age: + - "2643" + accept-ranges: + - bytes + http_version: "1.1" + message: OK + read: true + socket: diff --git a/features/fixtures/vcr_cassettes/1.8.7/cucumber_tags/replay_cassette3.yml b/features/fixtures/vcr_cassettes/1.8.7/cucumber_tags/replay_cassette3.yml new file mode 100644 index 00000000..9bdd10d7 --- /dev/null +++ b/features/fixtures/vcr_cassettes/1.8.7/cucumber_tags/replay_cassette3.yml @@ -0,0 +1,85 @@ +--- +- !ruby/struct:VCR::RecordedResponse + method: :get + uri: http://example.com:80/ + response: !ruby/object:Net::HTTPOK + body: | + + + Example Web Page + + +

+ This is not the real response from example.com +

+ + + + + body_exist: true + code: "200" + header: + etag: + - "\"24ec5-1b6-4059a80bfd280\"" + last-modified: + - Tue, 15 Nov 2005 13:24:10 GMT + connection: + - Keep-Alive + content-type: + - text/html; charset=UTF-8 + date: + - Thu, 25 Feb 2010 15:22:32 GMT + server: + - Apache/2.2.3 (CentOS) + content-length: + - "438" + age: + - "2643" + accept-ranges: + - bytes + http_version: "1.1" + message: OK + read: true + socket: +- !ruby/struct:VCR::RecordedResponse + method: :get + uri: http://example.com:80/ + response: !ruby/object:Net::HTTPOK + body: | + + + Example Web Page + + +

+ This is another fake response from example.com +

+ + + + + body_exist: true + code: "200" + header: + etag: + - "\"24ec5-1b6-4059a80bfd280\"" + last-modified: + - Tue, 15 Nov 2005 13:24:10 GMT + connection: + - Keep-Alive + content-type: + - text/html; charset=UTF-8 + date: + - Thu, 25 Feb 2010 15:22:32 GMT + server: + - Apache/2.2.3 (CentOS) + content-length: + - "438" + age: + - "2643" + accept-ranges: + - bytes + http_version: "1.1" + message: OK + read: true + socket: diff --git a/features/fixtures/vcr_cassettes/1.9.1/cucumber_tags/replay_cassette3.yml b/features/fixtures/vcr_cassettes/1.9.1/cucumber_tags/replay_cassette3.yml new file mode 100644 index 00000000..31418352 --- /dev/null +++ b/features/fixtures/vcr_cassettes/1.9.1/cucumber_tags/replay_cassette3.yml @@ -0,0 +1,85 @@ +--- +- !ruby/struct:VCR::RecordedResponse + :method: :get + :uri: http://example.com:80/ + :response: !ruby/object:Net::HTTPOK + body: | + + + Example Web Page + + +

+ This is not the real response from example.com +

+ + + + + body_exist: true + code: "200" + header: + server: + - Apache/2.2.3 (Red Hat) + last-modified: + - Tue, 15 Nov 2005 13:24:10 GMT + etag: + - "\"b300b4-1b6-4059a80bfd280\"" + accept-ranges: + - bytes + content-type: + - text/html; charset=UTF-8 + connection: + - Keep-Alive + date: + - Thu, 28 Jan 2010 07:14:48 GMT + age: + - "1696" + content-length: + - "438" + http_version: "1.1" + message: OK + read: true + socket: +- !ruby/struct:VCR::RecordedResponse + :method: :get + :uri: http://example.com:80/ + :response: !ruby/object:Net::HTTPOK + body: | + + + Example Web Page + + +

+ This is another fake response from example.com +

+ + + + + body_exist: true + code: "200" + header: + server: + - Apache/2.2.3 (Red Hat) + last-modified: + - Tue, 15 Nov 2005 13:24:10 GMT + etag: + - "\"b300b4-1b6-4059a80bfd280\"" + accept-ranges: + - bytes + content-type: + - text/html; charset=UTF-8 + connection: + - Keep-Alive + date: + - Thu, 28 Jan 2010 07:14:48 GMT + age: + - "1696" + content-length: + - "438" + http_version: "1.1" + message: OK + read: true + socket: diff --git a/features/replay_recorded_response.feature b/features/replay_recorded_response.feature index 31c88fb0..cf81994e 100644 --- a/features/replay_recorded_response.feature +++ b/features/replay_recorded_response.feature @@ -50,4 +50,14 @@ Feature: Replay recorded response And we have a "temp/not_the_real_response" file with no previously recorded response for "http://example.com/foo" When I make HTTP get requests to "http://example.com" and "http://example.com/foo" within the "temp/not_the_real_response" unregistered cassette Then the response for "http://example.com" should match /This is not the real response from example\.com/ - And the response for "http://example.com/foo" should match /The requested URL \/foo was not found/ \ No newline at end of file + And the response for "http://example.com/foo" should match /The requested URL \/foo was not found/ + + @replay_cassette3 + Scenario: Replay multiple different recorded responses for requests to the same URL + Given this scenario is tagged with the vcr cassette tag: "@replay_cassette3" + And the "cucumber_tags/replay_cassette3" cache file has a response for "http://example.com" that matches /This is not the real response from example\.com/ + And the "cucumber_tags/replay_cassette3" cache file has a response for "http://example.com" that matches /This is another fake response from example\.com/ + When I make an HTTP get request to "http://example.com" + And I make an HTTP get request to "http://example.com" + Then response 1 for "http://example.com" should match /This is not the real response from example\.com/ + And response 2 for "http://example.com" should match /This is another fake response from example\.com/ diff --git a/features/step_definitions/vcr_steps.rb b/features/step_definitions/vcr_steps.rb index 6cf15e17..022ebe3c 100644 --- a/features/step_definitions/vcr_steps.rb +++ b/features/step_definitions/vcr_steps.rb @@ -4,9 +4,8 @@ module VCRHelpers def have_expected_response(url, regex_str) simple_matcher("a response from #{url} that matches /#{regex_str}/") do |responses| regex = /#{regex_str}/i - response = responses.detect { |r| URI.parse(r.uri) == URI.parse(url) } - response.should_not be_nil - response.response.body.should =~ regex + responses = responses.select { |r| URI.parse(r.uri) == URI.parse(url) } + responses.detect { |r| r.response.body =~ regex } end end @@ -49,7 +48,7 @@ def recorded_responses_for(cassette_name) end When /^I make an(.*)? HTTP (?:get|post) request to "([^\"]*)"$/ do |request_type, url| - @http_requests ||= {} + @http_requests ||= Hash.new([]) uri = URI.parse(url) path = uri.path.to_s == '' ? '/' : uri.path begin @@ -65,7 +64,7 @@ def recorded_responses_for(cassette_name) rescue => e result = e end - @http_requests[url] = result + @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| @@ -94,12 +93,14 @@ def recorded_responses_for(cassette_name) end Then /^the HTTP get request to "([^\"]*)" should result in a fakeweb error$/ do |url| - @http_requests[url].should be_instance_of(FakeWeb::NetConnectNotAllowedError) + @http_requests[url][0].should be_instance_of(FakeWeb::NetConnectNotAllowedError) end -Then /^the response for "([^\"]*)" should match \/(.+)\/$/ do |url, regex_str| +Then /^(?:the )?response(?: (\d+))? for "([^\"]*)" should match \/(.+)\/$/ do |response_num, url, regex_str| + response_num = response_num.to_i || 0 + response_num -= 1 if response_num > 0 # translate to 0-based array index. regex = /#{regex_str}/i - @http_requests[url].body.should =~ regex + @http_requests[url][response_num].body.should =~ regex end Then /^there should not be a "([^\"]*)" cache file$/ do |cassette_name| diff --git a/features/support/env.rb b/features/support/env.rb index 64a8266e..fd066529 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -51,5 +51,5 @@ class << self VCR.cucumber_tags do |t| t.tags '@record_cassette1', '@record_cassette2', :record => :unregistered - t.tags '@replay_cassette1', '@replay_cassette2', :record => :none + t.tags '@replay_cassette1', '@replay_cassette2', '@replay_cassette3', :record => :none end \ No newline at end of file diff --git a/lib/vcr/cassette.rb b/lib/vcr/cassette.rb index 663ba009..c82debad 100644 --- a/lib/vcr/cassette.rb +++ b/lib/vcr/cassette.rb @@ -67,8 +67,16 @@ def load_recorded_responses recorded_responses.replace(@original_recorded_responses) end + register_responses_with_fakeweb + end + + def register_responses_with_fakeweb + requests = Hash.new([]) recorded_responses.each do |rr| - FakeWeb.register_uri(rr.method, rr.uri, { :response => rr.response }) + requests[[rr.method, rr.uri]] += [rr.response] + end + requests.each do |request, responses| + FakeWeb.register_uri(request.first, request.last, responses.map{ |r| { :response => r } }) end end diff --git a/spec/cassette_spec.rb b/spec/cassette_spec.rb index f0f9d257..45f1cdaf 100644 --- a/spec/cassette_spec.rb +++ b/spec/cassette_spec.rb @@ -76,9 +76,9 @@ cassette = VCR::Cassette.new('example', :record => record_mode) if load_responses - cassette.should have(2).recorded_responses + cassette.should have(3).recorded_responses - rr1, rr2 = cassette.recorded_responses.first, cassette.recorded_responses.last + rr1, rr2, rr3 = *cassette.recorded_responses rr1.method.should == :get rr1.uri.should == 'http://example.com:80/' @@ -87,6 +87,10 @@ rr2.method.should == :get rr2.uri.should == 'http://example.com:80/foo' rr2.response.body.should =~ /foo was not found on this server/ + + rr3.method.should == :get + rr3.uri.should == 'http://example.com:80/' + rr3.response.body.should =~ /Another example\.com response/ else cassette.should have(0).recorded_responses end @@ -98,15 +102,15 @@ rr1 = FakeWeb.response_for(:get, "http://example.com") rr2 = FakeWeb.response_for(:get, "http://example.com/foo") + rr3 = FakeWeb.response_for(:get, "http://example.com") if load_responses - rr1.should_not be_nil - rr2.should_not be_nil + [rr1, rr2, rr3].compact.should have(3).responses rr1.body.should =~ /You have reached this web page by typing.+example\.com/ rr2.body.should =~ /foo was not found on this server/ + rr3.body.should =~ /Another example\.com response/ else - rr1.should be_nil - rr2.should be_nil + [rr1, rr2, rr3].compact.should have(0).responses end end end @@ -153,12 +157,12 @@ cache_file = File.expand_path(File.dirname(__FILE__) + "/fixtures/#{RUBY_VERSION}/cassette_spec/example.yml") FileUtils.cp cache_file, File.join(@temp_dir, 'previously_recorded_responses.yml') cassette = VCR::Cassette.new('previously_recorded_responses') - cassette.should have(2).recorded_responses + cassette.should have(3).recorded_responses new_recorded_response = VCR::RecordedResponse.new(:get, 'http://example.com/bar', :example_dot_com_bar_response) cassette.store_recorded_response!(new_recorded_response) cassette.destroy! saved_recorded_responses = File.open(cassette.cache_file, "r") { |f| YAML.load(f.read) } - saved_recorded_responses.should have(3).recorded_responses + saved_recorded_responses.should have(4).recorded_responses saved_recorded_responses.last.should == new_recorded_response end end diff --git a/spec/fixtures/1.8.6/cassette_spec/example.yml b/spec/fixtures/1.8.6/cassette_spec/example.yml index e577581f..aa817558 100644 --- a/spec/fixtures/1.8.6/cassette_spec/example.yml +++ b/spec/fixtures/1.8.6/cassette_spec/example.yml @@ -1,9 +1,9 @@ ---- -- !ruby/struct:VCR::RecordedResponse - method: :get - uri: http://example.com:80/ - response: !ruby/object:Net::HTTPOK - body: | +--- +- !ruby/struct:VCR::RecordedResponse + method: :get + uri: http://example.com:80/ + response: !ruby/object:Net::HTTPOK + body: | Example Web Page @@ -18,61 +18,91 @@ - - body_exist: true - code: "200" - header: - last-modified: - - Tue, 15 Nov 2005 13:24:10 GMT - connection: - - Keep-Alive - date: - - Thu, 25 Feb 2010 07:52:38 GMT - content-type: - - text/html; charset=UTF-8 - etag: - - "\"24ec5-1b6-4059a80bfd280\"" - server: - - Apache/2.2.3 (CentOS) - content-length: - - "438" - age: - - "3009" - accept-ranges: - - bytes - http_version: "1.1" - message: OK - read: true - socket: -- !ruby/struct:VCR::RecordedResponse - method: :get - uri: http://example.com:80/foo - response: !ruby/object:Net::HTTPNotFound - body: | - - - 404 Not Found - -

Not Found

-

The requested URL /foo was not found on this server.

-
-
Apache/2.2.3 (CentOS) Server at example.com Port 80
- - - body_exist: true - code: "404" - header: - connection: - - close - content-type: - - text/html; charset=iso-8859-1 - date: - - Thu, 25 Feb 2010 07:52:38 GMT - server: - - Apache/2.2.3 (CentOS) - content-length: - - "277" - http_version: "1.1" - message: Not Found - read: true - socket: + + body_exist: true + code: "200" + header: + last-modified: + - Tue, 15 Nov 2005 13:24:10 GMT + connection: + - Keep-Alive + date: + - Thu, 25 Feb 2010 07:52:38 GMT + content-type: + - text/html; charset=UTF-8 + etag: + - "\"24ec5-1b6-4059a80bfd280\"" + server: + - Apache/2.2.3 (CentOS) + content-length: + - "438" + age: + - "3009" + accept-ranges: + - bytes + http_version: "1.1" + message: OK + read: true + socket: +- !ruby/struct:VCR::RecordedResponse + method: :get + uri: http://example.com:80/foo + response: !ruby/object:Net::HTTPNotFound + body: | + + + 404 Not Found + +

Not Found

+

The requested URL /foo was not found on this server.

+
+
Apache/2.2.3 (CentOS) Server at example.com Port 80
+ + + body_exist: true + code: "404" + header: + connection: + - close + content-type: + - text/html; charset=iso-8859-1 + date: + - Thu, 25 Feb 2010 07:52:38 GMT + server: + - Apache/2.2.3 (CentOS) + content-length: + - "277" + http_version: "1.1" + message: Not Found + read: true + socket: +- !ruby/struct:VCR::RecordedResponse + method: :get + uri: http://example.com:80/ + response: !ruby/object:Net::HTTPOK + body: Another example.com response + body_exist: true + code: "200" + header: + last-modified: + - Tue, 15 Nov 2005 13:24:10 GMT + connection: + - Keep-Alive + date: + - Thu, 25 Feb 2010 07:52:38 GMT + content-type: + - text/html; charset=UTF-8 + etag: + - "\"24ec5-1b6-4059a80bfd280\"" + server: + - Apache/2.2.3 (CentOS) + content-length: + - "438" + age: + - "3009" + accept-ranges: + - bytes + http_version: "1.1" + message: OK + read: true + socket: diff --git a/spec/fixtures/1.8.7/cassette_spec/example.yml b/spec/fixtures/1.8.7/cassette_spec/example.yml index 2726a15f..5295f9e7 100644 --- a/spec/fixtures/1.8.7/cassette_spec/example.yml +++ b/spec/fixtures/1.8.7/cassette_spec/example.yml @@ -1,9 +1,9 @@ ---- -- !ruby/struct:VCR::RecordedResponse - method: :get - uri: http://example.com:80/ - response: !ruby/object:Net::HTTPOK - body: | +--- +- !ruby/struct:VCR::RecordedResponse + method: :get + uri: http://example.com:80/ + response: !ruby/object:Net::HTTPOK + body: | Example Web Page @@ -18,61 +18,91 @@ - - body_exist: true - code: "200" - header: - etag: - - "\"24ec5-1b6-4059a80bfd280\"" - last-modified: - - Tue, 15 Nov 2005 13:24:10 GMT - connection: - - Keep-Alive - content-type: - - text/html; charset=UTF-8 - date: - - Thu, 25 Feb 2010 07:53:51 GMT - server: - - Apache/2.2.3 (CentOS) - content-length: - - "438" - age: - - "9260" - accept-ranges: - - bytes - http_version: "1.1" - message: OK - read: true - socket: -- !ruby/struct:VCR::RecordedResponse - method: :get - uri: http://example.com:80/foo - response: !ruby/object:Net::HTTPNotFound - body: | - - - 404 Not Found - -

Not Found

-

The requested URL /foo was not found on this server.

-
-
Apache/2.2.3 (CentOS) Server at example.com Port 80
- - - body_exist: true - code: "404" - header: - content-type: - - text/html; charset=iso-8859-1 - connection: - - close - server: - - Apache/2.2.3 (CentOS) - date: - - Thu, 25 Feb 2010 07:53:52 GMT - content-length: - - "277" - http_version: "1.1" - message: Not Found - read: true - socket: + + body_exist: true + code: "200" + header: + etag: + - "\"24ec5-1b6-4059a80bfd280\"" + last-modified: + - Tue, 15 Nov 2005 13:24:10 GMT + connection: + - Keep-Alive + content-type: + - text/html; charset=UTF-8 + date: + - Thu, 25 Feb 2010 07:53:51 GMT + server: + - Apache/2.2.3 (CentOS) + content-length: + - "438" + age: + - "9260" + accept-ranges: + - bytes + http_version: "1.1" + message: OK + read: true + socket: +- !ruby/struct:VCR::RecordedResponse + method: :get + uri: http://example.com:80/foo + response: !ruby/object:Net::HTTPNotFound + body: | + + + 404 Not Found + +

Not Found

+

The requested URL /foo was not found on this server.

+
+
Apache/2.2.3 (CentOS) Server at example.com Port 80
+ + + body_exist: true + code: "404" + header: + content-type: + - text/html; charset=iso-8859-1 + connection: + - close + server: + - Apache/2.2.3 (CentOS) + date: + - Thu, 25 Feb 2010 07:53:52 GMT + content-length: + - "277" + http_version: "1.1" + message: Not Found + read: true + socket: +- !ruby/struct:VCR::RecordedResponse + method: :get + uri: http://example.com:80/ + response: !ruby/object:Net::HTTPOK + body: Another example.com response + body_exist: true + code: "200" + header: + etag: + - "\"24ec5-1b6-4059a80bfd280\"" + last-modified: + - Tue, 15 Nov 2005 13:24:10 GMT + connection: + - Keep-Alive + content-type: + - text/html; charset=UTF-8 + date: + - Thu, 25 Feb 2010 07:53:51 GMT + server: + - Apache/2.2.3 (CentOS) + content-length: + - "438" + age: + - "9260" + accept-ranges: + - bytes + http_version: "1.1" + message: OK + read: true + socket: diff --git a/spec/fixtures/1.9.1/cassette_spec/example.yml b/spec/fixtures/1.9.1/cassette_spec/example.yml index 1924a486..75c891fe 100644 --- a/spec/fixtures/1.9.1/cassette_spec/example.yml +++ b/spec/fixtures/1.9.1/cassette_spec/example.yml @@ -75,3 +75,33 @@ message: Not Found read: true socket: +- !ruby/struct:VCR::RecordedResponse + :method: :get + :uri: http://example.com:80/ + :response: !ruby/object:Net::HTTPOK + body: Another example.com response + body_exist: true + code: "200" + header: + server: + - Apache/2.2.3 (Red Hat) + last-modified: + - Tue, 15 Nov 2005 13:24:10 GMT + etag: + - "\"b300b4-1b6-4059a80bfd280\"" + accept-ranges: + - bytes + content-type: + - text/html; charset=UTF-8 + connection: + - Keep-Alive + date: + - Mon, 25 Jan 2010 18:00:32 GMT + age: + - "2090" + content-length: + - "438" + http_version: "1.1" + message: OK + read: true + socket: