vcr 1.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. data/.document +5 -0
  2. data/.gitignore +27 -0
  3. data/CHANGELOG.md +13 -0
  4. data/Gemfile +24 -0
  5. data/Gemfile.lock +119 -0
  6. data/README.md +3 -6
  7. data/Rakefile +70 -0
  8. data/benchmarks/http_stubbing_libraries.rb +59 -0
  9. data/features/fixtures/vcr_cassettes/1.9.1/cucumber_tags/regex_cassette.yml +43 -0
  10. data/features/fixtures/vcr_cassettes/1.9.1/cucumber_tags/replay_cassette1.yml +43 -0
  11. data/features/fixtures/vcr_cassettes/1.9.1/cucumber_tags/replay_cassette2.yml +63 -0
  12. data/features/fixtures/vcr_cassettes/1.9.1/cucumber_tags/replay_cassette3.yml +85 -0
  13. data/features/fixtures/vcr_cassettes/1.9.1/erb_cassette.yml +36 -0
  14. data/features/fixtures/vcr_cassettes/1.9.1/match_requests_on.yml +35 -0
  15. data/features/fixtures/vcr_cassettes/1.9.1/nested_replay_cassette.yml +32 -0
  16. data/features/fixtures/vcr_cassettes/1.9.1/not_the_real_response.yml +43 -0
  17. data/features/fixtures/vcr_cassettes/1.9.1/replay_localhost_cassette.yml +32 -0
  18. data/features/fixtures/vcr_cassettes/not_1.9.1/cucumber_tags/regex_cassette.yml +43 -0
  19. data/features/fixtures/vcr_cassettes/not_1.9.1/cucumber_tags/replay_cassette1.yml +43 -0
  20. data/features/fixtures/vcr_cassettes/not_1.9.1/cucumber_tags/replay_cassette2.yml +47 -0
  21. data/features/fixtures/vcr_cassettes/not_1.9.1/cucumber_tags/replay_cassette3.yml +85 -0
  22. data/features/fixtures/vcr_cassettes/not_1.9.1/erb_cassette.yml +36 -0
  23. data/features/fixtures/vcr_cassettes/not_1.9.1/match_requests_on.yml +35 -0
  24. data/features/fixtures/vcr_cassettes/not_1.9.1/nested_replay_cassette.yml +24 -0
  25. data/features/fixtures/vcr_cassettes/not_1.9.1/not_the_real_response.yml +43 -0
  26. data/features/fixtures/vcr_cassettes/not_1.9.1/replay_localhost_cassette.yml +32 -0
  27. data/features/http_client.feature +16 -0
  28. data/features/net_http.feature +27 -0
  29. data/features/record_response.feature +66 -0
  30. data/features/replay_recorded_response.feature +96 -0
  31. data/features/step_definitions/http_client_steps.rb +7 -0
  32. data/features/step_definitions/net_http_steps.rb +37 -0
  33. data/features/step_definitions/vcr_steps.rb +240 -0
  34. data/features/support/env.rb +104 -0
  35. data/features/webmock.feature +26 -0
  36. data/lib/vcr.rb +2 -2
  37. data/lib/vcr/extensions/net_http.rb +0 -8
  38. data/lib/vcr/http_stubbing_adapters/common.rb +39 -0
  39. data/lib/vcr/http_stubbing_adapters/fakeweb.rb +74 -70
  40. data/lib/vcr/http_stubbing_adapters/webmock.rb +61 -62
  41. data/lib/vcr/version.rb +1 -1
  42. data/spec/cassette_spec.rb +280 -0
  43. data/spec/config_spec.rb +76 -0
  44. data/spec/cucumber_tags_spec.rb +55 -0
  45. data/spec/deprecations_spec.rb +52 -0
  46. data/spec/extensions/net_http_response_spec.rb +85 -0
  47. data/spec/extensions/net_http_spec.rb +77 -0
  48. data/spec/fixtures/1.9.1/0_3_1_cassette.yml +29 -0
  49. data/spec/fixtures/1.9.1/cassette_spec/erb_with_no_vars.yml +32 -0
  50. data/spec/fixtures/1.9.1/cassette_spec/erb_with_vars.yml +32 -0
  51. data/spec/fixtures/1.9.1/cassette_spec/example.yml +110 -0
  52. data/spec/fixtures/1.9.1/cassette_spec/with_localhost_requests.yml +86 -0
  53. data/spec/fixtures/1.9.1/example_net_http.yml +14 -0
  54. data/spec/fixtures/1.9.1/example_net_http_request.yml +12 -0
  55. data/spec/fixtures/1.9.1/example_net_http_response.yml +25 -0
  56. data/spec/fixtures/1.9.1/fake_example.com_responses.yml +106 -0
  57. data/spec/fixtures/1.9.1/match_requests_on.yml +185 -0
  58. data/spec/fixtures/not_1.9.1/0_3_1_cassette.yml +29 -0
  59. data/spec/fixtures/not_1.9.1/cassette_spec/erb_with_no_vars.yml +32 -0
  60. data/spec/fixtures/not_1.9.1/cassette_spec/erb_with_vars.yml +32 -0
  61. data/spec/fixtures/not_1.9.1/cassette_spec/example.yml +110 -0
  62. data/spec/fixtures/not_1.9.1/cassette_spec/with_localhost_requests.yml +86 -0
  63. data/spec/fixtures/not_1.9.1/example_net_http.yml +14 -0
  64. data/spec/fixtures/not_1.9.1/example_net_http_request.yml +12 -0
  65. data/spec/fixtures/not_1.9.1/example_net_http_response.yml +25 -0
  66. data/spec/fixtures/not_1.9.1/fake_example.com_responses.yml +106 -0
  67. data/spec/fixtures/not_1.9.1/match_requests_on.yml +185 -0
  68. data/spec/http_stubbing_adapters/fakeweb_spec.rb +35 -0
  69. data/spec/http_stubbing_adapters/webmock_spec.rb +35 -0
  70. data/spec/request_matcher_spec.rb +194 -0
  71. data/spec/spec_helper.rb +40 -0
  72. data/spec/structs_spec.rb +121 -0
  73. data/spec/support/disable_warnings.rb +12 -0
  74. data/spec/support/http_library_adapters.rb +272 -0
  75. data/spec/support/http_stubbing_adapter.rb +100 -0
  76. data/spec/support/pending_on_heroku.rb +14 -0
  77. data/spec/support/temp_cassette_library_dir.rb +16 -0
  78. data/spec/support/vcr_localhost_server.rb +53 -0
  79. data/spec/vcr_spec.rb +198 -0
  80. data/spec/version_spec.rb +11 -0
  81. data/vcr.gemspec +43 -0
  82. metadata +134 -73
  83. data/lib/vcr/http_stubbing_adapters/base.rb +0 -36
  84. data/lib/vcr/version.rbc +0 -572
@@ -0,0 +1,39 @@
1
+ module VCR
2
+ module HttpStubbingAdapters
3
+ autoload :FakeWeb, 'vcr/http_stubbing_adapters/fakeweb'
4
+ autoload :WebMock, 'vcr/http_stubbing_adapters/webmock'
5
+
6
+ class UnsupportedRequestMatchAttributeError < ArgumentError; end
7
+
8
+ module Common
9
+ def check_version!
10
+ version_too_low, version_too_high = compare_version
11
+
12
+ if version_too_low
13
+ raise "You are using #{library_name} #{version}. VCR requires version #{self::VERSION_REQUIREMENT} or greater."
14
+ elsif version_too_high
15
+ warn "You are using #{library_name} #{version}. VCR is known to work with #{library_name} ~> #{self::VERSION_REQUIREMENT}. It may not work with this version."
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def compare_version
22
+ major, minor, patch = *version.split('.').map { |v| v.to_i }
23
+ req_major, req_minor, req_patch = *self::VERSION_REQUIREMENT.split('.').map { |v| v.to_i }
24
+
25
+ return true, false if major < req_major
26
+ return false, true if major > req_major
27
+
28
+ return true, false if minor < req_minor
29
+ return false, true if minor > req_minor
30
+
31
+ return patch < req_patch, false
32
+ end
33
+
34
+ def library_name
35
+ @library_name ||= self.to_s.split('::').last
36
+ end
37
+ end
38
+ end
39
+ end
@@ -3,94 +3,98 @@ require 'vcr/extensions/net_http'
3
3
 
4
4
  module VCR
5
5
  module HttpStubbingAdapters
6
- class FakeWeb < Base
7
- class << self
8
- UNSUPPORTED_REQUEST_MATCH_ATTRIBUTES = [:body, :headers].freeze
9
-
10
- def check_version!
11
- unless meets_version_requirement?(::FakeWeb::VERSION, '1.2.8')
12
- raise "You are using FakeWeb #{::FakeWeb::VERSION}. VCR requires version 1.2.8 or greater."
13
- end
14
- end
6
+ module FakeWeb
7
+ include VCR::HttpStubbingAdapters::Common
8
+ extend self
15
9
 
16
- def http_connections_allowed?
17
- ::FakeWeb.allow_net_connect?
18
- end
10
+ UNSUPPORTED_REQUEST_MATCH_ATTRIBUTES = [:body, :headers].freeze
11
+ LOCALHOST_REGEX = %r|\Ahttps?://((\w+:)?\w+@)?(#{VCR::LOCALHOST_ALIASES.map { |a| Regexp.escape(a) }.join('|')})(:\d+)?/|i
19
12
 
20
- def http_connections_allowed=(value)
21
- ::FakeWeb.allow_net_connect = value
22
- end
13
+ VERSION_REQUIREMENT = '1.3.0'
23
14
 
24
- def stub_requests(http_interactions, match_attributes = RequestMatcher::DEFAULT_MATCH_ATTRIBUTES)
25
- validate_match_attributes(match_attributes)
26
- requests = Hash.new([])
27
-
28
- http_interactions.each do |i|
29
- requests[i.request.matcher(match_attributes)] += [i.response]
30
- end
31
-
32
- requests.each do |request_matcher, responses|
33
- ::FakeWeb.register_uri(
34
- request_matcher.method || :any,
35
- request_matcher.uri,
36
- responses.map{ |r| response_hash(r) }
37
- )
38
- end
39
- end
15
+ def http_connections_allowed?
16
+ !!::FakeWeb.allow_net_connect?("http://some.url/besides/localhost")
17
+ end
40
18
 
41
- def create_stubs_checkpoint(checkpoint_name)
42
- checkpoints[checkpoint_name] = ::FakeWeb::Registry.instance.uri_map.dup
43
- end
19
+ def http_connections_allowed=(value)
20
+ @http_connections_allowed = value
21
+ update_fakeweb_allow_net_connect
22
+ end
44
23
 
45
- def restore_stubs_checkpoint(checkpoint_name)
46
- ::FakeWeb::Registry.instance.uri_map = checkpoints.delete(checkpoint_name)
24
+ def stub_requests(http_interactions, match_attributes)
25
+ validate_match_attributes(match_attributes)
26
+ requests = Hash.new { |h,k| h[k] = [] }
27
+
28
+ http_interactions.each do |i|
29
+ requests[i.request.matcher(match_attributes)] << i.response
47
30
  end
48
31
 
49
- def request_stubbed?(request, match_attributes)
50
- validate_match_attributes(match_attributes)
51
- ::FakeWeb.registered_uri?(request.method, request.uri)
32
+ requests.each do |request_matcher, responses|
33
+ ::FakeWeb.register_uri(
34
+ request_matcher.method || :any,
35
+ request_matcher.uri,
36
+ responses.map{ |r| response_hash(r) }
37
+ )
52
38
  end
39
+ end
53
40
 
54
- def request_uri(net_http, request)
55
- # Copied from: http://github.com/chrisk/fakeweb/blob/fakeweb-1.2.8/lib/fake_web/ext/net_http.rb#L39-52
56
- protocol = net_http.use_ssl? ? "https" : "http"
41
+ def create_stubs_checkpoint(checkpoint_name)
42
+ checkpoints[checkpoint_name] = ::FakeWeb::Registry.instance.uri_map.dup
43
+ end
57
44
 
58
- path = request.path
59
- path = URI.parse(request.path).request_uri if request.path =~ /^http/
45
+ def restore_stubs_checkpoint(checkpoint_name)
46
+ ::FakeWeb::Registry.instance.uri_map = checkpoints.delete(checkpoint_name)
47
+ end
60
48
 
61
- if request["authorization"] =~ /^Basic /
62
- userinfo = ::FakeWeb::Utility.decode_userinfo_from_header(request["authorization"])
63
- userinfo = ::FakeWeb::Utility.encode_unsafe_chars_in_userinfo(userinfo) + "@"
64
- else
65
- userinfo = ""
66
- end
49
+ def request_stubbed?(request, match_attributes)
50
+ validate_match_attributes(match_attributes)
51
+ ::FakeWeb.registered_uri?(request.method, request.uri)
52
+ end
67
53
 
68
- "#{protocol}://#{userinfo}#{net_http.address}:#{net_http.port}#{path}"
69
- end
54
+ def request_uri(net_http, request)
55
+ ::FakeWeb::Utility.request_uri_as_string(net_http, request)
56
+ end
70
57
 
71
- attr_writer :ignore_localhost
72
- def ignore_localhost?
73
- @ignore_localhost
74
- end
58
+ def ignore_localhost=(value)
59
+ @ignore_localhost = value
60
+ update_fakeweb_allow_net_connect
61
+ end
75
62
 
76
- private
63
+ def ignore_localhost?
64
+ @ignore_localhost
65
+ end
77
66
 
78
- def checkpoints
79
- @checkpoints ||= {}
80
- end
67
+ private
81
68
 
82
- def response_hash(response)
83
- response.headers.merge(
84
- :body => response.body,
85
- :status => [response.status.code.to_s, response.status.message]
86
- )
69
+ def version
70
+ ::FakeWeb::VERSION
71
+ end
72
+
73
+ def update_fakeweb_allow_net_connect
74
+ ::FakeWeb.allow_net_connect = if @http_connections_allowed
75
+ true
76
+ elsif @ignore_localhost
77
+ LOCALHOST_REGEX
78
+ else
79
+ false
87
80
  end
