vcr 2.0.0.rc1 → 2.0.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. data/.gitignore +2 -0
  2. data/.limited_red +1 -0
  3. data/.travis.yml +10 -1
  4. data/.yardopts +9 -0
  5. data/CHANGELOG.md +51 -1
  6. data/Gemfile +5 -1
  7. data/LICENSE +1 -1
  8. data/README.md +23 -28
  9. data/Rakefile +63 -18
  10. data/Upgrade.md +200 -0
  11. data/features/.nav +2 -0
  12. data/features/cassettes/automatic_re_recording.feature +19 -15
  13. data/features/cassettes/dynamic_erb.feature +12 -4
  14. data/features/cassettes/exclusive.feature +31 -23
  15. data/features/cassettes/format.feature +54 -30
  16. data/features/cassettes/naming.feature +1 -1
  17. data/features/cassettes/update_content_length_header.feature +16 -12
  18. data/features/configuration/allow_http_connections_when_no_cassette.feature +1 -1
  19. data/features/configuration/debug_logging.feature +52 -0
  20. data/features/configuration/filter_sensitive_data.feature +4 -4
  21. data/features/configuration/hook_into.feature +5 -2
  22. data/features/configuration/ignore_request.feature +5 -3
  23. data/features/configuration/preserve_exact_body_bytes.feature +103 -0
  24. data/features/hooks/after_http_request.feature +17 -4
  25. data/features/hooks/around_http_request.feature +2 -1
  26. data/features/hooks/before_http_request.feature +25 -8
  27. data/features/hooks/before_playback.feature +16 -12
  28. data/features/hooks/before_record.feature +2 -2
  29. data/features/http_libraries/em_http_request.feature +82 -58
  30. data/features/http_libraries/net_http.feature +6 -6
  31. data/features/middleware/faraday.feature +2 -1
  32. data/features/middleware/rack.feature +2 -2
  33. data/features/record_modes/all.feature +19 -15
  34. data/features/record_modes/new_episodes.feature +17 -13
  35. data/features/record_modes/none.feature +15 -11
  36. data/features/record_modes/once.feature +16 -12
  37. data/features/request_matching/body.feature +28 -20
  38. data/features/request_matching/custom_matcher.feature +28 -20
  39. data/features/request_matching/headers.feature +34 -26
  40. data/features/request_matching/host.feature +28 -20
  41. data/features/request_matching/identical_request_sequence.feature +28 -20
  42. data/features/request_matching/method.feature +28 -20
  43. data/features/request_matching/path.feature +28 -20
  44. data/features/request_matching/playback_repeats.feature +28 -20
  45. data/features/request_matching/uri.feature +28 -20
  46. data/features/request_matching/uri_without_param.feature +28 -20
  47. data/features/support/env.rb +7 -6
  48. data/features/support/vcr_cucumber_helpers.rb +1 -0
  49. data/features/test_frameworks/cucumber.feature +8 -8
  50. data/features/test_frameworks/rspec_macro.feature +4 -4
  51. data/features/test_frameworks/rspec_metadata.feature +6 -6
  52. data/features/test_frameworks/shoulda.feature +1 -1
  53. data/features/test_frameworks/test_unit.feature +1 -1
  54. data/lib/vcr.rb +156 -5
  55. data/lib/vcr/cassette.rb +80 -30
  56. data/lib/vcr/cassette/http_interaction_list.rb +33 -4
  57. data/lib/vcr/cassette/migrator.rb +2 -3
  58. data/lib/vcr/cassette/reader.rb +1 -0
  59. data/lib/vcr/cassette/serializers.rb +22 -0
  60. data/lib/vcr/cassette/serializers/json.rb +27 -2
  61. data/lib/vcr/cassette/serializers/psych.rb +26 -2
  62. data/lib/vcr/cassette/serializers/syck.rb +28 -2
  63. data/lib/vcr/cassette/serializers/yaml.rb +28 -2
  64. data/lib/vcr/configuration.rb +348 -10
  65. data/lib/vcr/deprecations.rb +8 -0
  66. data/lib/vcr/errors.rb +40 -0
  67. data/lib/vcr/extensions/net_http_response.rb +12 -11
  68. data/lib/vcr/library_hooks.rb +1 -0
  69. data/lib/vcr/library_hooks/excon.rb +24 -3
  70. data/lib/vcr/library_hooks/fakeweb.rb +32 -16
  71. data/lib/vcr/library_hooks/faraday.rb +3 -0
  72. data/lib/vcr/library_hooks/typhoeus.rb +40 -37
  73. data/lib/vcr/library_hooks/webmock.rb +54 -34
  74. data/lib/vcr/middleware/faraday.rb +13 -0
  75. data/lib/vcr/middleware/rack.rb +35 -0
  76. data/lib/vcr/request_handler.rb +60 -8
  77. data/lib/vcr/request_ignorer.rb +1 -0
  78. data/lib/vcr/request_matcher_registry.rb +28 -0
  79. data/lib/vcr/structs.rb +245 -38
  80. data/lib/vcr/test_frameworks/cucumber.rb +10 -0
  81. data/lib/vcr/test_frameworks/rspec.rb +26 -1
  82. data/lib/vcr/util/hooks.rb +29 -27
  83. data/lib/vcr/util/internet_connection.rb +2 -0
  84. data/lib/vcr/util/logger.rb +25 -0
  85. data/lib/vcr/util/variable_args_block_caller.rb +1 -0
  86. data/lib/vcr/util/version_checker.rb +1 -0
  87. data/lib/vcr/version.rb +8 -1
  88. data/spec/capture_warnings.rb +3 -3
  89. data/spec/monkey_patches.rb +28 -13
  90. data/spec/spec_helper.rb +17 -0
  91. data/spec/support/http_library_adapters.rb +7 -4
  92. data/spec/support/shared_example_groups/hook_into_http_library.rb +96 -32
  93. data/spec/support/shared_example_groups/request_hooks.rb +9 -8
  94. data/spec/support/sinatra_app.rb +3 -1
  95. data/spec/support/vcr_localhost_server.rb +1 -0
  96. data/spec/vcr/cassette/http_interaction_list_spec.rb +119 -54
  97. data/spec/vcr/cassette/migrator_spec.rb +19 -6
  98. data/spec/vcr/cassette/serializers_spec.rb +51 -6
  99. data/spec/vcr/cassette_spec.rb +44 -19
  100. data/spec/vcr/configuration_spec.rb +91 -6
  101. data/spec/vcr/library_hooks/excon_spec.rb +54 -16
  102. data/spec/vcr/library_hooks/fakeweb_spec.rb +12 -21
  103. data/spec/vcr/library_hooks/typhoeus_spec.rb +2 -29
  104. data/spec/vcr/library_hooks/webmock_spec.rb +4 -18
  105. data/spec/vcr/middleware/faraday_spec.rb +1 -16
  106. data/spec/vcr/structs_spec.rb +194 -61
  107. data/spec/vcr/test_frameworks/rspec_spec.rb +10 -0
  108. data/spec/vcr/util/hooks_spec.rb +104 -56
  109. data/spec/vcr/util/version_checker_spec.rb +45 -0
  110. data/spec/vcr_spec.rb +11 -0
  111. data/vcr.gemspec +30 -34
  112. metadata +149 -95
  113. data/spec/support/shared_example_groups/version_checking.rb +0 -34
