vcr 1.0.3 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +13 -0
- data/README.md +51 -9
- data/lib/vcr.rb +1 -0
- data/lib/vcr/cassette.rb +14 -7
- data/lib/vcr/config.rb +2 -0
- data/lib/vcr/extensions/net_http.rb +7 -7
- data/lib/vcr/http_stubbing_adapters/base.rb +2 -0
- data/lib/vcr/http_stubbing_adapters/fakeweb.rb +21 -6
- data/lib/vcr/http_stubbing_adapters/webmock.rb +20 -9
- data/lib/vcr/request_matcher.rb +75 -0
- data/lib/vcr/structs.rb +4 -8
- data/lib/vcr/version.rb +1 -1
- data/lib/vcr/version.rbc +10 -9
- metadata +72 -45
- data/lib/vcr/task_runner.rb +0 -47
- data/lib/vcr/tasks/vcr.rake +0 -9
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,18 @@
|
|
1
1
|
#Changelog
|
2
2
|
|
3
|
+
## 1.1.0 (August 22, 2010)
|
4
|
+
|
5
|
+
* Added `:match_requests_on` cassette option, which determines how VCR matches requests.
|
6
|
+
* Removed VCR::TaskRunner and the corresponding rake task definition. The rake task migrated cassettes from the
|
7
|
+
0.3.1 format to the 0.4+ format. If you are still on 0.3.1 or earlier, I recommend you upgrade to 0.4.1 first,
|
8
|
+
migrate your cassettes and deal with migration warnings, then upgrade to the current release.
|
9
|
+
* Added some code to VCR::Cassette.new to check the options passed to the cassette and raise an error if any
|
10
|
+
invalid options are passed.
|
11
|
+
* Optimized ERB rendering a bit. Rather than creating a new struct subclass for each time we render an ERB
|
12
|
+
cassette with locals, we keep a cache of reusable struct subclasses based on the desired attributes.
|
13
|
+
[Benchmarking](http://gist.github.com/512948) reveals this is about 28% faster.
|
14
|
+
* Upgraded tests to use em-http-request 0.2.10 rather than 0.2.7.
|
15
|
+
|
3
16
|
## 1.0.3 (August 5, 2010)
|
4
17
|
|
5
18
|
* Upgraded VCR specs to RSpec 2.
|
data/README.md
CHANGED
@@ -47,11 +47,15 @@ maintenance) and accurate (the response from example.com will contain the same h
|
|
47
47
|
(all HTTP stubbing libraries), [Patron](http://github.com/toland/patron) (WebMock only),
|
48
48
|
[HTTPClient](http://github.com/nahi/httpclient) (WebMock only) and
|
49
49
|
[em-http-request](http://github.com/igrigorik/em-http-request) (WebMock only).
|
50
|
+
* Request matching is configurable based on HTTP method, URI, host, body and headers.
|
50
51
|
* The same request can receive different responses in different tests--just use different cassettes.
|
51
52
|
* The recorded requests and responses are stored on disk as YAML and can easily be inspected and edited.
|
52
53
|
* Dynamic responses are supported using ERB.
|
53
54
|
* Disables all HTTP requests that you don't explicitly allow.
|
54
55
|
* Simple cucumber integration is provided using tags.
|
56
|
+
* Known to work well with many popular ruby libraries including RSpec, Cucumber, Test::Unit, Capybara, Mechanize and
|
57
|
+
Rest-Client.
|
58
|
+
* Extensively tested on 5 different ruby interpretters.
|
55
59
|
|
56
60
|
## Development
|
57
61
|
|
@@ -74,6 +78,7 @@ Each cassette can be configured with a couple options:
|
|
74
78
|
|
75
79
|
* `:record`: Specifies a record mode for this cassette.
|
76
80
|
* `:erb`: Used for dynamic cassettes (see below for more details).
|
81
|
+
* `:match_requests_on`: An array of request attributes to match on (see below for more details).
|
77
82
|
|
78
83
|
## Record modes
|
79
84
|
|
@@ -84,12 +89,42 @@ and a per-cassette record mode when inserting a cassette. The record modes are:
|
|
84
89
|
* `:all`: Previously recorded HTTP interactions will be ignored. All HTTP interactions will be recorded.
|
85
90
|
* `:none`: Previously recorded HTTP interactions will be replayed. New HTTP interactions will result in an error.
|
86
91
|
|
92
|
+
## Request Matching
|
93
|
+
|
94
|
+
In order to properly replay previously recorded requests, VCR must match new HTTP requests to a previously
|
95
|
+
recorded one. By default, it matches on HTTP method and URI, since that is usually deterministic and
|
96
|
+
fully identifies the resource and action for typical RESTful APIs. In some cases (such as SOAP webservices)
|
97
|
+
this may not work so well, and VCR allows you to customize how requests are matched.
|
98
|
+
|
99
|
+
Cassettes take a `:match_requests_on` option that expects an array of request attributes to match on.
|
100
|
+
Supported attributes are:
|
101
|
+
|
102
|
+
* `:method`: The HTTP method (i.e. GET, POST, PUT or DELETE) of the request.
|
103
|
+
* `:uri`: The full URI of the request.
|
104
|
+
* `:host`: The host of the URI. You can use this (alone, or in combination with `:path`) as an alternative
|
105
|
+
to `:uri` to cause VCR to match using a regex that matches the host.
|
106
|
+
* `:path`: The path of the URI. You can use this (alone, or in combination with `:host`) as an alternative
|
107
|
+
to `:uri` to cause VCR to match using a regex that matches the path.
|
108
|
+
* `:body`: The body of the request.
|
109
|
+
* `:headers`: The request headers.
|
110
|
+
|
111
|
+
By default, VCR uses a `:match_requests_on` option like:
|
112
|
+
|
113
|
+
:match_requests_on => [:uri, :method]
|
114
|
+
|
115
|
+
If you want to match on another attribute, just add it to the array:
|
116
|
+
|
117
|
+
:match_requests_on => [:uri, :method, :body]
|
118
|
+
|
119
|
+
Note that FakeWeb cannot match on `:body` or `:headers`. In general, it is recommended that you configure
|
120
|
+
your cassettes to match on the most specific set of attributes that is deterministic.
|
121
|
+
|
87
122
|
## Configuration
|
88
123
|
|
89
124
|
require 'vcr'
|
90
125
|
|
91
126
|
VCR.config do |c|
|
92
|
-
c.cassette_library_dir =
|
127
|
+
c.cassette_library_dir = 'fixtures/cassette_library'
|
93
128
|
c.http_stubbing_library = :fakeweb
|
94
129
|
c.ignore_localhost = true
|
95
130
|
c.default_cassette_options = { :record => :none }
|
@@ -99,7 +134,10 @@ This can go pretty much wherever, as long as this code is run before your tests,
|
|
99
134
|
to put it in `spec/support/vcr.rb`, `test/support/vcr.rb` or `features/support/vcr.rb`. You can set the following
|
100
135
|
configuration options:
|
101
136
|
|
102
|
-
* `cassette_library_dir`: VCR will save the cassette YAML files to this directory.
|
137
|
+
* `cassette_library_dir`: VCR will save the cassette YAML files to this directory. If you are using Rails 3 and
|
138
|
+
ActiveRecord YAML fixtures, you will probably want to avoid putting VCR cassettes in a sub-directory of
|
139
|
+
`RAILS_ROOT/test/fixtures`. Rails will assume your cassette YAML files are ActiveRecord fixtures and raise an
|
140
|
+
error when the content doesn't conform to its expectations.
|
103
141
|
* `http_stubbing_library`: Which http stubbing library to use. Currently `:fakeweb` and `:webmock` are supported.
|
104
142
|
This is currently optional--VCR will try to guess based on the presence or absence of the `FakeWeb` or `WebMock`
|
105
143
|
constants, but this is mostly done to assist users upgrading from VCR 0.3.1, which only worked with fakeweb and
|
@@ -166,8 +204,8 @@ Then let VCR know about this tag, in `features/support/vcr.rb` (or some similar
|
|
166
204
|
t.tags '@another_scenario_tag'
|
167
205
|
end
|
168
206
|
|
169
|
-
For each of the tags you specify in your `cucumber_tags` block, VCR will set up
|
170
|
-
[
|
207
|
+
For each of the tags you specify in your `cucumber_tags` block, VCR will set up an appropriate
|
208
|
+
[After hook](http://wiki.github.com/aslakhellesoy/cucumber/hooks) to use a cassette
|
171
209
|
for the entire scenario. The tag (minus the '@') will be used as the cassette name, and it'll
|
172
210
|
go in the `cucumber_tags` subdirectory of the configured cassette library directory.
|
173
211
|
|
@@ -202,6 +240,10 @@ Edit your cassette file:
|
|
202
240
|
body:
|
203
241
|
headers:
|
204
242
|
|
243
|
+
Note that it may be simpler (and better!) to use the `:match_requests_on` cassette option with `:host` and/or `:path`,
|
244
|
+
as that gives you a a URL regex without the need to manually edit the cassette file. If you do change a url to a regex
|
245
|
+
in a cassette file, VCR will use it, regardless of the `:match_requests_on` setting.
|
246
|
+
|
205
247
|
## Dynamic Cassettes
|
206
248
|
|
207
249
|
VCR's default recording and replaying is static. The exact response that is initially recorded will
|
@@ -235,7 +277,7 @@ In your cassette:
|
|
235
277
|
## FakeWeb or WebMock?
|
236
278
|
|
237
279
|
VCR works fine with either FakeWeb or WebMock. Overall, WebMock has more features, and you'll need to use
|
238
|
-
WebMock if you want to use VCR with an HTTP library besides
|
280
|
+
WebMock if you want to use VCR with an HTTP library besides Net::HTTP. However, FakeWeb is currently
|
239
281
|
about three times faster than WebMock, so you may want to stick with FakeWeb if you don't need WebMock's
|
240
282
|
additional features. You can see the
|
241
283
|
[benchmarks](http://github.com/myronmarston/vcr/blob/master/benchmarks/http_stubbing_libraries.rb) for
|
@@ -289,10 +331,10 @@ blocks of code in `VCR.use_cassette` and record logically grouped sets of reques
|
|
289
331
|
|
290
332
|
VCR has been tested on the following ruby interpreters:
|
291
333
|
|
292
|
-
* MRI 1.8.6
|
293
|
-
* MRI 1.8.7
|
294
|
-
* MRI 1.9.1
|
295
|
-
* MRI 1.9.2
|
334
|
+
* MRI 1.8.6-p399
|
335
|
+
* MRI 1.8.7-p302
|
336
|
+
* MRI 1.9.1-p378
|
337
|
+
* MRI 1.9.2
|
296
338
|
* JRuby 1.5.1
|
297
339
|
|
298
340
|
## Notes, etc.
|
data/lib/vcr.rb
CHANGED
data/lib/vcr/cassette.rb
CHANGED
@@ -8,14 +8,17 @@ module VCR
|
|
8
8
|
|
9
9
|
VALID_RECORD_MODES = [:all, :none, :new_episodes].freeze
|
10
10
|
|
11
|
-
attr_reader :name, :record_mode
|
11
|
+
attr_reader :name, :record_mode, :match_requests_on
|
12
12
|
|
13
13
|
def initialize(name, options = {})
|
14
14
|
options = VCR::Config.default_cassette_options.merge(options)
|
15
|
+
invalid_options = options.keys - [:record, :erb, :allow_real_http, :match_requests_on]
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
if invalid_options.size > 0
|
18
|
+
raise ArgumentError.new("You passed the following invalid options to VCR::Cassette.new: #{invalid_options.inspect}.")
|
19
|
+
end
|
20
|
+
|
21
|
+
@name, @record_mode, @erb, @match_requests_on = name, options[:record], options[:erb], options[:match_requests_on]
|
19
22
|
|
20
23
|
deprecate_old_cassette_options(options)
|
21
24
|
raise_error_unless_valid_record_mode(record_mode)
|
@@ -96,7 +99,11 @@ module VCR
|
|
96
99
|
recorded_interactions.replace(@original_recorded_interactions)
|
97
100
|
end
|
98
101
|
|
99
|
-
VCR.http_stubbing_adapter.stub_requests(recorded_interactions)
|
102
|
+
VCR.http_stubbing_adapter.stub_requests(recorded_interactions, match_requests_on)
|
103
|
+
end
|
104
|
+
|
105
|
+
@@struct_cache = Hash.new do |hash, attributes|
|
106
|
+
hash[attributes] = Struct.new(*attributes)
|
100
107
|
end
|
101
108
|
|
102
109
|
def raw_yaml_content
|
@@ -109,7 +116,7 @@ module VCR
|
|
109
116
|
return template.result unless @erb.is_a?(Hash)
|
110
117
|
|
111
118
|
# create an object with methods for each desired local variable...
|
112
|
-
local_variables =
|
119
|
+
local_variables = @@struct_cache[@erb.keys].new(*@erb.values)
|
113
120
|
|
114
121
|
# instance_eval seems to be the only way to get the binding for ruby 1.9: http://redmine.ruby-lang.org/issues/show/2161
|
115
122
|
template.result(local_variables.instance_eval { binding })
|
@@ -132,4 +139,4 @@ module VCR
|
|
132
139
|
end
|
133
140
|
end
|
134
141
|
end
|
135
|
-
end
|
142
|
+
end
|
data/lib/vcr/config.rb
CHANGED
@@ -12,6 +12,8 @@ module VCR
|
|
12
12
|
attr_writer :default_cassette_options
|
13
13
|
def default_cassette_options
|
14
14
|
@default_cassette_options ||= {}
|
15
|
+
@default_cassette_options.merge!(:match_requests_on => RequestMatcher::DEFAULT_MATCH_ATTRIBUTES) unless @default_cassette_options.has_key?(:match_requests_on)
|
16
|
+
@default_cassette_options
|
15
17
|
end
|
16
18
|
|
17
19
|
attr_writer :http_stubbing_library
|
@@ -2,7 +2,9 @@ require 'net/http'
|
|
2
2
|
|
3
3
|
module Net
|
4
4
|
class HTTP
|
5
|
-
|
5
|
+
alias_method :request_without_vcr, :request
|
6
|
+
|
7
|
+
def request(request, body = nil, &block)
|
6
8
|
uri = URI.parse(VCR.http_stubbing_adapter.request_uri(self, request))
|
7
9
|
|
8
10
|
if VCR::LOCALHOST_ALIASES.include?(uri.host) && VCR.http_stubbing_adapter.ignore_localhost?
|
@@ -11,19 +13,17 @@ module Net
|
|
11
13
|
end
|
12
14
|
end
|
13
15
|
|
16
|
+
vcr_request = VCR::Request.from_net_http_request(self, request)
|
14
17
|
response = request_without_vcr(request, body)
|
15
18
|
|
16
|
-
|
17
|
-
|
19
|
+
match_attributes = (cass = VCR.current_cassette) ? cass.match_requests_on : VCR::RequestMatcher::DEFAULT_MATCH_ATTRIBUTES
|
20
|
+
if started? && !VCR.http_stubbing_adapter.request_stubbed?(vcr_request, match_attributes)
|
21
|
+
VCR.record_http_interaction VCR::HTTPInteraction.new(vcr_request, VCR::Response.from_net_http_response(response))
|
18
22
|
response.extend VCR::Net::HTTPResponse # "unwind" the response
|
19
|
-
|
20
|
-
VCR.record_http_interaction(http_interaction)
|
21
23
|
end
|
22
24
|
|
23
25
|
yield response if block_given?
|
24
26
|
response
|
25
27
|
end
|
26
|
-
alias_method :request_without_vcr, :request
|
27
|
-
alias_method :request, :request_with_vcr
|
28
28
|
end
|
29
29
|
end
|
@@ -3,6 +3,8 @@ module VCR
|
|
3
3
|
autoload :FakeWeb, 'vcr/http_stubbing_adapters/fakeweb'
|
4
4
|
autoload :WebMock, 'vcr/http_stubbing_adapters/webmock'
|
5
5
|
|
6
|
+
class UnsupportedRequestMatchAttributeError < ArgumentError; end
|
7
|
+
|
6
8
|
class Base
|
7
9
|
class << self
|
8
10
|
def with_http_connections_allowed_set_to(value)
|
@@ -5,6 +5,8 @@ module VCR
|
|
5
5
|
module HttpStubbingAdapters
|
6
6
|
class FakeWeb < Base
|
7
7
|
class << self
|
8
|
+
UNSUPPORTED_REQUEST_MATCH_ATTRIBUTES = [:body, :headers].freeze
|
9
|
+
|
8
10
|
def check_version!
|
9
11
|
unless meets_version_requirement?(::FakeWeb::VERSION, '1.2.8')
|
10
12
|
raise "You are using FakeWeb #{::FakeWeb::VERSION}. VCR requires version 1.2.8 or greater."
|
@@ -19,15 +21,20 @@ module VCR
|
|
19
21
|
::FakeWeb.allow_net_connect = value
|
20
22
|
end
|
21
23
|
|
22
|
-
def stub_requests(http_interactions)
|
24
|
+
def stub_requests(http_interactions, match_attributes = RequestMatcher::DEFAULT_MATCH_ATTRIBUTES)
|
25
|
+
validate_match_attributes(match_attributes)
|
23
26
|
requests = Hash.new([])
|
24
27
|
|
25
28
|
http_interactions.each do |i|
|
26
|
-
requests[
|
29
|
+
requests[i.request.matcher(match_attributes)] += [i.response]
|
27
30
|
end
|
28
31
|
|
29
|
-
requests.each do |
|
30
|
-
::FakeWeb.register_uri(
|
32
|
+
requests.each do |request_matcher, responses|
|
33
|
+
::FakeWeb.register_uri(
|
34
|
+
request_matcher.method || :any,
|
35
|
+
request_matcher.uri,
|
36
|
+
responses.map{ |r| response_hash(r) }
|
37
|
+
)
|
31
38
|
end
|
32
39
|
end
|
33
40
|
|
@@ -39,8 +46,9 @@ module VCR
|
|
39
46
|
::FakeWeb::Registry.instance.uri_map = checkpoints.delete(checkpoint_name)
|
40
47
|
end
|
41
48
|
|
42
|
-
def request_stubbed?(
|
43
|
-
|
49
|
+
def request_stubbed?(request, match_attributes)
|
50
|
+
validate_match_attributes(match_attributes)
|
51
|
+
::FakeWeb.registered_uri?(request.method, request.uri)
|
44
52
|
end
|
45
53
|
|
46
54
|
def request_uri(net_http, request)
|
@@ -77,6 +85,13 @@ module VCR
|
|
77
85
|
:status => [response.status.code.to_s, response.status.message]
|
78
86
|
)
|
79
87
|
end
|
88
|
+
|
89
|
+
def validate_match_attributes(match_attributes)
|
90
|
+
invalid_attributes = match_attributes & UNSUPPORTED_REQUEST_MATCH_ATTRIBUTES
|
91
|
+
if invalid_attributes.size > 0
|
92
|
+
raise UnsupportedRequestMatchAttributeError.new("FakeWeb does not support matching requests on #{invalid_attributes.join(' or ')}")
|
93
|
+
end
|
94
|
+
end
|
80
95
|
end
|
81
96
|
end
|
82
97
|
end
|
@@ -21,17 +21,20 @@ module VCR
|
|
21
21
|
::WebMock::Config.instance.allow_net_connect = value
|
22
22
|
end
|
23
23
|
|
24
|
-
def stub_requests(
|
24
|
+
def stub_requests(http_interactions, match_attributes = RequestMatcher::DEFAULT_MATCH_ATTRIBUTES)
|
25
25
|
requests = Hash.new([])
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
requests[[rr.method, rr.uri]] += [rr.response]
|
27
|
+
http_interactions.each do |i|
|
28
|
+
requests[i.request.matcher(match_attributes)] += [i.response]
|
30
29
|
end
|
31
30
|
|
32
|
-
requests.each do |
|
33
|
-
::WebMock.stub_request(
|
34
|
-
|
31
|
+
requests.each do |request_matcher, responses|
|
32
|
+
stub = ::WebMock.stub_request(request_matcher.method || :any, request_matcher.uri)
|
33
|
+
|
34
|
+
with_hash = request_signature_hash(request_matcher)
|
35
|
+
stub = stub.with(with_hash) if with_hash.size > 0
|
36
|
+
|
37
|
+
stub.to_return(responses.map{ |r| response_hash(r) })
|
35
38
|
end
|
36
39
|
end
|
37
40
|
|
@@ -43,8 +46,9 @@ module VCR
|
|
43
46
|
::WebMock::RequestRegistry.instance.request_stubs = checkpoints.delete(checkpoint_name)
|
44
47
|
end
|
45
48
|
|
46
|
-
def request_stubbed?(
|
47
|
-
|
49
|
+
def request_stubbed?(request, match_attributes)
|
50
|
+
matcher = request.matcher(match_attributes)
|
51
|
+
!!::WebMock.registered_request?(::WebMock::RequestSignature.new(matcher.method || :any, request.uri, request_signature_hash(matcher)))
|
48
52
|
end
|
49
53
|
|
50
54
|
def request_uri(net_http, request)
|
@@ -61,6 +65,13 @@ module VCR
|
|
61
65
|
|
62
66
|
private
|
63
67
|
|
68
|
+
def request_signature_hash(request_matcher)
|
69
|
+
signature = {}
|
70
|
+
signature[:body] = request_matcher.body if request_matcher.match_requests_on?(:body)
|
71
|
+
signature[:headers] = request_matcher.headers if request_matcher.match_requests_on?(:headers)
|
72
|
+
signature
|
73
|
+
end
|
74
|
+
|
64
75
|
def response_hash(response)
|
65
76
|
{
|
66
77
|
:body => response.body,
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module VCR
|
4
|
+
class RequestMatcher
|
5
|
+
VALID_MATCH_ATTRIBUTES = [:method, :uri, :host, :path, :headers, :body].freeze
|
6
|
+
DEFAULT_MATCH_ATTRIBUTES = [:method, :uri].freeze
|
7
|
+
|
8
|
+
attr_reader :request, :match_attributes
|
9
|
+
|
10
|
+
def initialize(request = nil, match_attributes = [])
|
11
|
+
if (match_attributes - VALID_MATCH_ATTRIBUTES).size > 0
|
12
|
+
raise ArgumentError.new("The only valid match_attributes options are: #{VALID_MATCH_ATTRIBUTES.inspect}. You passed: #{match_attributes.inspect}.")
|
13
|
+
end
|
14
|
+
|
15
|
+
@request, self.match_attributes = request, match_attributes
|
16
|
+
end
|
17
|
+
|
18
|
+
def match_attributes=(attributes)
|
19
|
+
# Unfortunately, 1.9.2 doesn't give the same hash code
|
20
|
+
# for two sets of the same elements unless they are ordered
|
21
|
+
# the same, so we sort the attributes here.
|
22
|
+
attributes = attributes.sort { |a, b| a.to_s <=> b.to_s }
|
23
|
+
@match_attributes = Set.new(attributes)
|
24
|
+
end
|
25
|
+
|
26
|
+
def uri
|
27
|
+
return request.uri unless request.uri.is_a?(String)
|
28
|
+
uri_matchers = match_attributes.to_a & [:uri, :host, :path]
|
29
|
+
|
30
|
+
case Set.new(uri_matchers)
|
31
|
+
when Set.new then /.*/
|
32
|
+
when Set.new([:uri]) then request.uri
|
33
|
+
when Set.new([:host]) then %r{\Ahttps?://((\w+:)?\w+@)?#{Regexp.escape(URI(request.uri).host)}(:\d+)?/}i
|
34
|
+
when Set.new([:path]) then %r{\Ahttps?://[^/]+#{Regexp.escape(URI(request.uri).path)}/?(\?.*)?\z}i
|
35
|
+
when Set.new([:host, :path])
|
36
|
+
uri = URI(request.uri)
|
37
|
+
%r{\Ahttps?://((\w+:)?\w+@)?#{Regexp.escape(uri.host)}(:\d+)?#{Regexp.escape(uri.path)}/?(\?.*)?\z}i
|
38
|
+
else raise ArgumentError.new("match_attributes cannot include #{uri_matchers.join(' and ')}")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def method
|
43
|
+
request.method if match_requests_on?(:method)
|
44
|
+
end
|
45
|
+
|
46
|
+
def headers
|
47
|
+
request.headers if match_requests_on?(:headers)
|
48
|
+
end
|
49
|
+
|
50
|
+
def body
|
51
|
+
request.body if match_requests_on?(:body)
|
52
|
+
end
|
53
|
+
|
54
|
+
def match_requests_on?(attribute)
|
55
|
+
match_attributes.include?(attribute)
|
56
|
+
end
|
57
|
+
|
58
|
+
def eql?(other)
|
59
|
+
self == other
|
60
|
+
end
|
61
|
+
|
62
|
+
def ==(other)
|
63
|
+
%w( class match_attributes method uri headers body ).all? do |attr|
|
64
|
+
send(attr) == other.send(attr)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def hash
|
69
|
+
# on Ruby 1.8.6, identical sets have different hash values,
|
70
|
+
# but identical arrays have the same hash values,
|
71
|
+
# so we convert match_attributes to an array here.
|
72
|
+
[match_attributes.to_a, method, uri, headers, body].hash
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/vcr/structs.rb
CHANGED
@@ -35,6 +35,10 @@ module VCR
|
|
35
35
|
request.to_hash
|
36
36
|
)
|
37
37
|
end
|
38
|
+
|
39
|
+
def matcher(match_attributes)
|
40
|
+
RequestMatcher.new(self, match_attributes)
|
41
|
+
end
|
38
42
|
end
|
39
43
|
|
40
44
|
class ResponseStatus < Struct.new(:code, :message)
|
@@ -69,14 +73,6 @@ module VCR
|
|
69
73
|
|
70
74
|
class HTTPInteraction < Struct.new(:request, :response)
|
71
75
|
extend ::Forwardable
|
72
|
-
|
73
76
|
def_delegators :request, :uri, :method
|
74
|
-
|
75
|
-
def self.from_net_http_objects(net_http, request, response)
|
76
|
-
new(
|
77
|
-
Request.from_net_http_request(net_http, request),
|
78
|
-
Response.from_net_http_response(response)
|
79
|
-
)
|
80
|
-
end
|
81
77
|
end
|
82
78
|
end
|
data/lib/vcr/version.rb
CHANGED
data/lib/vcr/version.rbc
CHANGED
@@ -115,16 +115,17 @@ x
|
|
115
115
|
7
|
116
116
|
version
|
117
117
|
i
|
118
|
-
|
118
|
+
74
|
119
119
|
39
|
120
120
|
0
|
121
121
|
13
|
122
122
|
10
|
123
|
-
|
123
|
+
73
|
124
124
|
15
|
125
125
|
79
|
126
126
|
78
|
127
|
-
|
127
|
+
4
|
128
|
+
3
|
128
129
|
35
|
129
130
|
3
|
130
131
|
7
|
@@ -501,27 +502,27 @@ I
|
|
501
502
|
I
|
502
503
|
6
|
503
504
|
I
|
504
|
-
|
505
|
+
15
|
505
506
|
I
|
506
507
|
8
|
507
508
|
I
|
508
|
-
|
509
|
+
21
|
509
510
|
I
|
510
511
|
9
|
511
512
|
I
|
512
|
-
|
513
|
+
2d
|
513
514
|
I
|
514
515
|
a
|
515
516
|
I
|
516
|
-
|
517
|
+
39
|
517
518
|
I
|
518
519
|
b
|
519
520
|
I
|
520
|
-
|
521
|
+
45
|
521
522
|
I
|
522
523
|
d
|
523
524
|
I
|
524
|
-
|
525
|
+
4a
|
525
526
|
x
|
526
527
|
43
|
527
528
|
/Users/mmarston/code/vcr/lib/vcr/version.rb
|
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:
|
4
|
+
hash: 19
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
+
- 1
|
8
9
|
- 0
|
9
|
-
|
10
|
-
version: 1.0.3
|
10
|
+
version: 1.1.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Myron Marston
|
@@ -15,13 +15,10 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-08-
|
18
|
+
date: 2010-08-22 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
|
-
type: :development
|
23
|
-
prerelease: false
|
24
|
-
name: rspec
|
25
22
|
version_requirements: &id001 !ruby/object:Gem::Requirement
|
26
23
|
none: false
|
27
24
|
requirements:
|
@@ -36,11 +33,39 @@ dependencies:
|
|
36
33
|
- 19
|
37
34
|
version: 2.0.0.beta.19
|
38
35
|
requirement: *id001
|
39
|
-
- !ruby/object:Gem::Dependency
|
40
36
|
type: :development
|
37
|
+
name: rspec
|
41
38
|
prerelease: false
|
42
|
-
|
39
|
+
- !ruby/object:Gem::Dependency
|
43
40
|
version_requirements: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 3
|
46
|
+
segments:
|
47
|
+
- 0
|
48
|
+
version: "0"
|
49
|
+
requirement: *id002
|
50
|
+
type: :development
|
51
|
+
name: rspec-core
|
52
|
+
prerelease: false
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 3
|
60
|
+
segments:
|
61
|
+
- 0
|
62
|
+
version: "0"
|
63
|
+
requirement: *id003
|
64
|
+
type: :development
|
65
|
+
name: rspec-expectations
|
66
|
+
prerelease: false
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
version_requirements: &id004 !ruby/object:Gem::Requirement
|
44
69
|
none: false
|
45
70
|
requirements:
|
46
71
|
- - ">="
|
@@ -51,12 +76,12 @@ dependencies:
|
|
51
76
|
- 8
|
52
77
|
- 5
|
53
78
|
version: 0.8.5
|
54
|
-
requirement: *
|
55
|
-
- !ruby/object:Gem::Dependency
|
79
|
+
requirement: *id004
|
56
80
|
type: :development
|
81
|
+
name: cucumber
|
57
82
|
prerelease: false
|
58
|
-
|
59
|
-
version_requirements: &
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
version_requirements: &id005 !ruby/object:Gem::Requirement
|
60
85
|
none: false
|
61
86
|
requirements:
|
62
87
|
- - ~>
|
@@ -67,12 +92,12 @@ dependencies:
|
|
67
92
|
- 2
|
68
93
|
- 8
|
69
94
|
version: 1.2.8
|
70
|
-
requirement: *
|
71
|
-
- !ruby/object:Gem::Dependency
|
95
|
+
requirement: *id005
|
72
96
|
type: :development
|
97
|
+
name: fakeweb
|
73
98
|
prerelease: false
|
74
|
-
|
75
|
-
version_requirements: &
|
99
|
+
- !ruby/object:Gem::Dependency
|
100
|
+
version_requirements: &id006 !ruby/object:Gem::Requirement
|
76
101
|
none: false
|
77
102
|
requirements:
|
78
103
|
- - ~>
|
@@ -83,12 +108,12 @@ dependencies:
|
|
83
108
|
- 3
|
84
109
|
- 3
|
85
110
|
version: 1.3.3
|
86
|
-
requirement: *
|
87
|
-
- !ruby/object:Gem::Dependency
|
111
|
+
requirement: *id006
|
88
112
|
type: :development
|
113
|
+
name: webmock
|
89
114
|
prerelease: false
|
90
|
-
|
91
|
-
version_requirements: &
|
115
|
+
- !ruby/object:Gem::Dependency
|
116
|
+
version_requirements: &id007 !ruby/object:Gem::Requirement
|
92
117
|
none: false
|
93
118
|
requirements:
|
94
119
|
- - ~>
|
@@ -100,12 +125,12 @@ dependencies:
|
|
100
125
|
- 5
|
101
126
|
- 2
|
102
127
|
version: 2.1.5.2
|
103
|
-
requirement: *
|
104
|
-
- !ruby/object:Gem::Dependency
|
128
|
+
requirement: *id007
|
105
129
|
type: :development
|
130
|
+
name: httpclient
|
106
131
|
prerelease: false
|
107
|
-
|
108
|
-
version_requirements: &
|
132
|
+
- !ruby/object:Gem::Dependency
|
133
|
+
version_requirements: &id008 !ruby/object:Gem::Requirement
|
109
134
|
none: false
|
110
135
|
requirements:
|
111
136
|
- - ~>
|
@@ -116,12 +141,12 @@ dependencies:
|
|
116
141
|
- 3
|
117
142
|
- 9
|
118
143
|
version: 0.3.9
|
119
|
-
requirement: *
|
120
|
-
- !ruby/object:Gem::Dependency
|
144
|
+
requirement: *id008
|
121
145
|
type: :development
|
146
|
+
name: capybara
|
122
147
|
prerelease: false
|
123
|
-
|
124
|
-
version_requirements: &
|
148
|
+
- !ruby/object:Gem::Dependency
|
149
|
+
version_requirements: &id009 !ruby/object:Gem::Requirement
|
125
150
|
none: false
|
126
151
|
requirements:
|
127
152
|
- - "="
|
@@ -132,12 +157,12 @@ dependencies:
|
|
132
157
|
- 2
|
133
158
|
- 0
|
134
159
|
version: 1.2.0
|
135
|
-
requirement: *
|
136
|
-
- !ruby/object:Gem::Dependency
|
160
|
+
requirement: *id009
|
137
161
|
type: :development
|
162
|
+
name: rack
|
138
163
|
prerelease: false
|
139
|
-
|
140
|
-
version_requirements: &
|
164
|
+
- !ruby/object:Gem::Dependency
|
165
|
+
version_requirements: &id010 !ruby/object:Gem::Requirement
|
141
166
|
none: false
|
142
167
|
requirements:
|
143
168
|
- - ~>
|
@@ -148,12 +173,12 @@ dependencies:
|
|
148
173
|
- 8
|
149
174
|
- 7
|
150
175
|
version: 0.8.7
|
151
|
-
requirement: *
|
152
|
-
- !ruby/object:Gem::Dependency
|
176
|
+
requirement: *id010
|
153
177
|
type: :development
|
178
|
+
name: rake
|
154
179
|
prerelease: false
|
155
|
-
|
156
|
-
version_requirements: &
|
180
|
+
- !ruby/object:Gem::Dependency
|
181
|
+
version_requirements: &id011 !ruby/object:Gem::Requirement
|
157
182
|
none: false
|
158
183
|
requirements:
|
159
184
|
- - ~>
|
@@ -164,15 +189,15 @@ dependencies:
|
|
164
189
|
- 4
|
165
190
|
- 6
|
166
191
|
version: 0.4.6
|
167
|
-
requirement: *
|
168
|
-
- !ruby/object:Gem::Dependency
|
192
|
+
requirement: *id011
|
169
193
|
type: :development
|
194
|
+
name: patron
|
170
195
|
prerelease: false
|
171
|
-
|
172
|
-
version_requirements: &
|
196
|
+
- !ruby/object:Gem::Dependency
|
197
|
+
version_requirements: &id012 !ruby/object:Gem::Requirement
|
173
198
|
none: false
|
174
199
|
requirements:
|
175
|
-
- -
|
200
|
+
- - ~>
|
176
201
|
- !ruby/object:Gem::Version
|
177
202
|
hash: 25
|
178
203
|
segments:
|
@@ -180,7 +205,10 @@ dependencies:
|
|
180
205
|
- 2
|
181
206
|
- 7
|
182
207
|
version: 0.2.7
|
183
|
-
requirement: *
|
208
|
+
requirement: *id012
|
209
|
+
type: :development
|
210
|
+
name: em-http-request
|
211
|
+
prerelease: false
|
184
212
|
description: VCR provides helpers to record your test suite's HTTP interactions and replay them during future test runs for fast, deterministic, accurate tests. It works with any ruby testing framework, and provides built-in support for cucumber.
|
185
213
|
email: myron.marston@gmail.com
|
186
214
|
executables: []
|
@@ -199,9 +227,8 @@ files:
|
|
199
227
|
- lib/vcr/http_stubbing_adapters/base.rb
|
200
228
|
- lib/vcr/http_stubbing_adapters/fakeweb.rb
|
201
229
|
- lib/vcr/http_stubbing_adapters/webmock.rb
|
230
|
+
- lib/vcr/request_matcher.rb
|
202
231
|
- lib/vcr/structs.rb
|
203
|
-
- lib/vcr/task_runner.rb
|
204
|
-
- lib/vcr/tasks/vcr.rake
|
205
232
|
- lib/vcr/version.rb
|
206
233
|
- lib/vcr/version.rbc
|
207
234
|
- lib/vcr.rb
|
data/lib/vcr/task_runner.rb
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
require 'vcr'
|
2
|
-
|
3
|
-
module VCR
|
4
|
-
module TaskRunner
|
5
|
-
extend self
|
6
|
-
|
7
|
-
def migrate_cassettes(dir)
|
8
|
-
with_recorded_response_defined do
|
9
|
-
FileUtils.cp_r(dir, "#{dir}-backup")
|
10
|
-
|
11
|
-
Dir.glob(dir + '/**/*.yml').each do |cassette_file|
|
12
|
-
recorded_responses = YAML.load(File.read(cassette_file))
|
13
|
-
next unless recorded_responses.is_a?(Enumerable) && recorded_responses.all? { |rr| rr.is_a?(VCR::RecordedResponse) }
|
14
|
-
|
15
|
-
interactions = recorded_responses.map do |recorded_response|
|
16
|
-
http_interaction(recorded_response)
|
17
|
-
end
|
18
|
-
|
19
|
-
File.open(cassette_file, 'w') { |f| f.write(interactions.to_yaml) }
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
def http_interaction(recorded_response)
|
27
|
-
VCR::HTTPInteraction.new(
|
28
|
-
request(recorded_response),
|
29
|
-
VCR::Response.from_net_http_response(recorded_response.response)
|
30
|
-
)
|
31
|
-
end
|
32
|
-
|
33
|
-
def request(recorded_response)
|
34
|
-
VCR::Request.new(recorded_response.method, recorded_response.uri)
|
35
|
-
end
|
36
|
-
|
37
|
-
def with_recorded_response_defined
|
38
|
-
VCR.const_set(:RecordedResponse, Class.new(Struct.new(:method, :uri, :response, :request_body, :request_headers)))
|
39
|
-
|
40
|
-
begin
|
41
|
-
yield
|
42
|
-
ensure
|
43
|
-
VCR.send(:remove_const, :RecordedResponse)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
data/lib/vcr/tasks/vcr.rake
DELETED
@@ -1,9 +0,0 @@
|
|
1
|
-
require 'vcr/task_runner'
|
2
|
-
|
3
|
-
namespace :vcr do
|
4
|
-
desc 'Migrates your VCR cassettes in DIR from the 0.3.1 format to the 0.4+ format'
|
5
|
-
task :migrate_cassettes do
|
6
|
-
raise "You must pass the cassette library directory as DIR" if ENV['DIR'].to_s == ''
|
7
|
-
VCR::TaskRunner.migrate_cassettes(ENV['DIR'])
|
8
|
-
end
|
9
|
-
end
|