vcr 1.1.0 → 1.1.1

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.
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