vcr 1.1.2 → 1.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.
- data/.gitignore +1 -1
- data/.gitmodules +3 -0
- data/CHANGELOG.md +58 -1
- data/Gemfile +2 -4
- data/Gemfile.lock +26 -49
- data/README.md +92 -23
- data/Rakefile +6 -3
- data/features/fixtures/vcr_cassettes/1.9.1/record_all.yml +62 -0
- data/features/fixtures/vcr_cassettes/not_1.9.1/record_all.yml +61 -0
- data/features/http_client.feature +2 -2
- data/features/net_http.feature +15 -4
- data/features/record_response.feature +36 -7
- data/features/replay_recorded_response.feature +8 -8
- data/features/rspec.feature +100 -0
- data/features/step_definitions/net_http_steps.rb +13 -1
- data/features/step_definitions/vcr_steps.rb +26 -16
- data/features/support/env.rb +13 -5
- data/features/webmock.feature +4 -4
- data/lib/vcr.rb +5 -5
- data/lib/vcr/cassette.rb +55 -19
- data/lib/vcr/extensions/net_http.rb +2 -4
- data/lib/vcr/http_stubbing_adapters/fakeweb.rb +0 -4
- data/lib/vcr/http_stubbing_adapters/webmock.rb +2 -9
- data/lib/vcr/internet_connection.rb +13 -0
- data/lib/vcr/ping.rb +26 -0
- data/lib/vcr/rspec.rb +39 -0
- data/lib/vcr/version.rb +1 -1
- data/spec/cassette_spec.rb +160 -69
- data/spec/config_spec.rb +1 -1
- data/spec/cucumber_tags_spec.rb +3 -2
- data/spec/deprecations_spec.rb +1 -1
- data/spec/extensions/net_http_response_spec.rb +2 -4
- data/spec/extensions/net_http_spec.rb +3 -1
- data/spec/fixtures/1.9.1/cassette_spec/with_localhost_requests.yml +23 -0
- data/spec/fixtures/not_1.9.1/cassette_spec/with_localhost_requests.yml +23 -0
- data/spec/http_stubbing_adapters/fakeweb_spec.rb +3 -9
- data/spec/http_stubbing_adapters/webmock_spec.rb +7 -18
- data/spec/internet_connection_spec.rb +19 -0
- data/spec/monkey_patches.rb +45 -6
- data/spec/request_matcher_spec.rb +1 -1
- data/spec/rspec_spec.rb +46 -0
- data/spec/spec_helper.rb +6 -11
- data/spec/structs_spec.rb +1 -1
- data/spec/support/fixnum_extension.rb +10 -0
- data/spec/support/http_library_adapters.rb +31 -2
- data/spec/support/ruby_interpreter.rb +7 -0
- data/spec/support/vcr_localhost_server.rb +86 -44
- data/spec/support/webmock_macros.rb +14 -0
- data/spec/vcr_spec.rb +1 -1
- data/spec/version_spec.rb +1 -1
- data/vcr.gemspec +10 -6
- metadata +155 -39
@@ -53,6 +53,29 @@
|
|
53
53
|
- "277"
|
54
54
|
body: 127.0.0.1 response
|
55
55
|
http_version: "1.1"
|
56
|
+
- !ruby/struct:VCR::HTTPInteraction
|
57
|
+
request: !ruby/struct:VCR::Request
|
58
|
+
method: :get
|
59
|
+
uri: http://0.0.0.0:80/
|
60
|
+
body:
|
61
|
+
headers:
|
62
|
+
response: !ruby/struct:VCR::Response
|
63
|
+
status: !ruby/struct:VCR::ResponseStatus
|
64
|
+
code: 404
|
65
|
+
message: Not Found
|
66
|
+
headers:
|
67
|
+
content-type:
|
68
|
+
- text/html; charset=iso-8859-1
|
69
|
+
connection:
|
70
|
+
- close
|
71
|
+
server:
|
72
|
+
- Apache/2.2.3 (CentOS)
|
73
|
+
date:
|
74
|
+
- Thu, 25 Feb 2010 07:53:52 GMT
|
75
|
+
content-length:
|
76
|
+
- "277"
|
77
|
+
body: 127.0.0.1 response
|
78
|
+
http_version: "1.1"
|
56
79
|
- !ruby/struct:VCR::HTTPInteraction
|
57
80
|
request: !ruby/struct:VCR::Request
|
58
81
|
method: :get
|
@@ -1,15 +1,9 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
describe VCR::HttpStubbingAdapters::FakeWeb do
|
4
|
-
|
5
|
-
|
6
|
-
describe '#should_unwind_response?' do
|
7
|
-
let(:response) { ::Net::HTTPOK.new('1.1', 200, 'OK') }
|
4
|
+
without_webmock_callbacks
|
8
5
|
|
9
|
-
|
10
|
-
described_class.should_unwind_response?(response).should be_true
|
11
|
-
end
|
12
|
-
end
|
6
|
+
it_should_behave_like 'an http stubbing adapter', ['net/http'], [:method, :uri, :host, :path]
|
13
7
|
|
14
8
|
describe '#check_version!' do
|
15
9
|
disable_warnings
|
@@ -1,27 +1,16 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
describe VCR::HttpStubbingAdapters::WebMock do
|
4
|
+
without_monkey_patches :vcr
|
5
|
+
|
4
6
|
it_should_behave_like 'an http stubbing adapter',
|
5
|
-
%w[net/http patron httpclient em-http-request],
|
7
|
+
%w[net/http patron httpclient em-http-request curb],
|
6
8
|
[:method, :uri, :host, :path, :body, :headers]
|
7
9
|
|
8
|
-
describe '#should_unwind_response?' do
|
9
|
-
let(:response) { ::Net::HTTPOK.new('1.1', 200, 'OK') }
|
10
|
-
|
11
|
-
it 'returns true when the response has not been extended with WebMock::Net::HTTPResponse' do
|
12
|
-
described_class.should_unwind_response?(response).should be_true
|
13
|
-
end
|
14
|
-
|
15
|
-
it 'returns false when the response has been extended with WebMock::Net::HTTPResponse' do
|
16
|
-
response.extend WebMock::Net::HTTPResponse
|
17
|
-
described_class.should_unwind_response?(response).should be_false
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
10
|
describe '#check_version!' do
|
22
11
|
before(:each) { WebMock.should respond_to(:version) }
|
23
12
|
|
24
|
-
%w( 0.9.9 0.9.10 0.1.30 1.0.30 1.2.9 1.3.
|
13
|
+
%w( 0.9.9 0.9.10 0.1.30 1.0.30 1.2.9 1.3.9 ).each do |version|
|
25
14
|
it "raises an error when WebMock's version is #{version}" do
|
26
15
|
WebMock.stub!(:version).and_return(version)
|
27
16
|
described_class.should_not_receive(:warn)
|
@@ -29,7 +18,7 @@ describe VCR::HttpStubbingAdapters::WebMock do
|
|
29
18
|
end
|
30
19
|
end
|
31
20
|
|
32
|
-
%w( 1.
|
21
|
+
%w( 1.4.0 1.4.10 1.4.99 ).each do |version|
|
33
22
|
it "does nothing when WebMock's version is #{version}" do
|
34
23
|
WebMock.stub!(:version).and_return(version)
|
35
24
|
described_class.should_not_receive(:warn)
|
@@ -37,7 +26,7 @@ describe VCR::HttpStubbingAdapters::WebMock do
|
|
37
26
|
end
|
38
27
|
end
|
39
28
|
|
40
|
-
%w( 1.
|
29
|
+
%w( 1.5.0 1.10.0 2.0.0 ).each do |version|
|
41
30
|
it "does nothing when WebMock's version is #{version}" do
|
42
31
|
WebMock.stub!(:version).and_return(version)
|
43
32
|
described_class.should_receive(:warn).with(/VCR is known to work with WebMock ~> .*\./)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe VCR::InternetConnection do
|
4
|
+
describe '.available?' do
|
5
|
+
before(:each) do
|
6
|
+
described_class.instance_variable_set(:@available, nil)
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'returns true when pinging example.com succeeds' do
|
10
|
+
Ping.stub(:pingecho).with("example.com", anything, anything).and_return(true)
|
11
|
+
described_class.available?.should be_true
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'returns false when pinging example.com fails' do
|
15
|
+
Ping.stub(:pingecho).with("example.com", anything, anything).and_return(false)
|
16
|
+
described_class.available?.should be_false
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/spec/monkey_patches.rb
CHANGED
@@ -1,6 +1,13 @@
|
|
1
1
|
module MonkeyPatches
|
2
2
|
extend self
|
3
3
|
|
4
|
+
module RSpecMacros
|
5
|
+
def without_monkey_patches(scope)
|
6
|
+
before(:each) { MonkeyPatches.disable!(scope) }
|
7
|
+
after(:each) { MonkeyPatches.enable!(scope) }
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
4
11
|
NET_HTTP_SINGLETON = class << Net::HTTP; self; end
|
5
12
|
|
6
13
|
MONKEY_PATCHES = [
|
@@ -10,15 +17,27 @@ module MonkeyPatches
|
|
10
17
|
[NET_HTTP_SINGLETON, :socket_type]
|
11
18
|
]
|
12
19
|
|
13
|
-
def enable!
|
14
|
-
|
15
|
-
|
20
|
+
def enable!(scope)
|
21
|
+
case scope
|
22
|
+
when :all
|
23
|
+
MONKEY_PATCHES.each do |mp|
|
24
|
+
realias mp.first, mp.last, :with_monkeypatches
|
25
|
+
end
|
26
|
+
when :vcr
|
27
|
+
realias Net::HTTP, :request, :with_vcr
|
28
|
+
else raise ArgumentError.new("Unexpected scope: #{scope}")
|
16
29
|
end
|
17
30
|
end
|
18
31
|
|
19
|
-
def disable!
|
20
|
-
|
21
|
-
|
32
|
+
def disable!(scope)
|
33
|
+
case scope
|
34
|
+
when :all
|
35
|
+
MONKEY_PATCHES.each do |mp|
|
36
|
+
realias mp.first, mp.last, :without_monkeypatches
|
37
|
+
end
|
38
|
+
when :vcr
|
39
|
+
realias Net::HTTP, :request, :without_vcr
|
40
|
+
else raise ArgumentError.new("Unexpected scope: #{scope}")
|
22
41
|
end
|
23
42
|
end
|
24
43
|
|
@@ -68,3 +87,23 @@ module MonkeyPatches
|
|
68
87
|
end
|
69
88
|
end
|
70
89
|
|
90
|
+
# Require all the HTTP libraries--these must be required before WebMock
|
91
|
+
# for WebMock to work with them.
|
92
|
+
require 'httpclient'
|
93
|
+
|
94
|
+
if RUBY_INTERPRETER == :mri
|
95
|
+
require 'patron'
|
96
|
+
require 'em-http-request'
|
97
|
+
require 'curb'
|
98
|
+
end
|
99
|
+
|
100
|
+
# The FakeWeb adapter must be required after WebMock's so
|
101
|
+
# that VCR's Net::HTTP monkey patch is loaded last.
|
102
|
+
# This allows us to disable it (i.e. by realiasing to
|
103
|
+
# the version of Net::HTTP's methods before it was loaded)
|
104
|
+
require 'vcr/http_stubbing_adapters/webmock'
|
105
|
+
require 'vcr/http_stubbing_adapters/fakeweb'
|
106
|
+
|
107
|
+
# All Net::HTTP monkey patches have now been loaded, so capture the
|
108
|
+
# appropriate method definitions so we can disable them later.
|
109
|
+
MonkeyPatches.init
|
data/spec/rspec_spec.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe VCR::RSpec::Macros do
|
4
|
+
extend described_class
|
5
|
+
|
6
|
+
describe '#use_vcr_cassette' do
|
7
|
+
def self.perform_test(context_name, expected_cassette_name, *args, &block)
|
8
|
+
context context_name do
|
9
|
+
after(:each) do
|
10
|
+
if @test_ejection
|
11
|
+
VCR.current_cassette.should be_nil
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
use_vcr_cassette *args
|
16
|
+
|
17
|
+
it 'ejects the cassette in an after hook' do
|
18
|
+
VCR.current_cassette.should be_a(VCR::Cassette)
|
19
|
+
@test_ejection = true
|
20
|
+
end
|
21
|
+
|
22
|
+
it "creates a cassette named '#{expected_cassette_name}" do
|
23
|
+
VCR.current_cassette.name.should == expected_cassette_name
|
24
|
+
end
|
25
|
+
|
26
|
+
module_eval(&block) if block
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
perform_test 'when called with an explicit name', 'explicit_name', 'explicit_name'
|
31
|
+
|
32
|
+
perform_test 'when called with an explicit name and some options', 'explicit_name', 'explicit_name', :match_requests_on => [:method, :host] do
|
33
|
+
it 'uses the provided cassette options' do
|
34
|
+
VCR.current_cassette.match_requests_on.should == [:method, :host]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
perform_test 'when called with nothing', 'VCR::RSpec::Macros/#use_vcr_cassette/when called with nothing'
|
39
|
+
|
40
|
+
perform_test 'when called with some options', 'VCR::RSpec::Macros/#use_vcr_cassette/when called with some options', :match_requests_on => [:method, :host] do
|
41
|
+
it 'uses the provided cassette options' do
|
42
|
+
VCR.current_cassette.match_requests_on.should == [:method, :host]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -2,14 +2,6 @@ require 'rubygems'
|
|
2
2
|
require 'bundler'
|
3
3
|
Bundler.setup
|
4
4
|
|
5
|
-
require 'monkey_patches'
|
6
|
-
|
7
|
-
require 'patron' unless RUBY_PLATFORM =~ /java/
|
8
|
-
require 'httpclient'
|
9
|
-
require 'em-http-request' unless RUBY_PLATFORM =~ /java/
|
10
|
-
require 'vcr'
|
11
|
-
require 'vcr/http_stubbing_adapters/fakeweb'
|
12
|
-
require 'vcr/http_stubbing_adapters/webmock'
|
13
5
|
require 'rspec'
|
14
6
|
|
15
7
|
# Ruby 1.9.1 has a different yaml serialization format.
|
@@ -19,12 +11,17 @@ YAML_SERIALIZATION_VERSION = RUBY_VERSION == '1.9.1' ? '1.9.1' : 'not_1.9.1'
|
|
19
11
|
# in ./support/ and its subdirectories.
|
20
12
|
Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f}
|
21
13
|
|
14
|
+
require 'vcr'
|
15
|
+
require 'monkey_patches'
|
16
|
+
|
22
17
|
RSpec.configure do |config|
|
23
18
|
config.extend TempCassetteLibraryDir
|
24
19
|
config.extend DisableWarnings
|
20
|
+
config.extend MonkeyPatches::RSpecMacros
|
21
|
+
config.extend WebMockMacros
|
25
22
|
|
26
23
|
config.color_enabled = true
|
27
|
-
config.debug =
|
24
|
+
config.debug = RUBY_INTERPRETER == :mri
|
28
25
|
|
29
26
|
config.before(:each) do
|
30
27
|
VCR::Config.default_cassette_options = { :record => :new_episodes }
|
@@ -41,5 +38,3 @@ RSpec.configure do |config|
|
|
41
38
|
config.run_all_when_everything_filtered = true
|
42
39
|
end
|
43
40
|
|
44
|
-
MonkeyPatches.init
|
45
|
-
|
data/spec/structs_spec.rb
CHANGED
@@ -67,12 +67,41 @@ HTTP_LIBRARY_ADAPTERS['em-http-request'] = Module.new do
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
+
HTTP_LIBRARY_ADAPTERS['curb'] = Module.new do
|
71
|
+
def self.http_library_name; "Curb"; end
|
72
|
+
|
73
|
+
def get_body_string(response)
|
74
|
+
response.body_str
|
75
|
+
end
|
76
|
+
|
77
|
+
def get_header(header_key, response)
|
78
|
+
headers = response.header_str.split("\r\n")[1..-1]
|
79
|
+
headers.each do |h|
|
80
|
+
if h =~ /^#{Regexp.escape(header_key)}: (.*)$/
|
81
|
+
return $1.split(', ')
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def make_http_request(method, url, body = nil, headers = {})
|
87
|
+
Curl::Easy.new(url) do |c|
|
88
|
+
c.headers = headers
|
89
|
+
|
90
|
+
if [:post, :put].include?(method)
|
91
|
+
c.send("http_#{method}", body)
|
92
|
+
else
|
93
|
+
c.send("http_#{method}")
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
70
99
|
NET_CONNECT_NOT_ALLOWED_ERROR = /You can use VCR to automatically record this request and replay it later/
|
71
100
|
|
72
101
|
module HttpLibrarySpecs
|
73
102
|
def test_http_library(library, supported_request_match_attributes)
|
74
|
-
# patron and em-http-client cannot be installed on jruby
|
75
|
-
return if %w[patron em-http-request].include?(library) &&
|
103
|
+
# curb, patron and em-http-client cannot be installed on jruby
|
104
|
+
return if %w[curb patron em-http-request].include?(library) && RUBY_INTERPRETER != :mri
|
76
105
|
|
77
106
|
unless adapter_module = HTTP_LIBRARY_ADAPTERS[library]
|
78
107
|
raise ArgumentError.new("No http library adapter module could be found for #{library}")
|
@@ -1,53 +1,95 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
3
|
-
|
4
|
-
#
|
5
|
-
#
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
Rack::Handler::WEBrick.run(Identify.new(@app), :Port => port, :AccessLog => [], :Logger => WEBrick::BasicLog.new(StringIO.new))
|
20
|
-
exit # manually exit; otherwise this sub-process will re-run the specs that haven't run yet.
|
21
|
-
end
|
22
|
-
Capybara.log "checking if application has booted"
|
23
|
-
|
24
|
-
Capybara::WaitUntil.timeout(10) do
|
25
|
-
if responsive?
|
26
|
-
Capybara.log("application has booted")
|
27
|
-
true
|
28
|
-
else
|
29
|
-
sleep 0.5
|
30
|
-
false
|
1
|
+
require 'rack'
|
2
|
+
require 'rack/handler/webrick'
|
3
|
+
|
4
|
+
# The code for this is inspired by Capybara's server:
|
5
|
+
# http://github.com/jnicklas/capybara/blob/0.3.9/lib/capybara/server.rb
|
6
|
+
module VCR
|
7
|
+
class LocalhostServer
|
8
|
+
class Identify
|
9
|
+
def initialize(app)
|
10
|
+
@app = app
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
if env["PATH_INFO"] == "/__identify__"
|
15
|
+
[200, {}, @app.object_id.to_s]
|
16
|
+
else
|
17
|
+
@app.call(env)
|
18
|
+
end
|
31
19
|
end
|
32
20
|
end
|
33
21
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
22
|
+
attr_reader :port
|
23
|
+
|
24
|
+
def initialize(rack_app)
|
25
|
+
@port = find_available_port
|
26
|
+
@rack_app = rack_app
|
27
|
+
concurrently { boot }
|
28
|
+
wait_until(10, "Boot failed.") { booted? }
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def find_available_port
|
34
|
+
server = TCPServer.new('127.0.0.1', 0)
|
35
|
+
server.addr[1]
|
36
|
+
ensure
|
37
|
+
server.close if server
|
38
|
+
end
|
39
|
+
|
40
|
+
def boot
|
41
|
+
# Use WEBrick since it's part of the ruby standard library and is available on all ruby interpreters.
|
42
|
+
Rack::Handler::WEBrick.run(Identify.new(@rack_app), :Port => port, :AccessLog => [], :Logger => WEBrick::BasicLog.new(StringIO.new))
|
43
|
+
end
|
44
|
+
|
45
|
+
def booted?
|
46
|
+
res = ::Net::HTTP.get_response("localhost", '/__identify__', port)
|
47
|
+
|
48
|
+
if res.is_a?(::Net::HTTPSuccess) or res.is_a?(::Net::HTTPRedirection)
|
49
|
+
return res.body == @rack_app.object_id.to_s
|
50
|
+
end
|
51
|
+
rescue Errno::ECONNREFUSED, Errno::EBADF
|
52
|
+
return false
|
53
|
+
end
|
54
|
+
|
55
|
+
def concurrently
|
56
|
+
if RUBY_INTERPRETER == :mri
|
57
|
+
# Patron times out when the server is running in a separate thread in the same process,
|
58
|
+
# so use a separate process.
|
59
|
+
pid = Process.fork do
|
60
|
+
yield
|
61
|
+
exit # manually exit; otherwise this sub-process will re-run the specs that haven't run yet.
|
62
|
+
end
|
63
|
+
|
64
|
+
at_exit do
|
65
|
+
Process.kill('INT', pid)
|
66
|
+
begin
|
67
|
+
Process.wait(pid)
|
68
|
+
rescue Errno::ECHILD
|
69
|
+
# ignore this error...I think it means the child process has already exited.
|
70
|
+
end
|
71
|
+
end
|
72
|
+
else
|
73
|
+
# JRuby doesn't support forking.
|
74
|
+
# Rubinius does, but there's a weird issue with the booted? check not working,
|
75
|
+
# so we're just using a thread for now.
|
76
|
+
Thread.new { yield }
|
40
77
|
end
|
41
78
|
end
|
42
79
|
|
43
|
-
|
44
|
-
|
45
|
-
Capybara.log "Rack application timed out during boot"
|
46
|
-
exit
|
47
|
-
end unless RUBY_PLATFORM =~ /java/
|
80
|
+
def wait_until(timeout, error_message, &block)
|
81
|
+
start_time = Time.now
|
48
82
|
|
49
|
-
|
50
|
-
|
51
|
-
|
83
|
+
while true
|
84
|
+
return if yield
|
85
|
+
raise TimeoutError.new(error_message) if (Time.now - start_time) > timeout
|
86
|
+
sleep(0.05)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
STATIC_SERVERS = Hash.new do |h, k|
|
91
|
+
h[k] = new(lambda { |env| [200, {}, StringIO.new(k)] })
|
92
|
+
end
|
52
93
|
end
|
53
94
|
end
|
95
|
+
|