mustwin-vcr 2.9.3

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 (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,53 @@
1
+ require 'spec_helper'
2
+
3
+ describe VCR::Cassette::ERBRenderer do
4
+ describe '#render' do
5
+ def render(*args)
6
+ described_class.new(*args).render
7
+ end
8
+
9
+ let(:no_vars_content) { '<%= 3 + 4 %>. Some ERB' }
10
+ let(:vars_content) { '<%= var1 %>. ERB with Vars! <%= var2 %>' }
11
+
12
+ context 'when ERB is disabled' do
13
+ it 'returns the given template' do
14
+ expect(render(no_vars_content, false)).to eq(no_vars_content)
15
+ expect(render(no_vars_content, nil)).to eq(no_vars_content)
16
+ end
17
+ end
18
+
19
+ context 'when ERB is enabled but no variables are passed' do
20
+ it 'renders the file content as ERB' do
21
+ expect(render(no_vars_content, true)).to eq("7. Some ERB")
22
+ end
23
+
24
+ it 'raises an appropriate error when the ERB template needs variables' do
25
+ expect {
26
+ render(vars_content, true, "vars")
27
+ }.to raise_error(VCR::Errors::MissingERBVariableError,
28
+ %{The ERB in the vars cassette file references undefined variable var1. } +
29
+ %{Pass it to the cassette using :erb => #{ {:var1=>"some value"}.inspect }.}
30
+ )
31
+ end
32
+
33
+ it 'gracefully handles the template being nil' do
34
+ expect(render(nil, true)).to be_nil
35
+ end
36
+ end
37
+
38
+ context 'when ERB is enabled and variables are passed' do
39
+ it 'renders the file content as ERB with the passed variables' do
40
+ expect(render(vars_content, :var1 => 'foo', :var2 => 'bar')).to eq('foo. ERB with Vars! bar')
41
+ end
42
+
43
+ it 'raises an appropriate error when one or more of the needed variables are not passed' do
44
+ expect {
45
+ render(vars_content, { :var1 => 'foo' }, "vars")
46
+ }.to raise_error(VCR::Errors::MissingERBVariableError,
47
+ %{The ERB in the vars cassette file references undefined variable var2. } +
48
+ %{Pass it to the cassette using :erb => #{ {:var1 => "foo", :var2 => "some value"}.inspect }.}
49
+ )
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,295 @@
1
+ require 'vcr/util/logger'
2
+ require 'vcr/cassette/http_interaction_list'
3
+ require 'vcr/request_matcher_registry'
4
+ require 'vcr/structs'
5
+ require 'support/configuration_stubbing'
6
+
7
+ module VCR
8
+ class Cassette
9
+ describe HTTPInteractionList do
10
+ include_context "configuration stubbing"
11
+
12
+ ::RSpec::Matchers.define :respond_with do |expected|
13
+ match { |a| expected.nil? ? a.nil? : a.body == expected }
14
+ end
15
+
16
+ before(:each) do
17
+ allow(VCR).to receive(:request_matchers).and_return(VCR::RequestMatcherRegistry.new)
18
+ allow(config).to receive(:logger).and_return(double.as_null_object)
19
+ end
20
+
21
+ def request_with(values)
22
+ VCR::Request.new.tap do |request|
23
+ values.each do |name, value|
24
+ request.send("#{name}=", value)
25
+ end
26
+ end
27
+ end
28
+
29
+ def response(body)
30
+ VCR::Response.new.tap do |r|
31
+ r.body = body
32
+ r.status = VCR::ResponseStatus.new(200)
33
+ end
34
+ end
35
+
36
+ def interaction(body, request_values)
37
+ VCR::HTTPInteraction.new \
38
+ request_with(request_values),
39
+ response(body)
40
+ end
41
+
42
+ let(:original_list_array) do [
43
+ interaction('put response', :method => :put),
44
+ interaction('post response 1', :method => :post),
45
+ interaction('post response 2', :method => :post)
46
+ ] end
47
+
48
+ let(:allow_playback_repeats) { false } # the default
49
+ let(:list) { HTTPInteractionList.new(original_list_array, [:method], allow_playback_repeats) }
50
+
51
+ describe "#has_used_interaction_matching?" do
52
+ it 'returns false when no interactions have been used' do
53
+ expect(list).not_to have_used_interaction_matching(request_with(:method => :put))
54
+ end
55
+
56
+ it 'returns true when there is a matching used interaction (even if there is also an unused one that matches)' do
57
+ list.response_for(request_with(:method => :post))
58
+ expect(list).to have_used_interaction_matching(request_with(:method => :post))
59
+ end
60
+
61
+ it 'returns false when none of the used interactions match' do
62
+ list.response_for(request_with(:method => :put))
63
+ expect(list).not_to have_used_interaction_matching(request_with(:method => :post))
64
+ end
65
+ end
66
+
67
+ describe "#remaining_unused_interaction_count" do
68
+ it 'returns the number of unused interactions' do
69
+ expect(list.remaining_unused_interaction_count).to eq(3)
70
+
71
+ list.response_for(request_with(:method => :get))
72
+ expect(list.remaining_unused_interaction_count).to eq(3)
73
+
74
+ list.response_for(request_with(:method => :put))
75
+ expect(list.remaining_unused_interaction_count).to eq(2)
76
+
77
+ list.response_for(request_with(:method => :put))
78
+ expect(list.remaining_unused_interaction_count).to eq(2)
79
+
80
+ list.response_for(request_with(:method => :post))
81
+ expect(list.remaining_unused_interaction_count).to eq(1)
82
+
83
+ list.response_for(request_with(:method => :post))
84
+ expect(list.remaining_unused_interaction_count).to eq(0)
85
+
86
+ list.response_for(request_with(:method => :post))
87
+ expect(list.remaining_unused_interaction_count).to eq(0)
88
+ end
89
+ end
90
+
91
+ describe "#assert_no_unused_interactions?" do
92
+ it 'should raise a SkippedHTTPRequestError when there are unused interactions left' do
93
+ expect {
94
+ list.assert_no_unused_interactions!
95
+ }.to raise_error(Errors::UnusedHTTPInteractionError)
96
+
97
+ list.response_for(request_with(:method => :put))
98
+ expect {
99
+ list.assert_no_unused_interactions!
100
+ }.to raise_error(Errors::UnusedHTTPInteractionError)
101
+ end
102
+
103
+ it 'should raise nothing when there are no unused interactions left' do
104
+ [:put, :post, :post].each do |method|
105
+ list.response_for(request_with(:method => method))
106
+ end
107
+
108
+ expect {
109
+ list.assert_no_unused_interactions!
110
+ }.not_to raise_error
111
+ end
112
+
113
+ context 'when the null logger is in use' do
114
+ before { allow(config).to receive(:logger).and_return(Logger::Null) }
115
+
116
+ it 'includes formatted request details in the error message' do
117
+ expect {
118
+ list.assert_no_unused_interactions!
119
+ }.to raise_error(/\[put/)
120
+ end
121
+
122
+ it 'includes formatted response details in the error message' do
123
+ expect {
124
+ list.assert_no_unused_interactions!
125
+ }.to raise_error(/\[200 "put response"\]/)
126
+ end
127
+ end
128
+ end
129
+
130
+ describe "has_interaction_matching?" do
131
+ it 'returns false when the list is empty' do
132
+ expect(HTTPInteractionList.new([], [:method])).not_to have_interaction_matching(double)
133
+ end
134
+
135
+ it 'returns false when there is no matching interaction' do
136
+ expect(list).not_to have_interaction_matching(request_with(:method => :get))
137
+ end
138
+
139
+ it 'returns true when there is a matching interaction' do
140
+ expect(list).to have_interaction_matching(request_with(:method => :post))
141
+ end
142
+
143
+ it 'does not consume the interactions when they match' do
144
+ expect(list).to have_interaction_matching(request_with(:method => :post))
145
+ expect(list.remaining_unused_interaction_count).to eq(3)
146
+ expect(list).to have_interaction_matching(request_with(:method => :post))
147
+ expect(list.remaining_unused_interaction_count).to eq(3)
148
+ end
149
+
150
+ it 'invokes each matcher block to find the matching interaction' do
151
+ VCR.request_matchers.register(:foo) { |r1, r2| true }
152
+ VCR.request_matchers.register(:bar) { |r1, r2| true }
153
+
154
+ calls = 0
155
+ VCR.request_matchers.register(:baz) { |r1, r2| calls += 1; calls == 2 }
156
+
157
+ list = HTTPInteractionList.new([
158
+ interaction('response', :method => :put)
159
+ ], [:foo, :bar, :baz])
160
+
161
+ expect(list).not_to have_interaction_matching(request_with(:method => :post))
162
+ expect(list).to have_interaction_matching(request_with(:method => :post))
163
+ end
164
+
165
+ it "delegates to the parent list when it can't find a matching interaction" do
166
+ parent_list = double(:has_interaction_matching? => true)
167
+ expect(HTTPInteractionList.new( [], [:method], false, parent_list)).to have_interaction_matching(double)
168
+ parent_list = double(:has_interaction_matching? => false)
169
+ expect(HTTPInteractionList.new( [], [:method], false, parent_list)).not_to have_interaction_matching(double)
170
+ end
171
+
172
+ context 'when allow_playback_repeats is set to true' do
173
+ let(:allow_playback_repeats) { true }
174
+
175
+ it 'considers used interactions' do
176
+ list.response_for(request_with(:method => :put))
177
+
178
+ results = 10.times.map do
179
+ list.has_interaction_matching?(request_with(:method => :put))
180
+ end
181
+
182
+ expect(results).to eq([true] * 10)
183
+ end
184
+ end
185
+
186
+ context 'when allow_playback_repeats is set to false' do
187
+ let(:allow_playback_repeats) { false }
188
+
189
+ it 'does not consider used interactions' do
190
+ list.response_for(request_with(:method => :put))
191
+
192
+ result = 10.times.map do
193
+ list.has_interaction_matching?(request_with(:method => :put))
194
+ end
195
+
196
+ expect(result).to eq([false] * 10)
197
+ end
198
+ end
199
+ end
200
+
201
+ describe "#response_for" do
202
+ it 'returns nil when the list is empty' do
203
+ expect(HTTPInteractionList.new([], [:method]).response_for(double)).to respond_with(nil)
204
+ end
205
+
206
+ it 'returns nil when there is no matching interaction' do
207
+ response = HTTPInteractionList.new([
208
+ interaction('foo', :method => :post),
209
+ interaction('foo', :method => :put)
210
+ ], [:method]).response_for(
211
+ request_with(:method => :get)
212
+ )
213
+
214
+ expect(response).to respond_with(nil)
215
+ end
216
+
217
+ it 'returns the first matching interaction' do
218
+ list = HTTPInteractionList.new([
219
+ interaction('put response', :method => :put),
220
+ interaction('post response 1', :method => :post),
221
+ interaction('post response 2', :method => :post)
222
+ ], [:method])
223
+
224
+ expect(list.response_for(request_with(:method => :post))).to respond_with("post response 1")
225
+ end
226
+
227
+ it 'invokes each matcher block to find the matching interaction' do
228
+ VCR.request_matchers.register(:foo) { |r1, r2| true }
229
+ VCR.request_matchers.register(:bar) { |r1, r2| true }
230
+
231
+ calls = 0
232
+ VCR.request_matchers.register(:baz) { |r1, r2| calls += 1; calls == 2 }
233
+
234
+ list = HTTPInteractionList.new([
235
+ interaction('response', :method => :put)
236
+ ], [:foo, :bar, :baz])
237
+
238
+ expect(list.response_for(request_with(:method => :post))).to respond_with(nil)
239
+ expect(list.response_for(request_with(:method => :post))).to respond_with('response')
240
+ end
241
+
242
+ it "delegates to the parent list when it can't find a matching interaction" do
243
+ parent_list = double(:response_for => response('parent'))
244
+ result = HTTPInteractionList.new(
245
+ [], [:method], false, parent_list
246
+ ).response_for(double)
247
+
248
+ expect(result).to respond_with('parent')
249
+ end
250
+
251
+ it 'consumes the first matching interaction so that it will not be used again' do
252
+ expect(list.response_for(request_with(:method => :post)).body).to eq("post response 1")
253
+ expect(list.response_for(request_with(:method => :post)).body).to eq("post response 2")
254
+ end
255
+
256
+ context 'when allow_playback_repeats is set to true' do
257
+ let(:allow_playback_repeats) { true }
258
+
259
+ it 'continues to return the response from the last matching interaction when there are no more' do
260
+ list.response_for(request_with(:method => :post))
261
+
262
+ results = 10.times.map do
263
+ response = list.response_for(request_with(:method => :post))
264
+ response ? response.body : nil
265
+ end
266
+
267
+ expect(results).to eq(["post response 2"] * 10)
268
+ end
269
+ end
270
+
271
+ context 'when allow_playback_repeats is set to false' do
272
+ let(:allow_playback_repeats) { false }
273
+
274
+ it 'returns nil when there are no more unused interactions' do
275
+ list.response_for(request_with(:method => :post))
276
+ list.response_for(request_with(:method => :post))
277
+
278
+ results = 10.times.map do
279
+ list.response_for(request_with(:method => :post))
280
+ end
281
+
282
+ expect(results).to eq([nil] * 10)
283
+ end
284
+ end
285
+
286
+ it 'does not modify the original interaction array the list was initialized with' do
287
+ original_dup = original_list_array.dup
288
+ list.response_for(request_with(:method => :post))
289
+ expect(original_list_array).to eq original_dup
290
+ end
291
+ end
292
+ end
293
+ end
294
+ end
295
+
@@ -0,0 +1,195 @@
1
+ require 'tmpdir'
2
+ require 'vcr/cassette/migrator'
3
+
4
+ describe VCR::Cassette::Migrator do
5
+ let(:original_contents) { <<-EOF
6
+ ---
7
+ - !ruby/struct:VCR::HTTPInteraction
8
+ request: !ruby/struct:VCR::Request
9
+ method: :get
10
+ uri: http://example.com:80/foo
11
+ body:
12
+ headers:
13
+ response: !ruby/struct:VCR::Response
14
+ status: !ruby/struct:VCR::ResponseStatus
15
+ code: 200
16
+ message: OK
17
+ headers:
18
+ content-type:
19
+ - text/html;charset=utf-8
20
+ content-length:
21
+ - "9"
22
+ body: Hello foo
23
+ http_version: "1.1"
24
+ - !ruby/struct:VCR::HTTPInteraction
25
+ request: !ruby/struct:VCR::Request
26
+ method: :get
27
+ uri: http://localhost:7777/bar
28
+ body:
29
+ headers:
30
+ response: !ruby/struct:VCR::Response
31
+ status: !ruby/struct:VCR::ResponseStatus
32
+ code: 200
33
+ message: OK
34
+ headers:
35
+ content-type:
36
+ - text/html;charset=utf-8
37
+ content-length:
38
+ - "9"
39
+ body: Hello bar
40
+ http_version: "1.1"
41
+ EOF
42
+ }
43
+
44
+ let(:updated_contents) { <<-EOF
45
+ ---
46
+ http_interactions:
47
+ - request:
48
+ method: get
49
+ uri: http://example.com/foo
50
+ body:
51
+ encoding: US-ASCII
52
+ string: ""
53
+ headers: {}
54
+
55
+ response:
56
+ status:
57
+ code: 200
58
+ message: OK
59
+ headers:
60
+ Content-Type:
61
+ - text/html;charset=utf-8
62
+ Content-Length:
63
+ - "9"
64
+ body:
65
+ encoding: UTF-8
66
+ string: Hello foo
67
+ http_version: "1.1"
68
+ recorded_at: Wed, 04 May 2011 12:30:00 GMT
69
+ - request:
70
+ method: get
71
+ uri: http://localhost:7777/bar
72
+ body:
73
+ encoding: US-ASCII
74
+ string: ""
75
+ headers: {}
76
+
77
+ response:
78
+ status:
79
+ code: 200
80
+ message: OK
81
+ headers:
82
+ Content-Type:
83
+ - text/html;charset=utf-8
84
+ Content-Length:
85
+ - "9"
86
+ body:
87
+ encoding: UTF-8
88
+ string: Hello bar
89
+ http_version: "1.1"
90
+ recorded_at: Wed, 04 May 2011 12:30:00 GMT
91
+ recorded_with: VCR #{VCR.version}
92
+ EOF
93
+ }
94
+
95
+ let(:dir) { './tmp/migrator' }
96
+
97
+ before(:each) do
98
+ # ensure the directory is empty
99
+ FileUtils.rm_rf dir
100
+ FileUtils.mkdir_p dir
101
+ end
102
+
103
+ before(:each) do
104
+ # the encoding won't be set on rubies that don't support it
105
+ updated_contents.gsub!(/^\s+encoding:.*$/, '')
106
+ end unless ''.respond_to?(:encoding)
107
+
108
+ # JRuby serializes YAML with some slightly different whitespace.
109
+ before(:each) do
110
+ [original_contents, updated_contents].each do |contents|
111
+ contents.gsub!(/^(\s+)-/, '\1 -')
112
+ end
113
+ updated_contents.gsub!(/^(- | )/, ' \1')
114
+ end if RUBY_PLATFORM == 'java'
115
+
116
+ # Use syck on all rubies for consistent results...
117
+ before(:each) do
118
+ YAML::ENGINE.yamler = 'syck' if defined?(YAML::ENGINE)
119
+ end
120
+
121
+ after(:each) do
122
+ YAML::ENGINE.yamler = 'psych' if defined?(YAML::ENGINE)
123
+ end
124
+
125
+ let(:filemtime) { Time.utc(2011, 5, 4, 12, 30) }
126
+ let(:out_io) { StringIO.new }
127
+ let(:file_name) { File.join(dir, "example.yml") }
128
+ let(:output) { out_io.rewind; out_io.read }
129
+
130
+ subject { described_class.new(dir, out_io) }
131
+
132
+ before(:each) do
133
+ allow(File).to receive(:mtime).with(file_name).and_return(filemtime)
134
+ end
135
+
136
+ it 'migrates a cassette from the 1.x to 2.x format' do
137
+ File.open(file_name, 'w') { |f| f.write(original_contents) }
138
+ subject.migrate!
139
+ expect(YAML.load_file(file_name)).to eq(YAML.load(updated_contents))
140
+ expect(output).to match(/Migrated example.yml/)
141
+ end
142
+
143
+ it 'ignores files that do not contain arrays' do
144
+ File.open(file_name, 'w') { |f| f.write(true.to_yaml) }
145
+ subject.migrate!
146
+ expect(File.read(file_name)).to eq(true.to_yaml)
147
+ expect(output).to match(/Ignored example.yml since it does not appear to be a valid VCR 1.x cassette/)
148
+ end
149
+
150
+ it 'ignores files that contain YAML arrays of other things' do
151
+ File.open(file_name, 'w') { |f| f.write([{}, {}].to_yaml) }
152
+ subject.migrate!
153
+ expect(File.read(file_name)).to eq([{}, {}].to_yaml)
154
+ expect(output).to match(/Ignored example.yml since it does not appear to be a valid VCR 1.x cassette/)
155
+ end
156
+
157
+ it 'ignores URIs that have sensitive data substitutions' do
158
+ modified_contents = original_contents.gsub('example.com', '<HOST>')
159
+ File.open(file_name, 'w') { |f| f.write(modified_contents) }
160
+ subject.migrate!
161
+ expect(YAML.load_file(file_name)).to eq(YAML.load(updated_contents.gsub('example.com', '<HOST>:80')))
162
+ end
163
+
164
+ it 'ignores files that are empty' do
165
+ File.open(file_name, 'w') { |f| f.write('') }
166
+ subject.migrate!
167
+ expect(File.read(file_name)).to eq('')
168
+ expect(output).to match(/Ignored example.yml since it could not be parsed as YAML/)
169
+ end
170
+
171
+ shared_examples_for "ignoring invalid YAML" do
172
+ it 'ignores files that cannot be parsed as valid YAML (such as ERB cassettes)' do
173
+ modified_contents = original_contents.gsub(/\A---/, "---\n<% 3.times do %>")
174
+ modified_contents = modified_contents.gsub(/\z/, "<% end %>")
175
+ File.open(file_name, 'w') { |f| f.write(modified_contents) }
176
+ subject.migrate!
177
+ expect(File.read(file_name)).to eq(modified_contents)
178
+ expect(output).to match(/Ignored example.yml since it could not be parsed as YAML/)
179
+ end
180
+ end
181
+
182
+ context 'with syck' do
183
+ it_behaves_like "ignoring invalid YAML"
184
+ end
185
+
186
+ context 'with psych' do
187
+ before(:each) do
188
+ pending "psych not available" unless defined?(YAML::ENGINE)
189
+ YAML::ENGINE.yamler = 'psych'
190
+ end
191
+
192
+ it_behaves_like "ignoring invalid YAML"
193
+ end
194
+ end
195
+