mustwin-vcr 2.9.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. checksums.yaml +7 -0
  2. data/features/about_these_examples.md +18 -0
  3. data/features/cassettes/allow_unused_http_interactions.feature +100 -0
  4. data/features/cassettes/automatic_re_recording.feature +72 -0
  5. data/features/cassettes/decompress.feature +74 -0
  6. data/features/cassettes/dynamic_erb.feature +100 -0
  7. data/features/cassettes/exclusive.feature +126 -0
  8. data/features/cassettes/format.feature +323 -0
  9. data/features/cassettes/freezing_time.feature +68 -0
  10. data/features/cassettes/naming.feature +28 -0
  11. data/features/cassettes/no_cassette.feature +152 -0
  12. data/features/cassettes/update_content_length_header.feature +112 -0
  13. data/features/configuration/allow_http_connections_when_no_cassette.feature +55 -0
  14. data/features/configuration/cassette_library_dir.feature +31 -0
  15. data/features/configuration/debug_logging.feature +59 -0
  16. data/features/configuration/default_cassette_options.feature +100 -0
  17. data/features/configuration/filter_sensitive_data.feature +153 -0
  18. data/features/configuration/hook_into.feature +172 -0
  19. data/features/configuration/ignore_request.feature +192 -0
  20. data/features/configuration/preserve_exact_body_bytes.feature +108 -0
  21. data/features/configuration/query_parser.feature +84 -0
  22. data/features/configuration/uri_parser.feature +89 -0
  23. data/features/getting_started.md +82 -0
  24. data/features/hooks/after_http_request.feature +58 -0
  25. data/features/hooks/around_http_request.feature +57 -0
  26. data/features/hooks/before_http_request.feature +63 -0
  27. data/features/hooks/before_playback.feature +184 -0
  28. data/features/hooks/before_record.feature +172 -0
  29. data/features/http_libraries/em_http_request.feature +250 -0
  30. data/features/http_libraries/net_http.feature +179 -0
  31. data/features/middleware/faraday.feature +56 -0
  32. data/features/middleware/rack.feature +92 -0
  33. data/features/record_modes/all.feature +82 -0
  34. data/features/record_modes/new_episodes.feature +79 -0
  35. data/features/record_modes/none.feature +72 -0
  36. data/features/record_modes/once.feature +95 -0
  37. data/features/request_matching/README.md +30 -0
  38. data/features/request_matching/body.feature +91 -0
  39. data/features/request_matching/body_as_json.feature +90 -0
  40. data/features/request_matching/custom_matcher.feature +135 -0
  41. data/features/request_matching/headers.feature +85 -0
  42. data/features/request_matching/host.feature +95 -0
  43. data/features/request_matching/identical_request_sequence.feature +89 -0
  44. data/features/request_matching/method.feature +96 -0
  45. data/features/request_matching/path.feature +96 -0
  46. data/features/request_matching/playback_repeats.feature +98 -0
  47. data/features/request_matching/query.feature +97 -0
  48. data/features/request_matching/uri.feature +94 -0
  49. data/features/request_matching/uri_without_param.feature +101 -0
  50. data/features/step_definitions/cli_steps.rb +193 -0
  51. data/features/support/env.rb +44 -0
  52. data/features/support/http_lib_filters.rb +53 -0
  53. data/features/test_frameworks/cucumber.feature +211 -0
  54. data/features/test_frameworks/rspec_macro.feature +81 -0
  55. data/features/test_frameworks/rspec_metadata.feature +150 -0
  56. data/features/test_frameworks/test_unit.feature +49 -0
  57. data/lib/vcr.rb +347 -0
  58. data/lib/vcr/cassette.rb +291 -0
  59. data/lib/vcr/cassette/erb_renderer.rb +55 -0
  60. data/lib/vcr/cassette/http_interaction_list.rb +108 -0
  61. data/lib/vcr/cassette/migrator.rb +118 -0
  62. data/lib/vcr/cassette/persisters.rb +42 -0
  63. data/lib/vcr/cassette/persisters/file_system.rb +64 -0
  64. data/lib/vcr/cassette/serializers.rb +57 -0
  65. data/lib/vcr/cassette/serializers/json.rb +48 -0
  66. data/lib/vcr/cassette/serializers/psych.rb +48 -0
  67. data/lib/vcr/cassette/serializers/syck.rb +61 -0
  68. data/lib/vcr/cassette/serializers/yaml.rb +50 -0
  69. data/lib/vcr/configuration.rb +555 -0
  70. data/lib/vcr/deprecations.rb +109 -0
  71. data/lib/vcr/errors.rb +266 -0
  72. data/lib/vcr/extensions/net_http_response.rb +36 -0
  73. data/lib/vcr/library_hooks.rb +18 -0
  74. data/lib/vcr/library_hooks/excon.rb +27 -0
  75. data/lib/vcr/library_hooks/fakeweb.rb +196 -0
  76. data/lib/vcr/library_hooks/faraday.rb +51 -0
  77. data/lib/vcr/library_hooks/typhoeus.rb +120 -0
  78. data/lib/vcr/library_hooks/typhoeus_0.4.rb +103 -0
  79. data/lib/vcr/library_hooks/webmock.rb +164 -0
  80. data/lib/vcr/middleware/excon.rb +221 -0
  81. data/lib/vcr/middleware/excon/legacy_methods.rb +33 -0
  82. data/lib/vcr/middleware/faraday.rb +118 -0
  83. data/lib/vcr/middleware/rack.rb +79 -0
  84. data/lib/vcr/request_handler.rb +114 -0
  85. data/lib/vcr/request_ignorer.rb +43 -0
  86. data/lib/vcr/request_matcher_registry.rb +149 -0
  87. data/lib/vcr/structs.rb +578 -0
  88. data/lib/vcr/tasks/vcr.rake +9 -0
  89. data/lib/vcr/test_frameworks/cucumber.rb +64 -0
  90. data/lib/vcr/test_frameworks/rspec.rb +47 -0
  91. data/lib/vcr/util/hooks.rb +61 -0
  92. data/lib/vcr/util/internet_connection.rb +43 -0
  93. data/lib/vcr/util/logger.rb +59 -0
  94. data/lib/vcr/util/variable_args_block_caller.rb +13 -0
  95. data/lib/vcr/util/version_checker.rb +48 -0
  96. data/lib/vcr/version.rb +34 -0
  97. data/spec/acceptance/threading_spec.rb +34 -0
  98. data/spec/fixtures/cassette_spec/1_x_cassette.yml +110 -0
  99. data/spec/fixtures/cassette_spec/empty.yml +0 -0
  100. data/spec/fixtures/cassette_spec/example.yml +111 -0
  101. data/spec/fixtures/cassette_spec/with_localhost_requests.yml +111 -0
  102. data/spec/fixtures/fake_example_responses.yml +110 -0
  103. data/spec/fixtures/match_requests_on.yml +187 -0
  104. data/spec/lib/vcr/cassette/erb_renderer_spec.rb +53 -0
  105. data/spec/lib/vcr/cassette/http_interaction_list_spec.rb +295 -0
  106. data/spec/lib/vcr/cassette/migrator_spec.rb +195 -0
  107. data/spec/lib/vcr/cassette/persisters/file_system_spec.rb +69 -0
  108. data/spec/lib/vcr/cassette/persisters_spec.rb +39 -0
  109. data/spec/lib/vcr/cassette/serializers_spec.rb +176 -0
  110. data/spec/lib/vcr/cassette_spec.rb +618 -0
  111. data/spec/lib/vcr/configuration_spec.rb +326 -0
  112. data/spec/lib/vcr/deprecations_spec.rb +85 -0
  113. data/spec/lib/vcr/errors_spec.rb +162 -0
  114. data/spec/lib/vcr/extensions/net_http_response_spec.rb +86 -0
  115. data/spec/lib/vcr/library_hooks/excon_spec.rb +104 -0
  116. data/spec/lib/vcr/library_hooks/fakeweb_spec.rb +169 -0
  117. data/spec/lib/vcr/library_hooks/faraday_spec.rb +68 -0
  118. data/spec/lib/vcr/library_hooks/typhoeus_0.4_spec.rb +36 -0
  119. data/spec/lib/vcr/library_hooks/typhoeus_spec.rb +162 -0
  120. data/spec/lib/vcr/library_hooks/webmock_spec.rb +118 -0
  121. data/spec/lib/vcr/library_hooks_spec.rb +51 -0
  122. data/spec/lib/vcr/middleware/faraday_spec.rb +182 -0
  123. data/spec/lib/vcr/middleware/rack_spec.rb +115 -0
  124. data/spec/lib/vcr/request_ignorer_spec.rb +70 -0
  125. data/spec/lib/vcr/request_matcher_registry_spec.rb +345 -0
  126. data/spec/lib/vcr/structs_spec.rb +732 -0
  127. data/spec/lib/vcr/test_frameworks/cucumber_spec.rb +107 -0
  128. data/spec/lib/vcr/test_frameworks/rspec_spec.rb +83 -0
  129. data/spec/lib/vcr/util/hooks_spec.rb +158 -0
  130. data/spec/lib/vcr/util/internet_connection_spec.rb +37 -0
  131. data/spec/lib/vcr/util/version_checker_spec.rb +31 -0
  132. data/spec/lib/vcr/version_spec.rb +27 -0
  133. data/spec/lib/vcr_spec.rb +349 -0
  134. data/spec/monkey_patches.rb +182 -0
  135. data/spec/spec_helper.rb +62 -0
  136. data/spec/support/configuration_stubbing.rb +8 -0
  137. data/spec/support/cucumber_helpers.rb +35 -0
  138. data/spec/support/fixnum_extension.rb +10 -0
  139. data/spec/support/http_library_adapters.rb +289 -0
  140. data/spec/support/limited_uri.rb +21 -0
  141. data/spec/support/ruby_interpreter.rb +7 -0
  142. data/spec/support/shared_example_groups/excon.rb +63 -0
  143. data/spec/support/shared_example_groups/hook_into_http_library.rb +594 -0
  144. data/spec/support/shared_example_groups/request_hooks.rb +59 -0
  145. data/spec/support/sinatra_app.rb +86 -0
  146. data/spec/support/vcr_localhost_server.rb +76 -0
  147. data/spec/support/vcr_stub_helpers.rb +17 -0
  148. metadata +677 -0
