From 253926461045c9deab9a823ac8781efdf276fd28 Mon Sep 17 00:00:00 2001 From: Shreyas Agarwal Date: Thu, 23 Nov 2017 18:30:11 +0100 Subject: [PATCH 01/16] Separate settings with Base and module --- airborne.gemspec | 1 + lib/airborne.rb | 32 +++++----- lib/airborne/base.rb | 106 +++++++++++++++------------------ lib/airborne/rspec_settings.rb | 21 +++++++ spec/spec_helper.rb | 3 +- 5 files changed, 88 insertions(+), 75 deletions(-) create mode 100644 lib/airborne/rspec_settings.rb diff --git a/airborne.gemspec b/airborne.gemspec index 1750e41..7c6e7b8 100644 --- a/airborne.gemspec +++ b/airborne.gemspec @@ -16,4 +16,5 @@ Gem::Specification.new do |s| s.add_runtime_dependency 'rack' s.add_runtime_dependency 'activesupport' s.add_development_dependency 'webmock', '~> 0' + s.add_development_dependency 'pry' end diff --git a/lib/airborne.rb b/lib/airborne.rb index a8d22a0..e0a87bb 100644 --- a/lib/airborne.rb +++ b/lib/airborne.rb @@ -1,3 +1,4 @@ +require 'airborne/rspec_settings' require 'airborne/optional_hash_type_expectations' require 'airborne/path_matcher' require 'airborne/request_expectations' @@ -5,23 +6,20 @@ require 'airborne/rack_test_requester' require 'airborne/base' -RSpec.configure do |config| - config.add_setting :base_url - config.add_setting :match_expected - config.add_setting :match_actual - config.add_setting :match_expected_default, default: true - config.add_setting :match_actual_default, default: false - config.add_setting :headers - config.add_setting :rack_app - config.add_setting :requester_type - config.add_setting :requester_module - config.before do |example| - config.match_expected = example.metadata[:match_expected].nil? ? - Airborne.configuration.match_expected_default? : example.metadata[:match_expected] - config.match_actual = example.metadata[:match_actual].nil? ? - Airborne.configuration.match_actual_default? : example.metadata[:match_actual] +module Airborne + class << self + def configuration + RSpec.configuration + end + + def configure + RSpec.configure do |config| + yield config + end + end end +end - # Include last since it depends on the configuration already being added - config.include Airborne +RSpec.configure do |config| + config.include Airborne::Base end diff --git a/lib/airborne/base.rb b/lib/airborne/base.rb index 7f900eb..1af4bdc 100644 --- a/lib/airborne/base.rb +++ b/lib/airborne/base.rb @@ -3,80 +3,72 @@ require 'active_support/core_ext/hash/indifferent_access' module Airborne - class InvalidJsonError < StandardError; end + module Base + class InvalidJsonError < StandardError; end - include RequestExpectations + include RequestExpectations - attr_reader :response, :headers, :body + attr_reader :response, :headers, :body - def self.configure - RSpec.configure do |config| - yield config + 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 - 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) + def get(url, headers = nil) + @response = make_request(:get, url, headers: headers) end - end - - def self.configuration - RSpec.configuration - end - def get(url, headers = nil) - @response = make_request(:get, url, headers: headers) - end - - def post(url, post_body = nil, headers = nil) - @response = make_request(:post, url, body: post_body, headers: headers) - end + def post(url, post_body = nil, headers = nil) + @response = make_request(:post, url, body: post_body, headers: headers) + end - def patch(url, patch_body = nil, headers = nil) - @response = make_request(:patch, url, body: patch_body, headers: headers) - end + def patch(url, patch_body = nil, headers = nil) + @response = make_request(:patch, url, body: patch_body, headers: headers) + end - def put(url, put_body = nil, headers = nil) - @response = make_request(:put, url, body: put_body, headers: headers) - end + def put(url, put_body = nil, headers = nil) + @response = make_request(:put, url, body: put_body, headers: headers) + end - def delete(url, delete_body = nil, headers = nil) - @response = make_request(:delete, url, body: delete_body, headers: headers) - end + def delete(url, delete_body = nil, headers = nil) + @response = make_request(:delete, url, body: delete_body, headers: headers) + end - def head(url, headers = nil) - @response = make_request(:head, url, headers: headers) - end + def head(url, headers = nil) + @response = make_request(:head, url, headers: headers) + end - def options(url, headers = nil) - @response = make_request(:options, url, headers: headers) - end + def options(url, headers = nil) + @response = make_request(:options, url, headers: headers) + end - def response - @response - end + def response + @response + end - def headers - HashWithIndifferentAccess.new(response.headers) - end + def headers + HashWithIndifferentAccess.new(response.headers) + end - def body - response.body - end + def body + response.body + end - def json_body - JSON.parse(response.body, symbolize_names: true) rescue fail InvalidJsonError, 'Api request returned invalid json' - end + def json_body + JSON.parse(response.body, symbolize_names: true) rescue fail InvalidJsonError, 'Api request returned invalid json' + end - private + private - def get_url(url) - base = Airborne.configuration.base_url || '' - base + url + def get_url(url) + base = Airborne.configuration.base_url || '' + base + url + end end end diff --git a/lib/airborne/rspec_settings.rb b/lib/airborne/rspec_settings.rb new file mode 100644 index 0000000..fd12893 --- /dev/null +++ b/lib/airborne/rspec_settings.rb @@ -0,0 +1,21 @@ +RSpec.configure do |config| + config.add_setting :base_url + config.add_setting :match_expected_default, default: true + config.add_setting :match_actual_default, default: false + config.add_setting :match_expected, default: config.match_expected_default + config.add_setting :match_actual, default: config.match_actual_default + config.add_setting :headers + config.add_setting :rack_app + config.add_setting :requester_type + config.add_setting :requester_module + config.around(:example, match_expected: !config.match_expected_default) do |example| + config.match_expected = !config.match_expected_default + example.run + config.match_expected = config.match_expected_default + end + config.around(:example, match_actual: !config.match_actual_default) do |example| + config.match_actual = !config.match_actual_default + example.run + config.match_actual = config.match_actual_default + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 0801c56..296ce8c 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -2,6 +2,7 @@ Coveralls.wear! require 'airborne' require 'stub_helper' +require 'pry' Airborne.configure do |config| config.base_url = 'http://www.example.com' @@ -10,5 +11,5 @@ ExpectationNotMetError = RSpec::Expectations::ExpectationNotMetError ExpectationError = Airborne::ExpectationError -InvalidJsonError = Airborne::InvalidJsonError +InvalidJsonError = Airborne::Base::InvalidJsonError PathError = Airborne::PathError From 3a18ed3a1aa3e8d77eff7444379d21d721f382e1 Mon Sep 17 00:00:00 2001 From: Shreyas Agarwal Date: Fri, 24 Nov 2017 07:50:32 +0100 Subject: [PATCH 02/16] Add body headers and a block options to the request --- lib/airborne/base.rb | 28 +++++++++++++------------- lib/airborne/rack_test_requester.rb | 8 +++----- lib/airborne/rest_client_requester.rb | 8 ++++---- spec/airborne/client_requester_spec.rb | 2 +- 4 files changed, 22 insertions(+), 24 deletions(-) diff --git a/lib/airborne/base.rb b/lib/airborne/base.rb index 1af4bdc..c1885f3 100644 --- a/lib/airborne/base.rb +++ b/lib/airborne/base.rb @@ -20,32 +20,32 @@ def self.included(base) end end - def get(url, headers = nil) - @response = make_request(:get, url, headers: headers) + def get(path, body = nil, headers = nil, &block) + @response = make_request(:get, path, body, headers, &block) end - def post(url, post_body = nil, headers = nil) - @response = make_request(:post, url, body: post_body, headers: headers) + def post(path, post_body = nil, headers = nil, &block) + @response = make_request(:post, path, post_body, headers, &block) end - def patch(url, patch_body = nil, headers = nil) - @response = make_request(:patch, url, body: patch_body, headers: headers) + def patch(path, patch_body = nil, headers = nil, &block) + @response = make_request(:patch, path, patch_body, headers, &block) end - def put(url, put_body = nil, headers = nil) - @response = make_request(:put, url, body: put_body, headers: headers) + def put(path, put_body = nil, headers = nil, &block) + @response = make_request(:put, path, put_body, headers, &block) end - def delete(url, delete_body = nil, headers = nil) - @response = make_request(:delete, url, body: delete_body, headers: headers) + def delete(path, delete_body = nil, headers = nil, &block) + @response = make_request(:delete, path, delete_body, headers, &block) end - def head(url, headers = nil) - @response = make_request(:head, url, headers: headers) + def head(path, body = nil, headers = nil, &block) + @response = make_request(:head, path, body, headers, &block) end - def options(url, headers = nil) - @response = make_request(:options, url, headers: headers) + def options(path, body = nil, headers = nil, &block) + @response = make_request(:options, path, body, headers, &block) end def response diff --git a/lib/airborne/rack_test_requester.rb b/lib/airborne/rack_test_requester.rb index abcb652..d308a61 100644 --- a/lib/airborne/rack_test_requester.rb +++ b/lib/airborne/rack_test_requester.rb @@ -2,13 +2,11 @@ module Airborne module RackTestRequester - def make_request(method, url, options = {}) - headers = options[:headers] || {} - base_headers = Airborne.configuration.headers || {} - headers = base_headers.merge(headers) + def make_request(method, url, body = {}, headers = {}, &block) + headers = (Airborne.configuration.headers || {}).merge(headers || {}) browser = Rack::Test::Session.new(Rack::MockSession.new(Airborne.configuration.rack_app)) headers.each { |name, value| browser.header(name, value) } - browser.send(method, url, options[:body] || {}, headers) + browser.send(method, url, body || {}, headers) Rack::MockResponse.class_eval do alias_method :code, :status end diff --git a/lib/airborne/rest_client_requester.rb b/lib/airborne/rest_client_requester.rb index 3ebe68f..fb52de9 100644 --- a/lib/airborne/rest_client_requester.rb +++ b/lib/airborne/rest_client_requester.rb @@ -2,12 +2,12 @@ module Airborne module RestClientRequester - def make_request(method, url, options = {}) - headers = base_headers.merge(options[:headers] || {}) + def make_request(method, url, body, headers, &block) + headers = base_headers.merge(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) + request_body = body || '' + request_body = request_body.to_json if request_body.is_a?(Hash) RestClient.send(method, get_url(url), request_body, headers) rescue RestClient::Exception => e e.response diff --git a/spec/airborne/client_requester_spec.rb b/spec/airborne/client_requester_spec.rb index 3023801..3ebfcc3 100644 --- a/spec/airborne/client_requester_spec.rb +++ b/spec/airborne/client_requester_spec.rb @@ -19,7 +19,7 @@ end it 'should override headers with option[:headers]' do - get '/foo', { content_type: 'application/x-www-form-urlencoded' } + get '/foo', {} ,{ 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' }) From bdc83aa225aee3d112a3f93e0b1cb2f087114007 Mon Sep 17 00:00:00 2001 From: Shreyas Agarwal Date: Fri, 24 Nov 2017 08:02:49 +0100 Subject: [PATCH 03/16] Add faraday to the gemspec --- airborne.gemspec | 1 + 1 file changed, 1 insertion(+) diff --git a/airborne.gemspec b/airborne.gemspec index 7c6e7b8..71b358f 100644 --- a/airborne.gemspec +++ b/airborne.gemspec @@ -15,6 +15,7 @@ Gem::Specification.new do |s| s.add_runtime_dependency 'rack-test', '~> 0.6', '>= 0.6.2' s.add_runtime_dependency 'rack' s.add_runtime_dependency 'activesupport' + s.add_runtime_dependency 'faraday', '~> 0.13' s.add_development_dependency 'webmock', '~> 0' s.add_development_dependency 'pry' end From ff974e48697821a69e443c1ecc9dc4171a95afba Mon Sep 17 00:00:00 2001 From: Shreyas Agarwal Date: Fri, 24 Nov 2017 08:03:34 +0100 Subject: [PATCH 04/16] Add setting add_faraday to default true --- lib/airborne/rspec_settings.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/airborne/rspec_settings.rb b/lib/airborne/rspec_settings.rb index fd12893..776a6bd 100644 --- a/lib/airborne/rspec_settings.rb +++ b/lib/airborne/rspec_settings.rb @@ -8,6 +8,7 @@ config.add_setting :rack_app config.add_setting :requester_type config.add_setting :requester_module + config.add_setting :use_faraday, default: true config.around(:example, match_expected: !config.match_expected_default) do |example| config.match_expected = !config.match_expected_default example.run From 27ef35c3503553a38c22bfbc502091fce71379e0 Mon Sep 17 00:00:00 2001 From: Shreyas Agarwal Date: Fri, 24 Nov 2017 08:03:54 +0100 Subject: [PATCH 05/16] Set to false only for test --- spec/spec_helper.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 296ce8c..44124ab 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -7,6 +7,7 @@ Airborne.configure do |config| config.base_url = 'http://www.example.com' config.include StubHelper + config.use_faraday = false end ExpectationNotMetError = RSpec::Expectations::ExpectationNotMetError From d673091a2fd38e51c83ba5add875e7027d5ebb00 Mon Sep 17 00:00:00 2001 From: Shreyas Agarwal Date: Fri, 24 Nov 2017 08:04:18 +0100 Subject: [PATCH 06/16] Add faraday_requester to make calls using Faraday --- lib/airborne.rb | 2 + lib/airborne/faraday_requester.rb | 23 +++++ spec/airborne/faraday_requester_spec.rb | 106 ++++++++++++++++++++++++ 3 files changed, 131 insertions(+) create mode 100644 lib/airborne/faraday_requester.rb create mode 100644 spec/airborne/faraday_requester_spec.rb diff --git a/lib/airborne.rb b/lib/airborne.rb index e0a87bb..eeecf65 100644 --- a/lib/airborne.rb +++ b/lib/airborne.rb @@ -4,8 +4,10 @@ require 'airborne/request_expectations' require 'airborne/rest_client_requester' require 'airborne/rack_test_requester' +require 'airborne/faraday_requester' require 'airborne/base' + module Airborne class << self def configuration diff --git a/lib/airborne/faraday_requester.rb b/lib/airborne/faraday_requester.rb new file mode 100644 index 0000000..bca715d --- /dev/null +++ b/lib/airborne/faraday_requester.rb @@ -0,0 +1,23 @@ +require 'faraday' + +module Airborne + class FaradayRequester + def conn + @conn ||= Faraday.new + end + + def make_request(method_name, path, body = {}, headers ={}, &block) + conn.send(method_name, path, body) do |req| + conn.url_prefix = base_url + req.path = path + req.headers = headers + yield req, conn if block_given? + end + end + + private + def base_url + Airborne.configuration.base_url + end + end +end diff --git a/spec/airborne/faraday_requester_spec.rb b/spec/airborne/faraday_requester_spec.rb new file mode 100644 index 0000000..ff3cb5a --- /dev/null +++ b/spec/airborne/faraday_requester_spec.rb @@ -0,0 +1,106 @@ +require 'spec_helper' + +RSpec.fdescribe Airborne::FaradayRequester do + before do + stub_request(:any, /www.example.com/) + Airborne.configure do |config| + config.use_faraday = true + config.base_url = 'http://www.example.com' + end + end + + subject { described_class.new } + + shared_examples 'faraday_get_delete_requests' do |kind_of_request| + describe "##{kind_of_request}" do + context 'when have only path' do + it "makes a simple #{kind_of_request} call" do + subject.make_request kind_of_request, '/asdasd' + expect(a_request(kind_of_request, "www.example.com/asdasd").with(body: {})).to have_been_made.once + end + end + + context 'when request has body' do + it 'makes calls with body specified in the body params' do + subject.make_request kind_of_request, '/asdasd', { jane: 'doe' } + expect(a_request(kind_of_request, "www.example.com/asdasd?jane=doe")).to have_been_made.once + end + end + + context 'when request also has headers' do + it 'makes calls with headers specified' do + subject.make_request kind_of_request, '/asdasd', { }, { a: '1' } + expect(a_request(kind_of_request, "www.example.com/asdasd").with({headers: {'A' => '1'}})).to have_been_made.once + end + end + + context 'when request has body and headers' do + it 'makes calls with body specified in the body params' do + subject.make_request kind_of_request, '/asdasd', { jane: 'doe' }, { a: '1' } + expect(a_request(kind_of_request, "www.example.com/asdasd?jane=doe").with({headers: {'A' => '1'}})).to have_been_made.once + end + end + + context 'when request has a different URL than the URL specified' do + before { stub_request(:any, /www.example.de/) } + + it 'makes calls with body specified in the body params' do + subject.make_request kind_of_request, '/asdasd', { jane: 'doe' } do |k, c| + c.url_prefix = 'http://www.example.de' + k.headers.merge!({ a: '1' }) + end + expect(a_request(kind_of_request, "www.example.de/asdasd?jane=doe").with({headers: {'A' => '1'}})).to have_been_made.once + end + end + end + end + + shared_examples 'faraday_put_post_requests' do |kind_of_request| + describe "##{kind_of_request}" do + context 'when have only path' do + it "makes a simple #{kind_of_request} call" do + subject.make_request kind_of_request, '/asdasd' + expect(a_request(kind_of_request, "www.example.com/asdasd").with(body: {})).to have_been_made.once + end + end + + context 'when request has body' do + it 'makes calls with body specified in the body params' do + subject.make_request kind_of_request, '/asdasd', { jane: 'doe' } + expect(a_request(kind_of_request, "www.example.com/asdasd").with(body: 'jane=doe')).to have_been_made.once + end + end + + context 'when request also has headers' do + it 'makes calls with headers specified' do + subject.make_request kind_of_request, '/asdasd', { }, { a: '1' } + expect(a_request(kind_of_request, "www.example.com/asdasd").with({headers: {'A' => '1'}})).to have_been_made.once + end + end + + context 'when request has body and headers' do + it 'makes calls with body specified in the body params' do + subject.make_request kind_of_request, '/asdasd', { jane: 'doe' }, { a: '1' } + expect(a_request(kind_of_request, "www.example.com/asdasd").with({headers: {'A' => '1'}, body: 'jane=doe'})).to have_been_made.once + end + end + + context 'when request has a different URL than the URL specified' do + before { stub_request(:any, /www.example.de/) } + + it 'makes calls with body specified in the body params' do + subject.make_request kind_of_request, '/asdasd', { jane: 'doe' } do |k, c| + c.url_prefix = 'http://www.example.de' + k.headers.merge!({ a: '1' }) + end + expect(a_request(kind_of_request, "www.example.de/asdasd").with({headers: {'A' => '1'}, body: 'jane=doe'})).to have_been_made.once + end + end + end + end + + it_behaves_like 'faraday_get_delete_requests', :get + it_behaves_like 'faraday_get_delete_requests', :delete + it_behaves_like 'faraday_put_post_requests', :put + it_behaves_like 'faraday_put_post_requests', :post +end From 4486fe35bb0b9bf89f49636431c4958c6cadaa3c Mon Sep 17 00:00:00 2001 From: Shreyas Agarwal Date: Fri, 24 Nov 2017 08:09:30 +0100 Subject: [PATCH 07/16] Run faraday when set true and refactor code --- lib/airborne/base.rb | 6 ++-- spec/airborne/base_spec.rb | 60 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/lib/airborne/base.rb b/lib/airborne/base.rb index c1885f3..6464aab 100644 --- a/lib/airborne/base.rb +++ b/lib/airborne/base.rb @@ -11,9 +11,11 @@ class InvalidJsonError < StandardError; end attr_reader :response, :headers, :body def self.included(base) - if !Airborne.configuration.requester_module.nil? + if Airborne.configuration.use_faraday + base.send(:include, Airborne::FaradayRequester) + elsif Airborne.configuration.requester_module base.send(:include, Airborne.configuration.requester_module) - elsif !Airborne.configuration.rack_app.nil? + elsif Airborne.configuration.rack_app base.send(:include, RackTestRequester) else base.send(:include, RestClientRequester) diff --git a/spec/airborne/base_spec.rb b/spec/airborne/base_spec.rb index 63d1da2..902c578 100644 --- a/spec/airborne/base_spec.rb +++ b/spec/airborne/base_spec.rb @@ -52,4 +52,64 @@ post '/simple_post', {} expect(json_body).to_not be(nil) end + + context 'when using faraday instead of RestClient' do + before do + Airborne.configure do |c| + c.use_faraday = true + end + end + it 'when request is made response should be set' do + mock_get('simple_get') + get '/simple_get' + expect(response).to_not be(nil) + end + + it 'when request is made headers should be set' do + mock_get('simple_get') + get '/simple_get' + expect(headers).to_not be(nil) + end + + it 'should throw an InvalidJsonError when accessing json_body on invalid json' do + mock_get('invalid_json') + get '/invalid_json' + expect(body).to eq('invalid1234') + expect { json_body }.to raise_error(InvalidJsonError) + end + + it 'when request is made headers should be hash with indifferent access' do + mock_get('simple_get', 'Content-Type' => 'application/json') + get '/simple_get' + expect(headers).to be_kind_of(Hash) + expect(headers[:content_type]).to eq('application/json') + expect(headers['content_type']).to eq('application/json') + end + + it 'when request is made body should be set' do + mock_get('simple_get') + get '/simple_get' + expect(body).to_not be(nil) + end + + it 'when request is made json body should be symbolized hash' do + mock_get('simple_get') + get '/simple_get' + expect(json_body).to be_kind_of(Hash) + expect(json_body.first[0]).to be_kind_of(Symbol) + end + + it 'should handle a 500 error on get' do + mock_get('simple_get', {}, [500, 'Internal Server Error']) + get '/simple_get' + expect(json_body).to_not be(nil) + end + + it 'should handle a 500 error on post' do + mock_post('simple_post', {}, [500, 'Internal Server Error']) + post '/simple_post', {} + expect(json_body).to_not be(nil) + end + + end end From 38af8e8d5a237445dee8b113ec5d12315f19f345 Mon Sep 17 00:00:00 2001 From: Shreyas Agarwal Date: Fri, 24 Nov 2017 08:16:36 +0100 Subject: [PATCH 08/16] Make it a perfect unit spec --- spec/airborne/faraday_requester_spec.rb | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/spec/airborne/faraday_requester_spec.rb b/spec/airborne/faraday_requester_spec.rb index ff3cb5a..fa792fa 100644 --- a/spec/airborne/faraday_requester_spec.rb +++ b/spec/airborne/faraday_requester_spec.rb @@ -3,10 +3,7 @@ RSpec.fdescribe Airborne::FaradayRequester do before do stub_request(:any, /www.example.com/) - Airborne.configure do |config| - config.use_faraday = true - config.base_url = 'http://www.example.com' - end + allow(Airborne).to receive_message_chain(:configuration, :base_url).and_return 'http://www.example.com' end subject { described_class.new } From 9a8409b5842ef5f2fa75d1c64b1d131b8310d814 Mon Sep 17 00:00:00 2001 From: Shreyas Agarwal Date: Fri, 24 Nov 2017 08:44:42 +0100 Subject: [PATCH 09/16] Add some basic configs to the airborne gem --- lib/airborne.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/airborne.rb b/lib/airborne.rb index eeecf65..0d690d4 100644 --- a/lib/airborne.rb +++ b/lib/airborne.rb @@ -24,4 +24,6 @@ def configure RSpec.configure do |config| config.include Airborne::Base + config.filter_run_when_matching :focus + config.order = :random end From 35d02733aadb5c420bfa4f9dc74f10004ed24912 Mon Sep 17 00:00:00 2001 From: Shreyas Agarwal Date: Fri, 24 Nov 2017 08:45:21 +0100 Subject: [PATCH 10/16] Remove focus tag --- spec/airborne/faraday_requester_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/airborne/faraday_requester_spec.rb b/spec/airborne/faraday_requester_spec.rb index fa792fa..f0c7bad 100644 --- a/spec/airborne/faraday_requester_spec.rb +++ b/spec/airborne/faraday_requester_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -RSpec.fdescribe Airborne::FaradayRequester do +RSpec.describe Airborne::FaradayRequester do before do stub_request(:any, /www.example.com/) allow(Airborne).to receive_message_chain(:configuration, :base_url).and_return 'http://www.example.com' From 940db8c352670e8254062d92c5d47ee101bf2db1 Mon Sep 17 00:00:00 2001 From: Shreyas Agarwal Date: Fri, 24 Nov 2017 08:45:54 +0100 Subject: [PATCH 11/16] Make spec better looking --- spec/airborne/base_spec.rb | 62 ++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/spec/airborne/base_spec.rb b/spec/airborne/base_spec.rb index 902c578..aeed130 100644 --- a/spec/airborne/base_spec.rb +++ b/spec/airborne/base_spec.rb @@ -59,16 +59,39 @@ c.use_faraday = true end end - it 'when request is made response should be set' do - mock_get('simple_get') - get '/simple_get' - expect(response).to_not be(nil) - end - it 'when request is made headers should be set' do - mock_get('simple_get') - get '/simple_get' - expect(headers).to_not be(nil) + context 'when sucessful request is made' do + + before { mock_get('simple_get') } + + it 'response should be set' do + get '/simple_get' + expect(response).to_not be(nil) + end + + it 'headers should be set' do + get '/simple_get' + expect(headers).to_not be(nil) + end + + it 'headers should be hash with indifferent access' do + mock_get('simple_get', 'Content-Type' => 'application/json') + get '/simple_get' + expect(headers).to be_kind_of(Hash) + expect(headers[:content_type]).to eq('application/json') + expect(headers['content_type']).to eq('application/json') + end + + it 'body should be set' do + get '/simple_get' + expect(body).to_not be(nil) + end + + it 'json body should be symbolized hash' do + get '/simple_get' + expect(json_body).to be_kind_of(Hash) + expect(json_body.first[0]).to be_kind_of(Symbol) + end end it 'should throw an InvalidJsonError when accessing json_body on invalid json' do @@ -78,27 +101,6 @@ expect { json_body }.to raise_error(InvalidJsonError) end - it 'when request is made headers should be hash with indifferent access' do - mock_get('simple_get', 'Content-Type' => 'application/json') - get '/simple_get' - expect(headers).to be_kind_of(Hash) - expect(headers[:content_type]).to eq('application/json') - expect(headers['content_type']).to eq('application/json') - end - - it 'when request is made body should be set' do - mock_get('simple_get') - get '/simple_get' - expect(body).to_not be(nil) - end - - it 'when request is made json body should be symbolized hash' do - mock_get('simple_get') - get '/simple_get' - expect(json_body).to be_kind_of(Hash) - expect(json_body.first[0]).to be_kind_of(Symbol) - end - it 'should handle a 500 error on get' do mock_get('simple_get', {}, [500, 'Internal Server Error']) get '/simple_get' From cb60fdfb3a10de4c45c55c59339c09745443d420 Mon Sep 17 00:00:00 2001 From: Shreyas Agarwal Date: Fri, 24 Nov 2017 10:24:36 +0100 Subject: [PATCH 12/16] Refactor to have a better representation of specs --- lib/airborne.rb | 2 +- spec/airborne/client_requester_spec.rb | 2 -- .../expectations/expect_header_contains_spec.rb | 8 +++++--- spec/airborne/expectations/expect_json_regex_spec.rb | 10 +++++----- spec/airborne/expectations/expect_status_spec.rb | 6 ------ 5 files changed, 11 insertions(+), 17 deletions(-) diff --git a/lib/airborne.rb b/lib/airborne.rb index 0d690d4..5de2c46 100644 --- a/lib/airborne.rb +++ b/lib/airborne.rb @@ -22,7 +22,7 @@ def configure end end -RSpec.configure do |config| +Airborne.configure do |config| config.include Airborne::Base config.filter_run_when_matching :focus config.order = :random diff --git a/spec/airborne/client_requester_spec.rb b/spec/airborne/client_requester_spec.rb index 3ebfcc3..d1dc616 100644 --- a/spec/airborne/client_requester_spec.rb +++ b/spec/airborne/client_requester_spec.rb @@ -3,11 +3,9 @@ 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 diff --git a/spec/airborne/expectations/expect_header_contains_spec.rb b/spec/airborne/expectations/expect_header_contains_spec.rb index 32d61aa..f65c8c6 100644 --- a/spec/airborne/expectations/expect_header_contains_spec.rb +++ b/spec/airborne/expectations/expect_header_contains_spec.rb @@ -1,20 +1,22 @@ require 'spec_helper' describe 'expect header contains' do - it 'should ensure partial header match exists' do + before do mock_get('simple_get', 'Content-Type' => 'application/json') + end + + it 'should ensure partial header match exists' do get '/simple_get' expect_header_contains(:content_type, 'json') end it 'should ensure header is present' do - mock_get('simple_get', 'Content-Type' => 'application/json') get '/simple_get' expect { expect_header_contains(:foo, 'bar') }.to raise_error(ExpectationNotMetError) end + it 'should ensure partial header is present' do - mock_get('simple_get', 'Content-Type' => 'application/json') get '/simple_get' expect { expect_header_contains(:content_type, 'bar') }.to raise_error(ExpectationNotMetError) end diff --git a/spec/airborne/expectations/expect_json_regex_spec.rb b/spec/airborne/expectations/expect_json_regex_spec.rb index e66905b..a28e502 100644 --- a/spec/airborne/expectations/expect_json_regex_spec.rb +++ b/spec/airborne/expectations/expect_json_regex_spec.rb @@ -4,30 +4,30 @@ it 'should test against regex' do mock_get('simple_get') get '/simple_get' - expect_json(name: regex('^A')) + expect_json(name: /^A/) end it 'should raise an error if regex does not match' do mock_get('simple_get') get '/simple_get' - expect { expect_json(name: regex('^B')) }.to raise_error(ExpectationNotMetError) + expect { expect_json(name: /^B/) }.to raise_error(ExpectationNotMetError) end it 'should allow regex(Regexp) to be tested against a path' do mock_get('simple_nested_path') get '/simple_nested_path' - expect_json('address.city', regex('^R')) + expect_json('address.city', /^R/) end it 'should allow testing regex against numbers directly' do mock_get('simple_nested_path') get '/simple_nested_path' - expect_json('address.coordinates.lattitude', regex('^3')) + expect_json('address.coordinates.lattitude', /^3/) end it 'should allow testing regex against numbers in the hash' do mock_get('simple_nested_path') get '/simple_nested_path' - expect_json('address.coordinates', lattitude: regex('^3')) + expect_json('address.coordinates', lattitude: /^3/) end end diff --git a/spec/airborne/expectations/expect_status_spec.rb b/spec/airborne/expectations/expect_status_spec.rb index d7817f5..9872b31 100644 --- a/spec/airborne/expectations/expect_status_spec.rb +++ b/spec/airborne/expectations/expect_status_spec.rb @@ -1,12 +1,6 @@ require 'spec_helper' describe 'expect_status' do - it 'should verify correct status code' do - mock_get('simple_get') - get '/simple_get' - expect_status 200 - end - it 'should fail when incorrect status code is returned' do mock_get('simple_get') get '/simple_get' From a3baf27ddf667627e71e6291d917d6a3ddc35a66 Mon Sep 17 00:00:00 2001 From: Shreyas Agarwal Date: Thu, 30 Nov 2017 14:58:05 +0100 Subject: [PATCH 13/16] Add support for basic_auth --- lib/airborne/base.rb | 4 ++++ spec/airborne/post_spec.rb | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/airborne/base.rb b/lib/airborne/base.rb index 6464aab..306c4d3 100644 --- a/lib/airborne/base.rb +++ b/lib/airborne/base.rb @@ -58,6 +58,10 @@ def headers HashWithIndifferentAccess.new(response.headers) end + def basic_auth(username, password) + "Basic " + ["#{username}:#{password}"].pack('m*') + end + def body response.body end diff --git a/spec/airborne/post_spec.rb b/spec/airborne/post_spec.rb index 22bce3c..1262324 100644 --- a/spec/airborne/post_spec.rb +++ b/spec/airborne/post_spec.rb @@ -11,7 +11,7 @@ it 'should allow testing on post requests' do url = 'http://www.example.com/simple_post' stub_request(:post, url) - post '/simple_post', 'hello', content_type: 'text/plain' - expect(WebMock).to have_requested(:post, url).with(body: 'hello', headers: { 'Content-Type' => 'text/plain' }) + post '/simple_post', 'hello', content_type: 'text/plain', 'Authorization' => basic_auth('shreyas', 'agarwal') + expect(WebMock).to have_requested(:post, url).with(body: 'hello', headers: { 'Content-Type' => 'text/plain', 'Authorization' => 'Basic c2hyZXlhczphZ2Fyd2Fs' }) end end From d555254b5ad2327f69b9e6018aebcc78ef8796b3 Mon Sep 17 00:00:00 2001 From: Shreyas Agarwal Date: Thu, 30 Nov 2017 16:50:30 +0100 Subject: [PATCH 14/16] Add basic auth to the faraday connection --- lib/airborne/base.rb | 5 +++-- lib/airborne/faraday_requester.rb | 10 ++++++--- spec/airborne/faraday_requester_spec.rb | 28 +++++++++++++++---------- spec/airborne/post_spec.rb | 9 ++++++++ 4 files changed, 36 insertions(+), 16 deletions(-) diff --git a/lib/airborne/base.rb b/lib/airborne/base.rb index 306c4d3..7ef2c8d 100644 --- a/lib/airborne/base.rb +++ b/lib/airborne/base.rb @@ -58,8 +58,9 @@ def headers HashWithIndifferentAccess.new(response.headers) end - def basic_auth(username, password) - "Basic " + ["#{username}:#{password}"].pack('m*') + def basic_auth(login, pass) + val = Base64.encode64([login, pass].join(':')).gsub!("\n", '') + "Basic #{val}" end def body diff --git a/lib/airborne/faraday_requester.rb b/lib/airborne/faraday_requester.rb index bca715d..5c548f7 100644 --- a/lib/airborne/faraday_requester.rb +++ b/lib/airborne/faraday_requester.rb @@ -1,17 +1,21 @@ require 'faraday' module Airborne - class FaradayRequester + module FaradayRequester def conn - @conn ||= Faraday.new + @conn ||= Faraday.new do |c| + c.request :url_encoded + c.adapter Faraday.default_adapter + end end def make_request(method_name, path, body = {}, headers ={}, &block) conn.send(method_name, path, body) do |req| conn.url_prefix = base_url req.path = path - req.headers = headers + req.headers.merge!(headers) yield req, conn if block_given? + req.headers.merge!(conn.headers) end end diff --git a/spec/airborne/faraday_requester_spec.rb b/spec/airborne/faraday_requester_spec.rb index f0c7bad..39023c0 100644 --- a/spec/airborne/faraday_requester_spec.rb +++ b/spec/airborne/faraday_requester_spec.rb @@ -3,38 +3,42 @@ RSpec.describe Airborne::FaradayRequester do before do stub_request(:any, /www.example.com/) - allow(Airborne).to receive_message_chain(:configuration, :base_url).and_return 'http://www.example.com' + allow(Airborne).to receive_message_chain(:configuration, :base_url).and_return 'https://www.example.com' end - subject { described_class.new } + class Test + include Airborne::FaradayRequester + end + + subject { Test.new } shared_examples 'faraday_get_delete_requests' do |kind_of_request| describe "##{kind_of_request}" do context 'when have only path' do it "makes a simple #{kind_of_request} call" do subject.make_request kind_of_request, '/asdasd' - expect(a_request(kind_of_request, "www.example.com/asdasd").with(body: {})).to have_been_made.once + expect(a_request(kind_of_request, "https://www.example.com/asdasd").with(body: {})).to have_been_made.once end end context 'when request has body' do it 'makes calls with body specified in the body params' do subject.make_request kind_of_request, '/asdasd', { jane: 'doe' } - expect(a_request(kind_of_request, "www.example.com/asdasd?jane=doe")).to have_been_made.once + expect(a_request(kind_of_request, "https://www.example.com/asdasd?jane=doe")).to have_been_made.once end end context 'when request also has headers' do it 'makes calls with headers specified' do subject.make_request kind_of_request, '/asdasd', { }, { a: '1' } - expect(a_request(kind_of_request, "www.example.com/asdasd").with({headers: {'A' => '1'}})).to have_been_made.once + expect(a_request(kind_of_request, "https://www.example.com/asdasd").with({headers: {'A' => '1'}})).to have_been_made.once end end context 'when request has body and headers' do it 'makes calls with body specified in the body params' do subject.make_request kind_of_request, '/asdasd', { jane: 'doe' }, { a: '1' } - expect(a_request(kind_of_request, "www.example.com/asdasd?jane=doe").with({headers: {'A' => '1'}})).to have_been_made.once + expect(a_request(kind_of_request, "https://www.example.com/asdasd?jane=doe").with({headers: {'A' => '1'}})).to have_been_made.once end end @@ -42,11 +46,13 @@ before { stub_request(:any, /www.example.de/) } it 'makes calls with body specified in the body params' do + subject.make_request kind_of_request, '/asdasd', { jane: 'doe' } do |k, c| c.url_prefix = 'http://www.example.de' + c.basic_auth 'asdsa', 'asdsa' k.headers.merge!({ a: '1' }) end - expect(a_request(kind_of_request, "www.example.de/asdasd?jane=doe").with({headers: {'A' => '1'}})).to have_been_made.once + expect(a_request(kind_of_request, "www.example.de/asdasd?jane=doe").with({headers: {'A' => '1', 'Authorization' => "Basic YXNkc2E6YXNkc2E="}})).to have_been_made.once end end end @@ -57,28 +63,28 @@ context 'when have only path' do it "makes a simple #{kind_of_request} call" do subject.make_request kind_of_request, '/asdasd' - expect(a_request(kind_of_request, "www.example.com/asdasd").with(body: {})).to have_been_made.once + expect(a_request(kind_of_request, "https://www.example.com/asdasd").with(body: {})).to have_been_made.once end end context 'when request has body' do it 'makes calls with body specified in the body params' do subject.make_request kind_of_request, '/asdasd', { jane: 'doe' } - expect(a_request(kind_of_request, "www.example.com/asdasd").with(body: 'jane=doe')).to have_been_made.once + expect(a_request(kind_of_request, "https://www.example.com/asdasd").with(body: 'jane=doe')).to have_been_made.once end end context 'when request also has headers' do it 'makes calls with headers specified' do subject.make_request kind_of_request, '/asdasd', { }, { a: '1' } - expect(a_request(kind_of_request, "www.example.com/asdasd").with({headers: {'A' => '1'}})).to have_been_made.once + expect(a_request(kind_of_request, "https://www.example.com/asdasd").with({headers: {'A' => '1'}})).to have_been_made.once end end context 'when request has body and headers' do it 'makes calls with body specified in the body params' do subject.make_request kind_of_request, '/asdasd', { jane: 'doe' }, { a: '1' } - expect(a_request(kind_of_request, "www.example.com/asdasd").with({headers: {'A' => '1'}, body: 'jane=doe'})).to have_been_made.once + expect(a_request(kind_of_request, "https://www.example.com/asdasd").with({headers: {'A' => '1'}, body: 'jane=doe'})).to have_been_made.once end end diff --git a/spec/airborne/post_spec.rb b/spec/airborne/post_spec.rb index 1262324..1c41240 100644 --- a/spec/airborne/post_spec.rb +++ b/spec/airborne/post_spec.rb @@ -14,4 +14,13 @@ post '/simple_post', 'hello', content_type: 'text/plain', 'Authorization' => basic_auth('shreyas', 'agarwal') expect(WebMock).to have_requested(:post, url).with(body: 'hello', headers: { 'Content-Type' => 'text/plain', 'Authorization' => 'Basic c2hyZXlhczphZ2Fyd2Fs' }) end + + context 'when using Faraday', :faraday do + it 'makes a post request to specfied URL with body and headers' do + url = 'http://www.example.com/simple_post' + stub_request(:post, url) + post '/simple_post', 'hello', content_type: 'text/plain', 'Authorization' => basic_auth('shreyasagarwaltesting', 'apiapplicationswithauthorisation') + expect(WebMock).to have_requested(:post, url).with(body: 'hello', headers: { 'Content-Type' => 'text/plain', 'Authorization' => 'Basic c2hyZXlhc2FnYXJ3YWx0ZXN0aW5nOmFwaWFwcGxpY2F0aW9uc3dpdGhhdXRob3Jpc2F0aW9u' }) + end + end end From 1d80d2885f57923cc5d92afb162232b829e9472f Mon Sep 17 00:00:00 2001 From: Shreyas Agarwal Date: Fri, 1 Dec 2017 16:15:08 +0100 Subject: [PATCH 15/16] Include base64 lib --- lib/airborne/base.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/airborne/base.rb b/lib/airborne/base.rb index 7ef2c8d..f119f0a 100644 --- a/lib/airborne/base.rb +++ b/lib/airborne/base.rb @@ -1,6 +1,7 @@ require 'json' require 'active_support' require 'active_support/core_ext/hash/indifferent_access' +require 'base64' module Airborne module Base From 082b6c1960f31264a2bd8e85119b7864e4e1e802 Mon Sep 17 00:00:00 2001 From: Shreyas Agarwal Date: Mon, 5 Nov 2018 14:12:14 +0100 Subject: [PATCH 16/16] Add code method for expect_status check --- lib/airborne/faraday_requester.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/airborne/faraday_requester.rb b/lib/airborne/faraday_requester.rb index 5c548f7..a3b45bc 100644 --- a/lib/airborne/faraday_requester.rb +++ b/lib/airborne/faraday_requester.rb @@ -25,3 +25,11 @@ def base_url end end end + +module FaradayResponse + def code + status + end +end + +Faraday::Response.send(:include, FaradayResponse)