vcr 2.5.0 → 2.6.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 +8 -8
- data/.travis.yml +0 -3
- data/CHANGELOG.md +32 -3
- data/Gemfile +33 -0
- data/Gemfile.lock +99 -119
- data/README.md +19 -7
- data/Rakefile +5 -9
- data/benchmarks/null_logging.rb +62 -0
- data/features/.nav +0 -1
- data/features/about_these_examples.md +1 -2
- data/features/cassettes/allow_unused_http_interactions.feature +15 -1
- data/features/cassettes/decompress.feature +6 -2
- data/features/cassettes/format.feature +20 -12
- data/features/cassettes/freezing_time.feature +68 -0
- data/features/configuration/cassette_library_dir.feature +5 -0
- data/features/configuration/preserve_exact_body_bytes.feature +5 -0
- data/features/configuration/uri_parser.feature +2 -4
- data/features/http_libraries/net_http.feature +1 -1
- data/features/request_matching/headers.feature +0 -1
- data/features/step_definitions/cli_steps.rb +1 -4
- data/features/test_frameworks/cucumber.feature +59 -0
- data/features/test_frameworks/rspec_metadata.feature +59 -1
- data/gemfiles/typhoeus_old.gemfile +19 -0
- data/gemfiles/typhoeus_old.gemfile.lock +84 -86
- data/lib/vcr.rb +12 -3
- data/lib/vcr/cassette.rb +32 -11
- data/lib/vcr/cassette/http_interaction_list.rb +3 -2
- data/lib/vcr/cassette/migrator.rb +1 -0
- data/lib/vcr/cassette/serializers/json.rb +1 -1
- data/lib/vcr/configuration.rb +17 -9
- data/lib/vcr/library_hooks/typhoeus.rb +3 -2
- data/lib/vcr/library_hooks/webmock.rb +1 -1
- data/lib/vcr/middleware/excon.rb +13 -1
- data/lib/vcr/middleware/faraday.rb +1 -0
- data/lib/vcr/request_handler.rb +1 -1
- data/lib/vcr/structs.rb +19 -4
- data/lib/vcr/test_frameworks/cucumber.rb +2 -2
- data/lib/vcr/test_frameworks/rspec.rb +10 -2
- data/lib/vcr/util/logger.rb +41 -7
- data/lib/vcr/version.rb +1 -1
- data/script/ci.sh +8 -1
- data/spec/acceptance/threading_spec.rb +6 -0
- data/spec/capture_warnings.rb +9 -1
- data/spec/spec_helper.rb +6 -2
- data/spec/support/configuration_stubbing.rb +8 -0
- data/spec/support/http_library_adapters.rb +1 -1
- data/spec/support/limited_uri.rb +1 -0
- data/spec/support/shared_example_groups/excon.rb +23 -1
- data/spec/support/shared_example_groups/hook_into_http_library.rb +12 -12
- data/spec/support/shared_example_groups/request_hooks.rb +1 -1
- data/spec/support/sinatra_app.rb +9 -0
- data/spec/support/vcr_localhost_server.rb +4 -25
- data/spec/support/vcr_stub_helpers.rb +1 -1
- data/spec/vcr/cassette/http_interaction_list_spec.rb +41 -14
- data/spec/vcr/cassette/migrator_spec.rb +1 -1
- data/spec/vcr/cassette/persisters_spec.rb +2 -2
- data/spec/vcr/cassette/serializers_spec.rb +13 -4
- data/spec/vcr/cassette_spec.rb +107 -58
- data/spec/vcr/configuration_spec.rb +23 -23
- data/spec/vcr/deprecations_spec.rb +9 -9
- data/spec/vcr/errors_spec.rb +6 -6
- data/spec/vcr/library_hooks/excon_spec.rb +15 -10
- data/spec/vcr/library_hooks/fakeweb_spec.rb +8 -8
- data/spec/vcr/library_hooks/faraday_spec.rb +1 -1
- data/spec/vcr/library_hooks/typhoeus_0.4_spec.rb +2 -2
- data/spec/vcr/library_hooks/typhoeus_spec.rb +68 -9
- data/spec/vcr/library_hooks/webmock_spec.rb +6 -10
- data/spec/vcr/middleware/faraday_spec.rb +33 -5
- data/spec/vcr/middleware/rack_spec.rb +2 -2
- data/spec/vcr/request_matcher_registry_spec.rb +11 -6
- data/spec/vcr/structs_spec.rb +114 -47
- data/spec/vcr/test_frameworks/cucumber_spec.rb +4 -4
- data/spec/vcr/util/hooks_spec.rb +2 -2
- data/spec/vcr/util/internet_connection_spec.rb +3 -3
- data/spec/vcr/util/version_checker_spec.rb +4 -4
- data/spec/vcr_spec.rb +22 -16
- data/vcr.gemspec +2 -31
- metadata +9 -328
- data/features/test_frameworks/shoulda.feature +0 -64
@@ -2,7 +2,7 @@ module VCR
|
|
2
2
|
class Cassette
|
3
3
|
# @private
|
4
4
|
class HTTPInteractionList
|
5
|
-
include Logger
|
5
|
+
include Logger::Mixin
|
6
6
|
|
7
7
|
# @private
|
8
8
|
module NullList
|
@@ -59,9 +59,10 @@ module VCR
|
|
59
59
|
# @raise [VCR::Errors::UnusedHTTPInteractionError] if not all interactions were played back.
|
60
60
|
def assert_no_unused_interactions!
|
61
61
|
return unless has_unused_interactions?
|
62
|
+
logger = Logger.new(nil)
|
62
63
|
|
63
64
|
descriptions = @interactions.map do |i|
|
64
|
-
" - #{request_summary(i.request)} => #{response_summary(i.response)}"
|
65
|
+
" - #{logger.request_summary(i.request, @request_matchers)} => #{logger.response_summary(i.response)}"
|
65
66
|
end.join("\n")
|
66
67
|
|
67
68
|
raise Errors::UnusedHTTPInteractionError, "There are unused HTTP interactions left in the cassette:\n#{descriptions}"
|
@@ -13,7 +13,7 @@ module VCR
|
|
13
13
|
extend EncodingErrorHandling
|
14
14
|
|
15
15
|
# @private
|
16
|
-
ENCODING_ERRORS = [MultiJson::DecodeError]
|
16
|
+
ENCODING_ERRORS = [MultiJson::DecodeError, ArgumentError]
|
17
17
|
ENCODING_ERRORS << EncodingError if defined?(EncodingError)
|
18
18
|
|
19
19
|
# The file extension to use for this serializer.
|
data/lib/vcr/configuration.rb
CHANGED
@@ -7,7 +7,7 @@ module VCR
|
|
7
7
|
class Configuration
|
8
8
|
include Hooks
|
9
9
|
include VariableArgsBlockCaller
|
10
|
-
include Logger
|
10
|
+
include Logger::Mixin
|
11
11
|
|
12
12
|
# Gets the directory to read cassettes from and write cassettes to.
|
13
13
|
#
|
@@ -430,7 +430,21 @@ module VCR
|
|
430
430
|
# VCR.configure do |c|
|
431
431
|
# c.debug_logger = File.open('vcr.log', 'w')
|
432
432
|
# end
|
433
|
-
|
433
|
+
attr_reader :debug_logger
|
434
|
+
# @private (documented above)
|
435
|
+
def debug_logger=(value)
|
436
|
+
@debug_logger = value
|
437
|
+
|
438
|
+
if value
|
439
|
+
@logger = Logger.new(value)
|
440
|
+
else
|
441
|
+
@logger = Logger::Null
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
# @private
|
446
|
+
# Logger object that provides logging APIs and helper methods.
|
447
|
+
attr_reader :logger
|
434
448
|
|
435
449
|
# Sets a callback that determines whether or not to base64 encode
|
436
450
|
# the bytes of a request or response body during serialization in
|
@@ -479,7 +493,7 @@ module VCR
|
|
479
493
|
|
480
494
|
self.uri_parser = URI
|
481
495
|
self.query_parser = CGI.method(:parse)
|
482
|
-
self.debug_logger =
|
496
|
+
self.debug_logger = nil
|
483
497
|
|
484
498
|
register_built_in_hooks
|
485
499
|
end
|
@@ -537,11 +551,5 @@ module VCR
|
|
537
551
|
# @private
|
538
552
|
define_hook :after_library_hooks_loaded
|
539
553
|
end
|
540
|
-
|
541
|
-
# @private
|
542
|
-
module NullDebugLogger
|
543
|
-
extend self
|
544
|
-
def puts(*); end
|
545
|
-
end
|
546
554
|
end
|
547
555
|
|
@@ -50,7 +50,7 @@ else
|
|
50
50
|
:status_message => stubbed_response.status.message,
|
51
51
|
:headers => stubbed_response_headers,
|
52
52
|
:body => stubbed_response.body,
|
53
|
-
:effective_url => request.url,
|
53
|
+
:effective_url => stubbed_response.adapter_metadata.fetch('effective_url', request.url),
|
54
54
|
:mock => true
|
55
55
|
end
|
56
56
|
|
@@ -69,7 +69,8 @@ else
|
|
69
69
|
VCR::ResponseStatus.new(response.code, response.status_message),
|
70
70
|
response.headers,
|
71
71
|
response.body,
|
72
|
-
response.http_version
|
72
|
+
response.http_version,
|
73
|
+
{ "effective_url" => response.effective_url }
|
73
74
|
end
|
74
75
|
|
75
76
|
::Typhoeus.on_complete do |response|
|
@@ -2,7 +2,7 @@ require 'vcr/util/version_checker'
|
|
2
2
|
require 'vcr/request_handler'
|
3
3
|
require 'webmock'
|
4
4
|
|
5
|
-
VCR::VersionChecker.new('WebMock', WebMock.version, '1.8.0', '1.
|
5
|
+
VCR::VersionChecker.new('WebMock', WebMock.version, '1.8.0', '1.13').check_version!
|
6
6
|
|
7
7
|
module VCR
|
8
8
|
class LibraryHooks
|
data/lib/vcr/middleware/excon.rb
CHANGED
@@ -2,7 +2,7 @@ require 'excon'
|
|
2
2
|
require 'vcr/request_handler'
|
3
3
|
require 'vcr/util/version_checker'
|
4
4
|
|
5
|
-
VCR::VersionChecker.new('Excon', Excon::VERSION, '0.22.0', '0.
|
5
|
+
VCR::VersionChecker.new('Excon', Excon::VERSION, '0.22.0', '0.26').check_version!
|
6
6
|
|
7
7
|
module VCR
|
8
8
|
# Contains middlewares for use with different libraries.
|
@@ -39,6 +39,7 @@ module VCR
|
|
39
39
|
|
40
40
|
# @private
|
41
41
|
def error_call(params)
|
42
|
+
@request_handler.ensure_response_body_can_be_read_for_error_case
|
42
43
|
@request_handler.after_request(params)
|
43
44
|
super
|
44
45
|
end
|
@@ -84,10 +85,21 @@ module VCR
|
|
84
85
|
invoke_after_request_hook(vcr_response)
|
85
86
|
end
|
86
87
|
|
88
|
+
def ensure_response_body_can_be_read_for_error_case
|
89
|
+
# Excon does not invoke the `:response_block` when an error
|
90
|
+
# has occurred, so we need to be sure to use the non-streaming
|
91
|
+
# body reader.
|
92
|
+
@response_body_reader = NonStreamingResponseBodyReader
|
93
|
+
end
|
94
|
+
|
87
95
|
attr_reader :request_params, :response_params, :response_body_reader
|
88
96
|
|
89
97
|
private
|
90
98
|
|
99
|
+
def externally_stubbed?
|
100
|
+
!!::Excon.stub_for(request_params)
|
101
|
+
end
|
102
|
+
|
91
103
|
def should_record?
|
92
104
|
@should_record
|
93
105
|
end
|
data/lib/vcr/request_handler.rb
CHANGED
data/lib/vcr/structs.rb
CHANGED
@@ -76,6 +76,11 @@ module VCR
|
|
76
76
|
private
|
77
77
|
|
78
78
|
def serializable_body
|
79
|
+
# Ensure it's just a string, and not a string with some
|
80
|
+
# extra state, as such strings serialize to YAML with
|
81
|
+
# all the extra state.
|
82
|
+
body = String.new(self.body.to_s)
|
83
|
+
|
79
84
|
if VCR.configuration.preserve_exact_body_bytes_for?(self)
|
80
85
|
base_body_hash(body).merge('base64_string' => Base64.encode64(body))
|
81
86
|
else
|
@@ -166,7 +171,7 @@ module VCR
|
|
166
171
|
module OrderedHashSerializer
|
167
172
|
def each
|
168
173
|
@ordered_keys.each do |key|
|
169
|
-
yield key, self[key]
|
174
|
+
yield key, self[key] if has_key?(key)
|
170
175
|
end
|
171
176
|
end
|
172
177
|
|
@@ -341,10 +346,16 @@ module VCR
|
|
341
346
|
# @attr [Hash{String => Array<String>}] headers the response headers
|
342
347
|
# @attr [String] body the response body
|
343
348
|
# @attr [nil, String] http_version the HTTP version
|
344
|
-
|
349
|
+
# @attr [Hash] adapter_metadata Additional metadata used by a specific VCR adapter.
|
350
|
+
class Response < Struct.new(:status, :headers, :body, :http_version, :adapter_metadata)
|
345
351
|
include Normalizers::Header
|
346
352
|
include Normalizers::Body
|
347
353
|
|
354
|
+
def initialize(*args)
|
355
|
+
super(*args)
|
356
|
+
self.adapter_metadata ||= {}
|
357
|
+
end
|
358
|
+
|
348
359
|
# Builds a serializable hash from the response data.
|
349
360
|
#
|
350
361
|
# @return [Hash] hash that represents this response
|
@@ -356,7 +367,10 @@ module VCR
|
|
356
367
|
'headers' => headers,
|
357
368
|
'body' => serializable_body,
|
358
369
|
'http_version' => http_version
|
359
|
-
}.tap
|
370
|
+
}.tap do |hash|
|
371
|
+
hash['adapter_metadata'] = adapter_metadata unless adapter_metadata.empty?
|
372
|
+
OrderedHashSerializer.apply_to(hash, members)
|
373
|
+
end
|
360
374
|
end
|
361
375
|
|
362
376
|
# Constructs a new instance from a hash.
|
@@ -367,7 +381,8 @@ module VCR
|
|
367
381
|
new ResponseStatus.from_hash(hash.fetch('status', {})),
|
368
382
|
hash['headers'],
|
369
383
|
body_from(hash['body']),
|
370
|
-
hash['http_version']
|
384
|
+
hash['http_version'],
|
385
|
+
hash['adapter_metadata']
|
371
386
|
end
|
372
387
|
|
373
388
|
# Updates the Content-Length response header so that it is
|
@@ -52,8 +52,8 @@ module VCR
|
|
52
52
|
VCR.insert_cassette(cassette_name, options)
|
53
53
|
end
|
54
54
|
|
55
|
-
@main_object.After(tag_name) do
|
56
|
-
VCR.eject_cassette
|
55
|
+
@main_object.After(tag_name) do |scenario|
|
56
|
+
VCR.eject_cassette(:skip_no_unused_interactions_assertion => scenario.failed?)
|
57
57
|
end
|
58
58
|
|
59
59
|
self.class.add_tag(tag_name)
|
@@ -17,14 +17,22 @@ module VCR
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
|
20
|
+
when_tagged_with_vcr = { :vcr => lambda { |v| !!v } }
|
21
|
+
|
22
|
+
config.before(:each, when_tagged_with_vcr) do |ex|
|
23
|
+
example = respond_to?(:example) ? self.example : ex
|
24
|
+
|
21
25
|
options = example.metadata[:vcr]
|
22
26
|
options = options.is_a?(Hash) ? options.dup : {} # in case it's just :vcr => true
|
23
27
|
|
24
28
|
cassette_name = options.delete(:cassette_name) ||
|
25
29
|
vcr_cassette_name_for[example.metadata]
|
30
|
+
VCR.insert_cassette(cassette_name, options)
|
31
|
+
end
|
26
32
|
|
27
|
-
|
33
|
+
config.after(:each, when_tagged_with_vcr) do |ex|
|
34
|
+
example = respond_to?(:example) ? self.example : ex
|
35
|
+
VCR.eject_cassette(:skip_no_unused_interactions_assertion => !!example.exception)
|
28
36
|
end
|
29
37
|
end
|
30
38
|
end
|
data/lib/vcr/util/logger.rb
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
module VCR
|
2
2
|
# @private
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
VCR.configuration.debug_logger.puts log_message
|
3
|
+
# Provides log message formatting helper methods.
|
4
|
+
class Logger
|
5
|
+
def initialize(stream)
|
6
|
+
@stream = stream
|
8
7
|
end
|
9
8
|
|
10
|
-
def log_prefix
|
11
|
-
''
|
9
|
+
def log(message, log_prefix, indentation_level = 0)
|
10
|
+
indentation = ' ' * indentation_level
|
11
|
+
log_message = indentation + log_prefix + message
|
12
|
+
@stream.puts log_message
|
12
13
|
end
|
13
14
|
|
14
15
|
def request_summary(request, request_matchers)
|
@@ -21,5 +22,38 @@ module VCR
|
|
21
22
|
def response_summary(response)
|
22
23
|
"[#{response.status.code} #{response.body[0, 80].inspect}]"
|
23
24
|
end
|
25
|
+
|
26
|
+
# @private
|
27
|
+
# A null-object version of the Logger. Used when
|
28
|
+
# a `debug_logger` has not been set.
|
29
|
+
#
|
30
|
+
# @note We used to use a null object for the `debug_logger` itself,
|
31
|
+
# but some users noticed a negative perf impact from having the
|
32
|
+
# logger formatting logic still executing in that case, so we
|
33
|
+
# moved the null object interface up a layer to here.
|
34
|
+
module Null
|
35
|
+
module_function
|
36
|
+
|
37
|
+
def log(*); end
|
38
|
+
def request_summary(*); end
|
39
|
+
def response_summary(*); end
|
40
|
+
end
|
41
|
+
|
42
|
+
# @private
|
43
|
+
# Provides common logger helper methods that simply delegate to
|
44
|
+
# the underlying logger object.
|
45
|
+
module Mixin
|
46
|
+
def log(message, indentation_level = 0)
|
47
|
+
VCR.configuration.logger.log(message, log_prefix, indentation_level)
|
48
|
+
end
|
49
|
+
|
50
|
+
def request_summary(*args)
|
51
|
+
VCR.configuration.logger.request_summary(*args)
|
52
|
+
end
|
53
|
+
|
54
|
+
def response_summary(*args)
|
55
|
+
VCR.configuration.logger.response_summary(*args)
|
56
|
+
end
|
57
|
+
end
|
24
58
|
end
|
25
59
|
end
|
data/lib/vcr/version.rb
CHANGED
data/script/ci.sh
CHANGED
@@ -1,6 +1,13 @@
|
|
1
1
|
# Kill the whole script on error
|
2
2
|
set -e -x
|
3
3
|
|
4
|
+
# idea taken from: http://blog.headius.com/2010/03/jruby-startup-time-tips.html
|
5
|
+
export JRUBY_OPTS='-X-C' # disable JIT since these processes are so short lived
|
6
|
+
|
7
|
+
# force jRuby to use client mode JVM or a compilation mode thats as close as possible,
|
8
|
+
# idea taken from https://github.com/jruby/jruby/wiki/Improving-startup-time
|
9
|
+
export JAVA_OPTS='-client -XX:+TieredCompilation -XX:TieredStopAtLevel=1'
|
10
|
+
|
4
11
|
echo "-------- Running Typhoeus 0.4 Specs ---------"
|
5
12
|
bundle install --gemfile=gemfiles/typhoeus_old.gemfile --without extras
|
6
13
|
BUNDLE_GEMFILE=gemfiles/typhoeus_old.gemfile bundle exec rspec spec/vcr/library_hooks/typhoeus_0.4_spec.rb --format progress --backtrace
|
@@ -10,7 +17,7 @@ git submodule init
|
|
10
17
|
git submodule update
|
11
18
|
|
12
19
|
echo "-------- Running Specs ---------"
|
13
|
-
bundle exec ruby -
|
20
|
+
bundle exec ruby -I./spec -r./spec/capture_warnings -rspec_helper -S rspec spec --format progress --backtrace
|
14
21
|
|
15
22
|
echo "-------- Running Cukes ---------"
|
16
23
|
bundle exec cucumber
|
@@ -2,6 +2,12 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe VCR do
|
4
4
|
context 'when used in a multithreaded environment', :with_monkey_patches => :excon do
|
5
|
+
def preload_yaml_serializer_to_avoid_circular_require_warning_race_condition
|
6
|
+
VCR.cassette_serializers[:yaml]
|
7
|
+
end
|
8
|
+
|
9
|
+
before { preload_yaml_serializer_to_avoid_circular_require_warning_race_condition }
|
10
|
+
|
5
11
|
def recorded_content_for(name)
|
6
12
|
VCR.cassette_persisters[:file_system]["#{name}.yml"].to_s
|
7
13
|
end
|
data/spec/capture_warnings.rb
CHANGED
@@ -1,17 +1,25 @@
|
|
1
1
|
require 'rubygems' if RUBY_VERSION =~ /^1\.8/
|
2
|
+
require 'bundler/setup'
|
2
3
|
require 'rspec/core'
|
3
4
|
require 'rspec/expectations'
|
4
5
|
require 'tempfile'
|
6
|
+
|
5
7
|
stderr_file = Tempfile.new("vcr.stderr")
|
6
|
-
$stderr.reopen(stderr_file.path)
|
7
8
|
current_dir = Dir.pwd
|
8
9
|
|
9
10
|
RSpec.configure do |config|
|
11
|
+
config.before(:suite) do
|
12
|
+
$stderr.reopen(stderr_file.path)
|
13
|
+
$VERBOSE = true
|
14
|
+
end
|
15
|
+
|
10
16
|
config.after(:suite) do
|
11
17
|
stderr_file.rewind
|
12
18
|
lines = stderr_file.read.split("\n").uniq
|
13
19
|
stderr_file.close!
|
14
20
|
|
21
|
+
$stderr.reopen(STDERR)
|
22
|
+
|
15
23
|
vcr_warnings, other_warnings = lines.partition { |line| line.include?(current_dir) }
|
16
24
|
|
17
25
|
# After upgrading to curb 0.8.1, I started to get a circular require
|
data/spec/spec_helper.rb
CHANGED
@@ -3,7 +3,7 @@ require 'rubygems'
|
|
3
3
|
using_git = File.exist?(File.expand_path('../../.git/', __FILE__))
|
4
4
|
require 'bundler/setup' if using_git
|
5
5
|
|
6
|
-
if RUBY_VERSION
|
6
|
+
if RUBY_VERSION.to_f >= 1.9 && RUBY_ENGINE == 'ruby'
|
7
7
|
require 'simplecov'
|
8
8
|
|
9
9
|
SimpleCov.start do
|
@@ -41,7 +41,7 @@ require 'monkey_patches'
|
|
41
41
|
require "support/http_library_adapters"
|
42
42
|
|
43
43
|
module VCR
|
44
|
-
SPEC_ROOT = File.dirname(__FILE__)
|
44
|
+
SPEC_ROOT = File.dirname(File.expand_path('.', __FILE__))
|
45
45
|
|
46
46
|
def reset!(hook = :fakeweb)
|
47
47
|
instance_variables.each do |ivar|
|
@@ -60,6 +60,10 @@ RSpec.configure do |config|
|
|
60
60
|
expectations.syntax = :expect
|
61
61
|
end
|
62
62
|
|
63
|
+
config.mock_with :rspec do |mocks|
|
64
|
+
mocks.syntax = :expect
|
65
|
+
end
|
66
|
+
|
63
67
|
tmp_dir = File.expand_path('../../tmp/cassette_library_dir', __FILE__)
|
64
68
|
config.before(:each) do
|
65
69
|
unless example.metadata[:skip_vcr_reset]
|