Permalink
Browse files

Rack integration

stub_request(...).to_rack(MyRackApp) will construct an appropriate
Rack environment and call your rack app with it.  Really handy for
testing your API server against an API client :)
  • Loading branch information...
1 parent 7ce90bb commit f1f3158fa2f4d281a965ac719b3531912b7a744e @jneen jneen committed Jun 13, 2011
Showing with 119 additions and 0 deletions.
  1. +5 −0 Gemfile
  2. +1 −0 lib/webmock.rb
  3. +52 −0 lib/webmock/rack_response.rb
  4. +4 −0 lib/webmock/request_stub.rb
  5. +34 −0 spec/rack_response_spec.rb
  6. +23 −0 test/my_rack_app.rb
View
@@ -3,10 +3,15 @@ source 'http://rubygems.org/'
gemspec
group :development do
+ gem 'rake', '~> 0.8.0'
gem 'guard-rspec'
gem 'rb-fsevent'
end
+group :test do
+ gem 'sinatra' # for testing rack delegation
+end
+
platforms :jruby do
gem 'jruby-openssl', '~> 0.7'
end
View
@@ -24,6 +24,7 @@
require 'webmock/responses_sequence'
require 'webmock/request_stub'
require 'webmock/response'
+require 'webmock/rack_response'
require 'webmock/stub_request_snippet'
@@ -0,0 +1,52 @@
+module WebMock
+ class RackResponse < Response
+ def initialize(app)
+ @app = app
+ end
+
+ def evaluate(request)
+ env = build_rack_env(request)
+
+ status, headers, response = @app.call(env)
+
+ Response.new(
+ :body => response.join,
+ :headers => headers,
+ :status => status
+ )
+ end
+
+ def build_rack_env(request)
+ uri = request.uri
+ headers = request.headers || {}
+ body = request.body || ''
+
+ env = {
+ # CGI variables specified by Rack
+ 'REQUEST_METHOD' => request.method.to_s.upcase,
+ 'CONTENT_TYPE' => headers.delete('Content-Type'),
+ 'CONTENT_LENGTH' => body.size,
+ 'PATH_INFO' => uri.path,
+ 'QUERY_STRING' => uri.query || '',
+ 'SERVER_NAME' => uri.host
+ }
+
+ # Rack-specific variables
+ env['rack.input'] = StringIO.new(body)
+ env['rack.version'] = Rack::VERSION
+ env['rack.url_scheme'] = uri.scheme
+ env['rack.run_once'] = true
+ env['rack.session'] = session
+
+ headers.each do |k, v|
+ env["HTTP_#{k.tr('-','_').upcase}"] = v
+ end
+
+ env
+ end
+
+ def session
+ @session ||= {}
+ end
+ end
+end
@@ -23,6 +23,10 @@ def to_return(*response_hashes, &block)
self
end
+ def to_rack(app, options={})
+ @responses_sequences << ResponsesSequence.new([RackResponse.new(app)])
+ end
+
def to_raise(*exceptions)
@responses_sequences << ResponsesSequence.new([*exceptions].flatten.map {|e|
ResponseFactory.response_for(:exception => e)
View
@@ -0,0 +1,34 @@
+require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
+require File.expand_path(File.dirname(__FILE__) + '/../test/my_rack_app')
+
+describe WebMock::RackResponse do
+ before :each do
+ @rack_response = WebMock::RackResponse.new(MyRackApp)
+ end
+
+ it "should hook up to a rack appliance" do
+ request = WebMock::RequestSignature.new(:get, 'www.example.com')
+ response = @rack_response.evaluate(request)
+
+ response.status.first.should == 200
+ response.body.should include 'This is my root!'
+ end
+
+ it "should send along params" do
+ request = WebMock::RequestSignature.new(:get, 'www.example.com/greet?name=Johnny')
+
+ response = @rack_response.evaluate(request)
+
+ response.status.first.should == 200
+ response.body.should include 'Hello, Johnny'
+ end
+
+ it "should send along POST params" do
+ request = WebMock::RequestSignature.new(:post, 'www.example.com/greet',
+ :body => 'name=Jimmy'
+ )
+
+ response = @rack_response.evaluate(request)
+ response.body.should include 'Good to meet you, Jimmy!'
+ end
+end
View
@@ -0,0 +1,23 @@
+require 'sinatra'
+
+class MyRackApp < Sinatra::Base
+ # debug
+ # def self.call(env)
+ # p env
+
+ # [200, {'Content-Length' => 13}, ['Hello, World!']]
+ # end
+
+ get '/' do
+ 'This is my root!'
+ end
+
+ get '/greet' do
+ "Hello, #{params[:name] || 'World'}"
+ end
+
+ # not something you'd really use a post request for, but hey.
+ post '/greet' do
+ "Good to meet you, #{params[:name]}!"
+ end
+end

0 comments on commit f1f3158

Please sign in to comment.