How to check if VCR uses the cassette or is recording

3,652 views
Skip to first unread message

Jeroen van Ingen

unread,
Sep 23, 2011, 5:36:27 AM9/23/11
to VCR Rubygem
Hi,

I want to check in an RSpec test if VCR is using the cassette or is
actually recording requests. In other words I want to check if VCR is
actually doing HTTP requests or not.
I found the method turned_on? in VCR, but I'm actually looking for a
method like 'recording?' or somethinhg like that.

I need this because I want to build in a delay (sleep) if I'm doing an
HTTP request, BUT the delay is not necessarry if I'm 'playing the
cassette' ;)

Does anyone knows how to do that?

Regards,

Jeroen

Myron Marston

unread,
Sep 23, 2011, 11:02:16 AM9/23/11
to VCR Rubygem
You can use `VCR.http_stubbing_adapter.http_connections_allowed?
`...however a few caveats:

* This isn't publicly documented, stable API that's guaranteed to
always be there. In fact, I'm working on VCR 2.0 now and I don't think
this API will be in 2.0.
* If you're using `:new_episodes` as your record mode, then this
doesn't help much. In fact, if you're using `:new_episodes` as your
record mode, your question ("is VCR currently recording?") doesn't
really make sense, because it's on a request-by-request basis (i.e.
new requests get recorded; previously recorded requests get
replayed). If you're using the `:once`, `:all` or `:none` record
modes, this method will work fine for you.

Given that this API will be changing, I'd recommend making a helper
method for your test suite (something like `#vcr_recording?`), call
that in your specs, and have it delegates to
`VCR.http_stubbing_adapter.http_connections_allowed?` for now...and
when VCR 2.0 comes out and if/when you upgrade, you can change your
helper method.

HTH,
Myron

Jeroen van Ingen

unread,
Sep 26, 2011, 5:11:49 AM9/26/11
to VCR Rubygem
Thanks, it works!

Unfortunately I ran into another problem:
My default VCR configurtation looks like this:
VCR.config do |c|
c.cassette_library_dir = 'spec/cassettes'
c.stub_with :fakeweb
c.default_cassette_options = { :record
=> :new_episodes, :re_record_interval => 259200 }
end

So for the Rspec files where I want to disable HTTP connections I have
to override the record mode. Regarding to the documentation I should
do this:
VCR.use_cassette "something", ;record => :once do
...
end
This won't work; the record_mode keeps to be "new_episodes". The
solution for me was to define a before and after callback:
before(:all) do
VCR.config do |c|
c.default_cassette_options = { :re_record_interval => 259200 }
end
end

after(:all) do
VCR.config do |c|
c.default_cassette_options = { :record
=> :new_episodes, :re_record_interval => 259200 }
end
end

This do the trick, but It's a little ugly IMHO. Did I ran into a bug,
or am I doing something else wrong?

Jeroen van Ingen

unread,
Sep 26, 2011, 6:39:45 AM9/26/11
to VCR Rubygem
Hmm, in some cases I need the record_mode 'new_episodes'

Somehow I could check whether VCR reads the yml file or is doing the
request. In other words I could check whether VCR is playing the
cassette or recording the cassette. I looked into the code, but I
can't find out where VCR decides to play the tape or actually records
the tape.

Can you explain how VCR decides to play the tape or records the tape?
In other words, how can I check whether VCR is reading the yml file or
is actually doing a HTTP request?

On Sep 23, 5:02 pm, Myron Marston <myron.mars...@gmail.com> wrote:

Myron Marston

unread,
Sep 26, 2011, 6:50:47 PM9/26/11
to vcr-...@googlegroups.com
This do the trick, but It's a little ugly IMHO. Did I ran into a bug,
or am I doing something else wrong?

I agree that that looks like an ugly hack.  However, it's hard for me to answer your question because it's not clear to me what it is you're trying to achieve.  Why do you feel the need to set the defaults one way, and then change the defaults in a before/after hooks?

In general, I would recommend using the `:once` record mode as the default, and use a different cassette for each different group/sequence of HTTP requests.  This will appropriately disable HTTP connections when playing back, and, in most cases, is what you'll want.

Can you explain how VCR decides to play the tape or records the tape?

It's based on the record mode.  Basically, the record mode determines whether or not FakeWeb/WebMock/Typhoeus/Excon are stubbed with the requests in the cassette or not.  It also determines whether or not real HTTP connections are allowed.  Anytime a real request is made, it is recorded to the current cassette.  Here is how the individual record modes work:
  • :all - Allows real HTTP connections (so that they get recorded).  Does not stub the requests in the cassette (i.e. no playback).
  • :none - Doesn't allow real HTTP connections.  Stubs all requests in the cassette (i.e. plays them back).
  • :new_episodes - Allows real HTTP connection (so that new requests get recorded) AND stubs the requests in the cassette (so that previously recorded requests get replayed).
  • :once - Either allows real HTTP connections OR stubs the requests in the cassette (but not both).  Which it does is based on whether or not there is a cassette file or not.  If there is one, it does playback but not recording; if there is not a file, it does recording but not playback.
Also, bear in mind that the configured record mode can be overridden based on the :re_record_interval option.  If, based on that option, VCR deems that it is time to re-record the cassette, it will force the record mode to be :all (regardless of what it is configured to be) so that the entire cassette is re-recorded.

Can you explain a bit more about what you're trying to achieve?  In general you should just let VCR do it's thing.  I've never heard of someone wanting to inspect and know when VCR is recording or playback or whatever.  It's not clear to me how that's useful.

Thanks,
Myron

Jeroen van Ingen