data/features/.nav CHANGED
@@ -24,6 +24,8 @@
24
24
  - ignore_request.feature
25
25
  - filter_sensitive_data.feature
26
26
  - allow_http_connections_when_no_cassette.feature
27
+ - debug_logging.feature
28
+ - preserve_exact_body_bytes.feature
27
29
  - hooks:
28
30
  - before_record.feature
29
31
  - before_playback.feature
@@ -13,22 +13,26 @@ Feature: Automatic Re-recording
13
13
  Background:
14
14
  Given a previously recorded cassette file "cassettes/example.yml" with:
15
15
  """
16
- ---
17
- http_interactions:
18
- - request:
16
+ ---
17
+ http_interactions:
18
+ - request:
19
19
  method: get
20
20
  uri: http://localhost:7777/
21
- body: ''
21
+ body:
22
+ encoding: UTF-8
23
+ string: ""
22
24
  headers: {}
23
- response:
24
- status:
25
+ response:
26
+ status:
25
27
  code: 200
26
28
  message: OK
27
- headers:
28
- Content-Length:
29
- - '12'
30
- body: Old Response
31
- http_version: '1.1'
29
+ headers:
30
+ Content-Length:
31
+ - "12"
32
+ body:
33
+ encoding: UTF-8
34
+ string: Old Response
35
+ http_version: "1.1"
32
36
  recorded_at: Tue, 01 Nov 2011 04:58:44 GMT
33
37
  recorded_with: VCR 2.0.0
34
38
  """
@@ -55,14 +59,14 @@ Feature: Automatic Re-recording
55
59
  When I run `ruby re_record.rb`
56
60
  Then the output should contain "Old Response"
57
61
  But the output should not contain "New Response"
58
- And the file "cassettes/example.yml" should contain "body: Old Response"
59
- But the file "cassettes/example.yml" should not contain "body: New Response"
62
+ And the file "cassettes/example.yml" should contain "Old Response"
63
+ But the file "cassettes/example.yml" should not contain "New Response"
60
64
 
61
65
  Scenario: Cassette is re-recorded when enough time has passed
62
66
  Given it is Tue, 09 Nov 2011
63
67
  When I run `ruby re_record.rb`
64
68
  Then the output should contain "New Response"
65
69
  But the output should not contain "Old Response"
66
- And the file "cassettes/example.yml" should contain "body: New Response"
67
- But the file "cassettes/example.yml" should not contain "body: Old Response"
70
+ And the file "cassettes/example.yml" should contain "New Response"
71
+ But the file "cassettes/example.yml" should not contain "Old Response"
68
72
 
@@ -17,7 +17,9 @@ Feature: Dynamic ERB cassettes
17
17
  - request:
18
18
  method: get
19
19
  uri: http://example.com/foo?a=<%= 'b' * 3 %>
20
- body: ''
20
+ body:
21
+ encoding: UTF-8
22
+ string: ''
21
23
  headers: {}
22
24
  response:
23
25
  status:
@@ -28,7 +30,9 @@ Feature: Dynamic ERB cassettes
28
30
  - text/html;charset=utf-8
29
31
  Content-Length:
30
32
  - '9'
31
- body: Hello <%= 'bar'.next %>
33
+ body:
34
+ encoding: UTF-8
35
+ string: Hello <%= 'bar'.next %>
32
36
  http_version: '1.1'
33
37
  recorded_at: Tue, 01 Nov 2011 04:58:44 GMT
34
38
  recorded_with: VCR 2.0.0
@@ -58,7 +62,9 @@ Feature: Dynamic ERB cassettes
58
62
  - request:
59
63
  method: get
60
64
  uri: http://example.com/foo?a=<%= arg1 %>
61
- body: ''
65
+ body:
66
+ encoding: UTF-8
67
+ string: ''
62
68
  headers: {}
63
69
  response:
64
70
  status:
@@ -69,7 +75,9 @@ Feature: Dynamic ERB cassettes
69
75
  - text/html;charset=utf-8
70
76
  Content-Length:
71
77
  - '9'
72
- body: Hello <%= arg2 %>
78
+ body:
79
+ encoding: UTF-8
80
+ string: Hello <%= arg2 %>
73
81
  http_version: '1.1'
74
82
  recorded_at: Tue, 01 Nov 2011 04:58:44 GMT
75
83
  recorded_with: VCR 2.0.0
@@ -17,43 +17,51 @@ Feature: exclusive cassette
17
17
  Background:
18
18
  Given a previously recorded cassette file "cassettes/outer.yml" with:
19
19
  """
20
- ---
21
- http_interactions:
22
- - request:
20
+ ---
21
+ http_interactions:
22
+ - request:
23
23
  method: get
24
24
  uri: http://localhost:7777/outer
25
- body: ''
25
+ body:
26
+ encoding: UTF-8
27
+ string: ""
26
28
  headers: {}
27
- response:
28
- status:
29
+ response:
30
+ status:
29
31
  code: 200
30
32
  message: OK
31
- headers:
32
- Content-Length:
33
- - '18'
34
- body: Old outer response
35
- http_version: '1.1'
33
+ headers:
34
+ Content-Length:
35
+ - "18"
36
+ body:
37
+ encoding: UTF-8
38
+ string: Old outer response
39
+ http_version: "1.1"
36
40
  recorded_at: Tue, 01 Nov 2011 04:58:44 GMT
37
41
  recorded_with: VCR 2.0.0
38
42
  """
39
43
  And a previously recorded cassette file "cassettes/inner.yml" with:
40
44
  """
41
- ---
42
- http_interactions:
43
- - request:
45
+ ---
46
+ http_interactions:
47
+ - request:
44
48
  method: get
45
49
  uri: http://localhost:7777/inner
46
- body: ''
50
+ body:
51
+ encoding: UTF-8
52
+ string: ""
47
53
  headers: {}
48
- response:
49
- status:
54
+ response:
55
+ status:
50
56
  code: 200
51
57
  message: OK
52
- headers:
53
- Content-Length:
54
- - '18'
55
- body: Old inner response
56
- http_version: '1.1'
58
+ headers:
59
+ Content-Length:
60
+ - "18"
61
+ body:
62
+ encoding: UTF-8
63
+ string: Old inner response
64
+ http_version: "1.1"
57
65
  recorded_at: Tue, 01 Nov 2011 04:58:44 GMT
58
66
  recorded_with: VCR 2.0.0
59
67
  """
@@ -111,5 +119,5 @@ Feature: exclusive cassette
111
119
  New outer response
112
120
  Old inner response
113
121
  """
114
- And the file "cassettes/inner.yml" should contain "body: New outer response"
122
+ And the file "cassettes/inner.yml" should contain "New outer response"
115
123
 
@@ -9,6 +9,8 @@ Feature: Cassette format
9
9
  - method
10
10
  - uri
11
11
  - body
12
+ - encoding
13
+ - string
12
14
  - headers
13
15
  - response
14
16
  - status
@@ -16,6 +18,8 @@ Feature: Cassette format
16
18
  - message
17
19
  - headers
18
20
  - body
21
+ - encoding
22
+ - string
19
23
  - http version
20
24
 
21
25
  By default, VCR uses YAML to serialize this data. You can configure
@@ -72,41 +76,49 @@ Feature: Cassette format
72
76
  When I run `ruby cassette_yaml.rb 'Hello'`
73
77
  Then the file "cassettes/example.yml" should contain YAML like:
74
78
  """
75
- ---
76
- http_interactions:
77
- - request:
79
+ ---
80
+ http_interactions:
81
+ - request:
78
82
  method: get
79
83
  uri: http://localhost:7777/foo
80
- body: ''
84
+ body:
85
+ encoding: UTF-8
86
+ string: ""
81
87
  headers: {}
82
- response:
83
- status:
88
+ response:
89
+ status:
84
90
  code: 200
85
91
  message: OK
86
- headers:
87
- Content-Type:
92
+ headers:
93
+ Content-Type:
88
94
  - text/html;charset=utf-8
89
- Content-Length:
90
- - '9'
91
- body: Hello foo
92
- http_version: '1.1'
95
+ Content-Length:
96
+ - "9"
97
+ body:
98
+ encoding: UTF-8
99
+ string: Hello foo
100
+ http_version: "1.1"
93
101
  recorded_at: Tue, 01 Nov 2011 04:58:44 GMT
94
- - request:
102
+ - request:
95
103
  method: get
96
104
  uri: http://localhost:7777/bar
97
- body: ''
105
+ body:
106
+ encoding: UTF-8
107
+ string: ""
98
108
  headers: {}
99
- response:
100
- status:
109
+ response:
110
+ status:
101
111
  code: 200
102
112
  message: OK
103
- headers:
104
- Content-Type:
113
+ headers:
114
+ Content-Type:
105
115
  - text/html;charset=utf-8
106
- Content-Length:
107
- - '9'
108
- body: Hello bar
109
- http_version: '1.1'
116
+ Content-Length:
117
+ - "9"
118
+ body:
119
+ encoding: UTF-8
120
+ string: Hello bar
121
+ http_version: "1.1"
110
122
  recorded_at: Tue, 01 Nov 2011 04:58:44 GMT
111
123
  recorded_with: VCR 2.0.0
112
124
  """
@@ -152,7 +164,10 @@ Feature: Cassette format
152
164
  "http_interactions": [
153
165
  {
154
166
  "response": {
155
- "body": "Hello foo",
167
+ "body": {
168
+ "encoding": "UTF-8",
169
+ "string": "Hello foo"
170
+ },
156
171
  "http_version": null,
157
172
  "status": { "code": 200, "message": "OK" },
158
173
  "headers": {
@@ -165,7 +180,10 @@ Feature: Cassette format
165
180
  },
166
181
  "request": {
167
182
  "uri": "http://localhost:7777/foo",
168
- "body": "",
183
+ "body": {
184
+ "encoding": "UTF-8",
185
+ "string": ""
186
+ },
169
187
  "method": "get",
170
188
  "headers": { }
171
189
  },
@@ -173,7 +191,10 @@ Feature: Cassette format
173
191
  },
174
192
  {
175
193
  "response": {
176
- "body": "Hello bar",
194
+ "body": {
195
+ "encoding": "UTF-8",
196
+ "string": "Hello bar"
197
+ },
177
198
  "http_version": null,
178
199
  "status": { "code": 200, "message": "OK" },
179
200
  "headers": {
@@ -186,7 +207,10 @@ Feature: Cassette format
186
207
  },
187
208
  "request": {
188
209
  "uri": "http://localhost:7777/bar",
189
- "body": "",
210
+ "body": {
211
+ "encoding": "UTF-8",
212
+ "string": ""
213
+ },
190
214
  "method": "get",
191
215
  "headers": { }
192
216
  },
@@ -241,7 +265,7 @@ Feature: Cassette format
241
265
  [{"request"=>
242
266
  {"method"=>"get",
243
267
  "uri"=>"http://localhost:7777/foo",
244
- "body"=>"",
268
+ "body"=>{"encoding"=>"UTF-8", "string"=>""},
245
269
  "headers"=>{"Accept"=>["*/*"], "User-Agent"=>["Ruby"]}},
246
270
  "response"=>
247
271
  {"status"=>{"code"=>200, "message"=>"OK "},
@@ -249,13 +273,13 @@ Feature: Cassette format
249
273
  {"Content-Type"=>["text/html;charset=utf-8"],
250
274
  "Content-Length"=>["9"],
251
275
  "Connection"=>["Keep-Alive"]},
252
- "body"=>"Hello foo",
276
+ "body"=>{"encoding"=>"UTF-8", "string"=>"Hello foo"},
253
277
  "http_version"=>nil},
254
278
  "recorded_at"=>"Tue, 01 Nov 2011 04:58:44 GMT"},
255
279
  {"request"=>
256
280
  {"method"=>"get",
257
281
  "uri"=>"http://localhost:7777/bar",
258
- "body"=>"",
282
+ "body"=>{"encoding"=>"UTF-8", "string"=>""},
259
283
  "headers"=>{"Accept"=>["*/*"], "User-Agent"=>["Ruby"]}},
260
284
  "response"=>
261
285
  {"status"=>{"code"=>200, "message"=>"OK "},
@@ -263,7 +287,7 @@ Feature: Cassette format
263
287
  {"Content-Type"=>["text/html;charset=utf-8"],
264
288
  "Content-Length"=>["9"],
265
289
  "Connection"=>["Keep-Alive"]},
266
- "body"=>"Hello bar",
290
+ "body"=>{"encoding"=>"UTF-8", "string"=>"Hello bar"},
267
291
  "http_version"=>nil},
268
292
  "recorded_at"=>"Tue, 01 Nov 2011 04:58:44 GMT"}],
269
293
  "recorded_with"=>"VCR 2.0.0"}
@@ -24,4 +24,4 @@ Feature: Naming
24
24
  """
25
25
  And the directory "cassettes" does not exist
26
26
  When I run `ruby name_sanitizing.rb`
27
- Then the file "cassettes/Fee_Fi_Fo_Fum.yml" should contain "body: Hello"
27
+ Then the file "cassettes/Fee_Fi_Fo_Fum.yml" should contain "Hello"
@@ -21,24 +21,28 @@ Feature: Update content_length header
21
21
  Background:
22
22
  Given a previously recorded cassette file "cassettes/example.yml" with:
