Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Include Rack::Response::Helpers in responses #99

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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