81
+ end
82
+
83
+ def checkpoints
84
+ @checkpoints ||= {}
85
+ end
86
+
87
+ def response_hash(response)
88
+ response.headers.merge(
89
+ :body => response.body,
90
+ :status => [response.status.code.to_s, response.status.message]
91
+ )
92
+ end
88
93
 
89
- def validate_match_attributes(match_attributes)
90
- invalid_attributes = match_attributes & UNSUPPORTED_REQUEST_MATCH_ATTRIBUTES
91
- if invalid_attributes.size > 0
92
- raise UnsupportedRequestMatchAttributeError.new("FakeWeb does not support matching requests on #{invalid_attributes.join(' or ')}")
93
- end
94
+ def validate_match_attributes(match_attributes)
95
+ invalid_attributes = match_attributes & UNSUPPORTED_REQUEST_MATCH_ATTRIBUTES
96
+ if invalid_attributes.size > 0
97
+ raise UnsupportedRequestMatchAttributeError.new("FakeWeb does not support matching requests on #{invalid_attributes.join(' or ')}")
94
98
  end
95
99
  end
96
100
  end
@@ -3,86 +3,85 @@ require 'vcr/extensions/net_http'
3
3
 
4
4
  module VCR
5
5
  module HttpStubbingAdapters
6
- class WebMock < Base
7
- class << self
8
- VERSION_REQUIREMENT = '1.3.3'
9
-
10
- def check_version!
11
- unless meets_version_requirement?(::WebMock.version, VERSION_REQUIREMENT)
12
- raise "You are using WebMock #{::WebMock.version}. VCR requires version #{VERSION_REQUIREMENT} or greater."
13
- end
14
- end
6
+ module WebMock
7
+ include VCR::HttpStubbingAdapters::Common
8
+ extend self
15
9
 
16
- def http_connections_allowed?
17
- ::WebMock::Config.instance.allow_net_connect
18
- end
10
+ VERSION_REQUIREMENT = '1.3.3'
19
11
 
20
- def http_connections_allowed=(value)
21
- ::WebMock::Config.instance.allow_net_connect = value
22
- end
12
+ def http_connections_allowed?
13
+ ::WebMock::Config.instance.allow_net_connect
14
+ end
23
15
 
24
- def stub_requests(http_interactions, match_attributes = RequestMatcher::DEFAULT_MATCH_ATTRIBUTES)
25
- requests = Hash.new([])
16
+ def http_connections_allowed=(value)
17
+ ::WebMock::Config.instance.allow_net_connect = value
18
+ end
26
19
 
27
- http_interactions.each do |i|
28
- requests[i.request.matcher(match_attributes)] += [i.response]
29
- end
20
+ def stub_requests(http_interactions, match_attributes)
21
+ requests = Hash.new { |h,k| h[k] = [] }
30
22
 
31
- requests.each do |request_matcher, responses|
32
- stub = ::WebMock.stub_request(request_matcher.method || :any, request_matcher.uri)
23
+ http_interactions.each do |i|
24
+ requests[i.request.matcher(match_attributes)] << i.response
25
+ end
33
26
 
34
- with_hash = request_signature_hash(request_matcher)
35
- stub = stub.with(with_hash) if with_hash.size > 0
27
+ requests.each do |request_matcher, responses|
28
+ stub = ::WebMock.stub_request(request_matcher.method || :any, request_matcher.uri)
36
29
 
37
- stub.to_return(responses.map{ |r| response_hash(r) })
38
- end
39
- end
30
+ with_hash = request_signature_hash(request_matcher)
31
+ stub = stub.with(with_hash) if with_hash.size > 0
40
32
 
41
- def create_stubs_checkpoint(checkpoint_name)
42
- checkpoints[checkpoint_name] = ::WebMock::RequestRegistry.instance.request_stubs.dup
33
+ stub.to_return(responses.map{ |r| response_hash(r) })
43
34
  end
35
+ end
44
36
 
45
- def restore_stubs_checkpoint(checkpoint_name)
46
- ::WebMock::RequestRegistry.instance.request_stubs = checkpoints.delete(checkpoint_name)
47
- end
37
+ def create_stubs_checkpoint(checkpoint_name)
38
+ checkpoints[checkpoint_name] = ::WebMock::RequestRegistry.instance.request_stubs.dup
39
+ end
48
40
 
49
- def request_stubbed?(request, match_attributes)
50
- matcher = request.matcher(match_attributes)
51
- !!::WebMock.registered_request?(::WebMock::RequestSignature.new(matcher.method || :any, request.uri, request_signature_hash(matcher)))
52
- end
41
+ def restore_stubs_checkpoint(checkpoint_name)
42
+ ::WebMock::RequestRegistry.instance.request_stubs = checkpoints.delete(checkpoint_name)
43
+ end
53
44
 