@@ -0,0 +1,69 @@
1
+ require 'spec_helper'
2
+ require 'vcr/cassette/persisters/file_system'
3
+
4
+ module VCR
5
+ class Cassette
6
+ class Persisters
7
+ describe FileSystem do
8
+ before { FileSystem.storage_location = VCR.configuration.cassette_library_dir }
9
+
10
+ describe "#[]" do
11
+ it 'reads from the given file, relative to the configured storage location' do
12
+ File.open(FileSystem.storage_location + '/foo.txt', 'w') { |f| f.write('1234') }
13
+ expect(FileSystem["foo.txt"]).to eq("1234")
14
+ end
15
+
16
+ it 'handles directories in the given file name' do
17
+ FileUtils.mkdir_p FileSystem.storage_location + '/a'
18
+ File.open(FileSystem.storage_location + '/a/b', 'w') { |f| f.write('1234') }
19
+ expect(FileSystem["a/b"]).to eq("1234")
20
+ end
21
+
22
+ it 'returns nil if the file does not exist' do
23
+ expect(FileSystem["non_existant_file"]).to be_nil
24
+ end
25
+ end
26
+
27
+ describe "#[]=" do
28
+ it 'writes the given file contents to the given file name' do
29
+ expect(File.exist?(FileSystem.storage_location + '/foo.txt')).to be false
30
+ FileSystem["foo.txt"] = "bar"
31
+ expect(File.read(FileSystem.storage_location + '/foo.txt')).to eq("bar")
32
+ end
33
+
34
+ it 'creates any needed intermediary directories' do
35
+ expect(File.exist?(FileSystem.storage_location + '/a')).to be false
36
+ FileSystem["a/b"] = "bar"
37
+ expect(File.read(FileSystem.storage_location + '/a/b')).to eq("bar")
38
+ end
39
+ end
40
+
41
+ describe "#absolute_path_to_file" do
42
+ it "returns the absolute path to the given relative file based on the storage location" do
43
+ expected = File.join(FileSystem.storage_location, "bar/bazz.json")
44
+ expect(FileSystem.absolute_path_to_file("bar/bazz.json")).to eq(expected)
45
+ end
46
+
47
+ it "returns nil if the storage_location is not set" do
48
+ FileSystem.storage_location = nil
49
+ expect(FileSystem.absolute_path_to_file("bar/bazz.json")).to be_nil
50
+ end
51
+
52
+ it "sanitizes the file name" do
53
+ expected = File.join(FileSystem.storage_location, "_t_i-t_1_2_f_n.json")
54
+ expect(FileSystem.absolute_path_to_file("\nt \t! i-t_1.2_f n.json")).to eq(expected)
55
+
56
+ expected = File.join(FileSystem.storage_location, "a_1/b")
57
+ expect(FileSystem.absolute_path_to_file("a 1/b")).to eq(expected)
58
+ end
59
+
60
+ it 'handles files with no extensions (even when there is a dot in the path)' do
61
+ expected = File.join(FileSystem.storage_location, "/foo_bar/baz_qux")
62
+ expect(FileSystem.absolute_path_to_file("/foo.bar/baz qux")).to eq(expected)
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+
@@ -0,0 +1,39 @@
1
+ require 'vcr/cassette/persisters'
2
+
3
+ module VCR
4
+ class Cassette
5
+ describe Persisters do
6
+ describe "#[]=" do
7
+ context 'when there is already a persister registered for the given name' do
8
+ before(:each) do
9
+ subject[:foo] = :old_persister
10
+ allow(subject).to receive :warn
11
+ end
12
+
13
+ it 'overrides the existing persister' do
14
+ subject[:foo] = :new_persister
15
+ expect(subject[:foo]).to be(:new_persister)
16
+ end
17
+
18
+ it 'warns that there is a name collision' do
19
+ expect(subject).to receive(:warn).with(
20
+ /WARNING: There is already a VCR cassette persister registered for :foo\. Overriding it/
21
+ )
22
+ subject[:foo] = :new_persister
23
+ end
24
+ end
25
+ end
26
+
27
+ describe "#[]" do
28
+ it 'raises an error when given an unrecognized persister name' do
29
+ expect { subject[:foo] }.to raise_error(ArgumentError)
30
+ end
31
+
32
+ it 'returns the named persister' do
33
+ expect(subject[:file_system]).to be(VCR::Cassette::Persisters::FileSystem)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+
@@ -0,0 +1,176 @@
1
+ require 'support/ruby_interpreter'
2
+ require 'vcr/cassette/serializers'
3
+ require 'multi_json'
4
+
5
+ begin
6
+ require 'psych' # ensure psych is loaded for these tests if its available
7
+ rescue LoadError
8
+ end
9
+
10
+ module VCR
11
+ class Cassette
12
+ describe Serializers do
13
+ shared_examples_for "encoding error handling" do |name, error_class|
14
+ context "the #{name} serializer" do
15
+ it 'appends info about the :preserve_exact_body_bytes option to the error' do
16
+ expect {
17
+ result = serializer.serialize("a" => string)
18
+ serializer.deserialize(result)
19
+ }.to raise_error(error_class, /preserve_exact_body_bytes/)
20
+ end unless (RUBY_INTERPRETER == :rubinius && RUBY_VERSION =~ /^1.9/)
21
+ end
22
+ end
23
+
24
+ shared_examples_for "a serializer" do |name, file_extension, lazily_loaded|
25
+ let(:serializer) { subject[name] }
26
+
27
+ context "the #{name} serializer" do
28
+ it 'lazily loads the serializer' do
29
+ serializers = subject.instance_variable_get(:@serializers)
30
+ expect(serializers).not_to have_key(name)
31
+ expect(subject[name]).not_to be_nil
32
+ expect(serializers).to have_key(name)
33
+ end if lazily_loaded
34
+
35
+ it "returns '#{file_extension}' as the file extension" do
36
+ expect(serializer.file_extension).to eq(file_extension)
37
+ end
38
+
39
+ it "can serialize and deserialize a hash" do
40
+ hash = { "a" => 7, "nested" => { "hash" => [1, 2, 3] }}
41
+ serialized = serializer.serialize(hash)
42
+ expect(serialized).not_to eq(hash)
43
+ expect(serialized).to be_a(String)
44
+ deserialized = serializer.deserialize(serialized)
45
+ expect(deserialized).to eq(hash)
46
+ end
47
+ end
48
+ end
49
+
50
+ it_behaves_like "a serializer", :yaml, "yml", :lazily_loaded do
51
+ it_behaves_like "encoding error handling", :yaml, ArgumentError do
52
+ let(:string) { "\xFA".force_encoding("UTF-8") }
53
+ before { ::YAML::ENGINE.yamler = 'psych' }
54
+ end if ''.respond_to?(:encoding)
55
+ end
56
+
57
+ it_behaves_like "a serializer", :syck, "yml", :lazily_loaded do
58
+ it_behaves_like "encoding error handling", :syck, ArgumentError do
59
+ let(:string) { "\xFA".force_encoding("UTF-8") }
60
+ end if ''.respond_to?(:encoding)
61
+ end
62
+
63
+ it_behaves_like "a serializer", :psych, "yml", :lazily_loaded do
64
+ it_behaves_like "encoding error handling", :psych, ArgumentError do
65
+ let(:string) { "\xFA".force_encoding("UTF-8") }
66
+ end if ''.respond_to?(:encoding)
67
+ end if RUBY_VERSION =~ /1.9/
68
+
69
+ it_behaves_like "a serializer", :json, "json", :lazily_loaded do
70
+ engines = {}
71
+
72
+ if RUBY_INTERPRETER == :jruby
73
+ # don't test yajl on jruby
74
+ else
75
+ engines[:yajl] = MultiJson::LoadError
76
+ end
77
+
78
+ if RUBY_VERSION =~ /1.9/
79
+ engines[:json_gem] = EncodingError
80
+
81
+ # Disable json_pure for now due to this bug:
82
+ # https://github.com/flori/json/issues/186
83
+ # engines[:json_pure] = EncodingError
84
+ end
85
+
86
+ engines.each do |engine, error|
87
+ context "when MultiJson is configured to use #{engine.inspect}", :unless => (RUBY_INTERPRETER == :jruby) do
88
+ before { MultiJson.engine = engine }
89
+ it_behaves_like "encoding error handling", :json, error do
90
+ let(:string) { "\xFA" }
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+ context "a custom :ruby serializer" do
97
+ let(:custom_serializer) do
98
+ Object.new.tap do |obj|
99
+ def obj.file_extension
100
+ "rb"
101
+ end
102
+
103
+ def obj.serialize(hash)
104
+ hash.inspect
105
+ end
106
+
107
+ def obj.deserialize(string)
108
+ eval(string)
109
+ end
110
+ end
111
+ end
112
+
113
+ before(:each) do
114
+ subject[:ruby] = custom_serializer
115
+ end
116
+
117
+ it_behaves_like "a serializer", :ruby, "rb", false
118
+ end
119
+
120
+ describe "#[]=" do
121
+ context 'when there is already a serializer registered for the given name' do
122
+ before(:each) do
123
+ subject[:foo] = :old_serializer
124
+ allow(subject).to receive :warn
125
+ end
126
+
127
+ it 'overrides the existing serializer' do
128
+ subject[:foo] = :new_serializer
129
+ expect(subject[:foo]).to be(:new_serializer)
130
+ end
131
+
132
+ it 'warns that there is a name collision' do
133
+ expect(subject).to receive(:warn).with(
134
+ /WARNING: There is already a VCR cassette serializer registered for :foo\. Overriding it/
135
+ )
136
+ subject[:foo] = :new_serializer
137
+ end
138
+ end
139
+ end
140
+
141
+ describe "#[]" do
142
+ it 'raises an error when given an unrecognized serializer name' do
143
+ expect { subject[:foo] }.to raise_error(ArgumentError)
144
+ end
145
+
146
+ it 'returns the named serializer' do
147
+ expect(subject[:yaml]).to be(VCR::Cassette::Serializers::YAML)
148
+ end
149
+ end
150
+
151
+ # see https://gist.github.com/815769
152
+ problematic_syck_string = "1\n \n2"
153
+
154
+ describe "psych serializer" do
155
+ it 'serializes things using pysch even if syck is configured as the default YAML engine' do
156
+ ::YAML::ENGINE.yamler = 'syck'
157
+ serialized = subject[:psych].serialize(problematic_syck_string)
158
+ expect(subject[:psych].deserialize(serialized)).to eq(problematic_syck_string)
159
+ end if defined?(::Psych)
160
+
161
+ it 'raises an error if psych cannot be loaded' do
162
+ expect { subject[:psych] }.to raise_error(LoadError)
163
+ end unless defined?(::Psych)
164
+ end
165
+
166
+ describe "syck serializer" do
167
+ it 'forcibly serializes things using syck even if psych is the currently configured YAML engine' do
168
+ ::YAML::ENGINE.yamler = 'psych'
169
+ serialized = subject[:syck].serialize(problematic_syck_string)
170
+ expect(subject[:syck].deserialize(serialized)).not_to eq(problematic_syck_string)
171
+ end if defined?(::Psych) && (RUBY_INTERPRETER != :jruby) && (RUBY_VERSION.to_f < 2.0)
172
+ end
173
+ end
174
+ end
175
+ end
176
+
@@ -0,0 +1,618 @@
1
+ require 'spec_helper'
2
+
3
+ describe VCR::Cassette do
4
+ def http_interaction
5
+ request = VCR::Request.new(:get)
6
+ response = VCR::Response.new
7
+ response.status = VCR::ResponseStatus.new
8
+ VCR::HTTPInteraction.new(request, response).tap { |i| yield i if block_given? }
9
+ end
10
+
11
+ def stub_old_interactions(interactions)
12
+ VCR.configuration.cassette_library_dir = "#{VCR::SPEC_ROOT}/fixtures/cassette_spec"
13
+
14
+ hashes = interactions.map(&:to_hash)
15
+ allow(VCR.cassette_serializers[:yaml]).to receive(:deserialize).and_return({ 'http_interactions' => hashes })
16
+ allow(VCR::HTTPInteraction).to receive(:from_hash) do |hash|
17
+ interactions[hashes.index(hash)]
18
+ end
19
+ end
20
+
21
+ describe '#file' do
22
+ it 'delegates the file resolution to the FileSystem persister' do
23
+ fs = VCR::Cassette::Persisters::FileSystem
24
+ expect(fs).to respond_to(:absolute_path_to_file).with(1).argument
25
+ expect(fs).to receive(:absolute_path_to_file).with("cassette name.yml") { "f.yml" }
26
+ expect(VCR::Cassette.new("cassette name").file).to eq("f.yml")
27
+ end
28
+
29
+ it 'raises a NotImplementedError when a different persister is used' do
30
+ VCR.cassette_persisters[:a] = double
31
+ cassette = VCR::Cassette.new("f", :persist_with => :a)
32
+ expect { cassette.file }.to raise_error(NotImplementedError)
33
+ end
34
+ end
35
+
36
+ describe '#tags' do
37
+ it 'returns a blank array if no tag has been set' do
38
+ expect(VCR::Cassette.new("name").tags).to eq([])
39
+ end
40
+
41
+ it 'converts a single :tag to an array' do
42
+ expect(VCR::Cassette.new("name", :tag => :foo).tags).to eq([:foo])
43
+ end
44
+
45
+ it 'accepts an array as the :tags option' do
46
+ expect(VCR::Cassette.new("name", :tags => [:foo]).tags).to eq([:foo])
47
+ end
48
+ end
49
+
50
+ describe '#record_http_interaction' do
51
+ let(:the_interaction) { double(:request => double(:method => :get).as_null_object).as_null_object }
52
+
53
+ it 'adds the interaction to #new_recorded_interactions' do
54
+ cassette = VCR::Cassette.new(:test_cassette)
55
+ expect(cassette.new_recorded_interactions).to eq([])
56
+ cassette.record_http_interaction(the_interaction)
57
+ expect(cassette.new_recorded_interactions).to eq([the_interaction])
58
+ end
59
+ end
60
+
61
+ describe "#serializable_hash" do
62
+ subject { VCR::Cassette.new("foo") }
63
+ let(:interaction_1) { http_interaction { |i| i.request.body = 'req body 1'; i.response.body = 'res body 1' } }
64
+ let(:interaction_2) { http_interaction { |i| i.request.body = 'req body 2'; i.response.body = 'res body 2' } }
65
+ let(:interactions) { [interaction_1, interaction_2] }
66
+
67
+ before(:each) do
68
+ interactions.each do |i|
69
+ subject.record_http_interaction(i)
70
+ end
71
+ end
72
+
73
+ let(:metadata) { subject.serializable_hash.reject { |k,v| k == "http_interactions" } }
74
+
75
+ it 'includes the hash form of all recorded interactions' do
76
+ hash_1 = interaction_1.to_hash
77
+ hash_2 = interaction_2.to_hash
78
+ expect(subject.serializable_hash).to include('http_interactions' => [hash_1, hash_2])
79
+ end
80
+
81
+ it 'includes additional metadata about the cassette' do
82
+ expect(metadata).to eq("recorded_with" => "VCR #{VCR.version}")
83
+ end
84
+
85
+ it 'does not allow the interactions to be mutated by configured hooks' do
86
+ VCR.configure do |c|
87
+ c.define_cassette_placeholder('<BODY>') { 'body' }
88
+ end
89
+
90
+ expect {
91
+ subject.serializable_hash
92
+ }.not_to change { interaction_1.response.body }
93
+ end
94
+ end
95
+
96
+ describe "#recording?" do
97
+ [:all, :new_episodes].each do |mode|
98
+ it "returns true when the record mode is :#{mode}" do
99
+ cassette = VCR::Cassette.new("foo", :record => mode)
100
+ expect(cassette).to be_recording
101
+ end
102
+ end
103
+
104
+ it "returns false when the record mode is :none" do
105
+ cassette = VCR::Cassette.new("foo", :record => :none)
106
+ expect(cassette).not_to be_recording
107
+ end
108
+
109
+ context 'when the record mode is :once' do
110
+ before(:each) do
111
+ VCR.configuration.cassette_library_dir = "#{VCR::SPEC_ROOT}/fixtures/cassette_spec"
112
+ end
113
+
114
+ it 'returns false when there is an existing cassette file with content' do
115
+ cassette = VCR::Cassette.new("example", :record => :once)
116
+ expect(::File).to exist(cassette.file)
117
+ expect(::File.size?(cassette.file)).to be_truthy
118
+ expect(cassette).not_to be_recording
119
+ end
120
+
121
+ it 'returns true when there is an empty existing cassette file' do
122
+ cassette = VCR::Cassette.new("empty", :record => :once)
123
+ expect(::File).to exist(cassette.file)
124
+ expect(::File.size?(cassette.file)).to be_falsey
125
+ expect(cassette).to be_recording
126
+ end
127
+
128
+ it 'returns true when there is no existing cassette file' do
129
+ cassette = VCR::Cassette.new("non_existant_file", :record => :once)
130
+ expect(::File).not_to exist(cassette.file)
131
+ expect(cassette).to be_recording
132
+ end
133
+ end
134
+ end
135
+
136
+ describe '#match_requests_on' do
137
+ before(:each) { VCR.configuration.default_cassette_options.merge!(:match_requests_on => [:uri, :method]) }
138
+
139
+ it "returns the provided options" do
140
+ c = VCR::Cassette.new('example', :match_requests_on => [:uri])
141
+ expect(c.match_requests_on).to eq([:uri])
142
+ end
143
+
144
+ it "returns a the default #match_requests_on when it has not been specified for the cassette" do
145
+ c = VCR::Cassette.new('example')
146
+ expect(c.match_requests_on).to eq([:uri, :method])
147
+ end
148
+ end
149
+
150
+ describe "reading the file from disk" do
151
+ let(:empty_cassette_yaml) { YAML.dump("http_interactions" => []) }
152
+
153
+ it 'optionally renders the file as ERB using the ERBRenderer' do
154
+ allow(VCR::Cassette::Persisters::FileSystem).to receive(:[]).and_return(empty_cassette_yaml)
155
+
156
+ expect(VCR::Cassette::ERBRenderer).to receive(:new).with(
157
+ empty_cassette_yaml, anything, "foo"
158
+ ).and_return(double('renderer', :render => empty_cassette_yaml))
159
+
160
+ VCR::Cassette.new('foo', :record => :new_episodes).http_interactions
161
+ end
162
+
163
+ [true, false, nil, { }].each do |erb|
164
+ it "passes #{erb.inspect} to the VCR::Cassette::ERBRenderer when given as the :erb option" do
165
+ # test that it overrides the default
166
+ VCR.configuration.default_cassette_options = { :erb => true }
167
+
168
+ expect(VCR::Cassette::ERBRenderer).to receive(:new).with(
169
+ anything, erb, anything
170
+ ).and_return(double('renderer', :render => empty_cassette_yaml))
171
+
172
+ VCR::Cassette.new('foo', :record => :new_episodes, :erb => erb).http_interactions
173
+ end
174
+
175
+ it "passes #{erb.inspect} to the VCR::Cassette::ERBRenderer when it is the default :erb option and none is given" do
176
+ VCR.configuration.default_cassette_options = { :erb => erb }
177
+
178
+ expect(VCR::Cassette::ERBRenderer).to receive(:new).with(
179
+ anything, erb, anything
180
+ ).and_return(double('renderer', :render => empty_cassette_yaml))
181
+
182
+ VCR::Cassette.new('foo', :record => :new_episodes).http_interactions
183
+ end
184
+ end
185
+
186
+ it 'raises a friendly error when the cassette file is in the old VCR 1.x format' do
187
+ VCR.configuration.cassette_library_dir = 'spec/fixtures/cassette_spec'
188
+ expect {
189
+ VCR::Cassette.new('1_x_cassette').http_interactions
190
+ }.to raise_error(VCR::Errors::InvalidCassetteFormatError)
191
+ end
192
+ end
193
+
194
+ describe '.new' do
195
+ it "raises an error if given an invalid record mode" do
196
+ expect { VCR::Cassette.new(:test, :record => :not_a_record_mode) }.to raise_error(ArgumentError)
197
+ end
198
+
199
+ it 'raises an error if given invalid options' do
200
+ expect {
201
+ VCR::Cassette.new(:test, :invalid => :option)
202
+ }.to raise_error(ArgumentError)
203
+ end
204
+
205
+ it 'does not raise an error in the case of an empty file' do
206
+ VCR.configuration.cassette_library_dir = "#{VCR::SPEC_ROOT}/fixtures/cassette_spec"
207
+ expect(VCR::Cassette.new('empty', :record => :none).send(:previously_recorded_interactions)).to eq([])
208
+ end
209
+
210
+ let(:custom_persister) { double("custom persister") }
211
+
212
+ it 'reads from the configured persister' do
213
+ VCR.configuration.cassette_library_dir = nil
214
+ VCR.cassette_persisters[:foo] = custom_persister
215
+ expect(custom_persister).to receive(:[]).with("abc.yml") { "" }
216
+ VCR::Cassette.new("abc", :persist_with => :foo).http_interactions
217
+ end
218
+
219
+ VCR::Cassette::VALID_RECORD_MODES.each do |record_mode|
220
+ stub_requests = (record_mode != :all)
221
+
222
+ context "when VCR.configuration.default_cassette_options[:record] is :#{record_mode}" do
223
+ before(:each) { VCR.configuration.default_cassette_options = { :record => record_mode } }
224
+
225
+ it "defaults the record mode to #{record_mode} when VCR.configuration.default_cassette_options[:record] is #{record_mode}" do
226
+ cassette = VCR::Cassette.new(:test)
227
+ expect(cassette.record_mode).to eq(record_mode)
228
+ end
229
+ end
230
+
231
+ context "when :#{record_mode} is passed as the record option" do
232
+ unless record_mode == :all
233
+ let(:interaction_1) { http_interaction { |i| i.request.uri = 'http://example.com/foo' } }
234
+ let(:interaction_2) { http_interaction { |i| i.request.uri = 'http://example.com/bar' } }
235
+ let(:interactions) { [interaction_1, interaction_2] }
236
+
237
+ it 'updates the content_length headers when given :update_content_length_header => true' do
238
+ stub_old_interactions(interactions)
239
+ expect(interaction_1.response).to receive(:update_content_length_header)
240
+ expect(interaction_2.response).to receive(:update_content_length_header)
241
+
242
+ VCR::Cassette.new('example', :record => record_mode, :update_content_length_header => true).http_interactions
243
+ end
244
+
245
+ [nil, false].each do |val|
246
+ it "does not update the content_lenth headers when given :update_content_length_header => #{val.inspect}" do
247
+ stub_old_interactions(interactions)
248
+ expect(interaction_1.response).not_to receive(:update_content_length_header)
249
+ expect(interaction_2.response).not_to receive(:update_content_length_header)
250
+
251
+ VCR::Cassette.new('example', :record => record_mode, :update_content_length_header => val).http_interactions
252
+ end
253
+ end
254
+
255
+ context "and re_record_interval is 7.days" do
256
+ let(:file_name) { ::File.join(VCR.configuration.cassette_library_dir, "cassette_name.yml") }
257
+ subject { VCR::Cassette.new(::File.basename(file_name).gsub('.yml', ''), :record => record_mode, :re_record_interval => 7.days) }
258
+
259
+ context 'when the cassette file does not exist' do
260
+ before(:each) { allow(::File).to receive(:exist?).with(file_name).and_return(false) }
261
+
262
+ it "has :#{record_mode} for the record mode" do
263
+ expect(subject.record_mode).to eq(record_mode)
264
+ end
265
+ end
266
+
267
+ context 'when the cassette file does exist' do
268
+ before(:each) do
269
+ interactions = timestamps.map do |ts|
270
+ http_interaction { |i| i.recorded_at = ts }.to_hash
271
+ end
272
+ yaml = YAML.dump("http_interactions" => interactions)
273
+
274
+ allow(::File).to receive(:exist?).with(file_name).and_return(true)
275
+ allow(::File).to receive(:size?).with(file_name).and_return(true)
276
+ allow(::File).to receive(:read).with(file_name).and_return(yaml)
277
+ end
278
+
279
+ context 'and the earliest recorded interaction was recorded less than 7 days ago' do
280
+ let(:timestamps) do [
281
+ Time.now - 6.days + 60,
282
+ Time.now - 7.days + 60,
283
+ Time.now - 5.days + 60
284
+ ] end
285
+
286
+ it "has :#{record_mode} for the record mode" do
287
+ expect(subject.record_mode).to eq(record_mode)
288
+ end
289
+ end
290
+
291
+ context 'and the earliest recorded interaction was recorded more than 7 days ago' do
292
+ let(:timestamps) do [
293
+ Time.now - 6.days - 60,
294
+ Time.now - 7.days - 60,
295
+ Time.now - 5.days - 60
296
+ ] end
297
+
298
+ it "has :all for the record mode when there is an internet connection available" do
299
+ allow(VCR::InternetConnection).to receive(:available?).and_return(true)
300
+ expect(subject.record_mode).to eq(:all)
301
+ end
302
+
303
+ it "has :#{record_mode} for the record mode when there is no internet connection available" do
304
+ allow(VCR::InternetConnection).to receive(:available?).and_return(false)
305
+ expect(subject.record_mode).to eq(record_mode)
306
+ end
307
+ end
308
+ end
309
+ end
310
+ end
311
+
312
+ it 'does not load ignored interactions' do
313
+ allow(VCR.request_ignorer).to receive(:ignore?) do |request|
314
+ request.uri !~ /example\.com/
315
+ end
316
+
317
+ VCR.configuration.cassette_library_dir = "#{VCR::SPEC_ROOT}/fixtures/cassette_spec"
318
+ cassette = VCR::Cassette.new('with_localhost_requests', :record => record_mode)
319
+ expect(cassette.send(:previously_recorded_interactions).map { |i| URI.parse(i.request.uri).host }).to eq(%w[example.com])
320
+ end
321
+
322
+ it "loads the recorded interactions from the library yml file" do
323
+ VCR.configuration.cassette_library_dir = "#{VCR::SPEC_ROOT}/fixtures/cassette_spec"
324
+ cassette = VCR::Cassette.new('example', :record => record_mode)
325
+
326
+ expect(cassette.send(:previously_recorded_interactions).size).to eq(3)
327
+
328
+ i1, i2, i3 = *cassette.send(:previously_recorded_interactions)
329
+
330
+ expect(i1.request.method).to eq(:get)
331
+ expect(i1.request.uri).to eq('http://example.com/')
332
+ expect(i1.response.body).to match(/You have reached this web page by typing.+example\.com/)
333
+
334
+ expect(i2.request.method).to eq(:get)
335
+ expect(i2.request.uri).to eq('http://example.com/foo')
336
+ expect(i2.response.body).to match(/foo was not found on this server/)
337
+
338
+ expect(i3.request.method).to eq(:get)
339
+ expect(i3.request.uri).to eq('http://example.com/')
340
+ expect(i3.response.body).to match(/Another example\.com response/)
341
+ end
342
+
343
+ [true, false].each do |value|
344
+ it "instantiates the http_interactions with allow_playback_repeats = #{value} if given :allow_playback_repeats => #{value}" do
345
+ VCR.configuration.cassette_library_dir = "#{VCR::SPEC_ROOT}/fixtures/cassette_spec"
346
+ cassette = VCR::Cassette.new('example', :record => record_mode, :allow_playback_repeats => value)
347
+ expect(cassette.http_interactions.allow_playback_repeats).to eq(value)
348
+ end
349
+ end
350
+
351
+ it "instantiates the http_interactions with parent_list set to a null list if given :exclusive => true" do
352
+ allow(VCR).to receive(:http_interactions).and_return(double)
353
+ VCR.configuration.cassette_library_dir = "#{VCR::SPEC_ROOT}/fixtures/cassette_spec"
354
+ cassette = VCR::Cassette.new('example', :record => record_mode, :exclusive => true)
355
+ expect(cassette.http_interactions.parent_list).to be(VCR::Cassette::HTTPInteractionList::NullList)
356
+ end
357
+
358
+ it "instantiates the http_interactions with parent_list set to VCR.http_interactions if given :exclusive => false" do
359
+ allow(VCR).to receive(:http_interactions).and_return(double)
360
+ VCR.configuration.cassette_library_dir = "#{VCR::SPEC_ROOT}/fixtures/cassette_spec"
361
+ cassette = VCR::Cassette.new('example', :record => record_mode, :exclusive => false)
362
+ expect(cassette.http_interactions.parent_list).to be(VCR.http_interactions)
363
+ end
364
+
365
+ if stub_requests
366
+ it 'invokes the before_playback hooks' do
367
+ VCR.configuration.cassette_library_dir = "#{VCR::SPEC_ROOT}/fixtures/cassette_spec"
368
+
369
+ expect(VCR.configuration).to receive(:invoke_hook).with(
370
+ :before_playback,
371
+ an_instance_of(VCR::HTTPInteraction::HookAware),
372
+ an_instance_of(VCR::Cassette)
373
+ ).exactly(3).times
374
+
375
+ cassette = VCR::Cassette.new('example', :record => record_mode)
376
+ expect(cassette.send(:previously_recorded_interactions).size).to eq(3)
377
+ end
378
+
379
+ it 'does not playback any interactions that are ignored in a before_playback hook' do
380
+ VCR.configure do |c|
381
+ c.before_playback { |i| i.ignore! if i.request.uri =~ /foo/ }
382
+ end
383
+
384
+ VCR.configuration.cassette_library_dir = "#{VCR::SPEC_ROOT}/fixtures/cassette_spec"
385
+ cassette = VCR::Cassette.new('example', :record => record_mode)
386
+ expect(cassette.send(:previously_recorded_interactions).size).to eq(2)
387
+ end
388
+
389
+ it 'instantiates the http_interactions with the loaded interactions and the request matchers' do
390
+ VCR.configuration.cassette_library_dir = "#{VCR::SPEC_ROOT}/fixtures/cassette_spec"
391
+ cassette = VCR::Cassette.new('example', :record => record_mode, :match_requests_on => [:body, :headers])
392
+ expect(cassette.http_interactions.interactions.size).to eq(3)
393
+ expect(cassette.http_interactions.request_matchers).to eq([:body, :headers])
394
+ end
395
+ else
396
+ it 'instantiates the http_interactions with the no interactions and the request matchers' do
397
+ VCR.configuration.cassette_library_dir = "#{VCR::SPEC_ROOT}/fixtures/cassette_spec"
398
+ cassette = VCR::Cassette.new('example', :record => record_mode, :match_requests_on => [:body, :headers])
399
+ expect(cassette.http_interactions.interactions.size).to eq(0)
400
+ expect(cassette.http_interactions.request_matchers).to eq([:body, :headers])
401
+ end
402
+ end
403
+ end
404
+ end
405
+ end
406
+
407
+ describe ".originally_recorded_at" do
408
+ it 'returns the earliest `recorded_at` timestamp' do
409
+ i1 = http_interaction { |i| i.recorded_at = Time.now - 1000 }
410
+ i2 = http_interaction { |i| i.recorded_at = Time.now - 10000 }
411
+ i3 = http_interaction { |i| i.recorded_at = Time.now - 100 }
412
+
413
+ stub_old_interactions([i1, i2, i3])
414
+
415
+ cassette = VCR::Cassette.new("example")
416
+ expect(cassette.originally_recorded_at).to eq(i2.recorded_at)
417
+ end
418
+
419
+ it 'records nil for a cassette that has no prior recorded interactions' do
420
+ stub_old_interactions([])
421
+ cassette = VCR::Cassette.new("example")
422
+ expect(cassette.originally_recorded_at).to be_nil
423
+ end
424
+ end
425
+
426
+ describe '#eject' do
427
+ let(:custom_persister) { double("custom persister", :[] => nil) }
428
+
429
+ context "when :allow_unused_http_interactions is set to false" do
430
+ it 'asserts that there are no unused interactions' do
431
+ cassette = VCR.insert_cassette("foo", :allow_unused_http_interactions => false)
432
+
433
+ interaction_list = cassette.http_interactions
434
+ expect(interaction_list).to respond_to(:assert_no_unused_interactions!).with(0).arguments
435
+ expect(interaction_list).to receive(:assert_no_unused_interactions!)
436
+
437
+ cassette.eject
438
+ end
439
+
440
+ it 'does not assert no unused interactions if there is an existing error' do
441
+ cassette = VCR.insert_cassette("foo", :allow_unused_http_interactions => false)
442
+ interaction_list = cassette.http_interactions
443
+ allow(interaction_list).to receive(:assert_no_unused_interactions!)
444
+
445
+ expect {
446
+ begin
447
+ raise "boom"
448
+ ensure
449
+ cassette.eject
450
+ end
451
+ }.to raise_error(/boom/)
452
+
453
+ expect(interaction_list).not_to have_received(:assert_no_unused_interactions!)
454
+ end
455
+
456
+ it 'does not assert no unused interactions if :skip_no_unused_interactions_assertion is passed' do
457
+ cassette = VCR.insert_cassette("foo", :allow_unused_http_interactions => false)
458
+
459
+ interaction_list = cassette.http_interactions
460
+ expect(interaction_list).not_to receive(:assert_no_unused_interactions!)
461
+
462
+ cassette.eject(:skip_no_unused_interactions_assertion => true)
463
+ end
464
+ end
465
+
466
+ it 'does not assert that there are no unused interactions if allow_unused_http_interactions is set to true' do
467
+ cassette = VCR.insert_cassette("foo", :allow_unused_http_interactions => true)
468
+
469
+ interaction_list = cassette.http_interactions
470
+ expect(interaction_list).to respond_to(:assert_no_unused_interactions!)
471
+ expect(interaction_list).not_to receive(:assert_no_unused_interactions!)
472
+
473
+ cassette.eject
474
+ end
475
+
476
+ it 'stores the cassette content using the configured persister' do
477
+ VCR.configuration.cassette_library_dir = nil
478
+ VCR.cassette_persisters[:foo] = custom_persister
479
+ cassette = VCR.insert_cassette("foo", :persist_with => :foo)
480
+ cassette.record_http_interaction http_interaction
481
+
482
+ expect(custom_persister).to receive(:[]=).with("foo.yml", /http_interactions/)
483
+
484
+ cassette.eject
485
+ end
486
+
487
+ it "writes the serializable_hash to disk as yaml" do
488
+ cassette = VCR::Cassette.new(:eject_test)
489
+ cassette.record_http_interaction http_interaction # so it has one
490
+ expect(cassette).to respond_to(:serializable_hash)
491
+ allow(cassette).to receive(:serializable_hash).and_return({ "http_interactions" => [1, 3, 5] })
492
+
493
+ expect { cassette.eject }.to change { ::File.exist?(cassette.file) }.from(false).to(true)
494
+ saved_stuff = YAML.load_file(cassette.file)
495
+ expect(saved_stuff).to eq("http_interactions" => [1, 3, 5])
496
+ end
497
+
498
+ it 'invokes the appropriately tagged before_record hooks' do
499
+ interactions = [
500
+ http_interaction { |i| i.request.uri = 'http://foo.com/'; i.response.body = 'res 1' },
501
+ http_interaction { |i| i.request.uri = 'http://bar.com/'; i.response.body = 'res 2' }
502
+ ]
503
+
504
+ cassette = VCR::Cassette.new('example', :tag => :foo)
505
+ allow(cassette).to receive(:new_recorded_interactions).and_return(interactions)
506
+
507
+ allow(VCR.configuration).to receive(:invoke_hook).and_return([false])
508
+
509
+ interactions.each do |i|
510
+ expect(VCR.configuration).to receive(:invoke_hook).with(
511
+ :before_record,
512
+ an_instance_of(VCR::HTTPInteraction::HookAware),
513
+ cassette
514
+ ).ordered
515
+ end
516
+
517
+ cassette.eject
518
+ end
519
+
520
+ it 'does not record interactions that have been ignored' do
521
+ VCR.configure do |c|
522
+ c.before_record { |i| i.ignore! if i.request.uri =~ /foo/ }
523
+ end
524
+
525
+ interaction_1 = http_interaction { |i| i.request.uri = 'http://foo.com/'; i.response.body = 'res 1' }
526
+ interaction_2 = http_interaction { |i| i.request.uri = 'http://bar.com/'; i.response.body = 'res 2' }
527
+
528
+ cassette = VCR::Cassette.new('test_cassette')
529
+ allow(cassette).to receive(:new_recorded_interactions).and_return([interaction_1, interaction_2])
530
+ cassette.eject
531
+
532
+ saved_recorded_interactions = ::YAML.load_file(cassette.file)
533
+ expect(saved_recorded_interactions["http_interactions"]).to eq([interaction_2.to_hash])
534
+ end
535
+
536
+ it 'does not write the cassette to disk if all interactions have been ignored' do
537
+ VCR.configure do |c|
538
+ c.before_record { |i| i.ignore! }
539
+ end
540
+
541
+ interaction_1 = http_interaction { |i| i.request.uri = 'http://foo.com/'; i.response.body = 'res 1' }
542
+
543
+ cassette = VCR::Cassette.new('test_cassette')
544
+ allow(cassette).to receive(:new_recorded_interactions).and_return([interaction_1])
545
+ cassette.eject
546
+
547
+ expect(::File).not_to exist(cassette.file)
548
+ end
549
+
550
+ it "writes the recorded interactions to a subdirectory if the cassette name includes a directory" do
551
+ recorded_interactions = [http_interaction { |i| i.response.body = "subdirectory response" }]
552
+ cassette = VCR::Cassette.new('subdirectory/test_cassette')
553
+ allow(cassette).to receive(:new_recorded_interactions).and_return(recorded_interactions)
554
+
555
+ expect { cassette.eject }.to change { ::File.exist?(cassette.file) }.from(false).to(true)
556
+ saved_recorded_interactions = YAML.load_file(cassette.file)
557
+ expect(saved_recorded_interactions["http_interactions"]).to eq(recorded_interactions.map(&:to_hash))
558
+ end
559
+
560
+ [:all, :none, :new_episodes].each do |record_mode|
561
+ context "for a :record => :#{record_mode} cassette with previously recorded interactions" do
562
+ subject { VCR::Cassette.new('example', :record => record_mode, :match_requests_on => [:uri]) }
563
+
564
+ before(:each) do
565
+ base_dir = "#{VCR::SPEC_ROOT}/fixtures/cassette_spec"
566
+ FileUtils.cp(base_dir + "/example.yml", VCR.configuration.cassette_library_dir + "/example.yml")
567
+ end
568
+
569
+ it "does not re-write to disk the previously recorded interactions if there are no new ones" do
570
+ yaml_file = subject.file
571
+ expect(::File).not_to receive(:open).with(subject.file, 'w')
572
+ expect { subject.eject }.to_not change { ::File.mtime(yaml_file) }
573
+ end
574
+
575
+ context 'when some new interactions have been recorded' do
576
+ def interaction(response_body, request_attributes)
577
+ http_interaction do |interaction|
578
+ interaction.response.body = response_body
579
+ request_attributes.each do |key, value|
580
+ interaction.request.send("#{key}=", value)
581
+ end
582
+ end
583
+ end
584
+
585
+ let(:interaction_foo_1) { interaction("foo 1", :uri => 'http://foo.com/') }
586
+ let(:interaction_foo_2) { interaction("foo 2", :uri => 'http://foo.com/') }
587
+ let(:interaction_bar) { interaction("bar", :uri => 'http://bar.com/') }
588
+
589
+ let(:saved_recorded_interactions) { YAML.load_file(subject.file)['http_interactions'].map { |h| VCR::HTTPInteraction.from_hash(h) } }
590
+ let(:now) { Time.utc(2011, 6, 11, 12, 30) }
591
+
592
+ before(:each) do
593
+ allow(Time).to receive(:now).and_return(now)
594
+ allow(subject).to receive(:previously_recorded_interactions).and_return([interaction_foo_1])
595
+ subject.record_http_interaction(interaction_foo_2)
596
+ subject.record_http_interaction(interaction_bar)
597
+ subject.eject
598
+ end
599
+
600
+ if record_mode == :all
601
+ it 'replaces previously recorded interactions with new ones when the requests match' do
602
+ expect(saved_recorded_interactions.first).to eq(interaction_foo_2)
603
+ expect(saved_recorded_interactions).not_to include(interaction_foo_1)
604
+ end
605
+
606
+ it 'appends new recorded interactions that do not match existing ones' do
607
+ expect(saved_recorded_interactions.last).to eq(interaction_bar)
608
+ end
609
+ else
610
+ it 'appends new recorded interactions after existing ones' do
611
+ expect(saved_recorded_interactions).to eq([interaction_foo_1, interaction_foo_2, interaction_bar])
612
+ end
613
+ end
614
+ end
615
+ end
616
+ end
617
+ end
618
+ end