vcr 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/CHANGELOG.md +12 -0
  2. data/FullBuildRakeFile +22 -0
  3. data/Gemfile +8 -0
  4. data/Gemfile.lock +46 -25
  5. data/Guardfile +9 -0
  6. data/README.md +10 -371
  7. data/Rakefile +6 -2
  8. data/TODO.md +4 -0
  9. data/features/support/env.rb +5 -1
  10. data/full_build +1 -0
  11. data/lib/vcr.rb +17 -7
  12. data/lib/vcr/basic_object.rb +39 -0
  13. data/lib/vcr/config.rb +4 -7
  14. data/lib/vcr/deprecations.rb +14 -0
  15. data/lib/vcr/http_stubbing_adapters/common.rb +44 -13
  16. data/lib/vcr/http_stubbing_adapters/fakeweb.rb +17 -28
  17. data/lib/vcr/http_stubbing_adapters/multi_object_proxy.rb +43 -0
  18. data/lib/vcr/http_stubbing_adapters/typhoeus.rb +101 -0
  19. data/lib/vcr/http_stubbing_adapters/webmock.rb +16 -37
  20. data/lib/vcr/internet_connection.rb +2 -1
  21. data/lib/vcr/structs.rb +32 -0
  22. data/lib/vcr/version.rb +1 -1
  23. data/spec/config_spec.rb +5 -25
  24. data/spec/deprecations_spec.rb +31 -3
  25. data/spec/extensions/net_http_spec.rb +1 -0
  26. data/spec/fixtures/1.9.1/fake_example.com_responses.yml +32 -1
  27. data/spec/fixtures/not_1.9.1/fake_example.com_responses.yml +32 -1
  28. data/spec/http_stubbing_adapters/fakeweb_spec.rb +9 -24
  29. data/spec/http_stubbing_adapters/multi_object_proxy_spec.rb +101 -0
  30. data/spec/http_stubbing_adapters/typhoeus_spec.rb +28 -0
  31. data/spec/http_stubbing_adapters/webmock_spec.rb +8 -26
  32. data/spec/internet_connection_spec.rb +25 -7
  33. data/spec/spec_helper.rb +3 -1
  34. data/spec/structs_spec.rb +30 -6
  35. data/spec/support/http_library_adapters.rb +50 -15
  36. data/spec/support/http_stubbing_adapter.rb +65 -56
  37. data/spec/support/version_checker.rb +29 -0
  38. data/spec/vcr_spec.rb +30 -12
  39. data/vcr.gemspec +5 -4
  40. metadata +44 -15
@@ -6,24 +6,27 @@ module VCR
6
6
  include VCR::HttpStubbingAdapters::Common
7
7
  extend self
8
8
 
9
- VERSION_REQUIREMENT = '1.4.0'
10
-
11
- def http_connections_allowed?
12
- ::WebMock::Config.instance.allow_net_connect
13
- end
9
+ MINIMUM_VERSION = '1.4.0'
10
+ MAXIMUM_VERSION = '1.5'
14
11
 
15
12
  def http_connections_allowed=(value)
16
13
  ::WebMock::Config.instance.allow_net_connect = value
17
14
  end
18
15
 
19
- def stub_requests(http_interactions, match_attributes)
20
- requests = Hash.new { |h,k| h[k] = [] }
16
+ def http_connections_allowed?
17
+ !!::WebMock::Config.instance.allow_net_connect
18
+ end
21
19
 
22
- http_interactions.each do |i|
23
- requests[i.request.matcher(match_attributes)] << i.response
24
- end
20
+ def ignore_localhost=(value)
21
+ ::WebMock::Config.instance.allow_localhost = value
22
+ end
25
23
 
26
- requests.each do |request_matcher, responses|
24
+ def ignore_localhost?
25
+ !!::WebMock::Config.instance.allow_localhost
26
+ end
27
+
28
+ def stub_requests(http_interactions, match_attributes)
29
+ grouped_responses(http_interactions, match_attributes).each do |request_matcher, responses|
27
30
  stub = ::WebMock.stub_request(request_matcher.method || :any, request_matcher.uri)
28
31
 
29
32
  with_hash = request_signature_hash(request_matcher)
@@ -41,23 +44,6 @@ module VCR
41
44
  ::WebMock::RequestRegistry.instance.request_stubs = checkpoints.delete(checkpoint_name)
42
45
  end
43
46
 
44
- def request_stubbed?(request, match_attributes)
45
- matcher = request.matcher(match_attributes)
46
- !!::WebMock.registered_request?(::WebMock::RequestSignature.new(matcher.method || :any, request.uri, request_signature_hash(matcher)))
47
- end
48
-
49
- def request_uri(net_http, request)
50
- ::WebMock::NetHTTPUtility.request_signature_from_request(net_http, request).uri.to_s
51
- end
52
-
53
- def ignore_localhost=(value)
54
- ::WebMock::Config.instance.allow_localhost = value
55
- end
56
-
57
- def ignore_localhost?
58
- ::WebMock::Config.instance.allow_localhost
59
- end
60
-
61
47
  private
62
48
 
63
49
  def version
@@ -108,12 +94,5 @@ WebMock.after_request(:real_requests_only => true) do |request, response|
108
94
  VCR.record_http_interaction(http_interaction)
109
95
  end
110
96
 
111
- if defined?(WebMock::NetConnectNotAllowedError)
112
- module WebMock
113
- class NetConnectNotAllowedError
114
- def message
115
- super + ". You can use VCR to automatically record this request and replay it later. For more details, see the VCR README at: http://github.com/myronmarston/vcr/tree/v#{VCR.version}"
116
- end
117
- end
118
- end
119
- end
97
+ VCR::HttpStubbingAdapters::Common.add_vcr_info_to_exception_message(WebMock::NetConnectNotAllowedError)
98
+
@@ -7,7 +7,8 @@ module VCR
7
7
  EXAMPLE_HOST = "example.com"
8
8
 
9
9
  def available?
10
- @available ||= Ping.pingecho(EXAMPLE_HOST, 1, 80)
10
+ @available = Ping.pingecho(EXAMPLE_HOST, 1, 80) unless defined?(@available)
11
+ @available
11
12
  end
12
13
  end
13
14
  end
data/lib/vcr/structs.rb CHANGED
@@ -24,8 +24,40 @@ module VCR
24
24
  end
25
25
  end
26
26
 
27
+ module URINormalizer
28
+ DEFAULT_PORTS = {
29
+ 'http' => 80,
30
+ 'https' => 443
31
+ }
32
+
33
+ def initialize(*args)
34
+ super
35
+ normalize_uri
36
+ end
37
+
38
+ private
39
+
40
+ def normalize_uri
41
+ u = begin
42
+ URI.parse(uri)
43
+ rescue URI::InvalidURIError
44
+ return
45
+ end
46
+
47
+ u.port ||= DEFAULT_PORTS[u.scheme]
48
+
49
+ # URI#to_s only includes the port if it's not the default
50
+ # but we want to always include it (since FakeWeb/WebMock
51
+ # urls have always included it). We force it to be included
52
+ # here by redefining default_port so that URI#to_s will include it.
53
+ def u.default_port; nil; end
54
+ self.uri = u.to_s
55
+ end
56
+ end
57
+
27
58
  class Request < Struct.new(:method, :uri, :body, :headers)
28
59
  include HeaderNormalizer
60
+ include URINormalizer
29
61
 
30
62
  def self.from_net_http_request(net_http, request)
31
63
  new(
data/lib/vcr/version.rb CHANGED
@@ -3,7 +3,7 @@ module VCR
3
3
 
4
4
  def version
5
5
  @version ||= begin
6
- string = '1.2.0'
6
+ string = '1.3.0'
7
7
 
8
8
  def string.parts; VCR.version.split('.').map { |p| p.to_i }; end
9
9
  def string.major; parts[0]; end
data/spec/config_spec.rb CHANGED
@@ -28,30 +28,10 @@ describe VCR::Config do
28
28
  end
29
29
  end
30
30
 
31
- describe '#http_stubbing_library' do
32
- it 'returns the configured value' do
33
- [:fakeweb, :webmock].each do |setting|
34
- VCR::Config.http_stubbing_library = setting
35
- VCR::Config.http_stubbing_library.should == setting
36
- end
37
- end
38
-
39
- context 'when set to nil' do
40
- before(:each) { VCR::Config.http_stubbing_library = nil }
41
-
42
- {
43
- [:FakeWeb, :WebMock] => nil,
44
- [] => nil,
45
- [:FakeWeb] => :fakeweb,
46
- [:WebMock] => :webmock
47
- }.each do |defined_constants, expected_return_value|
48
- it "returns #{expected_return_value.inspect} when these constants are defined: #{defined_constants.inspect}" do
49
- [:FakeWeb, :WebMock].each do |const|
50
- Object.should_receive(:const_defined?).with(const).and_return(defined_constants.include?(const))
51
- end
52
- VCR::Config.http_stubbing_library.should == expected_return_value
53
- end
54
- end
31
+ describe '.stub_with' do
32
+ it 'stores the given symbols in http_stubbing_libraries' do
33
+ VCR::Config.stub_with :fakeweb, :typhoeus
34
+ VCR::Config.http_stubbing_libraries.should == [:fakeweb, :typhoeus]
55
35
  end
56
36
  end
57
37
 
@@ -73,4 +53,4 @@ describe VCR::Config do
73
53
  end
74
54
  end
75
55
  end
76
- end
56
+ end
@@ -1,8 +1,36 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'Deprecations' do
4
+ disable_warnings
5
+
6
+ describe VCR::Config do
7
+ describe '.http_stubbing_library' do
8
+ before(:each) { described_class.stub_with :webmock, :typhoeus }
9
+
10
+ it 'returns the first configured stubbing library' do
11
+ described_class.http_stubbing_library.should == :webmock
12
+ end
13
+
14
+ it 'prints a warning: WARNING: VCR::Config.http_stubbing_library is deprecated. Use VCR::Config.http_stubbing_libraries instead' do
15
+ described_class.should_receive(:warn).with("WARNING: `VCR::Config.http_stubbing_library` is deprecated. Use `VCR::Config.http_stubbing_libraries` instead.")
16
+ described_class.http_stubbing_library
17
+ end
18
+ end
19
+
20
+ describe '.http_stubbing_library=' do
21
+ it 'sets http_stubbing_libraries to an array of the given value' do
22
+ described_class.http_stubbing_library = :webmock
23
+ described_class.http_stubbing_libraries.should == [:webmock]
24
+ end
25
+
26
+ it 'prints a warning: WARNING: VCR::Config.http_stubbing_library= is deprecated. Use VCR::Config.stub_with instead' do
27
+ described_class.should_receive(:warn).with("WARNING: `VCR::Config.http_stubbing_library = :webmock` is deprecated. Use `VCR::Config.stub_with :webmock` instead.")
28
+ described_class.http_stubbing_library = :webmock
29
+ end
30
+ end
31
+ end
32
+
4
33
  describe VCR::Cassette do
5
- disable_warnings
6
34
  subject { VCR::Cassette.new('cassette name') }
7
35
 
8
36
  it 'raises an error when an :allow_real_http lambda is given' do
@@ -23,7 +51,7 @@ describe 'Deprecations' do
23
51
 
24
52
  it "sets the http_stubbing_adapter's ignore_localhost attribute to true" do
25
53
  subject
26
- VCR.http_stubbing_adapter.ignore_localhost?.should be_true
54
+ VCR.http_stubbing_adapter.ignore_localhost?.should == true
27
55
  end
28
56
 
29
57
  it "prints a warning: VCR's :allow_real_http cassette option is deprecated. Instead, use the ignore_localhost configuration option." do
@@ -49,4 +77,4 @@ describe 'Deprecations' do
49
77
  end
50
78
  end
51
79
  end
52
- end
80
+ end
@@ -4,6 +4,7 @@ describe "Net::HTTP Extensions" do
4
4
  without_webmock_callbacks
5
5
 
6
6
  let(:uri) { URI.parse('http://example.com') }
7
+ before(:each) { VCR.stub(:http_stubbing_adapter).and_return(VCR::HttpStubbingAdapters::FakeWeb) }
7
8
 
8
9
  it 'checks if the request is stubbed using a VCR::Request' do
9
10
  VCR.http_stubbing_adapter.should_receive(:request_stubbed?) do |request, _|
@@ -57,7 +57,38 @@
57
57
  - "3285"
58
58
  accept-ranges:
59
59
  - bytes
60
- :body: example.com get response with path=foo
60
+ :body: example.com get response 1 with path=foo
61
+ :http_version: "1.1"
62
+ - !ruby/struct:VCR::HTTPInteraction
63
+ :request: !ruby/struct:VCR::Request
64
+ :method: :get
65
+ :uri: http://example.com:80/foo
66
+ :body:
67
+ :headers:
68
+ :response: !ruby/struct:VCR::Response
69
+ :status: !ruby/struct:VCR::ResponseStatus
70
+ :code: 200
71
+ :message: OK
72
+ :headers:
73
+ etag:
74
+ - "\"24ec5-1b6-4059a80bfd280\""
75
+ last-modified:
76
+ - Tue, 15 Nov 2005 13:24:10 GMT
77
+ connection:
78
+ - Keep-Alive
79
+ content-type:
80
+ - text/html; charset=UTF-8
81
+ date:
82
+ - Wed, 31 Mar 2010 02:43:23 GMT
83
+ server:
84
+ - Apache/2.2.3 (CentOS)
85
+ content-length:
86
+ - "438"
87
+ age:
88
+ - "3285"
89
+ accept-ranges:
90
+ - bytes
91
+ :body: example.com get response 2 with path=foo
61
92
  :http_version: "1.1"
62
93
  - !ruby/struct:VCR::HTTPInteraction
63
94
  :request: !ruby/struct:VCR::Request
@@ -57,7 +57,38 @@
57
57
  - "3285"
58
58
  accept-ranges:
59
59
  - bytes
60
- body: example.com get response with path=foo
60
+ body: example.com get response 1 with path=foo
61
+ http_version: "1.1"
62
+ - !ruby/struct:VCR::HTTPInteraction
63
+ request: !ruby/struct:VCR::Request
64
+ method: :get
65
+ uri: http://example.com:80/foo
66
+ body:
67
+ headers:
68
+ response: !ruby/struct:VCR::Response
69
+ status: !ruby/struct:VCR::ResponseStatus
70
+ code: 200
71
+ message: OK
72
+ headers:
73
+ last-modified:
74
+ - Tue, 15 Nov 2005 13:24:10 GMT
75
+ connection:
76
+ - Keep-Alive
77
+ etag:
78
+ - "\"24ec5-1b6-4059a80bfd280\""
79
+ content-type:
80
+ - text/html; charset=UTF-8
81
+ date:
82
+ - Wed, 31 Mar 2010 02:43:23 GMT
83
+ server:
84
+ - Apache/2.2.3 (CentOS)
85
+ content-length:
86
+ - "438"
87
+ age:
88
+ - "3285"
89
+ accept-ranges:
90
+ - bytes
91
+ body: example.com get response 2 with path=foo
61
92
  http_version: "1.1"
62
93
  - !ruby/struct:VCR::HTTPInteraction
63
94
  request: !ruby/struct:VCR::Request
@@ -3,35 +3,20 @@ require 'spec_helper'
3
3
  describe VCR::HttpStubbingAdapters::FakeWeb do
4
4
  without_webmock_callbacks
5
5
 
6
- it_should_behave_like 'an http stubbing adapter', ['net/http'], [:method, :uri, :host, :path]
6
+ it_behaves_like 'an http stubbing adapter', ['net/http'], [:method, :uri, :host, :path], :needs_net_http_extension
7
7
 
8
- describe '#check_version!' do
8
+ it_performs('version checking',
9
+ :valid => %w[ 1.3.0 1.3.1 1.3.99 ],
10
+ :too_low => %w[ 1.2.8 1.1.30 0.30.30 ],
11
+ :too_high => %w[ 1.4.0 1.10.0 2.0.0 ]
12
+ ) do
9
13
  disable_warnings
10
14
  before(:each) { @orig_version = FakeWeb::VERSION }
11
15
  after(:each) { FakeWeb::VERSION = @orig_version }
12
16
 
13
- %w( 1.2.8 1.1.30 0.30.30 ).each do |version|
14
- it "raises an error when FakeWeb's version is #{version}" do
15
- FakeWeb::VERSION = version
16
- described_class.should_not_receive(:warn)
17
- expect { described_class.check_version! }.to raise_error(/You are using FakeWeb #{version}. VCR requires version .* or greater/)
18
- end
19
- end
20
-
21
- %w( 1.3.0 1.3.1 1.3.99 ).each do |version|
22
- it "does nothing when FakeWeb's version is #{version}" do
23
- FakeWeb::VERSION = version
24
- described_class.should_not_receive(:warn)
25
- expect { described_class.check_version! }.to_not raise_error
26
- end
27
- end
28
-
29
- %w( 1.4.0 1.10.0 2.0.0 ).each do |version|
30
- it "prints a warning when FakeWeb's version is #{version}" do
31
- FakeWeb::VERSION = version
32
- described_class.should_receive(:warn).with(/VCR is known to work with FakeWeb ~> .*\./)
33
- expect { described_class.check_version! }.to_not raise_error
34
- end
17
+ # Cannot be regular method def as that raises a "dynamic constant assignment" error
18
+ define_method :stub_version do |version|
19
+ FakeWeb::VERSION = version
35
20
  end
36
21
  end
37
22
  end
@@ -0,0 +1,101 @@
1
+ require 'spec_helper'
2
+
3
+ module VCR
4
+ module HttpStubbingAdapters
5
+ describe MultiObjectProxy do
6
+ let(:mock1) { mock }
7
+ let(:mock2) { mock }
8
+ subject { described_class.new(mock1, mock2) }
9
+
10
+ it 'raises an error when it is created with no objects' do
11
+ expect { described_class.new }.to raise_error(ArgumentError)
12
+ end
13
+
14
+ it 'raises an error when one of the objects is nil' do
15
+ expect { described_class.new(Object.new, nil) }.to raise_error(ArgumentError)
16
+ end
17
+
18
+ it 'is a basic object with very few of its own methods' do
19
+ inst_methods = described_class.instance_methods.map { |m| m.to_sym }
20
+ inst_methods.should_not include(:send, :object_id, :__id__)
21
+ end
22
+
23
+ describe '#proxies_objects' do
24
+ it 'returns the proxied objects' do
25
+ subject.proxied_objects.should == [mock1, mock2]
26
+ end
27
+ end
28
+
29
+ describe '#respond_to?' do
30
+ it 'responds to any method that any of the objects responds to' do
31
+ mock1.stub(:respond_to?).with(:foo).and_return(true)
32
+ mock1.stub(:respond_to?).with(:bar).and_return(false)
33
+ mock2.stub(:respond_to?).with(:bar).and_return(true)
34
+ mock2.stub(:respond_to?).with(:foo).and_return(false)
35
+
36
+ subject.respond_to?(:foo).should be_true
37
+ subject.respond_to?(:bar).should be_true
38
+ end
39
+
40
+ it 'does not respond to a method that none of the objects respond to' do
41
+ subject.respond_to?(:bazz).should be_false
42
+ end
43
+ end
44
+
45
+ describe 'calling a method' do
46
+ it 'raises a no method error when none of the objects responds to the method' do
47
+ expect { subject.some_undefined_method }.to raise_error(NoMethodError)
48
+ end
49
+
50
+ it 'properly proxies messages to a single object when only one object responds to the message' do
51
+ mock1.should_not respond_to(:request_stubbed?)
52
+ mock2.should_receive(:request_stubbed?).and_return(true)
53
+
54
+ subject.request_stubbed?.should == true
55
+ end
56
+
57
+ it 'proxies messages to each object' do
58
+ mock1.should_receive(:stub_requests).with(:arg1, :arg2)
59
+ mock2.should_receive(:stub_requests).with(:arg1, :arg2)
60
+
61
+ subject.stub_requests(:arg1, :arg2)
62
+ end
63
+
64
+ [:http_connections_allowed?, :request_uri].each do |method|
65
+ context "for ##{method}" do
66
+ it 'raises an error if the the objects return different values' do
67
+ mock1.should_receive(method).and_return(:return_value_1)
68
+ mock2.should_receive(method).and_return(:return_value_2)
69
+
70
+ expect { subject.__send__(method) }.to raise_error(/proxied objects returned different values/)
71
+ end
72
+
73
+ it 'returns the value returned by both objects when they return the same value' do
74
+ mock1.should_receive(method).and_return(:return_value_1)
75
+ mock2.should_receive(method).and_return(:return_value_1)
76
+
77
+ subject.__send__(method).should == :return_value_1
78
+ end
79
+ end
80
+ end
81
+
82
+ context 'for a non-predicate method' do
83
+ it 'does not raise an error when the objects have different return values' do
84
+ mock1.should_receive(:stub_requests).and_return(:val1)
85
+ mock2.should_receive(:stub_requests).and_return(:val2)
86
+
87
+ subject.stub_requests
88
+ end
89
+
90
+ it 'returns nil regardless of the return values of the objects' do
91
+ mock1.should_receive(:stub_requests).and_return(:val1)
92
+ mock2.should_receive(:stub_requests).and_return(:val1)
93
+
94
+ subject.stub_requests.should be_nil
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+