54
- def request_uri(net_http, request)
55
- ::WebMock::NetHTTPUtility.request_signature_from_request(net_http, request).uri.to_s
56
- end
45
+ def request_stubbed?(request, match_attributes)
46
+ matcher = request.matcher(match_attributes)
47
+ !!::WebMock.registered_request?(::WebMock::RequestSignature.new(matcher.method || :any, request.uri, request_signature_hash(matcher)))
48
+ end
57
49
 
58
- def ignore_localhost=(value)
59
- ::WebMock::Config.instance.allow_localhost = value
60
- end
50
+ def request_uri(net_http, request)
51
+ ::WebMock::NetHTTPUtility.request_signature_from_request(net_http, request).uri.to_s
52
+ end
61
53
 
62
- def ignore_localhost?
63
- ::WebMock::Config.instance.allow_localhost
64
- end
54
+ def ignore_localhost=(value)
55
+ ::WebMock::Config.instance.allow_localhost = value
56
+ end
65
57
 
66
- private
58
+ def ignore_localhost?
59
+ ::WebMock::Config.instance.allow_localhost
60
+ end
67
61
 
68
- def request_signature_hash(request_matcher)
69
- signature = {}
70
- signature[:body] = request_matcher.body if request_matcher.match_requests_on?(:body)
71
- signature[:headers] = request_matcher.headers if request_matcher.match_requests_on?(:headers)
72
- signature
73
- end
62
+ private
74
63
 
75
- def response_hash(response)
76
- {
77
- :body => response.body,
78
- :status => [response.status.code.to_i, response.status.message],
79
- :headers => response.headers
80
- }
81
- end
64
+ def version
65
+ ::WebMock.version
66
+ end
82
67
 
83
- def checkpoints
84
- @checkpoints ||= {}
85
- end
68
+ def request_signature_hash(request_matcher)
69
+ signature = {}
70
+ signature[:body] = request_matcher.body if request_matcher.match_requests_on?(:body)
71
+ signature[:headers] = request_matcher.headers if request_matcher.match_requests_on?(:headers)
72
+ signature
73
+ end
74
+
75
+ def response_hash(response)
76
+ {
77
+ :body => response.body,
78
+ :status => [response.status.code.to_i, response.status.message],
79
+ :headers => response.headers
80
+ }
81
+ end
82
+
83
+ def checkpoints
84
+ @checkpoints ||= {}
86
85
  end
87
86
  end
88
87
  end
data/lib/vcr/version.rb CHANGED
@@ -3,7 +3,7 @@ module VCR
3
3
 
4
4
  def version
5
5
  @version ||= begin
6
- string = [1, 1, 0].join('.')
6
+ string = [1, 1, 1].join('.')
7
7
 
8
8
  def string.parts; VCR.version.split('.').map { |p| p.to_i }; end
9
9
  def string.major; parts[0]; end
