vcr 0.1.1 → 0.1.2

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.
@@ -42,7 +42,7 @@ Feature: Replay recorded response
42
42
  And we have a "temp/not_the_real_response" file with no previously recorded response for "http://example.com/foo"
43
43
  When I make HTTP get requests to "http://example.com" and "http://example.com/foo" within the "temp/not_the_real_response" none cassette
44
44
  Then the response for "http://example.com" should match /This is not the real response from example\.com/
45
- And the HTTP get request to "http://example.com/foo" should result in a fakeweb error
45
+ And the HTTP get request to "http://example.com/foo" should result in a fakeweb error that mentions VCR
46
46
 
47
47
  @copy_not_the_real_response_to_temp
48
48
  Scenario: Make an HTTP request in a cassette with record mode set to :unregistered
@@ -50,4 +50,14 @@ Feature: Replay recorded response
50
50
  And we have a "temp/not_the_real_response" file with no previously recorded response for "http://example.com/foo"
51
51
  When I make HTTP get requests to "http://example.com" and "http://example.com/foo" within the "temp/not_the_real_response" unregistered cassette
52
52
  Then the response for "http://example.com" should match /This is not the real response from example\.com/
53
- And the response for "http://example.com/foo" should match /The requested URL \/foo was not found/
53
+ And the response for "http://example.com/foo" should match /The requested URL \/foo was not found/
54
+
55
+ @replay_cassette3
56
+ Scenario: Replay multiple different recorded responses for requests to the same URL
57
+ Given this scenario is tagged with the vcr cassette tag: "@replay_cassette3"
58
+ 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/
59
+ 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/
60
+ When I make an HTTP get request to "http://example.com"
61
+ And I make an HTTP get request to "http://example.com"
62
+ Then response 1 for "http://example.com" should match /This is not the real response from example\.com/
63
+ And response 2 for "http://example.com" should match /This is another fake response from example\.com/
@@ -4,11 +4,16 @@ module VCRHelpers
4
4
  def have_expected_response(url, regex_str)
5
5
  simple_matcher("a response from #{url} that matches /#{regex_str}/") do |responses|
6
6
  regex = /#{regex_str}/i
7
- response = responses.detect { |r| URI.parse(r.uri) == URI.parse(url) }
8
- response.should_not be_nil
9
- response.response.body.should =~ regex
7
+ responses = responses.select { |r| URI.parse(r.uri) == URI.parse(url) }
8
+ responses.detect { |r| r.response.body =~ regex }
10
9
  end
11
10
  end
11
+
12
+ def recorded_responses_for(cassette_name)
13
+ yaml_file = File.join(VCR::Config.cache_dir, "#{cassette_name}.yml")
14
+ yaml = File.open(yaml_file, 'r') { |f| f.read }
15
+ responses = YAML.load(yaml)
16
+ end
12
17
  end
13
18
  World(VCRHelpers)
14
19
 
@@ -42,51 +47,62 @@ Given /^the previous scenario was tagged with the vcr cassette tag: "([^\"]*)"$/
42
47
  VCR::CucumberTags.tags.should include(tag)
43
48
  end
44
49
 
45
- When /^I make an( asynchronous)? HTTP get request to "([^\"]*)"$/ do |asynchronous, url|
46
- @http_requests ||= {}
50
+ When /^I make an(.*)? HTTP (?:get|post) request to "([^\"]*)"$/ do |request_type, url|
51
+ @http_requests ||= Hash.new([])
52
+ uri = URI.parse(url)
53
+ path = uri.path.to_s == '' ? '/' : uri.path
47
54
  begin
48
- if asynchronous =~ /asynchronous/
49
- uri = URI.parse(url)
50
- path = uri.path.to_s == '' ? '/' : uri.path
51
- result = Net::HTTP.new(uri.host, uri.port).request_get(path) { |r| r.read_body { } }
52
- result.body.should be_a(Net::ReadAdapter)
53
- else
54
- result = Net::HTTP.get_response(URI.parse(url))
55
+ case request_type
56
+ when /asynchronous/
57
+ result = Net::HTTP.new(uri.host, uri.port).request_get(path) { |r| r.read_body { } }
58
+ result.body.should be_a(Net::ReadAdapter)
59
+ when /recursive/
60
+ result = Net::HTTP.new(uri.host, uri.port).post(path, nil)
61
+ else
62
+ result = Net::HTTP.get_response(uri)
55
63
  end
