forked from vcr/vcr
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b845bb8
commit b58808d
Showing
7 changed files
with
235 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,95 @@ | |||
Feature: rack middleware | |||
|
|||
VCR provides a rack middleware that uses a cassette for the duration of | |||
a request. Simply provide VCR::Middleware::Rack with a block that sets | |||
the cassette name and options. You can set these based on the rack env | |||
if your block accepts two arguments. | |||
|
|||
There useful in a couple different ways: | |||
|
|||
* In a rails app, you could use this to log all HTTP API calls made by | |||
the rails app (using the :all record mode). Of course, this will only | |||
record HTTP API calls made in the request-response cycle--API calls that | |||
are offloaded to a background job will not be logged. | |||
* This can be used as middleware in a simple rack HTTP proxy, to record the | |||
and replay the proxied requests. | |||
|
|||
Background: | |||
Given a file named "remote_server.rb" with: | |||
""" | |||
require 'vcr_cucumber_helpers' | |||
request_count = 0 | |||
start_sinatra_app(:port => 7777) do | |||
get('/:path') { "Hello #{params[:path]} #{request_count += 1}" } | |||
end | |||
""" | |||
And a file named "client.rb" with: | |||
""" | |||
require 'remote_server' | |||
require 'proxy_server' | |||
require 'cgi' | |||
url = URI.parse("http://localhost:8888?url=#{CGI.escape('http://localhost:7777/foo')}") | |||
puts "Response 1: #{Net::HTTP.get_response(url).body}" | |||
puts "Response 2: #{Net::HTTP.get_response(url).body}" | |||
""" | |||
And the directory "cassettes" does not exist | |||
|
|||
Scenario: Use VCR rack middleware to record HTTP responses for a simple rack proxy app | |||
Given a file named "proxy_server.rb" with: | |||
""" | |||
require 'vcr' | |||
start_sinatra_app(:port => 8888) do | |||
use VCR::Middleware::Rack do |cassette| | |||
cassette.name 'proxied' | |||
cassette.options :record => :new_episodes | |||
end | |||
get('/') { Net::HTTP.get_response(URI.parse(params[:url])).body } | |||
end | |||
VCR.config do |c| | |||
c.cassette_library_dir = 'cassettes' | |||
c.stub_with :fakeweb | |||
c.allow_http_connections_when_no_cassette = true | |||
end | |||
""" | |||
When I run "ruby client.rb" | |||
Then the output should contain: | |||
""" | |||
Response 1: Hello foo 1 | |||
Response 2: Hello foo 1 | |||
""" | |||
And the file "cassettes/proxied.yml" should contain "body: Hello foo 1" | |||
|
|||
Scenario: Set cassette name based on rack request env | |||
Given a file named "proxy_server.rb" with: | |||
""" | |||
require 'vcr' | |||
start_sinatra_app(:port => 8888) do | |||
use VCR::Middleware::Rack do |cassette, env| | |||
cassette.name env['SERVER_NAME'] | |||
cassette.options :record => :new_episodes | |||
end | |||
get('/') { Net::HTTP.get_response(URI.parse(params[:url])).body } | |||
end | |||
VCR.config do |c| | |||
c.cassette_library_dir = 'cassettes' | |||
c.stub_with :fakeweb | |||
c.allow_http_connections_when_no_cassette = true | |||
end | |||
""" | |||
When I run "ruby client.rb" | |||
Then the output should contain: | |||
""" | |||
Response 1: Hello foo 1 | |||
Response 2: Hello foo 1 | |||
""" | |||
And the file "cassettes/localhost.yml" should contain "body: Hello foo 1" | |||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,18 @@ | |||
module VCR | |||
module Middleware | |||
class CassetteArguments | |||
def initialize | |||
@options = {} | |||
end | |||
|
|||
def name(name = nil) | |||
@name = name if name | |||
@name | |||
end | |||
|
|||
def options(options = {}) | |||
@options.merge!(options) | |||
end | |||
end | |||
end | |||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,28 @@ | |||
module VCR | |||
module Middleware | |||
class Rack | |||
def initialize(app, &block) | |||
raise ArgumentError.new("You must provide a block to set the cassette options") unless block | |||
@app, @cassette_arguments_block = app, block | |||
end | |||
|
|||
def call(env) | |||
VCR.use_cassette(*cassette_arguments(env)) do | |||
@app.call(env) | |||
end | |||
end | |||
|
|||
private | |||
|
|||
def cassette_arguments(env) | |||
arguments = CassetteArguments.new | |||
|
|||
block_args = [arguments] | |||
block_args << env unless @cassette_arguments_block.arity == 1 | |||
|
|||
@cassette_arguments_block.call(*block_args) | |||
[arguments.name, arguments.options] | |||
end | |||
end | |||
end | |||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,32 @@ | |||
require 'spec_helper' | |||
|
|||
describe VCR::Middleware::CassetteArguments do | |||
describe '#name' do | |||
it 'initially returns nil' do | |||
subject.name.should be_nil | |||
end | |||
|
|||
it 'stores the given value, returning it when no arg is given' do | |||
subject.name :value1 | |||
subject.name.should == :value1 | |||
|
|||
subject.name :value2 | |||
subject.name.should == :value2 | |||
end | |||
end | |||
|
|||
describe '#options' do | |||
it 'initially returns an empty hash' do | |||
subject.options.should == {} | |||
end | |||
|
|||
it 'merges the given hash options, returning them when no arg is given' do | |||
subject.options :record => :new_episodes | |||
subject.options.should == { :record => :new_episodes } | |||
|
|||
subject.options :erb => true | |||
subject.options.should == { :record => :new_episodes, :erb => true } | |||
end | |||
end | |||
end | |||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,54 @@ | |||
require 'spec_helper' | |||
|
|||
describe VCR::Middleware::Rack do | |||
describe '.new' do | |||
it 'raises an error if no cassette arguments block is provided' do | |||
expect { | |||
described_class.new(lambda { |env| }) | |||
}.to raise_error(ArgumentError) | |||
end | |||
end | |||
|
|||
describe '#call' do | |||
let(:env_hash) { { :env => :hash } } | |||
it 'calls the provided rack app and returns its response' do | |||
rack_app = mock | |||
rack_app.should_receive(:call).with(env_hash).and_return(:response) | |||
instance = described_class.new(rack_app) { |c| c.name 'cassette_name' } | |||
instance.call(env_hash).should == :response | |||
end | |||
|
|||
it 'uses a cassette when the rack app is called' do | |||
VCR.current_cassette.should be_nil | |||
rack_app = lambda { |env| VCR.current_cassette.should_not be_nil } | |||
instance = described_class.new(rack_app) { |c| c.name 'cassette_name' } | |||
instance.call({}) | |||
VCR.current_cassette.should be_nil | |||
end | |||
|
|||
it 'sets the cassette name based on the provided block' do | |||
rack_app = lambda { |env| VCR.current_cassette.name.should == 'rack_cassette' } | |||
instance = described_class.new(rack_app) { |c| c.name 'rack_cassette' } | |||
instance.call({}) | |||
end | |||
|
|||
it 'sets the cassette options based on the provided block' do | |||
rack_app = lambda { |env| VCR.current_cassette.erb.should == { :foo => :bar } } | |||
instance = described_class.new(rack_app) do |c| | |||
c.name 'c' | |||
c.options :erb => { :foo => :bar } | |||
end | |||
|
|||
instance.call({}) | |||
end | |||
|
|||
it 'yields the rack env to the provided block when the block accepts 2 arguments' do | |||
instance = described_class.new(lambda { |env| }) do |c, env| | |||
env.should == env_hash | |||
c.name 'c' | |||
end | |||
|
|||
instance.call(env_hash) | |||
end | |||
end | |||
end |