23
23
  """
24
- ---
25
- http_interactions:
26
- - request:
24
+ ---
25
+ http_interactions:
26
+ - request:
27
27
  method: get
28
28
  uri: http://example.com/
29
- body: ''
29
+ body:
30
+ encoding: UTF-8
31
+ string: ""
30
32
  headers: {}
31
- response:
32
- status:
33
+ response:
34
+ status:
33
35
  code: 200
34
36
  message: OK
35
- headers:
36
- Content-Type:
37
+ headers:
38
+ Content-Type:
37
39
  - text/html;charset=utf-8
38
- Content-Length:
39
- - '11'
40
- body: Hello <modified>
41
- http_version: '1.1'
40
+ Content-Length:
41
+ - "11"
42
+ body:
43
+ encoding: UTF-8
44
+ string: Hello <modified>
45
+ http_version: "1.1"
42
46
  recorded_at: Tue, 01 Nov 2011 04:58:44 GMT
43
47
  recorded_with: VCR 2.0.0
44
48
  """
@@ -45,7 +45,7 @@ Feature: Allow HTTP connections when no cassette
45
45
  """
46
46
  When I run `ruby record_replay_cassette.rb --with-server`
47
47
  Then the output should contain "Response: Hello"
48
- And the file "cassettes/localhost.yml" should contain "body: Hello"
48
+ And the file "cassettes/localhost.yml" should contain "Hello"
49
49
 
50
50
  When I run `ruby record_replay_cassette.rb`
51
51
  Then the output should contain "Response: Hello"
@@ -0,0 +1,52 @@
1
+ @exclude-18
2
+ Feature: Debug Logging
3
+
4
+ Use the `debug_logger` option to set an IO-like object that VCR will log
5
+ debug output to. This is a useful way to troubleshoot what VCR is doing.
6
+
7
+ The debug logger must respond to `#puts`.
8
+
9
+ Scenario: Use the debug logger for troubleshooting
10
+ Given a file named "debug_logger.rb" with:
11
+ """ruby
12
+ if ARGV.include?('--with-server')
13
+ start_sinatra_app(:port => 7777) do
14
+ get('/') { "Hello World" }
15
+ end
16
+ end
17
+
18
+ require 'vcr'
19
+
20
+ VCR.configure do |c|
21
+ c.hook_into :fakeweb
22
+ c.cassette_library_dir = 'cassettes'
23
+ c.debug_logger = File.open(ARGV.first, 'w')
24
+ end
25
+
26
+ VCR.use_cassette('example') do
27
+ Net::HTTP.get_response(URI("http://localhost:7777/"))
28
+ end
29
+ """
30
+ When I run `ruby debug_logger.rb record.log --with-server`
31
+ Then the file "record.log" should contain exactly:
32
+ """
33
+ [Cassette: 'example'] Initialized with options: {:record=>:once, :match_requests_on=>[:method, :uri], :serialize_with=>:yaml}
34
+ [fakeweb] Handling request: [get http://localhost:7777/] (disabled: false)
35
+ [Cassette: 'example'] Initialized HTTPInteractionList with request matchers [:method, :uri] and 0 interaction(s): { }
36
+ [fakeweb] Identified request type (recordable) for [get http://localhost:7777/]
37
+ [Cassette: 'example'] Recorded HTTP interaction [get http://localhost:7777/] => [200 "Hello World"]
38
+
39
+ """
40
+ When I run `ruby debug_logger.rb playback.log`
41
+ Then the file "playback.log" should contain exactly:
42
+ """
43
+ [Cassette: 'example'] Initialized with options: {:record=>:once, :match_requests_on=>[:method, :uri], :serialize_with=>:yaml}
44
+ [fakeweb] Handling request: [get http://localhost:7777/] (disabled: false)
45
+ [Cassette: 'example'] Initialized HTTPInteractionList with request matchers [:method, :uri] and 1 interaction(s): { [get http://localhost:7777/] => [200 "Hello World"] }
46
+ [Cassette: 'example'] Checking if [get http://localhost:7777/] matches [get http://localhost:7777/] using [:method, :uri]
47
+ [Cassette: 'example'] method (matched): current request [get http://localhost:7777/] vs [get http://localhost:7777/]
48
+ [Cassette: 'example'] uri (matched): current request [get http://localhost:7777/] vs [get http://localhost:7777/]
49
+ [Cassette: 'example'] Found matching interaction for [get http://localhost:7777/] at index 0: [200 "Hello World"]
50
+ [fakeweb] Identified request type (stubbed) for [get http://localhost:7777/]
51
+
52
+ """