56
64
  rescue => e
57
65
  result = e
58
66
  end
59
- @http_requests[url] = result
67
+ @http_requests[url] += [result]
60
68
  end
61
69
 
62
- When /^I make(?: an)?( asynchronous)? HTTP get requests? to "([^\"]*)"(?: and "([^\"]*)")? within the "([^\"]*)" ?(#{VCR::Cassette::VALID_RECORD_MODES.join('|')})? cassette$/ do |asynchronous, url1, url2, cassette_name, record_mode|
70
+ 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|
63
71
  record_mode ||= :unregistered
64
72
  record_mode = record_mode.to_sym
65
73
  urls = [url1, url2].select { |u| u.to_s.size > 0 }
66
74
  VCR.with_cassette(cassette_name, :record => record_mode) do
67
75
  urls.each do |url|
68
- When %{I make an#{asynchronous} HTTP get request to "#{url}"}
76
+ When %{I make an#{request_type} HTTP #{method} request to "#{url}"}
69
77
  end
70
78
  end
71
79
  end
72
80
 
73
81
  Then /^the "([^\"]*)" cache file should have a response for "([^\"]*)" that matches \/(.+)\/$/ do |cassette_name, url, regex_str|
74
- yaml_file = File.join(VCR::Config.cache_dir, "#{cassette_name}.yml")
75
- responses = File.open(yaml_file, 'r') { |f| YAML.load(f.read) }
82
+ responses = recorded_responses_for(cassette_name)
76
83
  responses.should have_expected_response(url, regex_str)
77
84
  end
78
85
 
86
+ Then /^the "([^\"]*)" cache file should have exactly (\d+) response$/ do |cassette_name, response_count|
87
+ responses = recorded_responses_for(cassette_name)
88
+ responses.should have(response_count.to_i).responses
89
+ end
90
+
79
91
  Then /^I can test the scenario cassette's recorded responses in the next scenario, after the cassette has been destroyed$/ do
80
92
  # do nothing...
81
93
  end
82
94
 
83
- Then /^the HTTP get request to "([^\"]*)" should result in a fakeweb error$/ do |url|
84
- @http_requests[url].should be_instance_of(FakeWeb::NetConnectNotAllowedError)
95
+ Then /^the HTTP get request to "([^\"]*)" should result in a fakeweb error that mentions VCR$/ do |url|
96
+ result = @http_requests[url][0]
97
+ result.should be_instance_of(FakeWeb::NetConnectNotAllowedError)
98
+ result.message.should =~ /VCR/
85
99
  end
86
100
 
87
- Then /^the response for "([^\"]*)" should match \/(.+)\/$/ do |url, regex_str|
101
+ Then /^(?:the )?response(?: (\d+))? for "([^\"]*)" should match \/(.+)\/$/ do |response_num, url, regex_str|
102
+ response_num = response_num.to_i || 0
103
+ response_num -= 1 if response_num > 0 # translate to 0-based array index.
88
104
  regex = /#{regex_str}/i
89
- @http_requests[url].body.should =~ regex
105
+ @http_requests[url][response_num].body.should =~ regex
90
106
  end
91
107
 
92
108
  Then /^there should not be a "([^\"]*)" cache file$/ do |cassette_name|
@@ -51,5 +51,5 @@ end
51
51
 
52
52
  VCR.cucumber_tags do |t|
53
53
  t.tags '@record_cassette1', '@record_cassette2', :record => :unregistered
54
- t.tags '@replay_cassette1', '@replay_cassette2', :record => :none
54
+ t.tags '@replay_cassette1', '@replay_cassette2', '@replay_cassette3', :record => :none
55
55
  end
data/lib/vcr.rb CHANGED
@@ -1,11 +1,12 @@
1
1
  require 'vcr/cassette'
2
2
  require 'vcr/config'
3
3
  require 'vcr/cucumber_tags'
4
- require 'vcr/fake_web_extensions'
5
- require 'vcr/net_http_extensions'
6
- require 'vcr/net_read_adapter_extensions'
7
4
  require 'vcr/recorded_response'
8
5
 
6
+ require 'vcr/extensions/fake_web'
7
+ require 'vcr/extensions/net_http'
8
+ require 'vcr/extensions/net_read_adapter'
9
+
9
10
  module VCR
10
11
  extend self
11
12
 
@@ -67,8 +67,16 @@ module VCR
67
67
  recorded_responses.replace(@original_recorded_responses)
68
68
  end
69
69
 
70
+ register_responses_with_fakeweb
71
+ end
72
+
73
+ def register_responses_with_fakeweb
74
+ requests = Hash.new([])
70
75
  recorded_responses.each do |rr|
71
- FakeWeb.register_uri(rr.method, rr.uri, { :response => rr.response })
76
+ requests[[rr.method, rr.uri]] += [rr.response]
77
+ end
78
+ requests.each do |request, responses|
79
+ FakeWeb.register_uri(request.first, request.last, responses.map{ |r| { :response => r } })
72
80
  end
73
81
  end
74
82
 
@@ -15,4 +15,10 @@ module FakeWeb
15
15
  end
16
16
  end
17
17
  end
18
+
19
+ class NetConnectNotAllowedError
20
+ def message
21
+ super + '. You can use VCR to automatically record this request and replay it later with fakeweb. For more details, see the VCR README at: http://github.com/myronmarston/vcr'
22
+ end
23
+ end
18
24
  end
@@ -3,9 +3,12 @@ require 'net/http'
3
3
  module Net
4
4
  class HTTP
5
5
  def request_with_vcr(request, body = nil, &block)
6
+ @__request_with_vcr_call_count = (@__request_with_vcr_call_count || 0) + 1
6
7
  response = request_without_vcr(request, body, &block)
7
- __store_response_with_vcr__(response, request)
8
+ __store_response_with_vcr__(response, request) if @__request_with_vcr_call_count == 1
8
9
  response
10
+ ensure
11
+ @__request_with_vcr_call_count -= 1
9
12
  end
10
13
  alias_method :request_without_vcr, :request
11
14
  alias_method :request, :request_with_vcr
@@ -76,9 +76,9 @@ describe VCR::Cassette do
76
76
  cassette = VCR::Cassette.new('example', :record => record_mode)
77
77
 
78
78
  if load_responses
79
- cassette.should have(2).recorded_responses
79
+ cassette.should have(3).recorded_responses
80
80
 
81
- rr1, rr2 = cassette.recorded_responses.first, cassette.recorded_responses.last
81
+ rr1, rr2, rr3 = *cassette.recorded_responses
82
82
 
83
83
  rr1.method.should == :get
84
84
  rr1.uri.should == 'http://example.com:80/'
@@ -87,6 +87,10 @@ describe VCR::Cassette do
87
87
  rr2.method.should == :get
88
88
  rr2.uri.should == 'http://example.com:80/foo'
89
89
  rr2.response.body.should =~ /foo was not found on this server/
90
+
91
+ rr3.method.should == :get
92
+ rr3.uri.should == 'http://example.com:80/'
93
+ rr3.response.body.should =~ /Another example\.com response/
90
94
  else
91
95
  cassette.should have(0).recorded_responses
92
96
  end
@@ -98,15 +102,15 @@ describe VCR::Cassette do
98
102
 
99
103
  rr1 = FakeWeb.response_for(:get, "http://example.com")
100
104
  rr2 = FakeWeb.response_for(:get, "http://example.com/foo")
105
+ rr3 = FakeWeb.response_for(:get, "http://example.com")
101
106
 
102
107
  if load_responses
103
- rr1.should_not be_nil
104
- rr2.should_not be_nil
108
+ [rr1, rr2, rr3].compact.should have(3).responses
105
109
  rr1.body.should =~ /You have reached this web page by typing.+example\.com/
106
110
  rr2.body.should =~ /foo was not found on this server/
111
+ rr3.body.should =~ /Another example\.com response/
107
112
  else
108
- rr1.should be_nil
109
- rr2.should be_nil
113
+ [rr1, rr2, rr3].compact.should have(0).responses
110
114
  end
111
115
  end
112
116
  end
@@ -153,12 +157,12 @@ describe VCR::Cassette do
153
157
  cache_file = File.expand_path(File.dirname(__FILE__) + "/fixtures/#{RUBY_VERSION}/cassette_spec/example.yml")
154
158
  FileUtils.cp cache_file, File.join(@temp_dir, 'previously_recorded_responses.yml')
155
159
  cassette = VCR::Cassette.new('previously_recorded_responses')
156
- cassette.should have(2).recorded_responses
160
+ cassette.should have(3).recorded_responses
157
161
  new_recorded_response = VCR::RecordedResponse.new(:get, 'http://example.com/bar', :example_dot_com_bar_response)
158
162
  cassette.store_recorded_response!(new_recorded_response)
159
163
  cassette.destroy!
160
164
  saved_recorded_responses = File.open(cassette.cache_file, "r") { |f| YAML.load(f.read) }
161
- saved_recorded_responses.should have(3).recorded_responses
165
+ saved_recorded_responses.should have(4).recorded_responses
162
166
  saved_recorded_responses.last.should == new_recorded_response
163
167
  end
164
168
  end
@@ -1,6 +1,6 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
2
 
3
- describe "FakeWebExtensions" do
3
+ describe "FakeWeb Extensions" do
4
4
  describe "#remove_from_registry with (:get, 'http://example.com')" do
5
5
  before(:each) do
6
6
  FakeWeb.register_uri(:get, 'http://example.com', :body => "Example dot com!")
@@ -23,4 +23,11 @@ describe "FakeWebExtensions" do
23
23
  @remove_example_dot_com.should_not change { FakeWeb.registered_uri?(:get, 'http://google.com') }
24
24
  end
25
25
  end
26
+
27
+ describe 'FakeWeb::NetConnectNotAllowedError#message' do
28
+ it 'includes a note about VCR' do
29
+ FakeWeb::NetConnectNotAllowedError.new('The fakeweb error message').message.should ==
30
+ 'The fakeweb error message. You can use VCR to automatically record this request and replay it later with fakeweb. For more details, see the VCR README at: http://github.com/myronmarston/vcr'
31
+ end
32
+ end
26
33
  end
@@ -1,6 +1,6 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
2
 
3
- describe "NetHttpExtensions" do
3
+ describe "Net::HTTP Extensions" do
4
4
  before(:all) do
5
5
  @orig_allow_net_connect = FakeWeb.allow_net_connect?
6
6
  FakeWeb.allow_net_connect = true
@@ -24,6 +24,11 @@ describe "NetHttpExtensions" do
24
24
  Net::HTTP.get(URI.parse('http://example.com'))
25
25
  end
26
26
 
27
+ it 'calls #store_recorded_response! only once, even when Net::HTTP internally recursively calls #request' do
28
+ @current_cassette.should_receive(:store_recorded_response!).once
29
+ Net::HTTP.new('example.com', 80).post('/', nil)
30
+ end
31
+
27
32
  it 'does not have an error if there is no current cassette' do
28
33
  VCR.stub!(:current_cassette).and_return(nil)
29
34
  lambda { Net::HTTP.get(URI.parse('http://example.com')) }.should_not raise_error
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
2
 
3
3
  describe 'Net::ReadAdapter extensions' do
4
4
  it 'delegates yaml serialization to the body string' do
@@ -1,9 +1,9 @@
1
- ---
2
- - !ruby/struct:VCR::RecordedResponse
3
- method: :get
4
- uri: http://example.com:80/
5
- response: !ruby/object:Net::HTTPOK
6
- body: |
1
+ ---
2
+ - !ruby/struct:VCR::RecordedResponse
3
+ method: :get
4
+ uri: http://example.com:80/
5
+ response: !ruby/object:Net::HTTPOK
6
+ body: |
7
7
  <HTML>
8
8
  <HEAD>
9
9
  <TITLE>Example Web Page</TITLE>
@@ -18,61 +18,91 @@
18
18
  </BODY>
19
19
  </HTML>
20
20
 
21
-
22
- body_exist: true
23
- code: "200"
24
- header:
25
- last-modified:
26
- - Tue, 15 Nov 2005 13:24:10 GMT
27
- connection:
28
- - Keep-Alive
29
- date:
30
- - Thu, 25 Feb 2010 07:52:38 GMT
31
- content-type:
32
- - text/html; charset=UTF-8
33
- etag:
34
- - "\"24ec5-1b6-4059a80bfd280\""
35
- server:
36
- - Apache/2.2.3 (CentOS)
37
- content-length:
38
- - "438"
39
- age:
40
- - "3009"
41
- accept-ranges:
42
- - bytes
43
- http_version: "1.1"
44
- message: OK
45
- read: true
46
- socket:
47
- - !ruby/struct:VCR::RecordedResponse
48
- method: :get
49
- uri: http://example.com:80/foo
50
- response: !ruby/object:Net::HTTPNotFound
51
- body: |
52
- <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
53
- <html><head>
54
- <title>404 Not Found</title>
55
- </head><body>
56
- <h1>Not Found</h1>
57
- <p>The requested URL /foo was not found on this server.</p>
58
- <hr>
59
- <address>Apache/2.2.3 (CentOS) Server at example.com Port 80</address>
60
- </body></html>
61
-
62
- body_exist: true
63
- code: "404"
64
- header:
65
- connection:
66
- - close
67
- content-type:
68
- - text/html; charset=iso-8859-1
69
- date:
70
- - Thu, 25 Feb 2010 07:52:38 GMT
71
- server:
72
- - Apache/2.2.3 (CentOS)
73
- content-length:
74
- - "277"
75
- http_version: "1.1"
76
- message: Not Found
77
- read: true
78
- socket:
21
+
22
+ body_exist: true
23
+ code: "200"
24
+ header:
25
+ last-modified:
26
+ - Tue, 15 Nov 2005 13:24:10 GMT
27
+ connection:
28
+ - Keep-Alive
29
+ date:
30
+ - Thu, 25 Feb 2010 07:52:38 GMT
31
+ content-type:
32
+ - text/html; charset=UTF-8
33
+ etag:
34
+ - "\"24ec5-1b6-4059a80bfd280\""
35
+ server:
36
+ - Apache/2.2.3 (CentOS)
37
+ content-length:
38
+ - "438"
39
+ age:
40
+ - "3009"
41
+ accept-ranges:
42
+ - bytes
43
+ http_version: "1.1"
44
+ message: OK
45
+ read: true
46
+ socket:
47
+ - !ruby/struct:VCR::RecordedResponse
48
+ method: :get
49
+ uri: http://example.com:80/foo
50
+ response: !ruby/object:Net::HTTPNotFound
51
+ body: |
52
+ <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
53
+ <html><head>
54
+ <title>404 Not Found</title>
55
+ </head><body>
56
+ <h1>Not Found</h1>
57
+ <p>The requested URL /foo was not found on this server.</p>
58
+ <hr>
59
+ <address>Apache/2.2.3 (CentOS) Server at example.com Port 80</address>
60
+ </body></html>
61
+
62
+ body_exist: true
63
+ code: "404"
64
+ header:
65
+ connection:
66
+ - close
67
+ content-type:
68
+ - text/html; charset=iso-8859-1
69
+ date:
70
+ - Thu, 25 Feb 2010 07:52:38 GMT
71
+ server:
72
+ - Apache/2.2.3 (CentOS)
73
+ content-length:
74
+ - "277"
75
+ http_version: "1.1"
76
+ message: Not Found
77
+ read: true
78
+ socket:
79
+ - !ruby/struct:VCR::RecordedResponse
80
+ method: :get
81
+ uri: http://example.com:80/
82
+ response: !ruby/object:Net::HTTPOK
83
+ body: Another example.com response
84
+ body_exist: true
85
+ code: "200"
86
+ header:
87
+ last-modified:
88
+ - Tue, 15 Nov 2005 13:24:10 GMT
89
+ connection:
90
+ - Keep-Alive
91
+ date:
92
+ - Thu, 25 Feb 2010 07:52:38 GMT
93
+ content-type:
94
+ - text/html; charset=UTF-8
95
+ etag:
96
+ - "\"24ec5-1b6-4059a80bfd280\""
97
+ server:
98
+ - Apache/2.2.3 (CentOS)
99
+ content-length:
100
+ - "438"
101
+ age:
102
+ - "3009"
103
+ accept-ranges:
104
+ - bytes
105
+ http_version: "1.1"
106
+ message: OK
107
+ read: true
108
+ socket: