vcr 1.11.3 → 2.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/.travis.yml +6 -2
- data/CHANGELOG.md +49 -1
- data/Gemfile +1 -5
- data/Guardfile +0 -5
- data/README.md +3 -2
- data/Rakefile +11 -16
- data/cucumber.yml +0 -4
- data/features/.nav +14 -2
- data/features/cassettes/automatic_re_recording.feature +4 -6
- data/features/cassettes/dynamic_erb.feature +6 -8
- data/features/cassettes/exclusive.feature +111 -0
- data/features/cassettes/format.feature +16 -14
- data/features/cassettes/naming.feature +4 -6
- data/features/cassettes/no_cassette.feature +25 -28
- data/features/cassettes/update_content_length_header.feature +9 -9
- data/features/configuration/allow_http_connections_when_no_cassette.feature +6 -8
- data/features/configuration/cassette_library_dir.feature +4 -6
- data/features/configuration/default_cassette_options.feature +12 -10
- data/features/configuration/filter_sensitive_data.feature +12 -17
- data/features/configuration/{stub_with.feature → hook_into.feature} +63 -62
- data/features/configuration/hooks.feature +23 -33
- data/features/configuration/ignore_hosts.feature +16 -17
- data/features/configuration/ignore_localhost.feature +33 -42
- data/features/http_libraries/em_http_request.feature +7 -8
- data/features/http_libraries/net_http.feature +26 -28
- data/features/middleware/faraday.feature +17 -56
- data/features/middleware/rack.feature +8 -11
- data/features/record_modes/all.feature +5 -7
- data/features/record_modes/new_episodes.feature +5 -7
- data/features/record_modes/none.feature +6 -6
- data/features/record_modes/once.feature +6 -8
- data/features/request_matching/README.md +28 -0
- data/features/request_matching/body.feature +81 -0
- data/features/request_matching/custom_matcher.feature +125 -0
- data/features/request_matching/headers.feature +85 -0
- data/features/request_matching/host.feature +85 -0
- data/features/request_matching/identical_request_sequence.feature +79 -0
- data/features/request_matching/method.feature +86 -0
- data/features/request_matching/path.feature +86 -0
- data/features/request_matching/playback_repeats.feature +87 -0
- data/features/request_matching/uri.feature +84 -0
- data/features/request_matching/uri_without_param.feature +85 -0
- data/features/step_definitions/cli_steps.rb +4 -28
- data/features/support/env.rb +11 -9
- data/features/support/http_lib_filters.rb +2 -11
- data/features/support/vcr_cucumber_helpers.rb +4 -5
- data/features/test_frameworks/cucumber.feature +17 -18
- data/features/test_frameworks/rspec.feature +8 -12
- data/features/test_frameworks/shoulda.feature +5 -8
- data/features/test_frameworks/test_unit.feature +5 -8
- data/lib/vcr.rb +38 -58
- data/lib/vcr/cassette.rb +41 -60
- data/lib/vcr/cassette/http_interaction_list.rb +56 -0
- data/lib/vcr/cassette/reader.rb +29 -31
- data/lib/vcr/configuration.rb +76 -0
- data/lib/vcr/deprecations.rb +39 -0
- data/lib/vcr/errors.rb +22 -0
- data/lib/vcr/library_hooks.rb +19 -0
- data/lib/vcr/library_hooks/excon.rb +136 -0
- data/lib/vcr/library_hooks/fakeweb.rb +110 -0
- data/lib/vcr/library_hooks/faraday.rb +3 -0
- data/lib/vcr/library_hooks/typhoeus.rb +98 -0
- data/lib/vcr/library_hooks/webmock.rb +100 -0
- data/lib/vcr/middleware/faraday.rb +43 -36
- data/lib/vcr/middleware/rack.rb +28 -4
- data/lib/vcr/request_handler.rb +43 -0
- data/lib/vcr/request_ignorer.rb +31 -0
- data/lib/vcr/request_matcher_registry.rb +86 -0
- data/lib/vcr/structs/http_interaction.rb +24 -18
- data/lib/vcr/structs/normalizers/body.rb +1 -1
- data/lib/vcr/structs/normalizers/header.rb +1 -1
- data/lib/vcr/structs/normalizers/status_message.rb +1 -1
- data/lib/vcr/structs/normalizers/uri.rb +1 -1
- data/lib/vcr/structs/request.rb +0 -13
- data/lib/vcr/structs/response.rb +2 -9
- data/lib/vcr/structs/response_status.rb +0 -4
- data/lib/vcr/test_frameworks/cucumber.rb +1 -1
- data/lib/vcr/test_frameworks/rspec.rb +1 -1
- data/lib/vcr/util/hooks.rb +28 -19
- data/lib/vcr/util/internet_connection.rb +29 -2
- data/lib/vcr/util/version_checker.rb +60 -0
- data/lib/vcr/version.rb +1 -1
- data/script/FullBuildRakeFile +0 -7
- data/script/full_build +1 -1
- data/spec/capture_warnings.rb +36 -31
- data/spec/fixtures/{1.9.1/cassette_spec → cassette_spec}/empty.yml +0 -0
- data/spec/fixtures/{not_1.9.1/cassette_spec → cassette_spec}/example.yml +0 -0
- data/spec/fixtures/{not_1.9.1/cassette_spec → cassette_spec}/with_localhost_requests.yml +0 -0
- data/spec/fixtures/{not_1.9.1/fake_example.com_responses.yml → fake_example.com_responses.yml} +0 -0
- data/spec/fixtures/{not_1.9.1/match_requests_on.yml → match_requests_on.yml} +0 -0
- data/spec/monkey_patches.rb +40 -11
- data/spec/spec_helper.rb +7 -43
- data/spec/support/http_library_adapters.rb +3 -13
- data/spec/support/shared_example_groups/{http_library.rb → hook_into_http_library.rb} +39 -111
- data/spec/support/shared_example_groups/version_checking.rb +9 -9
- data/spec/vcr/cassette/http_interaction_list_spec.rb +178 -0
- data/spec/vcr/cassette/reader_spec.rb +2 -2
- data/spec/vcr/cassette_spec.rb +121 -156
- data/spec/vcr/configuration_spec.rb +143 -0
- data/spec/vcr/deprecations_spec.rb +91 -0
- data/spec/vcr/{http_stubbing_adapters → library_hooks}/excon_spec.rb +6 -9
- data/spec/vcr/library_hooks/fakeweb_spec.rb +83 -0
- data/spec/vcr/{http_stubbing_adapters → library_hooks}/typhoeus_spec.rb +7 -11
- data/spec/vcr/library_hooks/webmock_spec.rb +17 -0
- data/spec/vcr/library_hooks_spec.rb +51 -0
- data/spec/vcr/middleware/faraday_spec.rb +17 -44
- data/spec/vcr/middleware/rack_spec.rb +94 -58
- data/spec/vcr/request_ignorer_spec.rb +54 -0
- data/spec/vcr/request_matcher_registry_spec.rb +223 -0
- data/spec/vcr/structs/request_spec.rb +0 -33
- data/spec/vcr/structs/response_spec.rb +0 -24
- data/spec/vcr/structs/response_status_spec.rb +0 -9
- data/spec/vcr/util/hooks_spec.rb +3 -5
- data/spec/vcr/version_spec.rb +1 -1
- data/spec/vcr_spec.rb +79 -91
- data/vcr.gemspec +1 -1
- metadata +83 -103
- data/features/cassettes/request_matching.feature +0 -383
- data/lib/vcr/config.rb +0 -84
- data/lib/vcr/deprecations/cassette.rb +0 -29
- data/lib/vcr/deprecations/config.rb +0 -18
- data/lib/vcr/deprecations/http_stubbing_adapters/common.rb +0 -9
- data/lib/vcr/deprecations/http_stubbing_adapters/fakeweb.rb +0 -11
- data/lib/vcr/extensions/net_http.rb +0 -32
- data/lib/vcr/http_stubbing_adapters/common.rb +0 -202
- data/lib/vcr/http_stubbing_adapters/excon.rb +0 -178
- data/lib/vcr/http_stubbing_adapters/fakeweb.rb +0 -107
- data/lib/vcr/http_stubbing_adapters/faraday.rb +0 -26
- data/lib/vcr/http_stubbing_adapters/multi_object_proxy.rb +0 -43
- data/lib/vcr/http_stubbing_adapters/typhoeus.rb +0 -115
- data/lib/vcr/http_stubbing_adapters/webmock.rb +0 -120
- data/lib/vcr/middleware/cassette_arguments.rb +0 -19
- data/lib/vcr/middleware/common.rb +0 -20
- data/lib/vcr/request_matcher.rb +0 -94
- data/lib/vcr/rspec.rb +0 -2
- data/lib/vcr/util/basic_object.rb +0 -43
- data/lib/vcr/util/ping.rb +0 -30
- data/lib/vcr/util/regexes.rb +0 -37
- data/spec/fixtures/1.9.1/0_3_1_cassette.yml +0 -29
- data/spec/fixtures/1.9.1/cassette_spec/example.yml +0 -110
- data/spec/fixtures/1.9.1/cassette_spec/with_localhost_requests.yml +0 -109
- data/spec/fixtures/1.9.1/example_net_http.yml +0 -14
- data/spec/fixtures/1.9.1/example_net_http_request.yml +0 -12
- data/spec/fixtures/1.9.1/example_net_http_response.yml +0 -25
- data/spec/fixtures/1.9.1/fake_example.com_responses.yml +0 -108
- data/spec/fixtures/1.9.1/match_requests_on.yml +0 -185
- data/spec/fixtures/not_1.9.1/0_3_1_cassette.yml +0 -29
- data/spec/fixtures/not_1.9.1/cassette_spec/empty.yml +0 -0
- data/spec/fixtures/not_1.9.1/example_net_http.yml +0 -14
- data/spec/fixtures/not_1.9.1/example_net_http_request.yml +0 -12
- data/spec/fixtures/not_1.9.1/example_net_http_response.yml +0 -25
- data/spec/support/shared_example_groups/http_stubbing_adapter.rb +0 -133
- data/spec/support/shared_example_groups/ignore_localhost_deprecation.rb +0 -28
- data/spec/vcr/config_spec.rb +0 -181
- data/spec/vcr/deprecations/cassette_spec.rb +0 -57
- data/spec/vcr/deprecations/config_spec.rb +0 -30
- data/spec/vcr/deprecations/http_stubbing_adapters/common_spec.rb +0 -7
- data/spec/vcr/deprecations/http_stubbing_adapters/fakeweb_spec.rb +0 -16
- data/spec/vcr/extensions/net_http_spec.rb +0 -80
- data/spec/vcr/http_stubbing_adapters/fakeweb_spec.rb +0 -19
- data/spec/vcr/http_stubbing_adapters/faraday_spec.rb +0 -76
- data/spec/vcr/http_stubbing_adapters/multi_object_proxy_spec.rb +0 -101
- data/spec/vcr/http_stubbing_adapters/webmock_spec.rb +0 -17
- data/spec/vcr/middleware/cassette_arguments_spec.rb +0 -32
- data/spec/vcr/request_matcher_spec.rb +0 -230
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'vcr/util/version_checker'
|
2
|
+
require 'vcr/request_handler'
|
3
|
+
require 'typhoeus'
|
4
|
+
|
5
|
+
VCR::VersionChecker.new('Typhoeus', Typhoeus::VERSION, '0.2.1', '0.2').check_version!
|
6
|
+
|
7
|
+
module VCR
|
8
|
+
class LibraryHooks
|
9
|
+
module Typhoeus
|
10
|
+
module Helpers
|
11
|
+
def vcr_request_from(request)
|
12
|
+
VCR::Request.new \
|
13
|
+
request.method,
|
14
|
+
request.url,
|
15
|
+
request.body,
|
16
|
+
request.headers
|
17
|
+
end
|
18
|
+
|
19
|
+
def vcr_response_from(response)
|
20
|
+
VCR::Response.new \
|
21
|
+
VCR::ResponseStatus.new(response.code, response.status_message),
|
22
|
+
response.headers_hash,
|
23
|
+
response.body,
|
24
|
+
response.http_version
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class RequestHandler < ::VCR::RequestHandler
|
29
|
+
include Helpers
|
30
|
+
|
31
|
+
attr_reader :request
|
32
|
+
def initialize(request)
|
33
|
+
@request = request
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def on_stubbed_request
|
39
|
+
hydra_mock
|
40
|
+
end
|
41
|
+
|
42
|
+
def vcr_request
|
43
|
+
@vcr_request ||= vcr_request_from(request)
|
44
|
+
end
|
45
|
+
|
46
|
+
def typhoeus_response
|
47
|
+
@typhoeus_response ||= ::Typhoeus::Response.new \
|
48
|
+
:http_version => stubbed_response.http_version,
|
49
|
+
:code => stubbed_response.status.code,
|
50
|
+
:status_message => stubbed_response.status.message,
|
51
|
+
:headers_hash => stubbed_response_headers,
|
52
|
+
:body => stubbed_response.body
|
53
|
+
end
|
54
|
+
|
55
|
+
def hydra_mock
|
56
|
+
@hydra_mock ||= ::Typhoeus::HydraMock.new(/.*/, :any).tap do |m|
|
57
|
+
m.and_return(typhoeus_response)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def stubbed_response_headers
|
62
|
+
@stubbed_response_headers ||= {}.tap do |hash|
|
63
|
+
stubbed_response.headers.each do |key, values|
|
64
|
+
hash[key] = values.size == 1 ? values.first : values
|
65
|
+
end if stubbed_response.headers
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
extend Helpers
|
71
|
+
::Typhoeus::Hydra.after_request_before_on_complete do |request|
|
72
|
+
unless VCR.library_hooks.disabled?(:typhoeus) || request.response.mock?
|
73
|
+
http_interaction = VCR::HTTPInteraction.new(vcr_request_from(request), vcr_response_from(request.response))
|
74
|
+
VCR.record_http_interaction(http_interaction)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# TODO: add Typhoeus::Hydra.register_stub_finder API to Typhoeus
|
83
|
+
# so we can use that instead of monkey-patching it.
|
84
|
+
Typhoeus::Hydra::Stubbing::SharedMethods.class_eval do
|
85
|
+
undef find_stub_from_request
|
86
|
+
def find_stub_from_request(request)
|
87
|
+
VCR::LibraryHooks::Typhoeus::RequestHandler.new(request).handle
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
VCR.configuration.after_library_hooks_loaded do
|
92
|
+
# ensure WebMock's Typhoeus adapter does not conflict with us here
|
93
|
+
# (i.e. to double record requests or whatever).
|
94
|
+
if defined?(WebMock::HttpLibAdapters::TyphoeusAdapter)
|
95
|
+
WebMock::HttpLibAdapters::TyphoeusAdapter.disable!
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'vcr/util/version_checker'
|
2
|
+
require 'vcr/request_handler'
|
3
|
+
require 'webmock'
|
4
|
+
|
5
|
+
VCR::VersionChecker.new('WebMock', WebMock.version, '1.7.0', '1.7').check_version!
|
6
|
+
|
7
|
+
module VCR
|
8
|
+
class LibraryHooks
|
9
|
+
module WebMock
|
10
|
+
module Helpers
|
11
|
+
def response_hash_for(response)
|
12
|
+
{
|
13
|
+
:body => response.body,
|
14
|
+
:status => [response.status.code.to_i, response.status.message],
|
15
|
+
:headers => response.headers
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def vcr_request_from(webmock_request)
|
20
|
+
VCR::Request.new \
|
21
|
+
webmock_request.method,
|
22
|
+
webmock_request.uri.to_s,
|
23
|
+
webmock_request.body,
|
24
|
+
webmock_request.headers
|
25
|
+
end
|
26
|
+
|
27
|
+
def vcr_response_from(response)
|
28
|
+
VCR::Response.new \
|
29
|
+
VCR::ResponseStatus.new(response.status.first, response.status.last),
|
30
|
+
response.headers,
|
31
|
+
response.body,
|
32
|
+
'1.1'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class RequestHandler < ::VCR::RequestHandler
|
37
|
+
include Helpers
|
38
|
+
|
39
|
+
attr_reader :request
|
40
|
+
def initialize(request)
|
41
|
+
@request = request
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def stubbed_response
|
47
|
+
VCR.http_interactions.has_interaction_matching?(vcr_request)
|
48
|
+
end
|
49
|
+
|
50
|
+
def vcr_request
|
51
|
+
@vcr_request ||= vcr_request_from(request)
|
52
|
+
end
|
53
|
+
|
54
|
+
def on_ignored_request; false; end
|
55
|
+
def on_stubbed_request; true; end
|
56
|
+
def on_recordable_request; false; end
|
57
|
+
end
|
58
|
+
|
59
|
+
extend Helpers
|
60
|
+
|
61
|
+
GLOBAL_VCR_HOOK = ::WebMock::RequestStub.new(:any, /.*/).tap do |stub|
|
62
|
+
stub.with { |request|
|
63
|
+
RequestHandler.new(request).handle
|
64
|
+
}.to_return(lambda { |request|
|
65
|
+
response_hash_for VCR.http_interactions.response_for(vcr_request_from(request))
|
66
|
+
})
|
67
|
+
end
|
68
|
+
|
69
|
+
::WebMock::StubRegistry.instance.register_request_stub(GLOBAL_VCR_HOOK)
|
70
|
+
|
71
|
+
::WebMock.after_request(:real_requests_only => true) do |request, response|
|
72
|
+
unless VCR.library_hooks.disabled?(:webmock)
|
73
|
+
http_interaction = VCR::HTTPInteraction.new \
|
74
|
+
vcr_request_from(request),
|
75
|
+
vcr_response_from(response)
|
76
|
+
|
77
|
+
VCR.record_http_interaction(http_interaction)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class << WebMock
|
85
|
+
# ensure HTTP requests are always allowed; VCR takes care of disallowing
|
86
|
+
# them at the appropriate times in its hook
|
87
|
+
undef net_connect_allowed?
|
88
|
+
def net_connect_allowed?(*args)
|
89
|
+
true
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
WebMock::StubRegistry.class_eval do
|
94
|
+
# ensure our VCR hook is not removed when WebMock is reset
|
95
|
+
undef reset!
|
96
|
+
def reset!
|
97
|
+
self.request_stubs = [VCR::LibraryHooks::WebMock::GLOBAL_VCR_HOOK]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
@@ -1,55 +1,41 @@
|
|
1
1
|
require 'faraday'
|
2
|
+
require 'vcr/util/version_checker'
|
3
|
+
require 'vcr/request_handler'
|
4
|
+
|
5
|
+
VCR::VersionChecker.new('Faraday', Faraday::VERSION, '0.7.0', '0.7').check_version!
|
2
6
|
|
3
7
|
module VCR
|
4
8
|
module Middleware
|
5
|
-
class Faraday
|
6
|
-
include
|
9
|
+
class Faraday
|
10
|
+
include VCR::Deprecations::Middleware::Faraday
|
7
11
|
|
8
|
-
|
12
|
+
def initialize(app)
|
13
|
+
super
|
14
|
+
@app = app
|
15
|
+
end
|
9
16
|
|
10
17
|
def call(env)
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
if VCR::HttpStubbingAdapters::Faraday.uri_should_be_ignored?(request.uri)
|
16
|
-
@app.call(env)
|
17
|
-
elsif response = VCR::HttpStubbingAdapters::Faraday.stubbed_response_for(request)
|
18
|
-
headers = env[:response_headers] ||= ::Faraday::Utils::Headers.new
|
19
|
-
headers.update response.headers if response.headers
|
20
|
-
env.update :status => response.status.code, :body => response.body
|
21
|
-
|
22
|
-
faraday_response = ::Faraday::Response.new
|
23
|
-
faraday_response.finish(env) unless env[:parallel_manager]
|
24
|
-
env[:response] = faraday_response
|
25
|
-
elsif VCR::HttpStubbingAdapters::Faraday.http_connections_allowed?
|
26
|
-
response = @app.call(env)
|
27
|
-
|
28
|
-
# Checking #enabled? isn't strictly needed, but conforms
|
29
|
-
# the Faraday adapter to the behavior of the other adapters
|
30
|
-
if VCR::HttpStubbingAdapters::Faraday.enabled?
|
31
|
-
VCR.record_http_interaction(VCR::HTTPInteraction.new(request, response_for(env)))
|
32
|
-
end
|
33
|
-
|
34
|
-
response
|
35
|
-
else
|
36
|
-
raise HttpConnectionNotAllowedError.new(
|
37
|
-
"Real HTTP connections are disabled. Request: #{request.method.inspect} #{request.uri}"
|
38
|
-
)
|
39
|
-
end
|
40
|
-
end
|
18
|
+
# Faraday must be exlusive here in case another library hook is being used.
|
19
|
+
# We don't want double recording/double playback.
|
20
|
+
VCR.library_hooks.exclusively_enabled(:faraday) do
|
21
|
+
RequestHandler.new(@app, env).handle
|
41
22
|
end
|
42
23
|
end
|
43
24
|
|
25
|
+
class RequestHandler < ::VCR::RequestHandler
|
26
|
+
attr_reader :app, :env
|
27
|
+
def initialize(app, env)
|
28
|
+
@app, @env = app, env
|
29
|
+
end
|
30
|
+
|
44
31
|
private
|
45
32
|
|
46
|
-
def
|
47
|
-
VCR::Request.new
|
33
|
+
def vcr_request
|
34
|
+
@vcr_request ||= VCR::Request.new \
|
48
35
|
env[:method],
|
49
36
|
env[:url].to_s,
|
50
37
|
env[:body],
|
51
38
|
env[:request_headers]
|
52
|
-
)
|
53
39
|
end
|
54
40
|
|
55
41
|
def response_for(env)
|
@@ -62,6 +48,27 @@ module VCR
|
|
62
48
|
'1.1'
|
63
49
|
)
|
64
50
|
end
|
51
|
+
|
52
|
+
def on_ignored_request
|
53
|
+
app.call(env)
|
54
|
+
end
|
55
|
+
|
56
|
+
def on_stubbed_request
|
57
|
+
headers = env[:response_headers] ||= ::Faraday::Utils::Headers.new
|
58
|
+
headers.update stubbed_response.headers if stubbed_response.headers
|
59
|
+
env.update :status => stubbed_response.status.code, :body => stubbed_response.body
|
60
|
+
|
61
|
+
faraday_response = ::Faraday::Response.new
|
62
|
+
faraday_response.finish(env) unless env[:parallel_manager]
|
63
|
+
env[:response] = faraday_response
|
64
|
+
end
|
65
|
+
|
66
|
+
def on_recordable_request
|
67
|
+
app.call(env).on_complete do |env|
|
68
|
+
VCR.record_http_interaction(VCR::HTTPInteraction.new(vcr_request, response_for(env)))
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
65
72
|
end
|
66
73
|
end
|
67
74
|
end
|
data/lib/vcr/middleware/rack.rb
CHANGED
@@ -1,11 +1,27 @@
|
|
1
1
|
module VCR
|
2
2
|
module Middleware
|
3
|
+
class CassetteArguments
|
4
|
+
def initialize
|
5
|
+
@name = nil
|
6
|
+
@options = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def name(name = nil)
|
10
|
+
@name = name if name
|
11
|
+
@name
|
12
|
+
end
|
13
|
+
|
14
|
+
def options(options = {})
|
15
|
+
@options.merge!(options)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
3
19
|
class Rack
|
4
|
-
include
|
20
|
+
include VCR::VariableArgsBlockCaller
|
5
21
|
|
6
|
-
def initialize(
|
7
|
-
|
8
|
-
|
22
|
+
def initialize(app, &block)
|
23
|
+
raise ArgumentError.new("You must provide a block to set the cassette options") unless block
|
24
|
+
@app, @cassette_arguments_block, @mutex = app, block, Mutex.new
|
9
25
|
end
|
10
26
|
|
11
27
|
def call(env)
|
@@ -15,6 +31,14 @@ module VCR
|
|
15
31
|
end
|
16
32
|
end
|
17
33
|
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def cassette_arguments(env)
|
38
|
+
arguments = CassetteArguments.new
|
39
|
+
call_block(@cassette_arguments_block, arguments, env)
|
40
|
+
[arguments.name, arguments.options]
|
41
|
+
end
|
18
42
|
end
|
19
43
|
end
|
20
44
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module VCR
|
2
|
+
class RequestHandler
|
3
|
+
def handle
|
4
|
+
return on_ignored_request if should_ignore?
|
5
|
+
return on_stubbed_request if stubbed_response
|
6
|
+
return on_recordable_request if VCR.real_http_connections_allowed?
|
7
|
+
on_connection_not_allowed
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def should_ignore?
|
13
|
+
disabled? || VCR.request_ignorer.ignore?(vcr_request)
|
14
|
+
end
|
15
|
+
|
16
|
+
def disabled?
|
17
|
+
VCR.library_hooks.disabled?(library_name)
|
18
|
+
end
|
19
|
+
|
20
|
+
def stubbed_response
|
21
|
+
@stubbed_response ||= VCR.http_interactions.response_for(vcr_request)
|
22
|
+
end
|
23
|
+
|
24
|
+
def library_name
|
25
|
+
# extracts `:typhoeus` from `VCR::LibraryHooks::Typhoeus::RequestHandler`
|
26
|
+
@library_name ||= self.class.name.split('::')[-2].downcase.to_sym
|
27
|
+
end
|
28
|
+
|
29
|
+
# Subclasses can implement these
|
30
|
+
def on_ignored_request
|
31
|
+
end
|
32
|
+
|
33
|
+
def on_stubbed_request
|
34
|
+
end
|
35
|
+
|
36
|
+
def on_recordable_request
|
37
|
+
end
|
38
|
+
|
39
|
+
def on_connection_not_allowed
|
40
|
+
raise VCR::HTTPConnectionNotAllowedError.new(vcr_request)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
module VCR
|
5
|
+
class RequestIgnorer
|
6
|
+
LOCALHOST_ALIASES = %w( localhost 127.0.0.1 0.0.0.0 )
|
7
|
+
|
8
|
+
def ignore_localhost=(value)
|
9
|
+
if value
|
10
|
+
ignore_hosts(*LOCALHOST_ALIASES)
|
11
|
+
else
|
12
|
+
ignored_hosts.reject! { |h| LOCALHOST_ALIASES.include?(h) }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def ignore_hosts(*hosts)
|
17
|
+
ignored_hosts.merge(hosts)
|
18
|
+
end
|
19
|
+
|
20
|
+
def ignore?(request)
|
21
|
+
ignored_hosts.include?(URI(request.uri).host)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def ignored_hosts
|
27
|
+
@ignored_hosts ||= Set.new
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module VCR
|
2
|
+
class RequestMatcherRegistry
|
3
|
+
DEFAULT_MATCHERS = [:method, :uri]
|
4
|
+
|
5
|
+
class Matcher < Struct.new(:callable)
|
6
|
+
def matches?(request_1, request_2)
|
7
|
+
callable.call(request_1, request_2)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@registry = {}
|
13
|
+
register_built_ins
|
14
|
+
end
|
15
|
+
|
16
|
+
def register(name, &block)
|
17
|
+
if @registry.has_key?(name)
|
18
|
+
warn "WARNING: There is already a VCR request matcher registered for #{name.inspect}. Overriding it."
|
19
|
+
end
|
20
|
+
|
21
|
+
@registry[name] = Matcher.new(block)
|
22
|
+
end
|
23
|
+
|
24
|
+
def [](matcher)
|
25
|
+
@registry.fetch(matcher) do
|
26
|
+
matcher.respond_to?(:call) ?
|
27
|
+
Matcher.new(matcher) :
|
28
|
+
raise_unregistered_matcher_error(matcher)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def uri_without_params(*ignores)
|
33
|
+
ignores = ignores.map { |i| i.to_s }
|
34
|
+
|
35
|
+
lambda do |request_1, request_2|
|
36
|
+
uri_1, uri_2 = [request_1, request_2].map do |r|
|
37
|
+
URI(r.uri).tap do |uri|
|
38
|
+
uri.query = uri.query.split('&').tap { |params|
|
39
|
+
params.map! do |p|
|
40
|
+
key, value = p.split('=')
|
41
|
+
key.gsub!(/\[\]\z/, '') # handle params like tag[]=
|
42
|
+
[key, value]
|
43
|
+
end
|
44
|
+
|
45
|
+
params.reject! { |p| ignores.include?(p.first) }
|
46
|
+
params.map! { |p| p.join('=') }
|
47
|
+
}.join('&')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
uri_1 == uri_2
|
52
|
+
end
|
53
|
+
end
|
54
|
+
alias uri_without_param uri_without_params
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def raise_unregistered_matcher_error(name)
|
59
|
+
raise Errors::UnregisteredMatcherError.new \
|
60
|
+
"There is no matcher registered for #{name.inspect}. " +
|
61
|
+
"Did you mean one of #{@registry.keys.map(&:inspect).join(', ')}?"
|
62
|
+
end
|
63
|
+
|
64
|
+
def register_built_ins
|
65
|
+
register(:method) { |r1, r2| r1.method == r2.method }
|
66
|
+
register(:uri) { |r1, r2| normalize_uri(r1.uri) == normalize_uri(r2.uri) }
|
67
|
+
register(:host) { |r1, r2| URI(r1.uri).host == URI(r2.uri).host }
|
68
|
+
register(:path) { |r1, r2| URI(r1.uri).path == URI(r2.uri).path }
|
69
|
+
register(:body) { |r1, r2| r1.body == r2.body }
|
70
|
+
register(:headers) { |r1, r2| r1.headers == r2.headers }
|
71
|
+
end
|
72
|
+
|
73
|
+
def normalize_uri(uri)
|
74
|
+
# TODO: find a better, less-hacky way to do this.
|
75
|
+
if defined?(::WebMock)
|
76
|
+
::WebMock::Util::URI.normalize_uri(uri).to_s
|
77
|
+
elsif defined?(VCR::Middleware::Faraday)
|
78
|
+
# Faraday normalizes URIs by replacing '+' with '%20'
|
79
|
+
uri.gsub('+', '%20')
|
80
|
+
else
|
81
|
+
uri
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|