vcr 2.0.0.beta1 → 2.0.0.beta2
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.
- data/.gitignore +1 -0
- data/.travis.yml +3 -0
- data/CHANGELOG.md +37 -2
- data/Gemfile +2 -2
- data/README.md +10 -1
- data/Rakefile +43 -7
- data/Upgrade.md +45 -0
- data/features/.nav +1 -0
- data/features/cassettes/automatic_re_recording.feature +19 -17
- data/features/cassettes/dynamic_erb.feature +32 -28
- data/features/cassettes/exclusive.feature +28 -24
- data/features/cassettes/format.feature +213 -31
- data/features/cassettes/update_content_length_header.feature +20 -18
- data/features/configuration/filter_sensitive_data.feature +4 -4
- data/features/configuration/hooks.feature +27 -23
- data/features/http_libraries/em_http_request.feature +79 -75
- data/features/record_modes/all.feature +14 -14
- data/features/record_modes/new_episodes.feature +15 -15
- data/features/record_modes/none.feature +15 -15
- data/features/record_modes/once.feature +15 -15
- data/features/request_matching/body.feature +25 -23
- data/features/request_matching/custom_matcher.feature +25 -23
- data/features/request_matching/headers.feature +32 -36
- data/features/request_matching/host.feature +27 -25
- data/features/request_matching/identical_request_sequence.feature +27 -25
- data/features/request_matching/method.feature +27 -25
- data/features/request_matching/path.feature +27 -25
- data/features/request_matching/playback_repeats.feature +27 -25
- data/features/request_matching/uri.feature +27 -25
- data/features/request_matching/uri_without_param.feature +28 -26
- data/features/step_definitions/cli_steps.rb +71 -17
- data/features/support/env.rb +3 -1
- data/features/support/http_lib_filters.rb +6 -3
- data/features/support/vcr_cucumber_helpers.rb +4 -2
- data/lib/vcr.rb +6 -2
- data/lib/vcr/cassette.rb +75 -51
- data/lib/vcr/cassette/migrator.rb +111 -0
- data/lib/vcr/cassette/serializers.rb +35 -0
- data/lib/vcr/cassette/serializers/json.rb +23 -0
- data/lib/vcr/cassette/serializers/psych.rb +24 -0
- data/lib/vcr/cassette/serializers/syck.rb +35 -0
- data/lib/vcr/cassette/serializers/yaml.rb +24 -0
- data/lib/vcr/configuration.rb +6 -1
- data/lib/vcr/errors.rb +1 -1
- data/lib/vcr/library_hooks/excon.rb +1 -7
- data/lib/vcr/library_hooks/typhoeus.rb +6 -22
- data/lib/vcr/library_hooks/webmock.rb +1 -1
- data/lib/vcr/middleware/faraday.rb +1 -1
- data/lib/vcr/request_matcher_registry.rb +43 -30
- data/lib/vcr/structs.rb +209 -0
- data/lib/vcr/tasks/vcr.rake +9 -0
- data/lib/vcr/version.rb +1 -1
- data/spec/fixtures/cassette_spec/1_x_cassette.yml +110 -0
- data/spec/fixtures/cassette_spec/example.yml +79 -78
- data/spec/fixtures/cassette_spec/with_localhost_requests.yml +79 -77
- data/spec/fixtures/fake_example.com_responses.yml +78 -76
- data/spec/fixtures/match_requests_on.yml +147 -145
- data/spec/monkey_patches.rb +5 -5
- data/spec/support/http_library_adapters.rb +48 -0
- data/spec/support/shared_example_groups/hook_into_http_library.rb +53 -20
- data/spec/support/sinatra_app.rb +12 -0
- data/spec/vcr/cassette/http_interaction_list_spec.rb +1 -1
- data/spec/vcr/cassette/migrator_spec.rb +183 -0
- data/spec/vcr/cassette/serializers_spec.rb +122 -0
- data/spec/vcr/cassette_spec.rb +147 -83
- data/spec/vcr/configuration_spec.rb +11 -1
- data/spec/vcr/library_hooks/typhoeus_spec.rb +3 -3
- data/spec/vcr/library_hooks/webmock_spec.rb +7 -1
- data/spec/vcr/request_ignorer_spec.rb +1 -1
- data/spec/vcr/request_matcher_registry_spec.rb +46 -4
- data/spec/vcr/structs_spec.rb +309 -0
- data/spec/vcr_spec.rb +7 -0
- data/vcr.gemspec +9 -12
- metadata +75 -61
- data/lib/vcr/structs/http_interaction.rb +0 -58
- data/lib/vcr/structs/normalizers/body.rb +0 -24
- data/lib/vcr/structs/normalizers/header.rb +0 -64
- data/lib/vcr/structs/normalizers/status_message.rb +0 -17
- data/lib/vcr/structs/normalizers/uri.rb +0 -34
- data/lib/vcr/structs/request.rb +0 -13
- data/lib/vcr/structs/response.rb +0 -13
- data/lib/vcr/structs/response_status.rb +0 -5
- data/lib/vcr/util/yaml.rb +0 -11
- data/spec/support/shared_example_groups/normalizers.rb +0 -94
- data/spec/vcr/structs/http_interaction_spec.rb +0 -89
- data/spec/vcr/structs/request_spec.rb +0 -39
- data/spec/vcr/structs/response_spec.rb +0 -44
- data/spec/vcr/structs/response_status_spec.rb +0 -9
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'vcr/cassette/serializers'
|
2
|
+
begin
|
3
|
+
require 'psych' # ensure psych is loaded for these tests if its available
|
4
|
+
rescue LoadError
|
5
|
+
end
|
6
|
+
|
7
|
+
module VCR
|
8
|
+
class Cassette
|
9
|
+
describe Serializers do
|
10
|
+
|
11
|
+
shared_examples_for "a serializer" do |name, file_extension, lazily_loaded|
|
12
|
+
context "the #{name} serializer" do
|
13
|
+
let(:serializer) { subject[name] }
|
14
|
+
|
15
|
+
it 'lazily loads the serializer' do
|
16
|
+
serializers = subject.instance_variable_get(:@serializers)
|
17
|
+
serializers.should_not have_key(name)
|
18
|
+
subject[name].should_not be_nil
|
19
|
+
serializers.should have_key(name)
|
20
|
+
end if lazily_loaded
|
21
|
+
|
22
|
+
it "returns '#{file_extension}' as the file extension" do
|
23
|
+
serializer.file_extension.should eq(file_extension)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "can serialize and deserialize a hash" do
|
27
|
+
hash = { "a" => 7, "nested" => { "hash" => [1, 2, 3] }}
|
28
|
+
serialized = serializer.serialize(hash)
|
29
|
+
serialized.should_not eq(hash)
|
30
|
+
serialized.should be_a(String)
|
31
|
+
deserialized = serializer.deserialize(serialized)
|
32
|
+
deserialized.should eq(hash)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
it_behaves_like "a serializer", :yaml, "yml", :lazily_loaded
|
38
|
+
it_behaves_like "a serializer", :syck, "yml", :lazily_loaded
|
39
|
+
it_behaves_like "a serializer", :psych, "yml", :lazily_loaded if RUBY_VERSION =~ /1.9/
|
40
|
+
it_behaves_like "a serializer", :json, "json", :lazily_loaded
|
41
|
+
|
42
|
+
context "a custom :ruby serializer" do
|
43
|
+
let(:custom_serializer) do
|
44
|
+
Object.new.tap do |obj|
|
45
|
+
def obj.file_extension
|
46
|
+
"rb"
|
47
|
+
end
|
48
|
+
|
49
|
+
def obj.serialize(hash)
|
50
|
+
hash.inspect
|
51
|
+
end
|
52
|
+
|
53
|
+
def obj.deserialize(string)
|
54
|
+
eval(string)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
before(:each) do
|
60
|
+
subject[:ruby] = custom_serializer
|
61
|
+
end
|
62
|
+
|
63
|
+
it_behaves_like "a serializer", :ruby, "rb", false
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "#[]=" do
|
67
|
+
context 'when there is already a serializer registered for the given name' do
|
68
|
+
before(:each) do
|
69
|
+
subject[:foo] = :old_serializer
|
70
|
+
subject.stub :warn
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'overrides the existing serializer' do
|
74
|
+
subject[:foo] = :new_serializer
|
75
|
+
subject[:foo].should be(:new_serializer)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'warns that there is a name collision' do
|
79
|
+
subject.should_receive(:warn).with(
|
80
|
+
/WARNING: There is already a VCR cassette serializer registered for :foo\. Overriding it/
|
81
|
+
)
|
82
|
+
subject[:foo] = :new_serializer
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "#[]" do
|
88
|
+
it 'raises an error when given an unrecognized serializer name' do
|
89
|
+
expect { subject[:foo] }.to raise_error(ArgumentError)
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'returns the named serializer' do
|
93
|
+
subject[:yaml].should be(VCR::Cassette::Serializers::YAML)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# see https://gist.github.com/815769
|
98
|
+
problematic_syck_string = "1\n \n2"
|
99
|
+
|
100
|
+
describe "psych serializer" do
|
101
|
+
it 'serializes things using pysch even if syck is configured as the default YAML engine' do
|
102
|
+
::YAML::ENGINE.yamler = 'syck'
|
103
|
+
serialized = subject[:psych].serialize(problematic_syck_string)
|
104
|
+
subject[:psych].deserialize(serialized).should eq(problematic_syck_string)
|
105
|
+
end if defined?(::Psych)
|
106
|
+
|
107
|
+
it 'raises an error if psych cannot be loaded' do
|
108
|
+
expect { subject[:psych] }.to raise_error(LoadError)
|
109
|
+
end unless defined?(::Psych)
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "syck serializer" do
|
113
|
+
it 'forcibly serializes things using syck even if psych is the currently configured YAML engine' do
|
114
|
+
::YAML::ENGINE.yamler = 'psych'
|
115
|
+
serialized = subject[:syck].serialize(problematic_syck_string)
|
116
|
+
subject[:syck].deserialize(serialized).should_not eq(problematic_syck_string)
|
117
|
+
end if defined?(::Psych)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
data/spec/vcr/cassette_spec.rb
CHANGED
@@ -1,12 +1,25 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
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
|
+
|
4
11
|
describe '#file' do
|
5
12
|
it 'combines the cassette_library_dir with the cassette name' do
|
6
13
|
cassette = VCR::Cassette.new('the_file')
|
7
14
|
cassette.file.should eq(File.join(VCR.configuration.cassette_library_dir, 'the_file.yml'))
|
8
15
|
end
|
9
16
|
|
17
|
+
it 'uses the file extension from the serializer' do
|
18
|
+
VCR.cassette_serializers[:custom] = stub(:file_extension => "custom")
|
19
|
+
cassette = VCR::Cassette.new('the_file', :serialize_with => :custom)
|
20
|
+
cassette.file.should =~ /\.custom$/
|
21
|
+
end
|
22
|
+
|
10
23
|
it 'strips out disallowed characters so that it is a valid file name with no spaces' do
|
11
24
|
cassette = VCR::Cassette.new("\nthis \t! is-the_13212_file name")
|
12
25
|
cassette.file.should =~ /#{Regexp.escape('_this_is-the_13212_file_name.yml')}$/
|
@@ -35,6 +48,27 @@ describe VCR::Cassette do
|
|
35
48
|
end
|
36
49
|
end
|
37
50
|
|
51
|
+
describe "#serializable_hash" do
|
52
|
+
subject { VCR::Cassette.new("foo") }
|
53
|
+
let(:interactions) { [stub(:to_hash => { "i" => 1 }, :ignored? => false), stub(:to_hash => { "i" => 2 }, :ignored? => false)] }
|
54
|
+
|
55
|
+
before(:each) do
|
56
|
+
interactions.each do |i|
|
57
|
+
subject.record_http_interaction(i)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
let(:metadata) { subject.serializable_hash.reject { |k,v| k == "http_interactions" } }
|
62
|
+
|
63
|
+
it 'includes the hash form of all recorded interactions' do
|
64
|
+
subject.serializable_hash.should include('http_interactions' => [{ "i" => 1 }, { "i" => 2 }])
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'includes additional metadata about the cassette' do
|
68
|
+
metadata.should eq("recorded_with" => "VCR #{VCR.version}")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
38
72
|
describe "#recording?" do
|
39
73
|
[:all, :new_episodes].each do |mode|
|
40
74
|
it "returns true when the record mode is :#{mode}" do
|
@@ -89,57 +123,66 @@ describe VCR::Cassette do
|
|
89
123
|
end
|
90
124
|
end
|
91
125
|
|
92
|
-
describe
|
93
|
-
|
94
|
-
|
126
|
+
describe "reading the file from disk" do
|
127
|
+
before(:each) do
|
128
|
+
File.stub(:size? => true)
|
95
129
|
end
|
96
130
|
|
97
|
-
|
98
|
-
expect {
|
99
|
-
VCR::Cassette.new(:test, :invalid => :option)
|
100
|
-
}.to raise_error(ArgumentError)
|
101
|
-
end
|
131
|
+
let(:empty_cassette_yaml) { YAML.dump("http_interactions" => []) }
|
102
132
|
|
103
|
-
it '
|
104
|
-
VCR.
|
105
|
-
|
133
|
+
it 'reads the appropriate file from disk using a VCR::Cassette::Reader' do
|
134
|
+
VCR::Cassette::Reader.should_receive(:new).with(
|
135
|
+
"#{VCR.configuration.cassette_library_dir}/foo.yml", anything
|
136
|
+
).and_return(mock('reader', :read => empty_cassette_yaml))
|
137
|
+
|
138
|
+
VCR::Cassette.new('foo', :record => :new_episodes).http_interactions
|
106
139
|
end
|
107
140
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
141
|
+
[true, false, nil, { }].each do |erb|
|
142
|
+
it "passes #{erb.inspect} to the VCR::Cassette::Reader when given as the :erb option" do
|
143
|
+
# test that it overrides the default
|
144
|
+
VCR.configuration.default_cassette_options = { :erb => true }
|
112
145
|
|
113
|
-
it 'reads the appropriate file from disk using a VCR::Cassette::Reader' do
|
114
146
|
VCR::Cassette::Reader.should_receive(:new).with(
|
115
|
-
|
116
|
-
).and_return(mock('reader', :read =>
|
147
|
+
anything, erb
|
148
|
+
).and_return(mock('reader', :read => empty_cassette_yaml))
|
117
149
|
|
118
|
-
VCR::Cassette.new('foo', :record => :new_episodes)
|
150
|
+
VCR::Cassette.new('foo', :record => :new_episodes, :erb => erb).http_interactions
|
119
151
|
end
|
120
152
|
|
121
|
-
|
122
|
-
|
123
|
-
# test that it overrides the default
|
124
|
-
VCR.configuration.default_cassette_options = { :erb => true }
|
153
|
+
it "passes #{erb.inspect} to the VCR::Cassette::Reader when it is the default :erb option and none is given" do
|
154
|
+
VCR.configuration.default_cassette_options = { :erb => erb }
|
125
155
|
|
126
|
-
|
127
|
-
|
128
|
-
|
156
|
+
VCR::Cassette::Reader.should_receive(:new).with(
|
157
|
+
anything, erb
|
158
|
+
).and_return(mock('reader', :read => empty_cassette_yaml))
|
129
159
|
|
130
|
-
|
131
|
-
|
160
|
+
VCR::Cassette.new('foo', :record => :new_episodes).http_interactions
|
161
|
+
end
|
162
|
+
end
|
132
163
|
|
133
|
-
|
134
|
-
|
164
|
+
it 'raises a friendly error when the cassette file is in the old VCR 1.x format' do
|
165
|
+
VCR.configuration.cassette_library_dir = 'spec/fixtures/cassette_spec'
|
166
|
+
expect {
|
167
|
+
VCR::Cassette.new('1_x_cassette').http_interactions
|
168
|
+
}.to raise_error(VCR::Errors::InvalidCassetteFormatError)
|
169
|
+
end
|
170
|
+
end
|
135
171
|
|
136
|
-
|
137
|
-
|
138
|
-
|
172
|
+
describe '.new' do
|
173
|
+
it "raises an error if given an invalid record mode" do
|
174
|
+
expect { VCR::Cassette.new(:test, :record => :not_a_record_mode) }.to raise_error(ArgumentError)
|
175
|
+
end
|
139
176
|
|
140
|
-
|
141
|
-
|
142
|
-
|
177
|
+
it 'raises an error if given invalid options' do
|
178
|
+
expect {
|
179
|
+
VCR::Cassette.new(:test, :invalid => :option)
|
180
|
+
}.to raise_error(ArgumentError)
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'does not raise an error in the case of an empty file' do
|
184
|
+
VCR.configuration.cassette_library_dir = "#{VCR::SPEC_ROOT}/fixtures/cassette_spec"
|
185
|
+
VCR::Cassette.new('empty', :record => :none).previously_recorded_interactions.should eq([])
|
143
186
|
end
|
144
187
|
|
145
188
|
VCR::Cassette::VALID_RECORD_MODES.each do |record_mode|
|
@@ -155,27 +198,35 @@ describe VCR::Cassette do
|
|
155
198
|
end
|
156
199
|
|
157
200
|
context "when :#{record_mode} is passed as the record option" do
|
201
|
+
def stub_old_interactions(interactions)
|
202
|
+
hashes = interactions.map(&:to_hash)
|
203
|
+
VCR.cassette_serializers[:yaml].stub(:deserialize => { 'http_interactions' => hashes })
|
204
|
+
VCR::HTTPInteraction.stub(:from_hash) do |hash|
|
205
|
+
interactions[hashes.index(hash)]
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
158
209
|
unless record_mode == :all
|
159
|
-
let(:interaction_1) {
|
160
|
-
let(:interaction_2) {
|
210
|
+
let(:interaction_1) { http_interaction { |i| i.request.uri = 'http://example.com/foo' } }
|
211
|
+
let(:interaction_2) { http_interaction { |i| i.request.uri = 'http://example.com/bar' } }
|
161
212
|
let(:interactions) { [interaction_1, interaction_2] }
|
162
213
|
before(:each) { VCR.configuration.cassette_library_dir = "#{VCR::SPEC_ROOT}/fixtures/cassette_spec" }
|
163
214
|
|
164
215
|
it 'updates the content_length headers when given :update_content_length_header => true' do
|
165
|
-
|
216
|
+
stub_old_interactions(interactions)
|
166
217
|
interaction_1.response.should_receive(:update_content_length_header)
|
167
218
|
interaction_2.response.should_receive(:update_content_length_header)
|
168
219
|
|
169
|
-
VCR::Cassette.new('example', :record => record_mode, :update_content_length_header => true)
|
220
|
+
VCR::Cassette.new('example', :record => record_mode, :update_content_length_header => true).http_interactions
|
170
221
|
end
|
171
222
|
|
172
223
|
[nil, false].each do |val|
|
173
224
|
it "does not update the content_lenth headers when given :update_content_length_header => #{val.inspect}" do
|
174
|
-
|
225
|
+
stub_old_interactions(interactions)
|
175
226
|
interaction_1.response.should_not_receive(:update_content_length_header)
|
176
227
|
interaction_2.response.should_not_receive(:update_content_length_header)
|
177
228
|
|
178
|
-
VCR::Cassette.new('example', :record => record_mode, :update_content_length_header => val)
|
229
|
+
VCR::Cassette.new('example', :record => record_mode, :update_content_length_header => val).http_interactions
|
179
230
|
end
|
180
231
|
end
|
181
232
|
|
@@ -193,20 +244,34 @@ describe VCR::Cassette do
|
|
193
244
|
|
194
245
|
context 'when the cassette file does exist' do
|
195
246
|
before(:each) do
|
247
|
+
interactions = timestamps.map do |ts|
|
248
|
+
http_interaction { |i| i.recorded_at = ts }.to_hash
|
249
|
+
end
|
250
|
+
yaml = YAML.dump("http_interactions" => interactions)
|
251
|
+
|
196
252
|
File.stub(:exist?).with(file_name).and_return(true)
|
197
|
-
File.stub(:
|
253
|
+
File.stub(:size?).with(file_name).and_return(true)
|
254
|
+
File.stub(:read).with(file_name).and_return(yaml)
|
198
255
|
end
|
199
256
|
|
200
|
-
context 'and the
|
201
|
-
|
257
|
+
context 'and the earliest recorded interaction was recorded less than 7 days ago' do
|
258
|
+
let(:timestamps) do [
|
259
|
+
Time.now - 6.days + 60,
|
260
|
+
Time.now - 7.days + 60,
|
261
|
+
Time.now - 5.days + 60
|
262
|
+
] end
|
202
263
|
|
203
264
|
it "has :#{record_mode} for the record mode" do
|
204
265
|
subject.record_mode.should eq(record_mode)
|
205
266
|
end
|
206
267
|
end
|
207
268
|
|
208
|
-
context 'and the
|
209
|
-
|
269
|
+
context 'and the earliest recorded interaction was recorded more than 7 days ago' do
|
270
|
+
let(:timestamps) do [
|
271
|
+
Time.now - 6.days - 60,
|
272
|
+
Time.now - 7.days - 60,
|
273
|
+
Time.now - 5.days - 60
|
274
|
+
] end
|
210
275
|
|
211
276
|
it "has :all for the record mode when there is an internet connection available" do
|
212
277
|
VCR::InternetConnection.stub(:available? => true)
|
@@ -229,27 +294,27 @@ describe VCR::Cassette do
|
|
229
294
|
|
230
295
|
VCR.configuration.cassette_library_dir = "#{VCR::SPEC_ROOT}/fixtures/cassette_spec"
|
231
296
|
cassette = VCR::Cassette.new('with_localhost_requests', :record => record_mode)
|
232
|
-
cassette.
|
297
|
+
cassette.previously_recorded_interactions.map { |i| URI.parse(i.uri).host }.should eq(%w[example.com])
|
233
298
|
end
|
234
299
|
|
235
300
|
it "loads the recorded interactions from the library yml file" do
|
236
301
|
VCR.configuration.cassette_library_dir = "#{VCR::SPEC_ROOT}/fixtures/cassette_spec"
|
237
302
|
cassette = VCR::Cassette.new('example', :record => record_mode)
|
238
303
|
|
239
|
-
cassette.should have(3).
|
304
|
+
cassette.should have(3).previously_recorded_interactions
|
240
305
|
|
241
|
-
i1, i2, i3 = *cassette.
|
306
|
+
i1, i2, i3 = *cassette.previously_recorded_interactions
|
242
307
|
|
243
308
|
i1.request.method.should eq(:get)
|
244
|
-
i1.request.uri.should eq('http://example.com
|
309
|
+
i1.request.uri.should eq('http://example.com/')
|
245
310
|
i1.response.body.should =~ /You have reached this web page by typing.+example\.com/
|
246
311
|
|
247
312
|
i2.request.method.should eq(:get)
|
248
|
-
i2.request.uri.should eq('http://example.com
|
313
|
+
i2.request.uri.should eq('http://example.com/foo')
|
249
314
|
i2.response.body.should =~ /foo was not found on this server/
|
250
315
|
|
251
316
|
i3.request.method.should eq(:get)
|
252
|
-
i3.request.uri.should eq('http://example.com
|
317
|
+
i3.request.uri.should eq('http://example.com/')
|
253
318
|
i3.response.body.should =~ /Another example\.com response/
|
254
319
|
end
|
255
320
|
|
@@ -285,7 +350,7 @@ describe VCR::Cassette do
|
|
285
350
|
).exactly(3).times
|
286
351
|
|
287
352
|
cassette = VCR::Cassette.new('example', :record => record_mode, :tag => :foo)
|
288
|
-
cassette.should have(3).
|
353
|
+
cassette.should have(3).previously_recorded_interactions
|
289
354
|
end
|
290
355
|
|
291
356
|
it 'does not playback any interactions that are ignored in a before_playback hook' do
|
@@ -295,7 +360,7 @@ describe VCR::Cassette do
|
|
295
360
|
|
296
361
|
VCR.configuration.cassette_library_dir = "#{VCR::SPEC_ROOT}/fixtures/cassette_spec"
|
297
362
|
cassette = VCR::Cassette.new('example', :record => record_mode)
|
298
|
-
cassette.should have(2).
|
363
|
+
cassette.should have(2).previously_recorded_interactions
|
299
364
|
end
|
300
365
|
|
301
366
|
it 'instantiates the http_interactions with the loaded interactions and the request matchers' do
|
@@ -317,25 +382,21 @@ describe VCR::Cassette do
|
|
317
382
|
end
|
318
383
|
|
319
384
|
describe '#eject' do
|
320
|
-
it "writes the
|
321
|
-
recorded_interactions = [
|
322
|
-
VCR::HTTPInteraction.new(:req_sig_1, :response_1),
|
323
|
-
VCR::HTTPInteraction.new(:req_sig_2, :response_2),
|
324
|
-
VCR::HTTPInteraction.new(:req_sig_3, :response_3)
|
325
|
-
]
|
326
|
-
|
385
|
+
it "writes the serializable_hash to disk as yaml" do
|
327
386
|
cassette = VCR::Cassette.new(:eject_test)
|
328
|
-
cassette.
|
387
|
+
cassette.record_http_interaction http_interaction # so it has one
|
388
|
+
cassette.should respond_to(:serializable_hash)
|
389
|
+
cassette.stub(:serializable_hash => { "http_interactions" => [1, 3, 5] })
|
329
390
|
|
330
391
|
expect { cassette.eject }.to change { File.exist?(cassette.file) }.from(false).to(true)
|
331
|
-
|
332
|
-
|
392
|
+
saved_stuff = YAML.load_file(cassette.file)
|
393
|
+
saved_stuff.should eq("http_interactions" => [1, 3, 5])
|
333
394
|
end
|
334
395
|
|
335
396
|
it 'invokes the appropriately tagged before_record hooks' do
|
336
397
|
interactions = [
|
337
|
-
|
338
|
-
|
398
|
+
http_interaction { |i| i.request.uri = 'http://foo.com/'; i.response.body = 'res 1' },
|
399
|
+
http_interaction { |i| i.request.uri = 'http://bar.com/'; i.response.body = 'res 2' }
|
339
400
|
]
|
340
401
|
|
341
402
|
cassette = VCR::Cassette.new('example', :tag => :foo)
|
@@ -354,8 +415,8 @@ describe VCR::Cassette do
|
|
354
415
|
end
|
355
416
|
|
356
417
|
it 'does not record interactions that have been ignored' do
|
357
|
-
interaction_1 =
|
358
|
-
interaction_2 =
|
418
|
+
interaction_1 = http_interaction { |i| i.request.uri = 'http://foo.com/'; i.response.body = 'res 1' }
|
419
|
+
interaction_2 = http_interaction { |i| i.request.uri = 'http://bar.com/'; i.response.body = 'res 2' }
|
359
420
|
|
360
421
|
interaction_1.ignore!
|
361
422
|
|
@@ -363,12 +424,12 @@ describe VCR::Cassette do
|
|
363
424
|
cassette.stub!(:new_recorded_interactions).and_return([interaction_1, interaction_2])
|
364
425
|
cassette.eject
|
365
426
|
|
366
|
-
saved_recorded_interactions =
|
367
|
-
saved_recorded_interactions.should eq([interaction_2])
|
427
|
+
saved_recorded_interactions = ::YAML.load_file(cassette.file)
|
428
|
+
saved_recorded_interactions["http_interactions"].should eq([interaction_2.to_hash])
|
368
429
|
end
|
369
430
|
|
370
431
|
it 'does not write the cassette to disk if all interactions have been ignored' do
|
371
|
-
interaction_1 =
|
432
|
+
interaction_1 = http_interaction { |i| i.request.uri = 'http://foo.com/'; i.response.body = 'res 1' }
|
372
433
|
interaction_1.ignore!
|
373
434
|
|
374
435
|
cassette = VCR::Cassette.new('test_cassette')
|
@@ -379,13 +440,13 @@ describe VCR::Cassette do
|
|
379
440
|
end
|
380
441
|
|
381
442
|
it "writes the recorded interactions to a subdirectory if the cassette name includes a directory" do
|
382
|
-
recorded_interactions = [
|
443
|
+
recorded_interactions = [http_interaction { |i| i.response.body = "subdirectory response" }]
|
383
444
|
cassette = VCR::Cassette.new('subdirectory/test_cassette')
|
384
|
-
cassette.stub
|
445
|
+
cassette.stub(:new_recorded_interactions => recorded_interactions)
|
385
446
|
|
386
447
|
expect { cassette.eject }.to change { File.exist?(cassette.file) }.from(false).to(true)
|
387
|
-
saved_recorded_interactions =
|
388
|
-
saved_recorded_interactions.should eq(recorded_interactions)
|
448
|
+
saved_recorded_interactions = YAML.load_file(cassette.file)
|
449
|
+
saved_recorded_interactions["http_interactions"].should eq(recorded_interactions.map(&:to_hash))
|
389
450
|
end
|
390
451
|
|
391
452
|
[:all, :none, :new_episodes].each do |record_mode|
|
@@ -404,22 +465,25 @@ describe VCR::Cassette do
|
|
404
465
|
end
|
405
466
|
|
406
467
|
context 'when some new interactions have been recorded' do
|
407
|
-
def interaction(
|
408
|
-
|
409
|
-
|
410
|
-
|
468
|
+
def interaction(response_body, request_attributes)
|
469
|
+
http_interaction do |interaction|
|
470
|
+
interaction.response.body = response_body
|
471
|
+
request_attributes.each do |key, value|
|
472
|
+
interaction.request.send("#{key}=", value)
|
473
|
+
end
|
411
474
|
end
|
412
|
-
VCR::HTTPInteraction.new(request, response)
|
413
475
|
end
|
414
476
|
|
415
477
|
let(:interaction_foo_1) { interaction("foo 1", :uri => 'http://foo.com/') }
|
416
478
|
let(:interaction_foo_2) { interaction("foo 2", :uri => 'http://foo.com/') }
|
417
479
|
let(:interaction_bar) { interaction("bar", :uri => 'http://bar.com/') }
|
418
480
|
|
419
|
-
let(:saved_recorded_interactions) {
|
481
|
+
let(:saved_recorded_interactions) { YAML.load_file(subject.file)['http_interactions'].map { |h| VCR::HTTPInteraction.from_hash(h) } }
|
482
|
+
let(:now) { Time.utc(2011, 6, 11, 12, 30) }
|
420
483
|
|
421
484
|
before(:each) do
|
422
|
-
|
485
|
+
Time.stub(:now => now)
|
486
|
+
subject.stub(:previously_recorded_interactions => [interaction_foo_1])
|
423
487
|
subject.record_http_interaction(interaction_foo_2)
|
424
488
|
subject.record_http_interaction(interaction_bar)
|
425
489
|
subject.eject
|