vcr 1.5.1 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +11 -1
- data/Gemfile +1 -1
- data/Gemfile.lock +4 -3
- data/benchmarks/http_stubbing_libraries.rb +4 -4
- data/features/.nav +1 -0
- data/features/configuration/ignore_hosts.feature +61 -0
- data/features/http_libraries/net_http.feature +34 -0
- data/features/step_definitions/cli_steps.rb +16 -1
- data/lib/vcr.rb +23 -14
- data/lib/vcr/cassette.rb +2 -4
- data/lib/vcr/config.rb +20 -5
- data/lib/vcr/deprecations.rb +27 -14
- data/lib/vcr/http_stubbing_adapters/fakeweb.rb +14 -9
- data/lib/vcr/http_stubbing_adapters/faraday.rb +12 -3
- data/lib/vcr/http_stubbing_adapters/typhoeus.rb +3 -7
- data/lib/vcr/http_stubbing_adapters/webmock.rb +17 -7
- data/lib/vcr/middleware/faraday.rb +1 -1
- data/lib/vcr/request_matcher.rb +12 -8
- data/lib/vcr/structs/http_interaction.rb +16 -0
- data/lib/vcr/structs/normalizers/body.rb +24 -0
- data/lib/vcr/structs/normalizers/header.rb +56 -0
- data/lib/vcr/structs/normalizers/status_message.rb +17 -0
- data/lib/vcr/structs/normalizers/uri.rb +34 -0
- data/lib/vcr/structs/request.rb +20 -0
- data/lib/vcr/structs/response.rb +16 -0
- data/lib/vcr/structs/response_status.rb +9 -0
- data/lib/vcr/util/regexes.rb +37 -0
- data/lib/vcr/version.rb +16 -5
- data/spec/spec_helper.rb +26 -3
- data/spec/support/http_library_adapters.rb +11 -12
- data/spec/support/http_stubbing_adapter.rb +2 -16
- data/spec/support/normalizers.rb +84 -0
- data/spec/support/version_checker.rb +1 -1
- data/spec/vcr/cassette_spec.rb +8 -10
- data/spec/vcr/config_spec.rb +63 -17
- data/spec/vcr/deprecations_spec.rb +83 -24
- data/spec/vcr/http_stubbing_adapters/multi_object_proxy_spec.rb +1 -1
- data/spec/vcr/http_stubbing_adapters/typhoeus_spec.rb +2 -2
- data/spec/vcr/middleware/faraday_spec.rb +1 -1
- data/spec/vcr/structs/http_interaction_spec.rb +23 -0
- data/spec/vcr/structs/request_spec.rb +54 -0
- data/spec/vcr/structs/response_spec.rb +39 -0
- data/spec/vcr/structs/response_status_spec.rb +18 -0
- data/spec/vcr_spec.rb +26 -54
- data/vcr.gemspec +1 -1
- metadata +48 -31
- data/TODO.md +0 -5
- data/lib/vcr/structs.rb +0 -176
- data/spec/vcr/structs_spec.rb +0 -201
@@ -9,14 +9,19 @@ module VCR
|
|
9
9
|
MINIMUM_VERSION = '0.5.3'
|
10
10
|
MAXIMUM_VERSION = '0.5'
|
11
11
|
|
12
|
-
attr_writer :http_connections_allowed
|
12
|
+
attr_writer :http_connections_allowed
|
13
13
|
|
14
14
|
def http_connections_allowed?
|
15
15
|
!!@http_connections_allowed
|
16
16
|
end
|
17
17
|
|
18
|
-
def
|
19
|
-
|
18
|
+
def ignored_hosts=(hosts)
|
19
|
+
@ignored_hosts = hosts
|
20
|
+
end
|
21
|
+
|
22
|
+
def uri_should_be_ignored?(uri)
|
23
|
+
uri = URI.parse(uri) unless uri.respond_to?(:host)
|
24
|
+
ignored_hosts.include?(uri.host)
|
20
25
|
end
|
21
26
|
|
22
27
|
def stub_requests(http_interactions, match_attributes)
|
@@ -52,6 +57,10 @@ module VCR
|
|
52
57
|
::Faraday::VERSION
|
53
58
|
end
|
54
59
|
|
60
|
+
def ignored_hosts
|
61
|
+
@ignored_hosts ||= []
|
62
|
+
end
|
63
|
+
|
55
64
|
def checkpoints
|
56
65
|
@checkpoints ||= {}
|
57
66
|
end
|
@@ -6,7 +6,7 @@ module VCR
|
|
6
6
|
include VCR::HttpStubbingAdapters::Common
|
7
7
|
extend self
|
8
8
|
|
9
|
-
MINIMUM_VERSION = '0.2.
|
9
|
+
MINIMUM_VERSION = '0.2.1'
|
10
10
|
MAXIMUM_VERSION = '0.2'
|
11
11
|
|
12
12
|
def http_connections_allowed=(value)
|
@@ -17,12 +17,8 @@ module VCR
|
|
17
17
|
!!::Typhoeus::Hydra.allow_net_connect?
|
18
18
|
end
|
19
19
|
|
20
|
-
def
|
21
|
-
::Typhoeus::Hydra.
|
22
|
-
end
|
23
|
-
|
24
|
-
def ignore_localhost?
|
25
|
-
!!::Typhoeus::Hydra.ignore_localhost?
|
20
|
+
def ignored_hosts=(hosts)
|
21
|
+
::Typhoeus::Hydra.ignore_hosts = hosts
|
26
22
|
end
|
27
23
|
|
28
24
|
def stub_requests(http_interactions, match_attributes)
|
@@ -10,19 +10,17 @@ module VCR
|
|
10
10
|
MAXIMUM_VERSION = '1.6'
|
11
11
|
|
12
12
|
def http_connections_allowed=(value)
|
13
|
-
|
13
|
+
@http_connections_allowed = value
|
14
|
+
update_webmock_allow_net_connect
|
14
15
|
end
|
15
16
|
|
16
17
|
def http_connections_allowed?
|
17
18
|
!!::WebMock::Config.instance.allow_net_connect
|
18
19
|
end
|
19
20
|
|
20
|
-
def
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
def ignore_localhost?
|
25
|
-
!!::WebMock::Config.instance.allow_localhost
|
21
|
+
def ignored_hosts=(hosts)
|
22
|
+
@ignored_hosts = hosts
|
23
|
+
update_webmock_allow_net_connect
|
26
24
|
end
|
27
25
|
|
28
26
|
def stub_requests(http_interactions, match_attributes)
|
@@ -50,6 +48,18 @@ module VCR
|
|
50
48
|
::WebMock.version
|
51
49
|
end
|
52
50
|
|
51
|
+
def ignored_hosts
|
52
|
+
@ignored_hosts ||= []
|
53
|
+
end
|
54
|
+
|
55
|
+
def update_webmock_allow_net_connect
|
56
|
+
if @http_connections_allowed
|
57
|
+
::WebMock.allow_net_connect!
|
58
|
+
else
|
59
|
+
::WebMock.disable_net_connect!(:allow => ignored_hosts)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
53
63
|
def request_signature_hash(request_matcher)
|
54
64
|
signature = {}
|
55
65
|
signature[:body] = request_matcher.body if request_matcher.match_requests_on?(:body)
|
@@ -13,7 +13,7 @@ module VCR
|
|
13
13
|
request = request_for(env)
|
14
14
|
request_matcher = request.matcher(cassette.match_requests_on)
|
15
15
|
|
16
|
-
if VCR::HttpStubbingAdapters::Faraday.
|
16
|
+
if VCR::HttpStubbingAdapters::Faraday.uri_should_be_ignored?(request.uri)
|
17
17
|
@app.call(env)
|
18
18
|
elsif response = VCR::HttpStubbingAdapters::Faraday.stubbed_response_for(request_matcher)
|
19
19
|
env.update(
|
data/lib/vcr/request_matcher.rb
CHANGED
@@ -20,21 +20,21 @@ module VCR
|
|
20
20
|
# for two sets of the same elements unless they are ordered
|
21
21
|
# the same, so we sort the attributes here.
|
22
22
|
attributes = attributes.sort { |a, b| a.to_s <=> b.to_s }
|
23
|
-
@match_attributes =
|
23
|
+
@match_attributes = set(attributes)
|
24
24
|
end
|
25
25
|
|
26
26
|
def uri
|
27
27
|
return request.uri unless request.uri.is_a?(String)
|
28
28
|
uri_matchers = match_attributes.to_a & [:uri, :host, :path]
|
29
29
|
|
30
|
-
case
|
31
|
-
when
|
32
|
-
when
|
33
|
-
when
|
34
|
-
when
|
35
|
-
when
|
30
|
+
case set(uri_matchers)
|
31
|
+
when set then /.*/
|
32
|
+
when set(:uri) then request.uri
|
33
|
+
when set(:host) then VCR::Regexes.url_regex_for_hosts([URI(request.uri).host])
|
34
|
+
when set(:path) then VCR::Regexes.url_regex_for_path(URI(request.uri).path)
|
35
|
+
when set(:host, :path)
|
36
36
|
uri = URI(request.uri)
|
37
|
-
|
37
|
+
VCR::Regexes.url_regex_for_host_and_path(uri.host, uri.path)
|
38
38
|
else raise ArgumentError.new("match_attributes cannot include #{uri_matchers.join(' and ')}")
|
39
39
|
end
|
40
40
|
end
|
@@ -74,6 +74,10 @@ module VCR
|
|
74
74
|
|
75
75
|
private
|
76
76
|
|
77
|
+
def set(*elements)
|
78
|
+
Set.new(elements.flatten)
|
79
|
+
end
|
80
|
+
|
77
81
|
def sorted_header_array
|
78
82
|
header_hash = headers
|
79
83
|
return header_hash unless header_hash.is_a?(Hash)
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module VCR
|
4
|
+
class HTTPInteraction < Struct.new(:request, :response)
|
5
|
+
extend ::Forwardable
|
6
|
+
def_delegators :request, :uri, :method
|
7
|
+
|
8
|
+
def ignore!
|
9
|
+
@ignored = true
|
10
|
+
end
|
11
|
+
|
12
|
+
def ignored?
|
13
|
+
@ignored
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module VCR
|
2
|
+
module Normalizers
|
3
|
+
module Body
|
4
|
+
def initialize(*args)
|
5
|
+
super
|
6
|
+
normalize_body
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def normalize_body
|
12
|
+
# Ensure that the body is a raw string, in case the string instance
|
13
|
+
# has been subclassed or extended with additional instance variables
|
14
|
+
# or attributes, so that it is serialized to YAML as a raw string.
|
15
|
+
# This is needed for rest-client. See this ticket for more info:
|
16
|
+
# http://github.com/myronmarston/vcr/issues/4
|
17
|
+
self.body = case body
|
18
|
+
when nil, ''; nil
|
19
|
+
else String.new(body)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module VCR
|
2
|
+
module Normalizers
|
3
|
+
module Header
|
4
|
+
# These headers get added by the various HTTP clients automatically,
|
5
|
+
# and we don't care about them. We store the headers for the purposes
|
6
|
+
# of request matching, and we only care to match on headers users
|
7
|
+
# explicitly set.
|
8
|
+
HEADERS_TO_SKIP = {
|
9
|
+
'connection' => %w[ close Keep-Alive ],
|
10
|
+
'accept' => %w[ */* ],
|
11
|
+
'expect' => [''],
|
12
|
+
'user-agent' => ["Typhoeus - http://github.com/dbalatero/typhoeus/tree/master", 'Ruby']
|
13
|
+
}
|
14
|
+
|
15
|
+
def initialize(*args)
|
16
|
+
super
|
17
|
+
normalize_headers
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def important_header_values(k, values)
|
23
|
+
skip_values = HEADERS_TO_SKIP[k] || []
|
24
|
+
values - skip_values
|
25
|
+
end
|
26
|
+
|
27
|
+
def normalize_headers
|
28
|
+
new_headers = {}
|
29
|
+
|
30
|
+
headers.each do |k, v|
|
31
|
+
k = k.downcase
|
32
|
+
|
33
|
+
val_array = case v
|
34
|
+
when Array then v
|
35
|
+
when nil then []
|
36
|
+
else [v]
|
37
|
+
end
|
38
|
+
|
39
|
+
important_vals = important_header_values(k, val_array)
|
40
|
+
next unless important_vals.size > 0
|
41
|
+
|
42
|
+
# Ensure the values are raw strings.
|
43
|
+
# Apparently for Paperclip uploads to S3, headers
|
44
|
+
# get serialized with some extra stuff which leads
|
45
|
+
# to a seg fault. See this issue for more info:
|
46
|
+
# https://github.com/myronmarston/vcr/issues#issue/39
|
47
|
+
string_vals = important_vals.map { |v| String.new(v) }
|
48
|
+
|
49
|
+
new_headers[k] = string_vals
|
50
|
+
end if headers
|
51
|
+
|
52
|
+
self.headers = new_headers.empty? ? nil : new_headers
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module VCR
|
2
|
+
module Normalizers
|
3
|
+
module StatusMessage
|
4
|
+
def initialize(*args)
|
5
|
+
super
|
6
|
+
normalize_status_message
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def normalize_status_message
|
12
|
+
self.message = message.strip if message
|
13
|
+
self.message = nil if message == ''
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module VCR
|
2
|
+
module Normalizers
|
3
|
+
module URI
|
4
|
+
DEFAULT_PORTS = {
|
5
|
+
'http' => 80,
|
6
|
+
'https' => 443
|
7
|
+
}
|
8
|
+
|
9
|
+
def initialize(*args)
|
10
|
+
super
|
11
|
+
normalize_uri
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def normalize_uri
|
17
|
+
u = begin
|
18
|
+
::URI.parse(uri)
|
19
|
+
rescue ::URI::InvalidURIError
|
20
|
+
return
|
21
|
+
end
|
22
|
+
|
23
|
+
u.port ||= DEFAULT_PORTS[u.scheme]
|
24
|
+
|
25
|
+
# URI#to_s only includes the port if it's not the default
|
26
|
+
# but we want to always include it (since FakeWeb/WebMock
|
27
|
+
# urls have always included it). We force it to be included
|
28
|
+
# here by redefining default_port so that URI#to_s will include it.
|
29
|
+
def u.default_port; nil; end
|
30
|
+
self.uri = u.to_s
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module VCR
|
2
|
+
class Request < Struct.new(:method, :uri, :body, :headers)
|
3
|
+
include Normalizers::Header
|
4
|
+
include Normalizers::URI
|
5
|
+
include Normalizers::Body
|
6
|
+
|
7
|
+
def self.from_net_http_request(net_http, request)
|
8
|
+
new(
|
9
|
+
request.method.downcase.to_sym,
|
10
|
+
VCR.http_stubbing_adapter.request_uri(net_http, request),
|
11
|
+
request.body,
|
12
|
+
request.to_hash
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
def matcher(match_attributes)
|
17
|
+
RequestMatcher.new(self, match_attributes)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module VCR
|
2
|
+
class Response < Struct.new(:status, :headers, :body, :http_version)
|
3
|
+
include Normalizers::Header
|
4
|
+
include Normalizers::Body
|
5
|
+
|
6
|
+
def self.from_net_http_response(response)
|
7
|
+
new(
|
8
|
+
ResponseStatus.from_net_http_response(response),
|
9
|
+
response.to_hash,
|
10
|
+
response.body,
|
11
|
+
response.http_version
|
12
|
+
)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module VCR
|
2
|
+
module Regexes
|
3
|
+
extend self
|
4
|
+
|
5
|
+
PROTOCOL = '\Ahttps?://'
|
6
|
+
CREDENTIALS = '((\w+:)?\w+@)?'
|
7
|
+
PORT = '(:\d+)?'
|
8
|
+
THE_REST = '/?(\?.*)?\z'
|
9
|
+
|
10
|
+
@@url_host_regexes = Hash.new do |hash, hosts|
|
11
|
+
hash[hosts] = begin
|
12
|
+
host_regex = hosts.map { |h| Regexp.escape(h) }.join('|')
|
13
|
+
%r|#{PROTOCOL}#{CREDENTIALS}(#{host_regex})#{PORT}/|i
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def url_regex_for_hosts(hosts)
|
18
|
+
@@url_host_regexes[hosts.sort]
|
19
|
+
end
|
20
|
+
|
21
|
+
@@url_path_regexes = Hash.new do |hash, path|
|
22
|
+
%r|#{PROTOCOL}[^/]+#{Regexp.escape(path)}#{THE_REST}|i
|
23
|
+
end
|
24
|
+
|
25
|
+
def url_regex_for_path(path)
|
26
|
+
@@url_path_regexes[path]
|
27
|
+
end
|
28
|
+
|
29
|
+
@@url_host_and_path_regexes = Hash.new do |hash, (host, path)|
|
30
|
+
%r|#{PROTOCOL}#{CREDENTIALS}#{Regexp.escape(host)}#{PORT}#{Regexp.escape(path)}#{THE_REST}|i
|
31
|
+
end
|
32
|
+
|
33
|
+
def url_regex_for_host_and_path(host, path)
|
34
|
+
@@url_host_and_path_regexes[[host, path]]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/vcr/version.rb
CHANGED
@@ -3,12 +3,23 @@ module VCR
|
|
3
3
|
|
4
4
|
def version
|
5
5
|
@version ||= begin
|
6
|
-
string = '1.
|
6
|
+
string = '1.6.0'
|
7
7
|
|
8
|
-
def string.parts
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
def string.parts
|
9
|
+
split('.').map { |p| p.to_i }
|
10
|
+
end
|
11
|
+
|
12
|
+
def string.major
|
13
|
+
parts[0]
|
14
|
+
end
|
15
|
+
|
16
|
+
def string.minor
|
17
|
+
parts[1]
|
18
|
+
end
|
19
|
+
|
20
|
+
def string.patch
|
21
|
+
parts[2]
|
22
|
+
end
|
12
23
|
|
13
24
|
string
|
14
25
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -14,6 +14,25 @@ require 'monkey_patches'
|
|
14
14
|
|
15
15
|
module VCR
|
16
16
|
SPEC_ROOT = File.dirname(__FILE__)
|
17
|
+
|
18
|
+
module Config
|
19
|
+
def reset!(stubbing_lib = :fakeweb)
|
20
|
+
self.default_cassette_options = { :record => :new_episodes }
|
21
|
+
|
22
|
+
if stubbing_lib
|
23
|
+
stub_with stubbing_lib
|
24
|
+
else
|
25
|
+
http_stubbing_libraries.clear
|
26
|
+
end
|
27
|
+
|
28
|
+
clear_hooks
|
29
|
+
@ignored_hosts = []
|
30
|
+
|
31
|
+
VCR.instance_eval do
|
32
|
+
instance_variables.each { |ivar| remove_instance_variable(ivar) }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
17
36
|
end
|
18
37
|
|
19
38
|
RSpec.configure do |config|
|
@@ -29,9 +48,7 @@ RSpec.configure do |config|
|
|
29
48
|
VCR.turn_on! unless VCR.turned_on?
|
30
49
|
VCR.eject_cassette while VCR.current_cassette
|
31
50
|
|
32
|
-
VCR::Config.
|
33
|
-
VCR::Config.stub_with :fakeweb
|
34
|
-
VCR::Config.clear_hooks
|
51
|
+
VCR::Config.reset!
|
35
52
|
|
36
53
|
WebMock.allow_net_connect!
|
37
54
|
WebMock.reset!
|
@@ -42,6 +59,12 @@ RSpec.configure do |config|
|
|
42
59
|
VCR::HttpStubbingAdapters::Faraday.reset!
|
43
60
|
end
|
44
61
|
|
62
|
+
config.after(:each) do
|
63
|
+
VCR::HttpStubbingAdapters::Common.adapters.each do |a|
|
64
|
+
a.ignored_hosts = []
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
45
68
|
config.filter_run :focus => true
|
46
69
|
config.run_all_when_everything_filtered = true
|
47
70
|
|