Skip to content

Commit

Permalink
Include Rack::Response::Helpers in responses
Browse files Browse the repository at this point in the history
  • Loading branch information
scttnlsn committed May 2, 2016
1 parent 3cc4112 commit 1eb107d
Show file tree
Hide file tree
Showing 8 changed files with 131 additions and 54 deletions.
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
source 'https://rubygems.org'

gem 'rspec'
gem 'rest-client'
gem 'rest-client', '2.0.0.rc2'
gem 'rack-test'
gem 'activesupport'
gem 'coveralls', require: false
Expand Down
1 change: 1 addition & 0 deletions lib/airborne.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
config.add_setting :rack_app
config.add_setting :requester_type
config.add_setting :requester_module
config.add_setting :rest_client_options, default: {}
config.before do |example|
config.match_expected = example.metadata[:match_expected].nil? ?
Airborne.configuration.match_expected_default? : example.metadata[:match_expected]
Expand Down
34 changes: 20 additions & 14 deletions lib/airborne/base.rb
Original file line number Diff line number Diff line change
@@ -1,34 +1,40 @@
require 'json'
require 'active_support'
require 'active_support/core_ext/hash/indifferent_access'
require 'active_support/core_ext/module/delegation'
require 'airborne/response'

module Airborne
class InvalidJsonError < StandardError; end

include RequestExpectations

attr_reader :response, :headers, :body
attr_reader :headers, :body

def self.configure
RSpec.configure do |config|
yield config
end
end

def self.included(base)
if !Airborne.configuration.requester_module.nil?
base.send(:include, Airborne.configuration.requester_module)
elsif !Airborne.configuration.rack_app.nil?
base.send(:include, RackTestRequester)
else
base.send(:include, RestClientRequester)
end
end

def self.configuration
RSpec.configuration
end

def requester
Class.new(self.class) do
if !Airborne.configuration.requester_module.nil?
include Airborne.configuration.requester_module
elsif !Airborne.configuration.rack_app.nil?
include RackTestRequester
else
include RestClientRequester
end
end.new
end

delegate :make_request, to: :requester

def get(url, headers = nil)
@response = make_request(:get, url, headers: headers)
end
Expand Down Expand Up @@ -58,15 +64,15 @@ def options(url, headers = nil)
end

def response
@response
Response.new(@response)
end

def headers
HashWithIndifferentAccess.new(response.headers)
HashWithIndifferentAccess.new(@response.headers)
end

def body
response.body
@response.body
end

def json_body
Expand Down
19 changes: 19 additions & 0 deletions lib/airborne/response.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
require 'rack/response'

module Airborne
class Response < Struct.new(:raw)
include Rack::Response::Helpers

alias_method :success?, :successful?
alias_method :missing?, :not_found?
alias_method :error?, :server_error?

def status
raw.code
end

def method_missing(name, *args, &block)
raw.send(name, *args, &block)
end
end
end
37 changes: 21 additions & 16 deletions lib/airborne/rest_client_requester.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,34 @@
module Airborne
module RestClientRequester
def make_request(method, url, options = {})
headers = base_headers.merge(options[:headers] || {})
res = if method == :post || method == :patch || method == :put
begin
request_body = options[:body].nil? ? '' : options[:body]
request_body = request_body.to_json if options[:body].is_a?(Hash)
RestClient.send(method, get_url(url), request_body, headers)
rescue RestClient::Exception => e
e.response
end
else
begin
RestClient.send(method, get_url(url), headers)
rescue RestClient::Exception => e
e.response
end
params = base_params.merge(
method: method,
url: get_url(url),
headers: base_headers.merge(options[:headers] || {}))

if include_body?(method)
request_body = options[:body].nil? ? '' : options[:body]
request_body = request_body.to_json if options[:body].is_a?(Hash)
params[:payload] = request_body
end
res

RestClient::Request.execute(params)
rescue RestClient::Exception => e
e.response
end

private

def include_body?(method)
[:post, :patch, :put].include?(method)
end

def base_headers
{ content_type: :json }.merge(Airborne.configuration.headers || {})
end

def base_params
Airborne.configuration.rest_client_options || {}
end
end
end
24 changes: 9 additions & 15 deletions spec/airborne/client_requester_spec.rb
Original file line number Diff line number Diff line change
@@ -1,36 +1,30 @@
require 'spec_helper'

describe 'client requester' do
before do
allow(RestClient).to receive(:send)
RSpec::Mocks.space.proxy_for(self).remove_stub_if_present(:get)
end

after do
allow(RestClient).to receive(:send).and_call_original
Airborne.configure { |config| config.headers = {} }
end

it 'should set :content_type to :json by default' do
get '/foo'
stub_request(:get, 'http://www.example.com/foo')
.with(headers: { 'Content-Type' => 'application/json' })

expect(RestClient).to have_received(:send)
.with(:get, 'http://www.example.com/foo', { content_type: :json })
get '/foo'
end

it 'should override headers with option[:headers]' do
get '/foo', { content_type: 'application/x-www-form-urlencoded' }
stub_request(:get, 'http://www.example.com/foo')
.with(headers: { 'Content-Type' => 'application/x-www-form-urlencoded' })

expect(RestClient).to have_received(:send)
.with(:get, 'http://www.example.com/foo', { content_type: 'application/x-www-form-urlencoded' })
get '/foo', { content_type: 'application/x-www-form-urlencoded' }
end

it 'should override headers with airborne config headers' do
Airborne.configure { |config| config.headers = { content_type: 'text/plain' } }

get '/foo'
stub_request(:get, 'http://www.example.com/foo')
.with(headers: { 'Content-Type' => 'text/plain' })

expect(RestClient).to have_received(:send)
.with(:get, 'http://www.example.com/foo', { content_type: 'text/plain' })
get '/foo'
end
end
15 changes: 7 additions & 8 deletions spec/airborne/rack/rack_sinatra_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ class SampleApp < Sinatra::Application
end
end

Airborne.configure do |config|
config.rack_app = SampleApp
end
TestResponse = Struct.new(:body, :headers)

describe 'rack app' do
before { Airborne.configuration.rack_app = SampleApp }
after { Airborne.configuration.rack_app = nil }

it 'should allow requests against a sinatra app' do
get '/'
expect_json_types(foo: :string)
Expand All @@ -27,17 +28,15 @@ class SampleApp < Sinatra::Application
end

it 'Should set json_body even when not using the airborne http requests' do
Response = Struct.new(:body, :headers)
@response = Response.new({ foo: 'bar' }.to_json)
@response = TestResponse.new({ foo: 'bar' }.to_json)
expect(json_body).to eq(foo: 'bar')
end

it 'Should work with consecutive requests' do
Response = Struct.new(:body, :headers)
@response = Response.new({ foo: 'bar' }.to_json)
@response = TestResponse.new({ foo: 'bar' }.to_json)
expect(json_body).to eq(foo: 'bar')

@response = Response.new({ foo: 'boo' }.to_json)
@response = TestResponse.new({ foo: 'boo' }.to_json)
expect(json_body).to eq(foo: 'boo')
end
end
53 changes: 53 additions & 0 deletions spec/airborne/response_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
require 'spec_helper'

describe 'response' do
let(:headers) { {} }
let(:status) { 200 }

before { Airborne.configuration.rest_client_options = { max_redirects: 0 } }
after { Airborne.configuration.rest_client_options = {} }

before do
mock_get('simple_get', headers, status)
get '/simple_get'
end

context 'with 200 status' do
let(:status) { 200 }

it { expect(response.status).to eq 200 }
it { expect(response).to be_successful }
it { expect(response).to be_success }
it { expect(response).to be_ok }
end

context 'with 404 status' do
let(:status) { 404 }

it { expect(response.status).to eq 404 }
it { expect(response).to_not be_success }
it { expect(response).to_not be_ok }
it { expect(response).to be_client_error }
it { expect(response).to be_not_found }
it { expect(response).to be_missing }
end

context 'with 302 status' do
let(:status) { 302 }
let(:headers) { { 'Location' => '/' } }

it { expect(response.status).to eq 302 }
it { expect(response).to be_redirection }
it { expect(response).to be_redirect }
end

context 'with 500 status' do
let(:status) { 500 }

it { expect(response.status).to eq 500 }
it { expect(response).to_not be_success }
it { expect(response).to_not be_ok }
it { expect(response).to be_server_error }
it { expect(response).to be_error }
end
end

0 comments on commit 1eb107d

Please sign in to comment.