vcr 1.8.0 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,9 @@
1
1
  script: "rake ci:build"
2
2
  rvm:
3
+ - 1.8.6
3
4
  - 1.8.7
5
+ - 1.9.1
4
6
  - 1.9.2
7
+ - ree
8
+ - rbx
9
+ - jruby
@@ -1,6 +1,12 @@
1
1
  ## In git
2
2
 
3
- [Full Changelog](http://github.com/myronmarston/vcr/compare/v1.8.0...master)
3
+ [Full Changelog](http://github.com/myronmarston/vcr/compare/v1.9.0...master)
4
+
5
+ ## 1.9.0 (April 14, 2011)
6
+
7
+ [Full Changelog](http://github.com/myronmarston/vcr/compare/v1.8.0...v1.9.0)
8
+
9
+ * Add support for [Excon](https://github.com/geemus/excon).
4
10
 
5
11
  ## 1.8.0 (March 31, 2011)
6
12
 
data/Gemfile CHANGED
@@ -33,6 +33,7 @@ group :extras do
33
33
  end
34
34
 
35
35
  platforms :mri_19 do
36
+ gem 'linecache19', '0.5.11' # 0.5.12 cannot install on 1.9.1, and 0.5.11 appears to work with both 1.9.1 & 1.9.2
36
37
  gem 'ruby-debug19'
37
38
  gem 'ruby-debug-base19', RUBY_VERSION == '1.9.1' ? '0.11.23' : '~> 0.11.24'
38
39
  end
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # VCR [![Build Status](http://travis-ci.org/myronmarston/vcr.png)](http://travis-ci.org/myronmarston/vcr)
1
+ # VCR
2
2
 
3
3
  Record your test suite's HTTP interactions and replay them during future test runs for fast, deterministic, accurate tests.
4
4
 
@@ -15,9 +15,9 @@ Record your test suite's HTTP interactions and replay them during future test ru
15
15
 
16
16
  class VCRTest < Test::Unit::TestCase
17
17
  def test_example_dot_com
18
- VCR.use_cassette('synopsis', :record => :new_episodes) do
19
- response = Net::HTTP.get_response(URI.parse('http://example.com/'))
20
- assert_match /You have reached this web page by typing.*example\.com/, response.body
18
+ VCR.use_cassette('synopsis') do
19
+ response = Net::HTTP.get_response(URI('http://www.iana.org/domains/example/'))
20
+ assert_match /Example Domains/, response.body
21
21
  end
22
22
  end
23
23
  end
@@ -36,6 +36,7 @@ maintenance) and accurate (the response from example.com will contain the same h
36
36
  * [WebMock](https://github.com/bblimke/webmock)
37
37
  * [Typhoeus](https://github.com/dbalatero/typhoeus)
38
38
  * [Faraday](https://github.com/technoweenie/faraday)
39
+ * [Excon](https://github.com/geemus/excon)
39
40
  * Supports multiple HTTP libraries:
40
41
  * [Patron](http://github.com/toland/patron) (when using WebMock)
41
42
  * [Curb](http://github.com/taf2/curb) (when using WebMock -- only supports Curb::Easy at the moment)
@@ -43,6 +44,7 @@ maintenance) and accurate (the response from example.com will contain the same h
43
44
  * [em-http-request](http://github.com/igrigorik/em-http-request) (when using WebMock)
44
45
  * [Net::HTTP](http://www.ruby-doc.org/stdlib/libdoc/net/http/rdoc/index.html) (when using FakeWeb and WebMock)
45
46
  * [Typhoeus](https://github.com/dbalatero/typhoeus) (Typhoeus::Hydra, but not Typhoeus::Easy or Typhoeus::Multi)
47
+ * [Excon](https://github.com/geemus/excon)
46
48
  * [Faraday](https://github.com/technoweenie/faraday)
47
49
  * And of course any library built on Net::HTTP, such as [Mechanize](http://github.com/tenderlove/mechanize),
48
50
  [HTTParty](http://github.com/jnunemaker/httparty) or [Rest Client](http://github.com/archiloque/rest-client).
@@ -125,6 +127,8 @@ If you find VCR useful, please recommend me on [working with rails](http://worki
125
127
  the inspiration for VCR.
126
128
  * [David Balatero](https://github.com/dbalatero) for help with [Typhoeus](https://github.com/pauldix/typhoeus)
127
129
  support.
130
+ * [Wesley Beary](https://github.com/geemus) for help with [Excon](https://github.com/geemus/excon)
131
+ support.
128
132
 
129
133
  Thanks also to the following people who have contributed patches or helpful suggestions:
130
134
 
data/Rakefile CHANGED
@@ -33,6 +33,7 @@ task :default => [:spec, :cucumber]
33
33
  namespace :ci do
34
34
  desc "Sets things up for a ci build on travis-ci.org"
35
35
  task :setup do
36
+ ENV['TRAVIS'] = 'true'
36
37
  sh "git submodule init"
37
38
  sh "git submodule update"
38
39
  end
@@ -7,6 +7,10 @@ interp_opts = if defined?(RUBY_ENGINE)
7
7
  else
8
8
  ''
9
9
  end
10
+
11
+ if ENV['TRAVIS'] && RUBY_VERSION == '1.8.6'
12
+ interp_opts << ' --tags ~@exclude-travis-186'
13
+ end
10
14
  %>
11
15
  default: <%= std_opts %><%= interp_opts %> features
12
16
  wip: --tags @wip:30 --wip features<%= interp_opts %>
@@ -89,3 +89,4 @@ Feature: Cassette format
89
89
  | :webmock | curb |
90
90
  | :webmock | em-http-request |
91
91
  | :typhoeus | typhoeus |
92
+ | :excon | excon |
@@ -46,6 +46,7 @@ Feature: Error for HTTP request made when no cassette is in use
46
46
  | :webmock | patron | Real HTTP connections are disabled |
47
47
  | :webmock | em-http-request | Real HTTP connections are disabled |
48
48
  | :typhoeus | typhoeus | Real HTTP requests are not allowed |
49
+ | :excon | excon | Real HTTP connections are disabled |
49
50
 
50
51
  Scenario: Temporarily turn VCR off to allow HTTP requests to procede as normal
51
52
  Given a file named "turn_off_vcr.rb" with:
@@ -95,6 +95,7 @@ Feature: Request matching
95
95
  | :webmock | curb |
96
96
  | :webmock | em-http-request |
97
97
  | :typhoeus | typhoeus |
98
+ | :excon | excon |
98
99
 
99
100
  Scenario Outline: match on host and path (to ignore query params)
100
101
  Given a previously recorded cassette file "cassettes/example.yml" with:
@@ -164,6 +165,7 @@ Feature: Request matching
164
165
  | :webmock | curb |
165
166
  | :webmock | em-http-request |
166
167
  | :typhoeus | typhoeus |
168
+ | :excon | excon |
167
169
 
168
170
  Scenario Outline: match on request body
169
171
  Given a previously recorded cassette file "cassettes/example.yml" with:
@@ -236,6 +238,7 @@ Feature: Request matching
236
238
  | :webmock | curb |
237
239
  | :webmock | em-http-request |
238
240
  | :typhoeus | typhoeus |
241
+ | :excon | excon |
239
242
 
240
243
  Scenario Outline: match on request headers
241
244
  Given a previously recorded cassette file "cassettes/example.yml" with:
@@ -308,6 +311,7 @@ Feature: Request matching
308
311
  | :webmock | curb |
309
312
  | :webmock | em-http-request |
310
313
  | :typhoeus | typhoeus |
314
+ | :excon | excon |
311
315
 
312
316
  Scenario Outline: Use a regex for the request URI
313
317
  Given a previously recorded cassette file "cassettes/example.yml" with:
@@ -146,8 +146,8 @@ Feature: Filter sensitive data
146
146
  And the file "cassettes/example.yml" should contain "body: john.doe/<PASSWORD>"
147
147
  And the file "cassettes/example.yml" should contain a YAML fragment like:
148
148
  """
149
- x-http-password:
150
- - <PASSWORD>
149
+ x-http-password:
150
+ - <PASSWORD>
151
151
  """
152
152
 
153
153
  When I run "ruby dynamic_filtering.rb"
@@ -58,4 +58,5 @@ Feature: ignore_hosts
58
58
  | :webmock | curb |
59
59
  | :webmock | em-http-request |
60
60
  | :typhoeus | typhoeus |
61
+ | :excon | excon |
61
62
 
@@ -61,6 +61,8 @@ Feature: ignore_localhost
61
61
  | :webmock | em-http-request | Real HTTP connections are disabled | c.ignore_localhost = false |
62
62
  | :typhoeus | typhoeus | Real HTTP requests are not allowed | |
63
63
  | :typhoeus | typhoeus | Real HTTP requests are not allowed | c.ignore_localhost = false |
64
+ | :excon | excon | Real HTTP connections are disabled | |
65
+ | :excon | excon | Real HTTP connections are disabled | c.ignore_localhost = false |
64
66
 
65
67
  Scenario Outline: localhost requests are allowed and not recorded when ignore_localhost = true
66
68
  Given a file named "ignore_localhost_true.rb" with:
@@ -100,4 +102,5 @@ Feature: ignore_localhost
100
102
  | :webmock | curb |
101
103
  | :webmock | em-http-request |
102
104
  | :typhoeus | typhoeus |
105
+ | :excon | excon |
103
106
 
@@ -13,6 +13,7 @@ Feature: stub_with
13
13
  - EM HTTP Request
14
14
  - Typhoeus can be used to stub itself (as long as you use Typhoeus::Hydra,
15
15
  but not Typhoeus::Easy or Typhoeus::Multi).
16
+ - Excon can be used to stub itself.
16
17
  - Faraday can be used (in combination with the provided Faraday middleware)
17
18
  to stub requests made through Faraday (regardless of which Faraday HTTP
18
19
  adapter is used).
@@ -30,12 +31,12 @@ Feature: stub_with
30
31
  supported HTTP libraries. No monkey patching is used for Typhoeus or
31
32
  Faraday.
32
33
  - FakeWeb and WebMock cannot both be used at the same time.
33
- - Typhoeus and Faraday can be used together, and with either
34
+ - Typhoeus, Excon and Faraday can be used together, and with either
34
35
  FakeWeb or WebMock.
35
36
 
36
37
  Regardless of which library you use, VCR takes care of all of the configuration
37
38
  for you. You should not need to interact directly with FakeWeb, WebMock or the
38
- stubbing facilities of Typhoeus or Faraday. If/when you decide to change stubbing
39
+ stubbing facilities of Typhoeus, Excon or Faraday. If/when you decide to change stubbing
39
40
  libraries (i.e. if you initially use FakeWeb because it's faster but later need the
40
41
  additional features of WebMock) you can change the `stub_with` configuration
41
42
  option and it'll work with no other changes required.
@@ -52,6 +53,7 @@ Feature: stub_with
52
53
  puts "FakeWeb Loaded: #{!!defined?(FakeWeb)}"
53
54
  puts "WebMock Loaded: #{!!defined?(WebMock)}"
54
55
  puts "Typhoeus Loaded: #{!!defined?(Typhoeus)}"
56
+ puts "Excon Loaded: #{!!defined?(Excon)}"
55
57
  """
56
58
  When I run "ruby vcr_stub_with.rb"
57
59
  Then the output should contain:
@@ -59,13 +61,15 @@ Feature: stub_with
59
61
  FakeWeb Loaded: <fakeweb_loaded>
60
62
  WebMock Loaded: <webmock_loaded>
61
63
  Typhoeus Loaded: <typhoeus_loaded>
64
+ Excon Loaded: <excon_loaded>
62
65
  """
63
66
 
64
67
  Examples:
65
- | stub_with | fakeweb_loaded | webmock_loaded | typhoeus_loaded |
66
- | :fakeweb | true | false | false |
67
- | :webmock | false | true | false |
68
- | :typhoeus | false | false | true |
68
+ | stub_with | fakeweb_loaded | webmock_loaded | typhoeus_loaded | excon_loaded |
69
+ | :fakeweb | true | false | false | false |
70
+ | :webmock | false | true | false | false |
71
+ | :typhoeus | false | false | true | false |
72
+ | :excon | false | false | false | true |
69
73
 
70
74
  Scenario Outline: Record and replay a request using each supported stubbing/http library combination
71
75
  Given a file named "stubbing_http_lib_combo.rb" with:
@@ -111,13 +115,15 @@ Feature: stub_with
111
115
  | :webmock | curb |
112
116
  | :webmock | em-http-request |
113
117
  | :typhoeus | typhoeus |
118
+ | :excon | excon |
114
119
 
115
120
  @exclude-jruby
116
- Scenario Outline: Use Typhoeus and Faraday in combination with FakeWeb or WebMock
121
+ Scenario Outline: Use Typhoeus, Excon and Faraday in combination with FakeWeb or WebMock
117
122
  Given a file named "stub_with_multiple.rb" with:
118
123
  """
119
124
  require 'vcr_cucumber_helpers'
120
125
  require 'typhoeus'
126
+ require 'excon'
121
127
 
122
128
  start_sinatra_app(:port => 7777) do
123
129
  get('/:path') { "#{ARGV[0]} #{params[:path]}" }
@@ -131,6 +137,10 @@ Feature: stub_with
131
137
  Typhoeus::Request.get("http://localhost:7777/typhoeus").body
132
138
  end
133
139
 
140
+ def excon_response
141
+ Excon.get("http://localhost:7777/excon").body
142
+ end
143
+
134
144
  def faraday_response
135
145
  Faraday::Connection.new(:url => 'http://localhost:7777') do |builder|
136
146
  builder.use VCR::Middleware::Faraday do |cassette|
@@ -144,17 +154,19 @@ Feature: stub_with
144
154
 
145
155
  puts "Net::HTTP 1: #{net_http_response}"
146
156
  puts "Typhoeus 1: #{typhoeus_response}"
157
+ puts "Excon 1: #{excon_response}"
147
158
 
148
159
  require 'vcr'
149
160
 
150
161
  VCR.config do |c|
151
- c.stub_with <stub_with>, :typhoeus, :faraday
162
+ c.stub_with <stub_with>, :typhoeus, :excon, :faraday
152
163
  c.cassette_library_dir = 'vcr_cassettes'
153
164
  end
154
165
 
155
166
  VCR.use_cassette('example', :record => :new_episodes) do
156
167
  puts "Net::HTTP 2: #{net_http_response}"
157
168
  puts "Typhoeus 2: #{typhoeus_response}"
169
+ puts "Excon 2: #{excon_response}"
158
170
  end
159
171
 
160
172
  puts "Faraday: #{faraday_response}"
@@ -163,20 +175,25 @@ Feature: stub_with
163
175
  Then the output should contain each of the following:
164
176
  | Net::HTTP 1: Hello net_http |
165
177
  | Typhoeus 1: Hello typhoeus |
178
+ | Excon 1: Hello excon |
166
179
  | Net::HTTP 2: Hello net_http |
167
180
  | Typhoeus 2: Hello typhoeus |
181
+ | Excon 2: Hello excon |
168
182
  | Faraday: Hello faraday |
169
183
  And the cassette "vcr_cassettes/example.yml" should have the following response bodies:
170
184
  | Hello net_http |
171
185
  | Hello typhoeus |
186
+ | Hello excon |
172
187
  | Hello faraday |
173
188
 
174
189
  When I run "ruby stub_with_multiple.rb 'Goodbye'"
175
190
  Then the output should contain each of the following:
176
191
  | Net::HTTP 1: Goodbye net_http |
177
192
  | Typhoeus 1: Goodbye typhoeus |
193
+ | Excon 1: Goodbye excon |
178
194
  | Net::HTTP 2: Hello net_http |
179
195
  | Typhoeus 2: Hello typhoeus |
196
+ | Excon 2: Hello excon |
180
197
  | Faraday: Hello faraday |
181
198
 
182
199
  Examples:
@@ -1,4 +1,4 @@
1
- @exclude-jruby @exclude-rbx
1
+ @exclude-jruby @exclude-rbx @exclude-travis-186
2
2
  Feature: EM HTTP Request
3
3
 
4
4
  EM HTTP Request allows multiple simultaneous asynchronous requests.
@@ -34,6 +34,16 @@ module VCRHelpers
34
34
  s.response.headers.reject! { |k, v| %w[ server date ].include?(k) }
35
35
  end
36
36
 
37
+ case $stubbing_lib_for_current_scenario
38
+ when ':excon'
39
+ # Excon does not expose the status message or http version,
40
+ # so we have no way to record these attributes.
41
+ structs.each do |s|
42
+ s.response.status.message = nil
43
+ s.response.http_version = nil
44
+ end
45
+ end
46
+
37
47
  structs
38
48
  end
39
49
 
@@ -100,17 +110,16 @@ Then /^the file "([^"]*)" should contain:$/ do |file_name, expected_content|
100
110
  end
101
111
 
102
112
  Then /^the file "([^"]*)" should contain a YAML fragment like:$/ do |file_name, fragment|
103
- if defined?(::Psych)
104
- # psych serializes things slightly differently...
105
- fragment = fragment.split("\n").map { |s| s.rstrip }.join("\n")
106
- end
113
+ in_current_dir do
114
+ file_content = File.read(file_name)
107
115
 
108
- # JRuby serializes things a bit differently
109
- if RUBY_PLATFORM == 'java'
110
- fragment = fragment.gsub(/^(\s+\-)/,' \1')
111
- end
116
+ # Normalize by removing leading and trailing whitespace...
117
+ file_content = file_content.split("\n").map do |line|
118
+ line.strip
119
+ end.join("\n")
112
120
 
113
- check_file_content(file_name, fragment, true)
121
+ file_content.should include(fragment)
122
+ end
114
123
  end
115
124
 
116
125
  Then /^the cassette "([^"]*)" should have the following response bodies:$/ do |file, table|
@@ -22,6 +22,8 @@ elsif defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
22
22
  elsif RUBY_PLATFORM == 'java'
23
23
  # These gems have C extensions and can't install on JRuby.
24
24
  UNSUPPORTED_HTTP_LIBS = %w[ typhoeus patron curb em-http-request ]
25
+ elsif RUBY_VERSION == '1.8.6' && ENV['TRAVIS']
26
+ UNSUPPORTED_HTTP_LIBS = %w[ em-http-request ]
25
27
  end
26
28
 
27
29
  if defined?(UNSUPPORTED_HTTP_LIBS)
@@ -35,3 +37,19 @@ if defined?(UNSUPPORTED_HTTP_LIBS)
35
37
  end
36
38
  end
37
39
 
40
+ stubbing_libs = %w[ :fakeweb :webmock :typhoeus :faraday :excon ]
41
+
42
+ # Set a global based on the current stubbing lib so we can put special-case
43
+ # logic in our step definitions based on the http stubbing library.
44
+ Before do |scenario|
45
+ if scenario.respond_to?(:cell_values)
46
+ stub_with = stubbing_libs & scenario.cell_values
47
+ if stub_with.size == 1
48
+ $stubbing_lib_for_current_scenario = stub_with.first
49
+ else
50
+ $stubbing_lib_for_current_scenario = nil
51
+ end
52
+ else
53
+ $stubbing_lib_for_current_scenario = nil
54
+ end
55
+ end
data/lib/vcr.rb CHANGED
@@ -140,10 +140,11 @@ module VCR
140
140
 
141
141
  def adapter_for(lib)
142
142
  case lib
143
+ when :excon; HttpStubbingAdapters::Excon
143
144
  when :fakeweb; HttpStubbingAdapters::FakeWeb
144
- when :webmock; HttpStubbingAdapters::WebMock
145
- when :typhoeus; HttpStubbingAdapters::Typhoeus
146
145
  when :faraday; HttpStubbingAdapters::Faraday
146
+ when :typhoeus; HttpStubbingAdapters::Typhoeus
147
+ when :webmock; HttpStubbingAdapters::WebMock
147
148
  else raise ArgumentError.new("#{lib.inspect} is not a supported HTTP stubbing library.")
148
149
  end
149
150
  end
@@ -1,5 +1,6 @@
1
1
  module VCR
2
2
  module HttpStubbingAdapters
3
+ autoload :Excon, 'vcr/http_stubbing_adapters/excon'
3
4
  autoload :FakeWeb, 'vcr/http_stubbing_adapters/fakeweb'
4
5
  autoload :Faraday, 'vcr/http_stubbing_adapters/faraday'
5
6
  autoload :MultiObjectProxy, 'vcr/http_stubbing_adapters/multi_object_proxy'
@@ -0,0 +1,221 @@
1
+ require 'excon'
2
+
3
+ module VCR
4
+ module HttpStubbingAdapters
5
+ module Excon
6
+ include VCR::HttpStubbingAdapters::Common
7
+ extend self
8
+
9
+ class HttpConnectionNotAllowedError < StandardError; end
10
+
11
+ MINIMUM_VERSION = '0.6.2'
12
+ MAXIMUM_VERSION = '0.6'
13
+
14
+ attr_writer :http_connections_allowed
15
+
16
+ def http_connections_allowed?
17
+ !!@http_connections_allowed
18
+ end
19
+
20
+ def ignored_hosts=(hosts)
21
+ @ignored_hosts = hosts
22
+ end
23
+
24
+ def uri_should_be_ignored?(uri)
25
+ uri = URI.parse(uri) unless uri.respond_to?(:host)
26
+ ignored_hosts.include?(uri.host)
27
+ end
28
+
29
+ def stub_requests(http_interactions, match_attributes)
30
+ match_attributes_stack << match_attributes
31
+ grouped_responses(http_interactions, match_attributes).each do |request_matcher, responses|
32
+ queue = stub_queues[request_matcher]
33
+ responses.each { |res| queue << res }
34
+ end
35
+ end
36
+
37
+ def create_stubs_checkpoint(cassette)
38
+ checkpoints[cassette] = stub_queue_dup
39
+ end
40
+
41
+ def restore_stubs_checkpoint(cassette)
42
+ match_attributes_stack.pop
43
+ @stub_queues = checkpoints.delete(cassette) || super
44
+ end
45
+
46
+ def stubbed_response_for(request)
47
+ return nil unless match_attributes_stack.any?
48
+ request_matcher = request.matcher(match_attributes_stack.last)
49
+ queue = stub_queues[request_matcher]
50
+ return queue.shift if queue.size > 1
51
+ queue.first
52
+ end
53
+
54
+ def reset!
55
+ instance_variables.each do |ivar|
56
+ remove_instance_variable(ivar)
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ def version
63
+ ::Excon::VERSION
64
+ end
65
+
66
+ def ignored_hosts
67
+ @ignored_hosts ||= []
68
+ end
69
+
70
+ def checkpoints
71
+ @checkpoints ||= {}
72
+ end
73
+
74
+ def stub_queues
75
+ @stub_queues ||= hash_of_arrays
76
+ end
77
+
78
+ def match_attributes_stack
79
+ @match_attributes_stack ||= []
80
+ end
81
+
82
+ def stub_queue_dup
83
+ dup = hash_of_arrays
84
+
85
+ stub_queues.each do |k, v|
86
+ dup[k] = v.dup
87
+ end
88
+
89
+ dup
90
+ end
91
+
92
+ def hash_of_arrays
93
+ Hash.new { |h, k| h[k] = [] }
94
+ end
95
+
96
+ class RequestHandler
97
+ attr_reader :params
98
+ def initialize(params)
99
+ @params = params
100
+ end
101
+
102
+ def handle
103
+ case
104
+ when request_should_be_ignored?
105
+ perform_real_request
106
+ when stubbed_response
107
+ stubbed_response
108
+ when http_connections_allowed?
109
+ record_interaction
110
+ else
111
+ raise_connections_disabled_error
112
+ end
113
+ end
114
+
115
+ private
116
+
117
+ def request_should_be_ignored?
118
+ VCR::HttpStubbingAdapters::Excon.uri_should_be_ignored?(uri)
119
+ end
120
+
121
+ def stubbed_response
122
+ unless defined?(@stubbed_response)
123
+ @stubbed_response = VCR::HttpStubbingAdapters::Excon.stubbed_response_for(vcr_request)
124
+
125
+ if @stubbed_response && @stubbed_response.headers
126
+ @stubbed_response.headers = normalized_headers(@stubbed_response.headers)
127
+ end
128
+ end
129
+
130
+ @stubbed_response
131
+ end
132
+
133
+ def http_connections_allowed?
134
+ VCR::HttpStubbingAdapters::Excon.http_connections_allowed?
135
+ end
136
+
137
+ def perform_real_request
138
+ connection = ::Excon.new(uri)
139
+ response = connection.request(params.merge(:mock => false))
140
+
141
+ yield response if block_given?
142
+
143
+ response.attributes
144
+ end
145
+
146
+ def record_interaction
147
+ perform_real_request do |response|
148
+ if VCR::HttpStubbingAdapters::Excon.enabled?
149
+ http_interaction = http_interaction_for(response)
150
+ VCR.record_http_interaction(http_interaction)
151
+ end
152
+ end
153
+ end
154
+
155
+ def uri
156
+ @uri ||= begin
157
+ uri = "#{params[:scheme]}://#{params[:host]}:#{params[:port]}#{params[:path]}"
158
+ uri << "?#{params[:query]}" if params[:query]
159
+ uri
160
+ end
161
+ end
162
+
163
+ def http_interaction_for(response)
164
+ VCR::HTTPInteraction.new \
165
+ vcr_request,
166
+ vcr_response(response)
167
+ end
168
+
169
+ def vcr_request
170
+ @vcr_request ||= begin
171
+ headers = params[:headers].dup
172
+ headers.delete("Host")
173
+
174
+ VCR::Request.new \
175
+ params[:method],
176
+ uri,
177
+ params[:body],
178
+ headers
179
+ end
180
+ end
181
+
182
+ def vcr_response(response)
183
+ VCR::Response.new \
184
+ VCR::ResponseStatus.new(response.status, nil),
185
+ response.headers,
186
+ response.body,
187
+ nil
188
+ end
189
+
190
+ def normalized_headers(headers)
191
+ normalized = {}
192
+ headers.each do |k, v|
193
+ v = v.join(', ') if v.respond_to?(:join)
194
+ normalized[normalize_header_key(k)] = v
195
+ end
196
+ normalized
197
+ end
198
+
199
+ def normalize_header_key(key)
200
+ key.split('-'). # 'user-agent' => %w(user agent)
201
+ each { |w| w.capitalize! }. # => %w(User Agent)
202
+ join('-')
203
+ end
204
+
205
+ def raise_connections_disabled_error
206
+ raise HttpConnectionNotAllowedError.new(
207
+ "Real HTTP connections are disabled. Request: #{params[:method]} #{uri}"
208
+ )
209
+ end
210
+
211
+ ::Excon.stub({}) do |params|
212
+ self.new(params).handle
213
+ end
214
+ end
215
+
216
+ end
217
+ end
218
+ end
219
+
220
+ Excon.mock = true
221
+ VCR::HttpStubbingAdapters::Common.add_vcr_info_to_exception_message(VCR::HttpStubbingAdapters::Excon::HttpConnectionNotAllowedError)
@@ -3,7 +3,7 @@ module VCR
3
3
 
4
4
  def version
5
5
  @version ||= begin
6
- string = '1.8.0'
6
+ string = '1.9.0'
7
7
 
8
8
  def string.parts
9
9
  split('.').map { |p| p.to_i }
@@ -1 +1 @@
1
- rvm 1.8.6,1.8.7,1.9.1,1.9.2,ree,rbx rake -f script/FullBuildRakeFile build && rvm use jruby && bundle install && rake | tee tmp/full_build.out
1
+ rvm 1.8.6,1.8.7,1.9.1,1.9.2,ree,rbx rake -f script/FullBuildRakeFile build | tee tmp/full_build.out
@@ -1 +1 @@
1
- rvm 1.8.6,1.8.7,1.9.1,1.9.2,ree,rbx rake -f script/FullBuildRakeFile spec && rvm use jruby && bundle install && rake spec | tee tmp/spec.out
1
+ rvm 1.8.6,1.8.7,1.9.1,1.9.2,ree,rbx rake -f script/FullBuildRakeFile spec | tee tmp/spec.out
@@ -43,7 +43,9 @@ RSpec.configure do |config|
43
43
  config.color_enabled = true
44
44
  config.debug = (using_git && RUBY_INTERPRETER == :mri)
45
45
 
46
+ tmp_dir = File.expand_path('../../tmp/cassette_library_dir', __FILE__)
46
47
  config.before(:each) do
48
+ VCR::Config.cassette_library_dir = tmp_dir
47
49
  VCR.turn_on! unless VCR.turned_on?
48
50
  VCR.eject_cassette while VCR.current_cassette
49
51
 
@@ -56,17 +58,11 @@ RSpec.configure do |config|
56
58
  FakeWeb.clean_registry
57
59
 
58
60
  VCR::HttpStubbingAdapters::Faraday.reset!
59
- end
60
-
61
- # Ensure each example uses a different cassette library to keep them isolated.
62
- config.around(:each) do |example|
63
- Dir.mktmpdir do |dir|
64
- VCR::Config.cassette_library_dir = dir
65
- example.run
66
- end
61
+ VCR::HttpStubbingAdapters::Excon.reset!
67
62
  end
68
63
 
69
64
  config.after(:each) do
65
+ FileUtils.rm_rf tmp_dir
70
66
  VCR::HttpStubbingAdapters::Common.adapters.each do |a|
71
67
  a.ignored_hosts = []
72
68
  end
@@ -11,7 +11,14 @@ HTTP_LIBRARY_ADAPTERS['net/http'] = Module.new do
11
11
 
12
12
  def make_http_request(method, url, body = nil, headers = {})
13
13
  uri = URI.parse(url)
14
- Net::HTTP.new(uri.host, uri.port).send_request(method.to_s.upcase, uri.request_uri, body, headers)
14
+ http = Net::HTTP.new(uri.host, uri.port)
15
+
16
+ if uri.scheme == "https"
17
+ http.use_ssl = true
18
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
19
+ end
20
+
21
+ http.send_request(method.to_s.upcase, uri.request_uri, body, headers)
15
22
  end
16
23
  end
17
24
 
@@ -112,6 +119,22 @@ HTTP_LIBRARY_ADAPTERS['typhoeus'] = Module.new do
112
119
  end
113
120
  end
114
121
 
122
+ HTTP_LIBRARY_ADAPTERS['excon'] = Module.new do
123
+ def self.http_library_name; "Excon"; end
124
+
125
+ def get_body_string(response)
126
+ response.body
127
+ end
128
+
129
+ def get_header(header_key, response)
130
+ response.headers[header_key]
131
+ end
132
+
133
+ def make_http_request(method, url, body = nil, headers = {})
134
+ Excon.send(method, url, :body => body, :headers => headers)
135
+ end
136
+ end
137
+
115
138
  %w[ net_http typhoeus patron ].each do |_faraday_adapter|
116
139
  HTTP_LIBRARY_ADAPTERS["faraday-#{_faraday_adapter}"] = Module.new do
117
140
  class << self; self; end.class_eval do
@@ -7,7 +7,15 @@ shared_examples_for "an http library" do |library, supported_request_match_attri
7
7
  raise ArgumentError.new("No http library adapter module could be found for #{library}")
8
8
  end
9
9
 
10
- describe "using #{adapter_module.http_library_name}", :unless => (RUBY_INTERPRETER != :mri && library =~ /(typhoeus|curb|patron|em-http)/) do
10
+ http_lib_unsupported = if RUBY_INTERPRETER == :mri
11
+ # em-http-request is causing issues on 1.8.6 on travis like:
12
+ # ruby: symbol lookup error: /home/travis/.rvm/gems/ruby-1.8.6-p420/gems/em-http-request-0.3.0/lib/http11_client.so: undefined symbol: rb_hash_lookup
13
+ library =~ /em-http/ && RUBY_VERSION == '1.8.6' && ENV['TRAVIS']
14
+ else
15
+ library =~ /(typhoeus|curb|patron|em-http)/
16
+ end
17
+
18
+ describe "using #{adapter_module.http_library_name}", :unless => http_lib_unsupported do
11
19
  include adapter_module
12
20
 
13
21
  # Necessary for ruby 1.9.2. On 1.9.2 we get an error when we use super,
@@ -79,6 +87,9 @@ shared_examples_for "an http library" do |library, supported_request_match_attri
79
87
  end
80
88
  end
81
89
 
90
+ test_url "using https and no explicit port", "https://example.com/foo"
91
+ test_url "using https and port 443", "https://example.com:443/foo"
92
+ test_url "using https and some other port", "https://example.com:5190/foo"
82
93
  test_url "that has query params", "http://example.com/search?q=param"
83
94
  test_url "with spaces encoded as +", "http://example.com/search?q=a+b"
84
95
  test_url "with spaces encoded as %20", "http://example.com/search?q=a%20b"
@@ -307,7 +318,9 @@ shared_examples_for "an http library" do |library, supported_request_match_attri
307
318
  end unless other.include?(:does_not_support_rotating_responses)
308
319
 
309
320
  it "correctly handles stubbing multiple values for the same header" do
310
- get_header('Set-Cookie', make_http_request(:get, 'http://example.com/two_set_cookie_headers')).should =~ ['bar=bazz', 'foo=bar']
321
+ header = get_header('Set-Cookie', make_http_request(:get, 'http://example.com/two_set_cookie_headers'))
322
+ header = header.split(', ') if header.respond_to?(:split)
323
+ header.should =~ ['bar=bazz', 'foo=bar']
311
324
  end
312
325
 
313
326
  context 'when we restore our previous check point' do
@@ -80,13 +80,12 @@ describe VCR::Cassette do
80
80
 
81
81
  describe "reading the file from disk" do
82
82
  before(:each) do
83
- VCR::Config.cassette_library_dir = "cassette_lib"
84
83
  File.stub(:size? => true)
85
84
  end
86
85
 
87
86
  it 'reads the appropriate file from disk using a VCR::Cassette::Reader' do
88
87
  VCR::Cassette::Reader.should_receive(:new).with(
89
- 'cassette_lib/foo.yml', anything
88
+ "#{VCR::Config.cassette_library_dir}/foo.yml", anything
90
89
  ).and_return(mock('reader', :read => VCR::YAML.dump([])))
91
90
 
92
91
  VCR::Cassette.new('foo', :record => :new_episodes)
@@ -7,11 +7,11 @@ describe VCR::Config do
7
7
  end
8
8
 
9
9
  describe '.cassette_library_dir=' do
10
+ let(:tmp_dir) { VCR::SPEC_ROOT + '/../tmp/cassette_library_dir/new_dir' }
11
+ after(:each) { FileUtils.rm_rf tmp_dir }
12
+
10
13
  it 'creates the directory if it does not exist' do
11
- Dir.mktmpdir do |dir|
12
- dir += '/cassettes'
13
- expect { VCR::Config.cassette_library_dir = dir }.to change { File.exist?(dir) }.from(false).to(true)
14
- end
14
+ expect { VCR::Config.cassette_library_dir = tmp_dir }.to change { File.exist?(tmp_dir) }.from(false).to(true)
15
15
  end
16
16
 
17
17
  it 'does not raise an error if given nil' do
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe VCR::HttpStubbingAdapters::Excon, :without_monkey_patches => :vcr do
4
+ it_behaves_like 'an http stubbing adapter',
5
+ ['excon'],
6
+ [:method, :uri, :host, :path, :body, :headers],
7
+ :status_message_not_exposed
8
+
9
+ it_performs('version checking',
10
+ :valid => %w[ 0.6.2 0.6.99 ],
11
+ :too_low => %w[ 0.5.99 0.6.1 ],
12
+ :too_high => %w[ 0.7.0 1.0.0 ]
13
+ ) do
14
+ before(:each) { @orig_version = Excon::VERSION }
15
+ after(:each) { Excon::VERSION = @orig_version }
16
+
17
+ # Cannot be regular method def as that raises a "dynamic constant assignment" error
18
+ define_method :stub_version do |version|
19
+ Excon::VERSION = version
20
+ end
21
+ end
22
+ end
23
+
@@ -40,7 +40,7 @@ describe VCR::RequestMatcher do
40
40
 
41
41
  for_matcher :path do
42
42
  it("matches a basic URL for the same path") { should =~ 'http://domain.tld/path/to/something?p=v&q=r' }
43
- it("matches an https URL") { should =~ 'http://domain.tld/path/to/something?p=v&q=r' }
43
+ it("matches an https URL") { should =~ 'https://domain.tld/path/to/something?p=v&q=r' }
44
44
  it("ignores the case of the URL") { should =~ 'HTTP://DOMAIN.TLD/PATH/TO/SOMETHING?P=V&Q=R' }
45
45
  it("matches with a trailing slash") { should =~ 'http://domain.tld/path/to/something/' }
46
46
  it("matches without a trailing slash") { should =~ 'http://domain.tld/path/to/something' }
@@ -147,7 +147,8 @@ describe VCR do
147
147
  {
148
148
  :fakeweb => VCR::HttpStubbingAdapters::FakeWeb,
149
149
  :webmock => VCR::HttpStubbingAdapters::WebMock,
150
- :faraday => VCR::HttpStubbingAdapters::Faraday
150
+ :faraday => VCR::HttpStubbingAdapters::Faraday,
151
+ :excon => VCR::HttpStubbingAdapters::Excon
151
152
  }.each do |symbol, klass|
152
153
  it "returns #{klass} for :#{symbol}" do
153
154
  VCR::Config.stub_with symbol
@@ -31,6 +31,7 @@ Gem::Specification.new do |s|
31
31
 
32
32
  'faraday' => '~> 0.6.0',
33
33
  'httpclient' => '~> 2.1.5.2',
34
+ 'excon' => '~> 0.6.2',
34
35
 
35
36
  'timecop' => '~> 0.3.5',
36
37
  'rack' => '1.1.0',
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vcr
3
3
  version: !ruby/object:Gem::Version
4
- hash: 55
4
+ hash: 51
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
- - 8
8
+ - 9
9
9
  - 0
10
- version: 1.8.0
10
+ version: 1.9.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Myron Marston
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-03-31 00:00:00 -07:00
18
+ date: 2011-04-14 00:00:00 -07:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -197,8 +197,24 @@ dependencies:
197
197
  - !ruby/object:Gem::Dependency
198
198
  prerelease: false
199
199
  type: :development
200
- name: cucumber
200
+ name: excon
201
201
  version_requirements: &id012 !ruby/object:Gem::Requirement
202
+ none: false
203
+ requirements:
204
+ - - ~>
205
+ - !ruby/object:Gem::Version
206
+ hash: 3
207
+ segments:
208
+ - 0
209
+ - 6
210
+ - 2
211
+ version: 0.6.2
212
+ requirement: *id012
213
+ - !ruby/object:Gem::Dependency
214
+ prerelease: false
215
+ type: :development
216
+ name: cucumber
217
+ version_requirements: &id013 !ruby/object:Gem::Requirement
202
218
  none: false
203
219
  requirements:
204
220
  - - ~>
@@ -209,12 +225,12 @@ dependencies:
209
225
  - 9
210
226
  - 4
211
227
  version: 0.9.4
212
- requirement: *id012
228
+ requirement: *id013
213
229
  - !ruby/object:Gem::Dependency
214
230
  prerelease: false
215
231
  type: :development
216
232
  name: webmock
217
- version_requirements: &id013 !ruby/object:Gem::Requirement
233
+ version_requirements: &id014 !ruby/object:Gem::Requirement
218
234
  none: false
219
235
  requirements:
220
236
  - - ~>
@@ -225,12 +241,12 @@ dependencies:
225
241
  - 6
226
242
  - 0
227
243
  version: 1.6.0
228
- requirement: *id013
244
+ requirement: *id014
229
245
  - !ruby/object:Gem::Dependency
230
246
  prerelease: false
231
247
  type: :development
232
248
  name: curb
233
- version_requirements: &id014 !ruby/object:Gem::Requirement
249
+ version_requirements: &id015 !ruby/object:Gem::Requirement
234
250
  none: false
235
251
  requirements:
236
252
  - - "="
@@ -241,12 +257,12 @@ dependencies:
241
257
  - 7
242
258
  - 8
243
259
  version: 0.7.8
244
- requirement: *id014
260
+ requirement: *id015
245
261
  - !ruby/object:Gem::Dependency
246
262
  prerelease: false
247
263
  type: :development
248
264
  name: patron
249
- version_requirements: &id015 !ruby/object:Gem::Requirement
265
+ version_requirements: &id016 !ruby/object:Gem::Requirement
250
266
  none: false
251
267
  requirements:
252
268
  - - "="
@@ -257,12 +273,12 @@ dependencies:
257
273
  - 4
258
274
  - 9
259
275
  version: 0.4.9
260
- requirement: *id015
276
+ requirement: *id016
261
277
  - !ruby/object:Gem::Dependency
262
278
  prerelease: false
263
279
  type: :development
264
280
  name: em-http-request
265
- version_requirements: &id016 !ruby/object:Gem::Requirement
281
+ version_requirements: &id017 !ruby/object:Gem::Requirement
266
282
  none: false
267
283
  requirements:
268
284
  - - ~>
@@ -273,12 +289,12 @@ dependencies:
273
289
  - 3
274
290
  - 0
275
291
  version: 0.3.0
276
- requirement: *id016
292
+ requirement: *id017
277
293
  - !ruby/object:Gem::Dependency
278
294
  prerelease: false
279
295
  type: :development
280
296
  name: typhoeus
281
- version_requirements: &id017 !ruby/object:Gem::Requirement
297
+ version_requirements: &id018 !ruby/object:Gem::Requirement
282
298
  none: false
283
299
  requirements:
284
300
  - - ~>
@@ -289,7 +305,7 @@ dependencies:
289
305
  - 2
290
306
  - 1
291
307
  version: 0.2.1
292
- requirement: *id017
308
+ requirement: *id018
293
309
  description: VCR provides a simple API to record and replay your test suite's HTTP interactions. It works with a variety of HTTP client libraries, HTTP stubbing libraries and testing frameworks.
294
310
  email: myron.marston@gmail.com
295
311
  executables: []
@@ -359,6 +375,7 @@ files:
359
375
  - lib/vcr/extensions/net_http.rb
360
376
  - lib/vcr/extensions/net_http_response.rb
361
377
  - lib/vcr/http_stubbing_adapters/common.rb
378
+ - lib/vcr/http_stubbing_adapters/excon.rb
362
379
  - lib/vcr/http_stubbing_adapters/fakeweb.rb
363
380
  - lib/vcr/http_stubbing_adapters/faraday.rb
364
381
  - lib/vcr/http_stubbing_adapters/multi_object_proxy.rb
@@ -430,6 +447,7 @@ files:
430
447
  - spec/vcr/deprecations/http_stubbing_adapters/fakeweb_spec.rb
431
448
  - spec/vcr/extensions/net_http_response_spec.rb
432
449
  - spec/vcr/extensions/net_http_spec.rb
450
+ - spec/vcr/http_stubbing_adapters/excon_spec.rb
433
451
  - spec/vcr/http_stubbing_adapters/fakeweb_spec.rb
434
452
  - spec/vcr/http_stubbing_adapters/faraday_spec.rb
435
453
  - spec/vcr/http_stubbing_adapters/multi_object_proxy_spec.rb
@@ -562,6 +580,7 @@ test_files:
562
580
  - spec/vcr/deprecations/http_stubbing_adapters/fakeweb_spec.rb
563
581
  - spec/vcr/extensions/net_http_response_spec.rb
564
582
  - spec/vcr/extensions/net_http_spec.rb
583
+ - spec/vcr/http_stubbing_adapters/excon_spec.rb
565
584
  - spec/vcr/http_stubbing_adapters/fakeweb_spec.rb
566
585
  - spec/vcr/http_stubbing_adapters/faraday_spec.rb
567
586
  - spec/vcr/http_stubbing_adapters/multi_object_proxy_spec.rb