@@ -0,0 +1,280 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe VCR::Cassette do
4
+ describe '#file' do
5
+ temp_dir File.expand_path(File.dirname(__FILE__) + '/fixtures/file'), :assign_to_cassette_library_dir => true
6
+
7
+ it 'combines the cassette_library_dir with the cassette name' do
8
+ cassette = VCR::Cassette.new('the_file')
9
+ cassette.file.should == File.join(VCR::Config.cassette_library_dir, 'the_file.yml')
10
+ end
11
+
12
+ it 'strips out disallowed characters so that it is a valid file name with no spaces' do
13
+ cassette = VCR::Cassette.new("\nthis \t! is-the_13212_file name")
14
+ cassette.file.should =~ /#{Regexp.escape('_this_is-the_13212_file_name.yml')}$/
15
+ end
16
+
17
+ it 'keeps any path separators' do
18
+ cassette = VCR::Cassette.new("dir/file_name")
19
+ cassette.file.should =~ /#{Regexp.escape('dir/file_name.yml')}$/
20
+ end
21
+
22
+ it 'returns nil if the cassette_library_dir is not set' do
23
+ VCR::Config.cassette_library_dir = nil
24
+ cassette = VCR::Cassette.new('the_file')
25
+ cassette.file.should be_nil
26
+ end
27
+ end
28
+
29
+ describe '#record_http_interaction' do
30
+ it 'adds the interaction to #recorded_interactions' do
31
+ cassette = VCR::Cassette.new(:test_cassette)
32
+ cassette.recorded_interactions.should == []
33
+ cassette.record_http_interaction(:the_interaction)
34
+ cassette.recorded_interactions.should == [:the_interaction]
35
+ end
36
+ end
37
+
38
+ describe '#match_requests_on' do
39
+ before(:each) { VCR::Config.default_cassette_options.merge!(:match_requests_on => [:uri, :method]) }
40
+
41
+ it "returns the provided options" do
42
+ c = VCR::Cassette.new('example', :match_requests_on => [:uri])
43
+ c.match_requests_on.should == [:uri]
44
+ end
45
+
46
+ it "returns a the default #match_requests_on when it has not been specified for the cassette" do
47
+ c = VCR::Cassette.new('example')
48
+ c.match_requests_on.should == [:uri, :method]
49
+ end
50
+ end
51
+
52
+ describe 'on creation' do
53
+ it 'raises an error with a helpful message when loading an old unsupported cassette' do
54
+ VCR::Config.cassette_library_dir = File.expand_path(File.dirname(__FILE__) + "/fixtures/#{YAML_SERIALIZATION_VERSION}")
55
+ lambda { VCR::Cassette.new('0_3_1_cassette') }.should raise_error(/The VCR cassette 0_3_1_cassette.yml uses an old format that is now deprecated/)
56
+ end
57
+
58
+ it "raises an error if given an invalid record mode" do
59
+ lambda { VCR::Cassette.new(:test, :record => :not_a_record_mode) }.should raise_error(ArgumentError)
60
+ end
61
+
62
+ it 'raises an error if given invalid options' do
63
+ expect {
64
+ VCR::Cassette.new(:test, :invalid => :option)
65
+ }.to raise_error(ArgumentError)
66
+ end
67
+
68
+ it 'creates a stubs checkpoint on the http_stubbing_adapter' do
69
+ VCR.http_stubbing_adapter.should_receive(:create_stubs_checkpoint).with('example').once
70
+ VCR::Cassette.new('example')
71
+ end
72
+
73
+ describe 'ERB support' do
74
+ before(:each) do
75
+ @orig_default_options = VCR::Config.default_cassette_options
76
+ end
77
+
78
+ after(:each) do
79
+ VCR::Config.default_cassette_options = @orig_default_options
80
+ end
81
+
82
+ def cassette_body(name, options = {})
83
+ VCR::Config.cassette_library_dir = File.expand_path(File.dirname(__FILE__) + "/fixtures/#{YAML_SERIALIZATION_VERSION}/cassette_spec")
84
+ VCR::Cassette.new(name, options.merge(:record => :new_episodes)).recorded_interactions.first.response.body
85
+ end
86
+
87
+ it "compiles a template as ERB if the :erb option is passed as true" do
88
+ cassette_body('erb_with_no_vars', :erb => true).should == 'sum: 3'
89
+ end
90
+
91
+ it "compiles a template as ERB if the default :erb option is true, and no option is passed to the cassette" do
92
+ VCR::Config.default_cassette_options = { :erb => true }
93
+ cassette_body('erb_with_no_vars').should == 'sum: 3'
94
+ end
95
+
96
+ it "does not compile a template as ERB if the default :erb option is true, and :erb => false is passed to the cassette" do
97
+ VCR::Config.default_cassette_options = { :erb => true }
98
+ cassette_body('erb_with_no_vars', :erb => false).should == 'sum: <%= 1 + 2 %>'
99
+ end
100
+
101
+ it "compiles a template as ERB if the :erb option is passed a hash" do
102
+ cassette_body('erb_with_vars', :erb => { :var1 => 'a', :var3 => 'c', :var2 => 'b' }).should == 'var1: a; var2: b; var3: c'
103
+ end
104
+
105
+ it "does not compile a template as ERB if the :erb option is not used" do
106
+ cassette_body('erb_with_no_vars').should == 'sum: <%= 1 + 2 %>'
107
+ end
108
+
109
+ it "raises a helpful error if the ERB template references variables that are not passed in the :erb hash" do
110
+ expect {
111
+ cassette_body('erb_with_vars', :erb => { :var1 => 'a', :var2 => 'b' })
112
+ }.to raise_error(VCR::Cassette::MissingERBVariableError,
113
+ %{The ERB in the erb_with_vars.yml cassette file references undefined variable var3. } +
114
+ %{Pass it to the cassette using :erb => #{ { :var1 => 'a', :var2 => 'b' }.merge(:var3 => 'some value').inspect }.}
115
+ )
116
+ end
117
+
118
+ it "raises a helpful error if the ERB template references variables and :erb => true is passed" do
119
+ expect {
120
+ cassette_body('erb_with_vars', :erb => true)
121
+ }.to raise_error(VCR::Cassette::MissingERBVariableError,
122
+ %{The ERB in the erb_with_vars.yml cassette file references undefined variable var1. } +
123
+ %{Pass it to the cassette using :erb => {:var1=>"some value"}.}
124
+ )
125
+ end
126
+ end
127
+
128
+ VCR::Cassette::VALID_RECORD_MODES.each do |record_mode|
129
+ http_connections_allowed = (record_mode != :none)
130
+ load_interactions = (record_mode != :all)
131
+
132
+ context "when VCR::Config.default_cassette_options[:record] is :#{record_mode}" do
133
+ before(:each) { VCR::Config.default_cassette_options = { :record => record_mode } }
134
+
135
+ it "defaults the record mode to #{record_mode} when VCR::Config.default_cassette_options[:record] is #{record_mode}" do
136
+ cassette = VCR::Cassette.new(:test)
137
+ cassette.record_mode.should == record_mode
138
+ end
139
+ end
140
+
141
+ context "when the record mode is :#{record_mode}" do
142
+ it "sets http_connections_allowed to #{http_connections_allowed} on the http stubbing adapter" do
143
+ VCR.http_stubbing_adapter.should_receive(:http_connections_allowed=).with(http_connections_allowed)
144
+ VCR::Cassette.new(:name, :record => record_mode)
145
+ end
146
+
147
+ if load_interactions
148
+
149
+ [true, false].each do |ignore_localhost|
150
+ expected_uri_hosts = %w(example.com)
151
+ expected_uri_hosts += VCR::LOCALHOST_ALIASES unless ignore_localhost
152
+
153
+ it "#{ ignore_localhost ? 'does not load' : 'loads' } localhost interactions from the cassette file when http_stubbing_adapter.ignore_localhost is set to #{ignore_localhost}" do
154
+ VCR.http_stubbing_adapter.stub!(:ignore_localhost?).and_return(ignore_localhost)
155
+ VCR::Config.cassette_library_dir = File.expand_path(File.dirname(__FILE__) + "/fixtures/#{YAML_SERIALIZATION_VERSION}/cassette_spec")
156
+ cassette = VCR::Cassette.new('with_localhost_requests', :record => record_mode)
157
+ cassette.recorded_interactions.map { |i| URI.parse(i.uri).host }.should =~ expected_uri_hosts
158
+ end
159
+ end
160
+
161
+ it "loads the recorded interactions from the library yml file" do
162
+ VCR::Config.cassette_library_dir = File.expand_path(File.dirname(__FILE__) + "/fixtures/#{YAML_SERIALIZATION_VERSION}/cassette_spec")
163
+ cassette = VCR::Cassette.new('example', :record => record_mode)
164
+
165
+ cassette.should have(3).recorded_interactions
166
+
167
+ i1, i2, i3 = *cassette.recorded_interactions
168
+
169
+ i1.request.method.should == :get
170
+ i1.request.uri.should == 'http://example.com:80/'
171
+ i1.response.body.should =~ /You have reached this web page by typing.+example\.com/
172
+
173
+ i2.request.method.should == :get
174
+ i2.request.uri.should == 'http://example.com:80/foo'
175
+ i2.response.body.should =~ /foo was not found on this server/
176
+
177
+ i3.request.method.should == :get
178
+ i3.request.uri.should == 'http://example.com:80/'
179
+ i3.response.body.should =~ /Another example\.com response/
180
+ end
181
+
182
+ it "stubs the recorded requests with the http stubbing adapter" do
183
+ VCR::Config.cassette_library_dir = File.expand_path(File.dirname(__FILE__) + "/fixtures/#{YAML_SERIALIZATION_VERSION}/cassette_spec")
184
+ VCR.http_stubbing_adapter.should_receive(:stub_requests).with([an_instance_of(VCR::HTTPInteraction)]*3, anything)
185
+ cassette = VCR::Cassette.new('example', :record => record_mode)
186
+ end
187
+
188
+ it "passes the :match_request_on option to #stub_requests" do
189
+ VCR::Config.cassette_library_dir = File.expand_path(File.dirname(__FILE__) + "/fixtures/#{YAML_SERIALIZATION_VERSION}/cassette_spec")
190
+ VCR.http_stubbing_adapter.should_receive(:stub_requests).with(anything, [:body, :headers])
191
+ cassette = VCR::Cassette.new('example', :record => record_mode, :match_requests_on => [:body, :headers])
192
+ end
193
+
194
+ else
195
+
196
+ it "does not stub the recorded requests with the http stubbing adapter" do
197
+ VCR::Config.cassette_library_dir = File.expand_path(File.dirname(__FILE__) + "/fixtures/#{YAML_SERIALIZATION_VERSION}/cassette_spec")
198
+ VCR.http_stubbing_adapter.should_not_receive(:stub_requests)
199
+ cassette = VCR::Cassette.new('example', :record => record_mode)
200
+ end
201
+
202
+ it "does not load the recorded interactions from the library yml file" do
203
+ VCR::Config.cassette_library_dir = File.expand_path(File.dirname(__FILE__) + "/fixtures/#{YAML_SERIALIZATION_VERSION}/cassette_spec")
204
+ cassette = VCR::Cassette.new('example', :record => record_mode)
205
+ cassette.should have(0).recorded_interactions
206
+ end
207
+
208
+ end
209
+ end
210
+ end
211
+ end
212
+
213
+ describe '#eject' do
214
+ temp_dir File.expand_path(File.dirname(__FILE__) + '/fixtures/cassette_spec_eject'), :assign_to_cassette_library_dir => true
215
+
216
+ [true, false].each do |orig_http_connections_allowed|
217
+ it "resets #{orig_http_connections_allowed} on the http stubbing adapter if it was originally #{orig_http_connections_allowed}" do
218
+ VCR.http_stubbing_adapter.should_receive(:http_connections_allowed?).and_return(orig_http_connections_allowed)
219
+ cassette = VCR::Cassette.new(:name)
220
+ VCR.http_stubbing_adapter.should_receive(:http_connections_allowed=).with(orig_http_connections_allowed)
221
+ cassette.eject
222
+ end
223
+ end
224
+
225
+ it "writes the recorded interactions to disk as yaml" do
226
+ recorded_interactions = [
227
+ VCR::HTTPInteraction.new(:req_sig_1, :response_1),
228
+ VCR::HTTPInteraction.new(:req_sig_2, :response_2),
229
+ VCR::HTTPInteraction.new(:req_sig_3, :response_3)
230
+ ]
231
+
232
+ cassette = VCR::Cassette.new(:eject_test)
233
+ cassette.stub!(:recorded_interactions).and_return(recorded_interactions)
234
+
235
+ lambda { cassette.eject }.should change { File.exist?(cassette.file) }.from(false).to(true)
236
+ saved_recorded_interactions = File.open(cassette.file, "r") { |f| YAML.load(f.read) }
237
+ saved_recorded_interactions.should == recorded_interactions
238
+ end
239
+
240
+ it "writes the recorded interactions to a subdirectory if the cassette name includes a directory" do
241
+ recorded_interactions = [VCR::HTTPInteraction.new(:the_request, :the_response)]
242
+ cassette = VCR::Cassette.new('subdirectory/test_cassette')
243
+ cassette.stub!(:recorded_interactions).and_return(recorded_interactions)
244
+
245
+ lambda { cassette.eject }.should change { File.exist?(cassette.file) }.from(false).to(true)
246
+ saved_recorded_interactions = File.open(cassette.file, "r") { |f| YAML.load(f.read) }
247
+ saved_recorded_interactions.should == recorded_interactions
248
+ end
249
+
250
+ it "writes both old and new recorded interactions to disk" do
251
+ file = File.expand_path(File.dirname(__FILE__) + "/fixtures/#{YAML_SERIALIZATION_VERSION}/cassette_spec/example.yml")
252
+ FileUtils.cp file, File.join(@temp_dir, 'previously_recorded_interactions.yml')
253
+ cassette = VCR::Cassette.new('previously_recorded_interactions')
254
+ cassette.should have(3).recorded_interactions
255
+ new_recorded_interaction = VCR::HTTPInteraction.new(:the_request, :the_response)
256
+ cassette.record_http_interaction(new_recorded_interaction)
257
+ cassette.eject
258
+ saved_recorded_interactions = File.open(cassette.file, "r") { |f| YAML.load(f.read) }
259
+ saved_recorded_interactions.should have(4).recorded_interactions
260
+ saved_recorded_interactions.last.should == new_recorded_interaction
261
+ end
262
+ end
263
+
264
+ describe '#eject for a cassette with previously recorded interactions' do
265
+ it "restore the stubs checkpoint on the http stubbing adapter" do
266
+ VCR::Config.cassette_library_dir = File.expand_path(File.dirname(__FILE__) + "/fixtures/#{YAML_SERIALIZATION_VERSION}/cassette_spec")
267
+ cassette = VCR::Cassette.new('example', :record => :none)
268
+ VCR.http_stubbing_adapter.should_receive(:restore_stubs_checkpoint).with('example')
269
+ cassette.eject
270
+ end
271
+
272
+ it "does not re-write to disk the previously recorded interactions if there are no new ones" do
273
+ VCR::Config.cassette_library_dir = File.expand_path(File.dirname(__FILE__) + "/fixtures/#{YAML_SERIALIZATION_VERSION}/cassette_spec")
274
+ yaml_file = File.join(VCR::Config.cassette_library_dir, 'example.yml')
275
+ cassette = VCR::Cassette.new('example', :record => :none)
276
+ File.should_not_receive(:open).with(cassette.file, 'w')
277
+ lambda { cassette.eject }.should_not change { File.mtime(yaml_file) }
278
+ end
279
+ end
280
+ end