vcr 3.0.3 → 6.2.0
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.
- checksums.yaml +5 -5
- data/lib/vcr/cassette/erb_renderer.rb +4 -2
- data/lib/vcr/cassette/http_interaction_list.rb +14 -9
- data/lib/vcr/cassette/migrator.rb +5 -6
- data/lib/vcr/cassette/persisters/file_system.rb +9 -1
- data/lib/vcr/cassette/serializers/compressed.rb +2 -2
- data/lib/vcr/cassette/serializers/json.rb +14 -8
- data/lib/vcr/cassette/serializers/psych.rb +10 -2
- data/lib/vcr/cassette/serializers/syck.rb +7 -1
- data/lib/vcr/cassette/serializers/yaml.rb +14 -2
- data/lib/vcr/cassette/serializers.rb +10 -0
- data/lib/vcr/cassette.rb +63 -16
- data/lib/vcr/configuration.rb +21 -8
- data/lib/vcr/deprecations.rb +0 -62
- data/lib/vcr/errors.rb +17 -12
- data/lib/vcr/library_hooks/excon.rb +8 -0
- data/lib/vcr/library_hooks/typhoeus.rb +91 -79
- data/lib/vcr/library_hooks/webmock.rb +2 -11
- data/lib/vcr/linked_cassette.rb +4 -4
- data/lib/vcr/middleware/excon.rb +1 -1
- data/lib/vcr/middleware/faraday.rb +29 -2
- data/lib/vcr/request_ignorer.rb +8 -1
- data/lib/vcr/request_matcher_registry.rb +3 -3
- data/lib/vcr/structs.rb +48 -32
- data/lib/vcr/test_frameworks/cucumber.rb +16 -5
- data/lib/vcr/test_frameworks/rspec.rb +34 -22
- data/lib/vcr/util/hooks.rb +1 -0
- data/lib/vcr/util/internet_connection.rb +15 -21
- data/lib/vcr/version.rb +2 -2
- data/lib/vcr.rb +52 -2
- metadata +45 -272
- data/features/CHANGELOG.md +0 -710
- data/features/CONTRIBUTING.md +0 -26
- data/features/LICENSE.md +0 -20
- data/features/README.md +0 -339
- data/features/Upgrade.md +0 -289
- data/features/about_these_examples.md +0 -18
- data/features/cassettes/allow_unused_http_interactions.feature +0 -100
- data/features/cassettes/automatic_re_recording.feature +0 -72
- data/features/cassettes/decompress.feature +0 -74
- data/features/cassettes/dynamic_erb.feature +0 -100
- data/features/cassettes/exclusive.feature +0 -126
- data/features/cassettes/format.feature +0 -411
- data/features/cassettes/freezing_time.feature +0 -68
- data/features/cassettes/naming.feature +0 -28
- data/features/cassettes/no_cassette.feature +0 -152
- data/features/cassettes/update_content_length_header.feature +0 -112
- data/features/configuration/allow_http_connections_when_no_cassette.feature +0 -55
- data/features/configuration/cassette_library_dir.feature +0 -31
- data/features/configuration/debug_logging.feature +0 -58
- data/features/configuration/default_cassette_options.feature +0 -100
- data/features/configuration/filter_sensitive_data.feature +0 -153
- data/features/configuration/hook_into.feature +0 -172
- data/features/configuration/ignore_request.feature +0 -192
- data/features/configuration/preserve_exact_body_bytes.feature +0 -108
- data/features/configuration/query_parser.feature +0 -84
- data/features/configuration/uri_parser.feature +0 -93
- data/features/getting_started.md +0 -82
- data/features/hooks/after_http_request.feature +0 -58
- data/features/hooks/around_http_request.feature +0 -57
- data/features/hooks/before_http_request.feature +0 -63
- data/features/hooks/before_playback.feature +0 -184
- data/features/hooks/before_record.feature +0 -172
- data/features/http_libraries/em_http_request.feature +0 -250
- data/features/http_libraries/net_http.feature +0 -179
- data/features/middleware/faraday.feature +0 -56
- data/features/middleware/rack.feature +0 -92
- data/features/record_modes/all.feature +0 -82
- data/features/record_modes/new_episodes.feature +0 -79
- data/features/record_modes/none.feature +0 -72
- data/features/record_modes/once.feature +0 -95
- data/features/request_matching/README.md +0 -30
- data/features/request_matching/body.feature +0 -91
- data/features/request_matching/body_as_json.feature +0 -90
- data/features/request_matching/custom_matcher.feature +0 -135
- data/features/request_matching/headers.feature +0 -85
- data/features/request_matching/host.feature +0 -95
- data/features/request_matching/identical_request_sequence.feature +0 -89
- data/features/request_matching/method.feature +0 -96
- data/features/request_matching/path.feature +0 -96
- data/features/request_matching/playback_repeats.feature +0 -98
- data/features/request_matching/query.feature +0 -97
- data/features/request_matching/uri.feature +0 -94
- data/features/request_matching/uri_without_param.feature +0 -101
- data/features/step_definitions/cli_steps.rb +0 -199
- data/features/support/env.rb +0 -46
- data/features/support/http_lib_filters.rb +0 -46
- data/features/test_frameworks/cucumber.feature +0 -211
- data/features/test_frameworks/rspec_macro.feature +0 -81
- data/features/test_frameworks/rspec_metadata.feature +0 -150
- data/features/test_frameworks/test_unit.feature +0 -49
- data/lib/vcr/extensions/net_http_response.rb +0 -36
- data/lib/vcr/library_hooks/fakeweb.rb +0 -197
- data/lib/vcr/library_hooks/typhoeus_0.4.rb +0 -103
- data/spec/acceptance/concurrency_spec.rb +0 -51
- data/spec/acceptance/threading_spec.rb +0 -34
- data/spec/fixtures/cassette_spec/1_x_cassette.yml +0 -110
- data/spec/fixtures/cassette_spec/empty.yml +0 -0
- data/spec/fixtures/cassette_spec/example.yml +0 -111
- data/spec/fixtures/cassette_spec/with_localhost_requests.yml +0 -111
- data/spec/fixtures/fake_example_responses.yml +0 -110
- data/spec/fixtures/match_requests_on.yml +0 -187
- data/spec/lib/vcr/cassette/erb_renderer_spec.rb +0 -53
- data/spec/lib/vcr/cassette/http_interaction_list_spec.rb +0 -295
- data/spec/lib/vcr/cassette/migrator_spec.rb +0 -196
- data/spec/lib/vcr/cassette/persisters/file_system_spec.rb +0 -75
- data/spec/lib/vcr/cassette/persisters_spec.rb +0 -39
- data/spec/lib/vcr/cassette/serializers_spec.rb +0 -182
- data/spec/lib/vcr/cassette_spec.rb +0 -618
- data/spec/lib/vcr/configuration_spec.rb +0 -326
- data/spec/lib/vcr/deprecations_spec.rb +0 -85
- data/spec/lib/vcr/errors_spec.rb +0 -178
- data/spec/lib/vcr/extensions/net_http_response_spec.rb +0 -86
- data/spec/lib/vcr/library_hooks/excon_spec.rb +0 -104
- data/spec/lib/vcr/library_hooks/fakeweb_spec.rb +0 -169
- data/spec/lib/vcr/library_hooks/faraday_spec.rb +0 -68
- data/spec/lib/vcr/library_hooks/typhoeus_0.4_spec.rb +0 -36
- data/spec/lib/vcr/library_hooks/typhoeus_spec.rb +0 -162
- data/spec/lib/vcr/library_hooks/webmock_spec.rb +0 -117
- data/spec/lib/vcr/library_hooks_spec.rb +0 -51
- data/spec/lib/vcr/middleware/faraday_spec.rb +0 -181
- data/spec/lib/vcr/middleware/rack_spec.rb +0 -115
- data/spec/lib/vcr/request_ignorer_spec.rb +0 -70
- data/spec/lib/vcr/request_matcher_registry_spec.rb +0 -345
- data/spec/lib/vcr/structs_spec.rb +0 -732
- data/spec/lib/vcr/test_frameworks/cucumber_spec.rb +0 -107
- data/spec/lib/vcr/test_frameworks/rspec_spec.rb +0 -94
- data/spec/lib/vcr/util/hooks_spec.rb +0 -158
- data/spec/lib/vcr/util/internet_connection_spec.rb +0 -37
- data/spec/lib/vcr/util/version_checker_spec.rb +0 -31
- data/spec/lib/vcr/version_spec.rb +0 -27
- data/spec/lib/vcr_spec.rb +0 -354
- data/spec/monkey_patches.rb +0 -186
- data/spec/spec_helper.rb +0 -63
- data/spec/support/configuration_stubbing.rb +0 -8
- data/spec/support/cucumber_helpers.rb +0 -39
- data/spec/support/fixnum_extension.rb +0 -10
- data/spec/support/http_library_adapters.rb +0 -289
- data/spec/support/limited_uri.rb +0 -21
- data/spec/support/ruby_interpreter.rb +0 -7
- data/spec/support/shared_example_groups/excon.rb +0 -63
- data/spec/support/shared_example_groups/hook_into_http_library.rb +0 -594
- data/spec/support/shared_example_groups/request_hooks.rb +0 -59
- data/spec/support/sinatra_app.rb +0 -86
- data/spec/support/vcr_localhost_server.rb +0 -76
- data/spec/support/vcr_stub_helpers.rb +0 -17
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 902881c25780fa44253365c8f5fd0bb260510d7f754287d74a70275abc2dabce
|
|
4
|
+
data.tar.gz: fe52ddaa831a711b7415c350205a2662e833de2c4a6d58b8b6539170645bd218
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f79ffb02f15e691a1266c3421043a5ee95f3bd35715687137f139b291c490ee87a93351e0526faa0f29c73deba80ba41740f87d0fc9d50793a6b6d4101c7b116
|
|
7
|
+
data.tar.gz: 3e9276ffc9e2a2ae07f4a11054dcb484a324dc18e28a4badaa06df7454db36cfdbfbf38b95aec40c01a15a40cde56fb6cd9868780e50994fc2f554caf86e209a
|
|
@@ -32,7 +32,7 @@ module VCR
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
def erb_variables
|
|
35
|
-
@erb if @erb.is_a?(Hash)
|
|
35
|
+
@erb if @erb.is_a?(Hash) && !@erb.empty?
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
def template
|
|
@@ -40,7 +40,9 @@ module VCR
|
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
@@struct_cache = Hash.new do |hash, attributes|
|
|
43
|
-
|
|
43
|
+
attributes = attributes.map(&:to_sym)
|
|
44
|
+
hash[attributes] = Struct.new(*attributes) unless hash.key?(attributes)
|
|
45
|
+
hash[attributes]
|
|
44
46
|
end
|
|
45
47
|
|
|
46
48
|
def variables_object
|
|
@@ -22,21 +22,26 @@ module VCR
|
|
|
22
22
|
@parent_list = parent_list
|
|
23
23
|
@used_interactions = []
|
|
24
24
|
@log_prefix = log_prefix
|
|
25
|
+
@mutex = Mutex.new
|
|
25
26
|
|
|
26
27
|
interaction_summaries = interactions.map { |i| "#{request_summary(i.request)} => #{response_summary(i.response)}" }
|
|
27
28
|
log "Initialized HTTPInteractionList with request matchers #{request_matchers.inspect} and #{interactions.size} interaction(s): { #{interaction_summaries.join(', ')} }", 1
|
|
28
29
|
end
|
|
29
30
|
|
|
30
31
|
def response_for(request)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
32
|
+
# Without this mutex, under threaded access, the wrong response may be removed
|
|
33
|
+
# out of the (remaining) interactions list (and other problems).
|
|
34
|
+
@mutex.synchronize do
|
|
35
|
+
if index = matching_interaction_index_for(request)
|
|
36
|
+
interaction = @interactions.delete_at(index)
|
|
37
|
+
@used_interactions.unshift interaction
|
|
38
|
+
log "Found matching interaction for #{request_summary(request)} at index #{index}: #{response_summary(interaction.response)}", 1
|
|
39
|
+
interaction.response
|
|
40
|
+
elsif interaction = matching_used_interaction_for(request)
|
|
41
|
+
interaction.response
|
|
42
|
+
else
|
|
43
|
+
@parent_list.response_for(request)
|
|
44
|
+
end
|
|
40
45
|
end
|
|
41
46
|
end
|
|
42
47
|
|
|
@@ -45,17 +45,16 @@ module VCR
|
|
|
45
45
|
"recorded_with" => "VCR #{VCR.version}"
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
def hash.each
|
|
49
|
-
yield 'http_interactions', self['http_interactions']
|
|
50
|
-
yield 'recorded_with', self['recorded_with']
|
|
51
|
-
end
|
|
52
|
-
|
|
53
48
|
File.open(cassette, 'w') { |f| f.write ::YAML.dump(hash) }
|
|
54
49
|
@out.puts " - Migrated #{relative_casssette_name(cassette)}"
|
|
55
50
|
end
|
|
56
51
|
|
|
57
52
|
def load_yaml(cassette)
|
|
58
|
-
::YAML.
|
|
53
|
+
if ::YAML.respond_to?(:unsafe_load_file)
|
|
54
|
+
::YAML.unsafe_load_file(cassette)
|
|
55
|
+
else
|
|
56
|
+
::YAML.load_file(cassette)
|
|
57
|
+
end
|
|
59
58
|
rescue *@yaml_load_errors
|
|
60
59
|
return nil
|
|
61
60
|
end
|
|
@@ -55,7 +55,15 @@ module VCR
|
|
|
55
55
|
file_extension = '.' + parts.pop
|
|
56
56
|
end
|
|
57
57
|
|
|
58
|
-
parts.join('.').gsub(/[
|
|
58
|
+
file_name = parts.join('.').gsub(/[^[:word:]\-\/]+/, '_') + file_extension.to_s
|
|
59
|
+
file_name.downcase! if downcase_cassette_names?
|
|
60
|
+
file_name
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def downcase_cassette_names?
|
|
64
|
+
!!VCR.configuration
|
|
65
|
+
.default_cassette_options
|
|
66
|
+
.dig(:persister_options, :downcase_cassette_names)
|
|
59
67
|
end
|
|
60
68
|
end
|
|
61
69
|
end
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
require '
|
|
1
|
+
require 'json'
|
|
2
2
|
|
|
3
3
|
module VCR
|
|
4
4
|
class Cassette
|
|
5
5
|
class Serializers
|
|
6
|
-
# The JSON serializer.
|
|
6
|
+
# The JSON serializer.
|
|
7
7
|
#
|
|
8
8
|
# @see Psych
|
|
9
9
|
# @see Syck
|
|
@@ -11,10 +11,14 @@ module VCR
|
|
|
11
11
|
module JSON
|
|
12
12
|
extend self
|
|
13
13
|
extend EncodingErrorHandling
|
|
14
|
+
extend SyntaxErrorHandling
|
|
14
15
|
|
|
15
16
|
# @private
|
|
16
|
-
ENCODING_ERRORS = [
|
|
17
|
-
ENCODING_ERRORS <<
|
|
17
|
+
ENCODING_ERRORS = [ArgumentError]
|
|
18
|
+
ENCODING_ERRORS << ::JSON::GeneratorError
|
|
19
|
+
|
|
20
|
+
# @private
|
|
21
|
+
SYNTAX_ERRORS = [::JSON::ParserError]
|
|
18
22
|
|
|
19
23
|
# The file extension to use for this serializer.
|
|
20
24
|
#
|
|
@@ -23,23 +27,25 @@ module VCR
|
|
|
23
27
|
"json"
|
|
24
28
|
end
|
|
25
29
|
|
|
26
|
-
# Serializes the given hash using `
|
|
30
|
+
# Serializes the given hash using `JSON`.
|
|
27
31
|
#
|
|
28
32
|
# @param [Hash] hash the object to serialize
|
|
29
33
|
# @return [String] the JSON string
|
|
30
34
|
def serialize(hash)
|
|
31
35
|
handle_encoding_errors do
|
|
32
|
-
|
|
36
|
+
::JSON.pretty_generate(hash)
|
|
33
37
|
end
|
|
34
38
|
end
|
|
35
39
|
|
|
36
|
-
# Deserializes the given string using `
|
|
40
|
+
# Deserializes the given string using `JSON`.
|
|
37
41
|
#
|
|
38
42
|
# @param [String] string the JSON string
|
|
39
43
|
# @return [Hash] the deserialized object
|
|
40
44
|
def deserialize(string)
|
|
41
45
|
handle_encoding_errors do
|
|
42
|
-
|
|
46
|
+
handle_syntax_errors do
|
|
47
|
+
::JSON.parse(string)
|
|
48
|
+
end
|
|
43
49
|
end
|
|
44
50
|
end
|
|
45
51
|
end
|
|
@@ -11,10 +11,14 @@ module VCR
|
|
|
11
11
|
module Psych
|
|
12
12
|
extend self
|
|
13
13
|
extend EncodingErrorHandling
|
|
14
|
+
extend SyntaxErrorHandling
|
|
14
15
|
|
|
15
16
|
# @private
|
|
16
17
|
ENCODING_ERRORS = [ArgumentError]
|
|
17
18
|
|
|
19
|
+
# @private
|
|
20
|
+
SYNTAX_ERRORS = [::Psych::SyntaxError]
|
|
21
|
+
|
|
18
22
|
# The file extension to use for this serializer.
|
|
19
23
|
#
|
|
20
24
|
# @return [String] "yml"
|
|
@@ -28,7 +32,9 @@ module VCR
|
|
|
28
32
|
# @return [String] the YAML string
|
|
29
33
|
def serialize(hash)
|
|
30
34
|
handle_encoding_errors do
|
|
31
|
-
::Psych.dump(hash)
|
|
35
|
+
result = ::Psych.dump(hash)
|
|
36
|
+
result.gsub!(": \n", ": null\n") # set canonical null value in order to avoid trailing whitespaces
|
|
37
|
+
result
|
|
32
38
|
end
|
|
33
39
|
end
|
|
34
40
|
|
|
@@ -38,7 +44,9 @@ module VCR
|
|
|
38
44
|
# @return [Hash] the deserialized object
|
|
39
45
|
def deserialize(string)
|
|
40
46
|
handle_encoding_errors do
|
|
41
|
-
|
|
47
|
+
handle_syntax_errors do
|
|
48
|
+
::Psych.load(string)
|
|
49
|
+
end
|
|
42
50
|
end
|
|
43
51
|
end
|
|
44
52
|
end
|
|
@@ -11,10 +11,14 @@ module VCR
|
|
|
11
11
|
module Syck
|
|
12
12
|
extend self
|
|
13
13
|
extend EncodingErrorHandling
|
|
14
|
+
extend SyntaxErrorHandling
|
|
14
15
|
|
|
15
16
|
# @private
|
|
16
17
|
ENCODING_ERRORS = [ArgumentError]
|
|
17
18
|
|
|
19
|
+
# @private
|
|
20
|
+
SYNTAX_ERRORS = [::Psych::SyntaxError]
|
|
21
|
+
|
|
18
22
|
# The file extension to use for this serializer.
|
|
19
23
|
#
|
|
20
24
|
# @return [String] "yml"
|
|
@@ -38,7 +42,9 @@ module VCR
|
|
|
38
42
|
# @return [Hash] the deserialized object
|
|
39
43
|
def deserialize(string)
|
|
40
44
|
handle_encoding_errors do
|
|
41
|
-
|
|
45
|
+
handle_syntax_errors do
|
|
46
|
+
using_syck { ::YAML.load(string) }
|
|
47
|
+
end
|
|
42
48
|
end
|
|
43
49
|
end
|
|
44
50
|
|
|
@@ -13,10 +13,14 @@ module VCR
|
|
|
13
13
|
module YAML
|
|
14
14
|
extend self
|
|
15
15
|
extend EncodingErrorHandling
|
|
16
|
+
extend SyntaxErrorHandling
|
|
16
17
|
|
|
17
18
|
# @private
|
|
18
19
|
ENCODING_ERRORS = [ArgumentError]
|
|
19
20
|
|
|
21
|
+
# @private
|
|
22
|
+
SYNTAX_ERRORS = [::Psych::SyntaxError]
|
|
23
|
+
|
|
20
24
|
# The file extension to use for this serializer.
|
|
21
25
|
#
|
|
22
26
|
# @return [String] "yml"
|
|
@@ -30,7 +34,9 @@ module VCR
|
|
|
30
34
|
# @return [String] the YAML string
|
|
31
35
|
def serialize(hash)
|
|
32
36
|
handle_encoding_errors do
|
|
33
|
-
::YAML.dump(hash)
|
|
37
|
+
result = ::YAML.dump(hash)
|
|
38
|
+
result.gsub!(": \n", ": null\n") # set canonical null value in order to avoid trailing whitespaces
|
|
39
|
+
result
|
|
34
40
|
end
|
|
35
41
|
end
|
|
36
42
|
|
|
@@ -40,7 +46,13 @@ module VCR
|
|
|
40
46
|
# @return [Hash] the deserialized object
|
|
41
47
|
def deserialize(string)
|
|
42
48
|
handle_encoding_errors do
|
|
43
|
-
|
|
49
|
+
handle_syntax_errors do
|
|
50
|
+
if ::YAML.respond_to?(:unsafe_load)
|
|
51
|
+
::YAML.unsafe_load(string)
|
|
52
|
+
else
|
|
53
|
+
::YAML.load(string)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
44
56
|
end
|
|
45
57
|
end
|
|
46
58
|
end
|
|
@@ -54,6 +54,16 @@ module VCR
|
|
|
54
54
|
raise
|
|
55
55
|
end
|
|
56
56
|
end
|
|
57
|
+
|
|
58
|
+
# @private
|
|
59
|
+
module SyntaxErrorHandling
|
|
60
|
+
def handle_syntax_errors
|
|
61
|
+
yield
|
|
62
|
+
rescue *self::SYNTAX_ERRORS => e
|
|
63
|
+
e.message << "\nNote: This is a VCR cassette. If it is using ERB, you may have forgotten to pass the `:erb` option to `use_cassette`."
|
|
64
|
+
raise
|
|
65
|
+
end
|
|
66
|
+
end
|
|
57
67
|
end
|
|
58
68
|
end
|
|
59
69
|
|
data/lib/vcr/cassette.rb
CHANGED
|
@@ -24,6 +24,13 @@ module VCR
|
|
|
24
24
|
# plays them back, or does both.
|
|
25
25
|
attr_reader :record_mode
|
|
26
26
|
|
|
27
|
+
# @return [Boolean] The cassette's record_on_error mode. When the code that uses the cassette
|
|
28
|
+
# raises an error (for example a test failure) and record_on_error is set to false, no
|
|
29
|
+
# cassette will be recorded. This is useful when you are TDD'ing an API integration: when
|
|
30
|
+
# an error is raised that often means your request is invalid, so you don't want the cassette
|
|
31
|
+
# to be recorded.
|
|
32
|
+
attr_reader :record_on_error
|
|
33
|
+
|
|
27
34
|
# @return [Array<Symbol, #call>] List of request matchers. Used to find a response from an
|
|
28
35
|
# existing HTTP interaction to play back.
|
|
29
36
|
attr_reader :match_requests_on
|
|
@@ -36,6 +43,12 @@ module VCR
|
|
|
36
43
|
# @return [Integer, nil] How frequently (in seconds) the cassette should be re-recorded.
|
|
37
44
|
attr_reader :re_record_interval
|
|
38
45
|
|
|
46
|
+
# @return [Boolean, nil] Should outdated interactions be recorded back to file
|
|
47
|
+
attr_reader :clean_outdated_http_interactions
|
|
48
|
+
|
|
49
|
+
# @return [Boolean] Should unused requests be dropped from the cassette?
|
|
50
|
+
attr_reader :drop_unused_requests
|
|
51
|
+
|
|
39
52
|
# @return [Array<Symbol>] If set, {VCR::Configuration#before_record} and
|
|
40
53
|
# {VCR::Configuration#before_playback} hooks with a corresponding tag will apply.
|
|
41
54
|
attr_reader :tags
|
|
@@ -45,6 +58,7 @@ module VCR
|
|
|
45
58
|
def initialize(name, options = {})
|
|
46
59
|
@name = name
|
|
47
60
|
@options = VCR.configuration.default_cassette_options.merge(options)
|
|
61
|
+
@mutex = Mutex.new
|
|
48
62
|
|
|
49
63
|
assert_valid_options!
|
|
50
64
|
extract_options
|
|
@@ -62,21 +76,40 @@ module VCR
|
|
|
62
76
|
# @param (see VCR#eject_casssette)
|
|
63
77
|
# @see VCR#eject_cassette
|
|
64
78
|
def eject(options = {})
|
|
65
|
-
write_recorded_interactions_to_disk
|
|
79
|
+
write_recorded_interactions_to_disk if should_write_recorded_interactions_to_disk?
|
|
66
80
|
|
|
67
81
|
if should_assert_no_unused_interactions? && !options[:skip_no_unused_interactions_assertion]
|
|
68
82
|
http_interactions.assert_no_unused_interactions!
|
|
69
83
|
end
|
|
70
84
|
end
|
|
71
85
|
|
|
86
|
+
# @private
|
|
87
|
+
def run_failed!
|
|
88
|
+
@run_failed = true
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# @private
|
|
92
|
+
def run_failed?
|
|
93
|
+
@run_failed = false unless defined?(@run_failed)
|
|
94
|
+
@run_failed
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def should_write_recorded_interactions_to_disk?
|
|
98
|
+
!run_failed? || record_on_error
|
|
99
|
+
end
|
|
100
|
+
|
|
72
101
|
# @private
|
|
73
102
|
def http_interactions
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
@
|
|
78
|
-
|
|
79
|
-
|
|
103
|
+
# Without this mutex, under threaded access, an HTTPInteractionList will overwrite
|
|
104
|
+
# the first.
|
|
105
|
+
@mutex.synchronize do
|
|
106
|
+
@http_interactions ||= HTTPInteractionList.new \
|
|
107
|
+
should_stub_requests? ? previously_recorded_interactions : [],
|
|
108
|
+
match_requests_on,
|
|
109
|
+
@allow_playback_repeats,
|
|
110
|
+
@parent_list,
|
|
111
|
+
log_prefix
|
|
112
|
+
end
|
|
80
113
|
end
|
|
81
114
|
|
|
82
115
|
# @private
|
|
@@ -143,10 +176,11 @@ module VCR
|
|
|
143
176
|
|
|
144
177
|
def assert_valid_options!
|
|
145
178
|
invalid_options = @options.keys - [
|
|
146
|
-
:record, :erb, :match_requests_on, :re_record_interval, :tag, :tags,
|
|
179
|
+
:record, :record_on_error, :erb, :match_requests_on, :re_record_interval, :tag, :tags,
|
|
147
180
|
:update_content_length_header, :allow_playback_repeats, :allow_unused_http_interactions,
|
|
148
181
|
:exclusive, :serialize_with, :preserve_exact_body_bytes, :decode_compressed_response,
|
|
149
|
-
:persist_with
|
|
182
|
+
:recompress_response, :persist_with, :persister_options, :clean_outdated_http_interactions,
|
|
183
|
+
:drop_unused_requests
|
|
150
184
|
]
|
|
151
185
|
|
|
152
186
|
if invalid_options.size > 0
|
|
@@ -155,24 +189,23 @@ module VCR
|
|
|
155
189
|
end
|
|
156
190
|
|
|
157
191
|
def extract_options
|
|
158
|
-
[:erb, :match_requests_on, :re_record_interval,
|
|
159
|
-
:allow_playback_repeats, :allow_unused_http_interactions, :exclusive].each do |name|
|
|
192
|
+
[:record_on_error, :erb, :match_requests_on, :re_record_interval, :clean_outdated_http_interactions,
|
|
193
|
+
:allow_playback_repeats, :allow_unused_http_interactions, :exclusive, :drop_unused_requests].each do |name|
|
|
160
194
|
instance_variable_set("@#{name}", @options[name])
|
|
161
195
|
end
|
|
162
196
|
|
|
163
197
|
assign_tags
|
|
164
198
|
|
|
165
|
-
@record_mode = @options[:record]
|
|
166
199
|
@serializer = VCR.cassette_serializers[@options[:serialize_with]]
|
|
167
200
|
@persister = VCR.cassette_persisters[@options[:persist_with]]
|
|
168
|
-
@record_mode = :all
|
|
201
|
+
@record_mode = should_re_record?(@options[:record]) ? :all : @options[:record]
|
|
169
202
|
@parent_list = @exclusive ? HTTPInteractionList::NullList : VCR.http_interactions
|
|
170
203
|
end
|
|
171
204
|
|
|
172
205
|
def assign_tags
|
|
173
206
|
@tags = Array(@options.fetch(:tags) { @options[:tag] })
|
|
174
207
|
|
|
175
|
-
[:update_content_length_header, :preserve_exact_body_bytes, :decode_compressed_response].each do |tag|
|
|
208
|
+
[:update_content_length_header, :preserve_exact_body_bytes, :decode_compressed_response, :recompress_response].each do |tag|
|
|
176
209
|
@tags << tag if @options[tag]
|
|
177
210
|
end
|
|
178
211
|
end
|
|
@@ -201,9 +234,10 @@ module VCR
|
|
|
201
234
|
end
|
|
202
235
|
end
|
|
203
236
|
|
|
204
|
-
def should_re_record?
|
|
237
|
+
def should_re_record?(record_mode)
|
|
205
238
|
return false unless @re_record_interval
|
|
206
239
|
return false unless originally_recorded_at
|
|
240
|
+
return false if record_mode == :none
|
|
207
241
|
|
|
208
242
|
now = Time.now
|
|
209
243
|
|
|
@@ -229,6 +263,10 @@ module VCR
|
|
|
229
263
|
record_mode == :all
|
|
230
264
|
end
|
|
231
265
|
|
|
266
|
+
def should_remove_unused_interactions?
|
|
267
|
+
@drop_unused_requests
|
|
268
|
+
end
|
|
269
|
+
|
|
232
270
|
def should_assert_no_unused_interactions?
|
|
233
271
|
!(@allow_unused_http_interactions || $!)
|
|
234
272
|
end
|
|
@@ -247,7 +285,16 @@ module VCR
|
|
|
247
285
|
end
|
|
248
286
|
end
|
|
249
287
|
|
|
250
|
-
|
|
288
|
+
if should_remove_unused_interactions?
|
|
289
|
+
new_recorded_interactions
|
|
290
|
+
else
|
|
291
|
+
up_to_date_interactions(old_interactions) + new_recorded_interactions
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
def up_to_date_interactions(interactions)
|
|
296
|
+
return interactions unless clean_outdated_http_interactions && re_record_interval
|
|
297
|
+
interactions.take_while { |x| x[:recorded_at] > Time.now - re_record_interval }
|
|
251
298
|
end
|
|
252
299
|
|
|
253
300
|
def interactions_to_record
|
data/lib/vcr/configuration.rb
CHANGED
|
@@ -54,16 +54,14 @@ module VCR
|
|
|
54
54
|
#
|
|
55
55
|
# @example
|
|
56
56
|
# VCR.configure do |c|
|
|
57
|
-
# c.hook_into :
|
|
57
|
+
# c.hook_into :webmock, :typhoeus
|
|
58
58
|
# end
|
|
59
59
|
#
|
|
60
60
|
# @param hooks [Array<Symbol>] List of libraries. Valid values are
|
|
61
|
-
# `:
|
|
61
|
+
# `:webmock`, `:typhoeus`, `:excon` and `:faraday`.
|
|
62
62
|
# @raise [ArgumentError] when given an unsupported library name.
|
|
63
63
|
# @raise [VCR::Errors::LibraryVersionTooLowError] when the version
|
|
64
64
|
# of a library you are using is too low for VCR to support.
|
|
65
|
-
# @note `:fakeweb` and `:webmock` cannot both be used since they both monkey patch
|
|
66
|
-
# `Net::HTTP`. Otherwise, you can use any combination of these.
|
|
67
65
|
def hook_into(*hooks)
|
|
68
66
|
hooks.each { |a| load_library_hook(a) }
|
|
69
67
|
invoke_hook(:after_library_hooks_loaded)
|
|
@@ -79,6 +77,15 @@ module VCR
|
|
|
79
77
|
end
|
|
80
78
|
alias ignore_host ignore_hosts
|
|
81
79
|
|
|
80
|
+
# Specifies host(s) that VCR should stop ignoring.
|
|
81
|
+
#
|
|
82
|
+
# @param hosts [Array<String>] List of hosts to unignore
|
|
83
|
+
# @see #ignore_hosts
|
|
84
|
+
def unignore_hosts(*hosts)
|
|
85
|
+
VCR.request_ignorer.unignore_hosts(*hosts)
|
|
86
|
+
end
|
|
87
|
+
alias unignore_host unignore_hosts
|
|
88
|
+
|
|
82
89
|
# Sets whether or not VCR should ignore localhost requests.
|
|
83
90
|
#
|
|
84
91
|
# @param value [Boolean] the value to set
|
|
@@ -224,7 +231,7 @@ module VCR
|
|
|
224
231
|
|
|
225
232
|
before_playback(tag) do |interaction|
|
|
226
233
|
orig_text = call_block(block, interaction)
|
|
227
|
-
log "before_playback: replacing #{
|
|
234
|
+
log "before_playback: replacing #{orig_text.inspect} with #{placeholder.inspect}"
|
|
228
235
|
interaction.filter!(placeholder, orig_text)
|
|
229
236
|
end
|
|
230
237
|
end
|
|
@@ -485,10 +492,13 @@ module VCR
|
|
|
485
492
|
@rspec_metadata_configured = false
|
|
486
493
|
@default_cassette_options = {
|
|
487
494
|
:record => :once,
|
|
495
|
+
:record_on_error => true,
|
|
488
496
|
:match_requests_on => RequestMatcherRegistry::DEFAULT_MATCHERS,
|
|
489
497
|
:allow_unused_http_interactions => true,
|
|
498
|
+
:drop_unused_requests => false,
|
|
490
499
|
:serialize_with => :yaml,
|
|
491
|
-
:persist_with => :file_system
|
|
500
|
+
:persist_with => :file_system,
|
|
501
|
+
:persister_options => {}
|
|
492
502
|
}
|
|
493
503
|
|
|
494
504
|
self.uri_parser = URI
|
|
@@ -502,7 +512,7 @@ module VCR
|
|
|
502
512
|
file = "vcr/library_hooks/#{hook}"
|
|
503
513
|
require file
|
|
504
514
|
rescue LoadError => e
|
|
505
|
-
raise e unless e.message.include?(file) # in case
|
|
515
|
+
raise e unless e.message.include?(file) # in case WebMock itself is not available
|
|
506
516
|
raise ArgumentError.new("#{hook.inspect} is not a supported VCR HTTP library hook.")
|
|
507
517
|
end
|
|
508
518
|
|
|
@@ -552,6 +562,10 @@ module VCR
|
|
|
552
562
|
end
|
|
553
563
|
|
|
554
564
|
def register_built_in_hooks
|
|
565
|
+
before_playback(:recompress_response) do |interaction|
|
|
566
|
+
interaction.response.recompress if interaction.response.vcr_decompressed?
|
|
567
|
+
end
|
|
568
|
+
|
|
555
569
|
before_playback(:update_content_length_header) do |interaction|
|
|
556
570
|
interaction.response.update_content_length_header
|
|
557
571
|
end
|
|
@@ -573,4 +587,3 @@ module VCR
|
|
|
573
587
|
define_hook :after_library_hooks_loaded
|
|
574
588
|
end
|
|
575
589
|
end
|
|
576
|
-
|
data/lib/vcr/deprecations.rb
CHANGED
|
@@ -43,67 +43,5 @@ module VCR
|
|
|
43
43
|
end
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
|
-
|
|
47
|
-
module RSpec
|
|
48
|
-
# Contains macro methods to assist with VCR usage. These methods are
|
|
49
|
-
# intended to be used directly in an RSpec example group. To make these
|
|
50
|
-
# available in your RSpec example groups, extend the module in an individual
|
|
51
|
-
# example group, or configure RSpec to extend the module in all example groups.
|
|
52
|
-
#
|
|
53
|
-
# @example
|
|
54
|
-
# RSpec.configure do |c|
|
|
55
|
-
# c.extend VCR::RSpec::Macros
|
|
56
|
-
# end
|
|
57
|
-
#
|
|
58
|
-
module Macros
|
|
59
|
-
def self.extended(base)
|
|
60
|
-
Kernel.warn "WARNING: VCR::RSpec::Macros is deprecated. Use RSpec metadata options instead `:vcr => vcr_options`"
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
# Sets up a `before` and `after` hook that will insert and eject a
|
|
64
|
-
# cassette, respectively.
|
|
65
|
-
#
|
|
66
|
-
# @example
|
|
67
|
-
# describe "Some API Client" do
|
|
68
|
-
# use_vcr_cassette "some_api", :record => :new_episodes
|
|
69
|
-
# end
|
|
70
|
-
#
|
|
71
|
-
# @param [(optional) String] name the cassette name; it will be inferred by the example
|
|
72
|
-
# group descriptions if not given.
|
|
73
|
-
# @param [(optional) Hash] options the cassette options
|
|
74
|
-
# @deprecated Use RSpec metadata options
|
|
75
|
-
def use_vcr_cassette(*args)
|
|
76
|
-
options = args.last.is_a?(Hash) ? args.pop : {}
|
|
77
|
-
name = args.first || infer_cassette_name
|
|
78
|
-
|
|
79
|
-
before(:each) do
|
|
80
|
-
VCR.insert_cassette(name, options)
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
after(:each) do
|
|
84
|
-
VCR.eject_cassette
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
private
|
|
89
|
-
|
|
90
|
-
def infer_cassette_name
|
|
91
|
-
# RSpec 1 exposes #description_parts; use that if its available
|
|
92
|
-
return description_parts.join("/") if respond_to?(:description_parts)
|
|
93
|
-
|
|
94
|
-
# Otherwise use RSpec 2/3 metadata...
|
|
95
|
-
group_descriptions = []
|
|
96
|
-
klass = self
|
|
97
|
-
|
|
98
|
-
while klass.respond_to?(:metadata) && klass.metadata
|
|
99
|
-
group_descriptions << klass.metadata[:description] ||
|
|
100
|
-
klass.metadata[:example_group][:description]
|
|
101
|
-
klass = klass.superclass
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
group_descriptions.compact.reverse.join('/')
|
|
105
|
-
end
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
46
|
end
|
|
109
47
|
|
data/lib/vcr/errors.rb
CHANGED
|
@@ -88,18 +88,7 @@ module VCR
|
|
|
88
88
|
end
|
|
89
89
|
|
|
90
90
|
def current_cassettes
|
|
91
|
-
@cassettes ||=
|
|
92
|
-
cassettes = VCR.cassettes.to_a.reverse
|
|
93
|
-
|
|
94
|
-
begin
|
|
95
|
-
loop do
|
|
96
|
-
break unless VCR.eject_cassette
|
|
97
|
-
end
|
|
98
|
-
rescue EjectLinkedCassetteError
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
cassettes
|
|
102
|
-
end
|
|
91
|
+
@cassettes ||= VCR.cassettes.to_a.reverse
|
|
103
92
|
end
|
|
104
93
|
|
|
105
94
|
def request_description
|
|
@@ -107,6 +96,10 @@ module VCR
|
|
|
107
96
|
|
|
108
97
|
lines << " #{request.method.to_s.upcase} #{request.uri}"
|
|
109
98
|
|
|
99
|
+
if match_request_on_headers?
|
|
100
|
+
lines << " Headers:\n#{formatted_headers}"
|
|
101
|
+
end
|
|
102
|
+
|
|
110
103
|
if match_request_on_body?
|
|
111
104
|
lines << " Body: #{request.body}"
|
|
112
105
|
end
|
|
@@ -114,6 +107,10 @@ module VCR
|
|
|
114
107
|
lines.join("\n")
|
|
115
108
|
end
|
|
116
109
|
|
|
110
|
+
def match_request_on_headers?
|
|
111
|
+
current_matchers.include?(:headers)
|
|
112
|
+
end
|
|
113
|
+
|
|
117
114
|
def match_request_on_body?
|
|
118
115
|
current_matchers.include?(:body)
|
|
119
116
|
end
|
|
@@ -128,6 +125,14 @@ module VCR
|
|
|
128
125
|
end
|
|
129
126
|
end
|
|
130
127
|
|
|
128
|
+
def formatted_headers
|
|
129
|
+
request.headers.flat_map do |header, values|
|
|
130
|
+
values.map do |val|
|
|
131
|
+
" #{header}: #{val.inspect}"
|
|
132
|
+
end
|
|
133
|
+
end.join("\n")
|
|
134
|
+
end
|
|
135
|
+
|
|
131
136
|
def cassettes_description
|
|
132
137
|
if current_cassettes.size > 0
|
|
133
138
|
[cassettes_list << "\n",
|