vcr 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: