diff options
Diffstat (limited to 'lib/vendor/excon/spec')
11 files changed, 620 insertions, 0 deletions
diff --git a/lib/vendor/excon/spec/excon/error_spec.rb b/lib/vendor/excon/spec/excon/error_spec.rb new file mode 100644 index 0000000..3354c6a --- /dev/null +++ b/lib/vendor/excon/spec/excon/error_spec.rb @@ -0,0 +1,137 @@ +describe Excon::Error do + # Regression against e300458f2d9330cb265baeb8973120d08c665d9 + describe '#status_errors' do + describe '.keys ' do + expected = [ + 100, + 101, + (200..206).to_a, + (300..307).to_a, + (400..417).to_a, + 422, + 429, + (500..504).to_a + ].flatten + + it('returns the pertinent HTTP error numbers') do + expected.flatten == Excon::Error.status_errors.keys + end + end + end + + describe '#new' do + it('returns an Excon::Error') do + expect(Excon::Error.new('bar').class == Excon::Error).to be true + end + it('raises errors for bad URIs') do + expect { Excon.new('foo') }.to raise_error(ArgumentError) + end + + it('raises errors for bad paths') do + expect { Excon.new('http://localhost', path: "foo\r\nbar: baz") }.to raise_error(URI::InvalidURIError) + end + end + + context 'when remaining backwards compatible' do + describe '#new' do + it 'should raise standard error and catch standard error' do + expect { raise Excon::Error::Client, 'foo' }.to raise_error(Excon::Error) + end + + it 'should raise legacy errors and catch legacy errors' do + expect do + raise Excon::Errors::Error, 'bar' + end.to raise_error(Excon::Errors::Error) + end + + it 'should raise standard error and catch legacy errors' do + expect do + raise Excon::Error::NotFound, 'bar' + end.to raise_error(Excon::Errors::Error) + end + end + + describe '#status_error' do + it 'should raise with status_error() and catch with standard error' do + expect do + raise Excon::Error.status_error({ expects: 200 }, status: 400) + end.to raise_error(Excon::Error) + end + + it 'should raise with status_error() and catch with legacy error' do + expect do + raise Excon::Error.status_error({ expects: 200 }, status: 400) + end.to raise_error(Excon::Errors::BadRequest) + end + + it 'should raise with legacy status_error() and catch with standard' do + expect do + raise Excon::Errors.status_error({ expects: 200 }, status: 400) + end.to raise_error(Excon::Error) + end + end + end + + context 'when exceptions are rescued' do + include_context("test server", :exec, 'error.rb', :before => :start, :after => :stop ) + + context 'when :debug_request and :debug_response are switched off' do + it('exception message does not include response or response info') do + begin + Excon.get('http://127.0.0.1:9292/error/not_found', expects: 200) + rescue Excon::Errors::HTTPStatusError => err + truth = + err.message.include?('Expected(200) <=> Actual(404 Not Found)') && + !err.message.include?('excon.error.request') && + !err.message.include?('excon.error.response') + expect(truth).to be true + end + end + end + + context 'when :debug_request and :debug_response are switched on' do + it 'exception message includes request and response info' do + begin + Excon.get('http://127.0.0.1:9292/error/not_found', expects: 200, + debug_request: true, debug_response: true) + rescue Excon::Errors::HTTPStatusError => err + truth = + err.message.include?('Expected(200) <=> Actual(404 Not Found)') && + err.message.include?('excon.error.request') && + err.message.include?('excon.error.response') + expect(truth).to be true + end + end + end + + context 'when only :debug_request is turned on' do + it('exception message includes only request info') do + begin + Excon.get('http://127.0.0.1:9292/error/not_found', expects: 200, + debug_request: true) + rescue Excon::Errors::HTTPStatusError => err + truth = + err.message.include?('Expected(200) <=> Actual(404 Not Found)') && + err.message.include?('excon.error.request') && + !err.message.include?('excon.error.response') + expect(truth).to be true + end + end + end + + context 'when only :debug_response is turned on ' do + it('exception message includes only response info') do + begin + Excon.get('http://127.0.0.1:9292/error/not_found', expects: 200, + debug_response: true) + rescue Excon::Errors::HTTPStatusError => err + truth = + err.message.include?('Expected(200) <=> Actual(404 Not Found)') && + !err.message.include?('excon.error.request') && + err.message.include?('excon.error.response') + expect(truth).to be true + end + end + end + end +end diff --git a/lib/vendor/excon/spec/excon/test/server_spec.rb b/lib/vendor/excon/spec/excon/test/server_spec.rb new file mode 100644 index 0000000..3fadb04 --- /dev/null +++ b/lib/vendor/excon/spec/excon/test/server_spec.rb @@ -0,0 +1,28 @@ +require 'spec_helper' + +describe Excon::Test::Server do + + context 'when the web server is webrick' do + it_should_behave_like "a excon test server", :webrick, 'basic.ru' + end + + + context 'when the web server is unicorn' do + context 'bound to a tcp socket' do + it_should_behave_like "a excon test server", :unicorn, 'streaming.ru' + end + + context "bound to a unix socket" do + socket_uri = 'unix:///tmp/unicorn.socket' + it_should_behave_like "a excon test server", :unicorn, 'streaming.ru', socket_uri + end + end + + context 'when the web server is puma' do + it_should_behave_like "a excon test server", :puma, 'streaming.ru' + end + + context 'when the web server is a executable' do + it_should_behave_like "a excon test server", :exec, 'good.rb' + end +end diff --git a/lib/vendor/excon/spec/excon_spec.rb b/lib/vendor/excon/spec/excon_spec.rb new file mode 100644 index 0000000..64cc5a8 --- /dev/null +++ b/lib/vendor/excon/spec/excon_spec.rb @@ -0,0 +1,7 @@ +require 'spec_helper' + +describe Excon do + it 'has a version number' do + expect(Excon::VERSION).not_to be nil + end +end diff --git a/lib/vendor/excon/spec/helpers/file_path_helpers.rb b/lib/vendor/excon/spec/helpers/file_path_helpers.rb new file mode 100644 index 0000000..2424ec6 --- /dev/null +++ b/lib/vendor/excon/spec/helpers/file_path_helpers.rb @@ -0,0 +1,22 @@ +# Todo: s/tests/specs when migration is complete +def get_abs_path(*parts) + File.join(File.expand_path('../../..', __FILE__), 'tests', *parts) +end + +def data_path(*parts) + get_abs_path('data', *parts) +end + +def rackup_path(*parts) + get_abs_path('rackups', *parts) +end + +def webrick_path(*parts) rackup_path(*parts); end + +def unicorn_path(*parts) rackup_path(*parts); end + +def puma_path(*parts) rackup_path(*parts); end + +def exec_path(*parts) + get_abs_path('servers', *parts) +end diff --git a/lib/vendor/excon/spec/requests/basic_spec.rb b/lib/vendor/excon/spec/requests/basic_spec.rb new file mode 100644 index 0000000..c46dc6f --- /dev/null +++ b/lib/vendor/excon/spec/requests/basic_spec.rb @@ -0,0 +1,40 @@ +require 'spec_helper' + +describe Excon::Connection do + include_context('test server', :webrick, 'basic.ru', before: :start, after: :stop) + context 'when an explicit uri is passed' do + let(:conn) do + Excon::Connection.new(host: '127.0.0.1', + hostname: '127.0.0.1', + nonblock: false, + port: 9292, + scheme: 'http', + ssl_verify_peer: false) + end + + describe '.new' do + it 'returns an instance' do + expect(conn).to be_instance_of Excon::Connection + end + end + + context "when :method is :get and :path is /content-length/100" do + describe "#request" do + let(:response) do + response = conn.request(method: :get, path: '/content-length/100') + end + it 'returns an Excon::Response' do + expect(response).to be_instance_of Excon::Response + end + describe Excon::Response do + describe '#status' do + it 'returns 200' do + expect(response.status).to eq 200 + end + end + end + end + end + include_examples 'a basic client' + end +end diff --git a/lib/vendor/excon/spec/requests/eof_requests_spec.rb b/lib/vendor/excon/spec/requests/eof_requests_spec.rb new file mode 100644 index 0000000..e918ec7 --- /dev/null +++ b/lib/vendor/excon/spec/requests/eof_requests_spec.rb @@ -0,0 +1,36 @@ +require 'spec_helper' + +describe Excon do + context "when dispatching requests" do + context('to a server that does not supply response headers') do + include_context("test server", :exec, 'bad.rb', :before => :start, :after => :stop ) + before(:all) do + @conn = Excon.new('http://127.0.0.1:9292') + end + + context('when no block is given') do + it 'should rescue from an EOFError and return response' do + body = @conn.request(:method => :get, :path => '/eof/no_content_length_and_no_chunking').body + expect(body).to eq 'hello' + end + end + + context('when a block is given') do + it 'should rescue from EOFError and return response' do + body = "" + response_block = lambda {|chunk, remaining, total| body << chunk } + @conn.request(:method => :get, :path => '/eof/no_content_length_and_no_chunking', :response_block => response_block) + expect(body).to eq 'hello' + end + end + end + + context('to a server that prematurely aborts the request with no response') do + include_context("test server", :exec, 'eof.rb', :before => :start, :after => :stop ) + + it 'should raise an EOFError' do + expect { Excon.get('http://127.0.0.1:9292/eof') }.to raise_error(Excon::Errors::SocketError) + end + end + end +end diff --git a/lib/vendor/excon/spec/spec_helper.rb b/lib/vendor/excon/spec/spec_helper.rb new file mode 100644 index 0000000..999f830 --- /dev/null +++ b/lib/vendor/excon/spec/spec_helper.rb @@ -0,0 +1,24 @@ +require 'excon' +require 'excon/test/server' +require 'json' + +# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration +RSpec.configure do |config| + config.expect_with :rspec do |expectations| + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + config.mock_with :rspec do |mocks| + mocks.verify_partial_doubles = true + end + + if config.files_to_run.one? + config.default_formatter = 'doc' + end +end + +# Load helpers +Dir["./spec/helpers/**/*.rb"].sort.each { |f| require f} + +# Load shared examples and contexts +Dir["./spec/support/**/*.rb"].sort.each { |f| require f} diff --git a/lib/vendor/excon/spec/support/shared_contexts/test_server_context.rb b/lib/vendor/excon/spec/support/shared_contexts/test_server_context.rb new file mode 100644 index 0000000..f40e34c --- /dev/null +++ b/lib/vendor/excon/spec/support/shared_contexts/test_server_context.rb @@ -0,0 +1,83 @@ +# TODO: Clean up this doc and dry up the conditionals +# +# Required params: +# plugin (e.g., webrick, unicorn, etc) +# file (e.g. a rackup ) +# +# Optional params: +# optional paramters may given as a hash +# opts may contain a bind argument +# opts may also contain before and after options +# +# In its simplest form: +# { :before => :start, :after => :stop } +# +# With lambdas, which recieve @server as an argument +# { before: lambda {|s| s.start }, after: lambda { |s| s.stop} } +# +# In both the cases above, before defaults to before(:all) +# This can be circumvented with a Hash +# { before: { :context => :start }, after: { :context => :stop } } +# or +# { before: { context: lambda { |s| s.start } }, after: { context: lambda { |s| s.stop } } } + +shared_context "test server" do |plugin, file, opts = {}| + plugin = plugin.to_sym unless plugin.is_a? Symbol + if plugin == :unicorn && RUBY_PLATFORM == "java" + before { skip("until unicorn supports jruby") } + end + abs_file = Object.send("#{plugin}_path", file) + args = { plugin => abs_file} + args[:bind] = opts[:bind] if opts.key? :bind + + + before_hook = opts.key?(:before) && (opts[:before].is_a?(Symbol) || opts[:before].is_a?(Proc) || opts[:before].is_a?(Hash)) + + if before_hook && opts[:before].is_a?(Hash) + event = opts[:before].keys.first + before(event) { + @server = Excon::Test::Server.new(args) + if opts[:before][event].is_a? Symbol + @server.send(opts[:before][event]) + else + opts[:before][event].call(@server) + end + } + elsif + before(:all) { + @server = Excon::Test::Server.new(args) + before_hook = opts.key?(:before) && (opts[:before].is_a?(Symbol) || opts[:before].is_a?(Proc) || opts[:before].is_a?(Hash)) + + if before_hook + if opts[:before].is_a? Symbol + @server.send(opts[:before]) + else + opts[:before].call(@server) + end + end + } + end + + after_hook = opts.key?(:after) && (opts[:after].is_a?(Symbol) || opts[:after].is_a?(Proc) || opts[:after].is_a?(Hash)) + + if after_hook && opts[:after].is_a?(Hash) + event = opts[:after].keys.first + after(event) { + if opts[:after][event].is_a? Symbol + @server.send(opts[:after][event]) + else + opts[:after][event].call(@server) + end + } + elsif after_hook + after(:all) { + if opts[:after].is_a? Symbol + @server.send(opts[:after]) + elsif opts[:after].is_a? Hash + + else + opts[:after].call(@server) + end + } + end +end diff --git a/lib/vendor/excon/spec/support/shared_examples/shared_example_for_clients.rb b/lib/vendor/excon/spec/support/shared_examples/shared_example_for_clients.rb new file mode 100644 index 0000000..786e98f --- /dev/null +++ b/lib/vendor/excon/spec/support/shared_examples/shared_example_for_clients.rb @@ -0,0 +1,207 @@ +shared_examples_for 'a basic client' do |url = 'http://127.0.0.1:9292', opts = {}| + # TODO: Ditch iterator and manually write a context for each set of options + ([true, false] * 2).combination(2).to_a.uniq.each do |nonblock, persistent| + context "when nonblock is #{nonblock} and persistent is #{persistent}" do + opts = opts.merge(ssl_verify_peer: false, nonblock: nonblock, persistent: persistent) + + let(:conn) { Excon.new(url, opts) } + + context 'when :method is get and :path is /content-length/100' do + describe '#request' do + let(:response) do + conn.request(method: :get, path: '/content-length/100') + end + + it 'returns an Excon::Response' do + expect(response).to be_instance_of Excon::Response + end + describe Excon::Response do + describe '#status' do + it 'returns 200' do + expect(response.status).to eq 200 + end + + it '#status returns 200' do + expect(response[:status]).to eq 200 + end + end + describe '#headers' do + it '["Content-Length"] returns 100' do + expect(response.headers['Content-Length']).to eq '100' + end + it '["Content-Type"] returns "text/html;charset=utf-8"' do + expect(response.headers['Content-Type']).to eq 'text/html;charset=utf-8' + end + + it "['Date'] returns a valid date" do + if RUBY_PLATFORM == 'java' && conn.data[:scheme] == Excon::UNIX + skip('until puma responds with a date header') + else + time = Time.parse(response.headers['Date']) + expect(time.is_a?(Time)).to be true + end + end + + it "['Server'] matches /^WEBrick/" do + pending('until unix_socket response has server header') if conn.data[:scheme] == Excon::UNIX + expect(!!(response.headers['Server'] =~ /^WEBrick/)).to be true + end + + it "['Custom'] returns Foo: bar" do + expect(response.headers['Custom']).to eq 'Foo: bar' + end + end + describe '#remote_ip' do + it 'returns 127.0.0.1' do + pending('until pigs can fly') if conn.data[:scheme] == Excon::UNIX + expect(response.remote_ip).to eq '127.0.0.1' + end + end + end + + context('when tcp_nodelay is true') do + describe '#request' do + response = nil + options = opts.merge(ssl_verify_peer: false, nonblock: nonblock, tcp_nodelay: true) + connection = Excon.new(url, options) + + it 'returns an Excon::Response' do + expect do + response = connection.request(method: :get, path: '/content-length/100') + end.to_not raise_error + end + + describe Excon::Response do + describe '#body' do + describe '.status' do + it '#returns 200' do + expect(response.status).to eq 200 + end + end + end + end + end + end + end + + context 'when utilizing deprecated block usage' do + describe '#request' do + data = [] + it 'yields with a chunk, remaining length, and total length' do + expect do + conn.request(method: :get, path: '/content-length/100') do |chunk, remaining_length, total_length| + data = [chunk, remaining_length, total_length] + end + end.to_not raise_error + end + it 'completes with expected data' do + expect(data).to eq ['x' * 100, 0, 100] + end + end + end + + context 'when utilizing response_block usage' do + describe '#request' do + data = [] + it 'yields a chunk, remaining length, and total_length' do + response_block = lambda do |chunk, remaining_length, total_length| + data = [chunk, remaining_length, total_length] + end + expect do + conn.request(method: :get, path: '/content-length/100', response_block: response_block) + end.to_not raise_error + end + it 'completes with expected data' do + expect(data).to eq ['x' * 100, 0, 100] + end + end + end + context 'when method is :post' do + context 'when :path is /body-sink' do + context 'when a body parameter is supplied' do + response = nil + it 'returns an Excon::Response' do + response = conn.request(method: :post, path: '/body-sink', headers: { 'Content-Type' => 'text/plain' }, body: 'x' * 5_000_000) + expect(response).to be_instance_of Excon::Response + end + describe Excon::Response do + describe '#body' do + it 'equals "5000000"' do + expect(response.body).to eq '5000000' + end + end + end + end + context 'when the body parameter is an empty string' do + response = nil + + it 'returns an Excon::Response' do + response = conn.request(method: :post, path: '/body-sink', headers: { 'Content-Type' => 'text/plain' }, body: '') + expect(response).to be_instance_of Excon::Response + end + describe Excon::Response do + describe '#body' do + it 'equals "0"' do + expect(response.body).to eq '0' + end + end + end + end + end + + context 'when :path is /echo' do + context('when a file handle is the body paramter') do + describe Excon::Response do + it '#body equals "x" * 100 + "\n"' do + file_path = data_path('xs') + response = conn.request(method: :post, path: '/echo', body: File.open(file_path)) + expect(response.body).to eq 'x' * 100 + "\n" + end + end + end + + context 'when a string is the body paramter' do + context 'without request_block' do + describe Excon::Response do + it "#body equals 'x' * 100)" do + response = conn.request(method: :post, path: '/echo', body: 'x' * 100) + expect(response.body).to eq 'x' * 100 + end + end + end + + context 'when a request_block paramter is supplied' do + describe Excon::Response do + it "#body equals'x' * 100" do + data = ['x'] * 100 + request_block = lambda do + data.shift.to_s + end + response = conn.request(method: :post, path: '/echo', request_block: request_block) + expect(response.body).to eq 'x' * 100 + end + end + end + + context('when a multi-byte string is the body paramter') do + body = "\xC3\xBC" * 100 + headers = { 'Custom' => body.dup } + if RUBY_VERSION >= '1.9' + body.force_encoding('BINARY') + headers['Custom'].force_encoding('UTF-8') + end + describe Excon::Response do + it '#body properly concatenates request+headers and body' do + response = conn.request(method: :post, path: '/echo', + headers: headers, body: body) + expect(response.body).to eq body + end + end + end + end + end + end + end + end + end +end diff --git a/lib/vendor/excon/spec/support/shared_examples/shared_example_for_streaming_clients.rb b/lib/vendor/excon/spec/support/shared_examples/shared_example_for_streaming_clients.rb new file mode 100644 index 0000000..15a9f05 --- /dev/null +++ b/lib/vendor/excon/spec/support/shared_examples/shared_example_for_streaming_clients.rb @@ -0,0 +1,20 @@ +shared_examples_for 'a streaming client' do |endpoint, timeout| + ret = [] + timing = 'response times ok' + start = Time.now + block = lambda do |c,r,t| + # add the response + ret.push(c) + # check if the timing is ok + # each response arrives after timeout and before timeout + 1 + cur_time = Time.now - start + if cur_time < ret.length * timeout or cur_time > (ret.length+1) * timeout + timing = 'response time not ok!' + end + end + it "gets a response in less than or equal to #{(timeout*3).round(2)} seconds" do + Excon.get(endpoint, :response_block => block) + # validate the final timing + expect((Time.now - start <= timeout*3) == true && timing == 'response times not ok!').to be false + end +end diff --git a/lib/vendor/excon/spec/support/shared_examples/shared_example_for_test_servers.rb b/lib/vendor/excon/spec/support/shared_examples/shared_example_for_test_servers.rb new file mode 100644 index 0000000..fe0b569 --- /dev/null +++ b/lib/vendor/excon/spec/support/shared_examples/shared_example_for_test_servers.rb @@ -0,0 +1,16 @@ +shared_examples_for "a excon test server" do |plugin, file| + + include_context("test server", plugin, file) + + it "returns an instance" do + expect(@server).to be_instance_of Excon::Test::Server + end + + it 'starts the server' do + expect(@server.start).to be true + end + + it 'stops the server' do + expect(@server.stop).to be true + end +end |