unread,
Sep 27, 2011, 4:53:14 AM9/27/11
to VCR Rubygem
Hi Myron,

Thanks for all your help so far ;). I really appreciete it.

My situation is as follows:

I do a lot of different HTTP requests to a specific site; i.e. I test
a lot of different pages on the same site. If I do too much requests
in a certain time, the site will block me forever. To prevent that I
let my application (AND RSpec tests) sleep for 5 seconds between each
HTTP request. The sleep of 5 seconds is only necessarry on a real HTTP
request. You can imagine that this slows down my RSpec tests
dramatically. To speed up my RSpec tests I want to skip the sleep when
the tape is played(i.e. when the HTTP request is stubbed).
So to know if I can skip the sleep I think I have to know for each
request if it is playing a tape or actually recording.

Because the URLs of the actual tested pages changes a lot I can do two
things:
1. Use different tapes for each group of URLs with record_mode 'once'
2. Use one tape with record_mode 'new_episodes' as I do now.

The problem with option 1 is that I need for every Rspec file about 20
different tapes and I have more then 10 RSpec files. So that gonna
cost me a lot of work and I think it's gonna be confusing if I use
over 200 different tapes.

In short my problem is that I want to let my application sleep for 5
seconds on an HTTP request, but when the HTTP request is stubbed I
want to skip the sleep.
Do you have an idea how to do that? Am I thinking in the right
direction with trying to find out whether the tape is played or
recorded?

Regards,

Jeroen

On Sep 27, 12:50 am, Myron Marston <myron.mars...@gmail.com> wrote:
> > This do the trick, but It's a little ugly IMHO. Did I ran into a bug,
> > or am I doing something else wrong?
>
> I agree that that looks like an ugly hack.  However, it's hard for me to
> answer your question because it's not clear to me what it is you're trying
> to achieve.  Why do you feel the need to set the defaults one way, and then
> change the defaults in a before/after hooks?
>
> In general, I would recommend using the `:once` record mode as the default,
> and use a different cassette for each different group/sequence of HTTP
> requests.  This will appropriately disable HTTP connections when playing
> back, and, in most cases, is what you'll want.
>
> Can you explain how VCR decides to play the tape or records the tape?
>
> It's based on the record mode.  Basically, the record mode determines
> whether or not FakeWeb/WebMock/Typhoeus/Excon are stubbed with the requests
> in the cassette or not.  It also determines whether or not real HTTP
> connections are allowed.  Anytime a real request is made, it is recorded to
> the current cassette.  Here is how the individual record modes work:
>
>    - :all - Allows real HTTP connections (so that they get recorded).  Does
>    not stub the requests in the cassette (i.e. no playback).
>    - :none - Doesn't allow real HTTP connections.  Stubs all requests in the
>    cassette (i.e. plays them back).
>    - :new_episodes - Allows real HTTP connection (so that new requests get
>    recorded) AND stubs the requests in the cassette (so that previously
>    recorded requests get replayed).
>    - :once - Either allows real HTTP connections OR stubs the requests in

Myron Marston

unread,
Sep 27, 2011, 11:06:48 PM9/27/11
to vcr-...@googlegroups.com
First off, I would really recommend you use the :once record mode.  Using one cassette for all your tests is a bad idea for lots of reasons.  On one of my projects I have over 2000 cassette files.  When you record everything to the same cassette file, you are in danger of having tests that pass when run in a particular order but fail when run in a different order.  The ordering of the HTTP interactions in a cassette does matter and is taken into account.

I'm not sure why you find it to be a lot of work to use separate cassettes rather than one...but you can take a look at VCR's RSpec support [1] you can get an idea of how to automatically use a different cassette for each test based on the example name.  Maybe that would cut down on your work?

As for the task at hand (getting a 5 second delay after every real HTTP request to this API), there are a couple of easy ways you can accomplish this.

* Use a before_record hook [2]
* Monkey patch VCR.record_http_interaction [3]

Monkey patch with care, of course, and VCR.record_http_interaction isn't a documented public API (it's meant to be used internally) so I make no promises I won't change that API in the future....but take your pick.

Myron

Jeroen van Ingen

unread,
Sep 28, 2011, 8:21:43 AM9/28/11
to VCR Rubygem
OK, thanks for all your help.

You're right, using different tapes might be a better solution. When I
looked into the source, it doesn't seem to be possible to put tapes in
namespaces / subdirs. Isn't it a good idea to make it possible to put
tapes in subdirs, so you get a better overview?

On Sep 28, 5:06 am, Myron Marston <myron.mars...@gmail.com> wrote:
> [1]https://github.com/myronmarston/vcr/blob/v1.11.3/lib/vcr/test_framewo...

Myron Marston

unread,
Sep 29, 2011, 2:14:08 PM9/29/11
to vcr-...@googlegroups.com
On Wed, Sep 28, 2011 at 5:21 AM, Jeroen van Ingen <jeroe...@gmail.com> wrote:
OK, thanks for all your help.

You're right, using different tapes might be a better solution. When I
looked into the source, it doesn't seem to be possible to put tapes in
namespaces / subdirs. Isn't it a good idea to make it possible to put
tapes in subdirs, so you get a better overview?

Just name your cassette with a directory and it'll work:

VCR.use_cassette("my_directory/another_subdirectory/my_cassette_file") { ... }

hunt....@gmail.com

unread,
Mar 25, 2015, 2:33:28 PM3/25/15
to vcr-...@googlegroups.com
For any future readers, see this solution to a near-identical issue. The short answer is yes: (as of 2015) VCR has an easy way to check whether a cassette is present and recording.

Reply all
Reply to author
Forward
0 new messages