httparty/spec/httparty/connection_adapter_spec.rb

503 lines
16 KiB
Ruby

require 'spec_helper'
RSpec.describe HTTParty::ConnectionAdapter do
describe "initialization" do
let(:uri) { URI 'http://www.google.com' }
it "takes a URI as input" do
HTTParty::ConnectionAdapter.new(uri)
end
it "raises an ArgumentError if the uri is nil" do
expect { HTTParty::ConnectionAdapter.new(nil) }.to raise_error ArgumentError
end
it "raises an ArgumentError if the uri is a String" do
expect { HTTParty::ConnectionAdapter.new('http://www.google.com') }.to raise_error ArgumentError
end
it "sets the uri" do
adapter = HTTParty::ConnectionAdapter.new(uri)
expect(adapter.uri).to be uri
end
it "also accepts an optional options hash" do
HTTParty::ConnectionAdapter.new(uri, {})
end
it "sets the options" do
options = {foo: :bar}
adapter = HTTParty::ConnectionAdapter.new(uri, options)
expect(adapter.options.keys).to include(:verify, :verify_peer, :foo)
end
end
describe ".call" do
let(:uri) { URI 'http://www.google.com' }
let(:options) { { foo: :bar } }
it "generates an HTTParty::ConnectionAdapter instance with the given uri and options" do
expect(HTTParty::ConnectionAdapter).to receive(:new).with(uri, options).and_return(double(connection: nil))
HTTParty::ConnectionAdapter.call(uri, options)
end
it "calls #connection on the connection adapter" do
adapter = double('Adapter')
connection = double('Connection')
expect(adapter).to receive(:connection).and_return(connection)
allow(HTTParty::ConnectionAdapter).to receive_messages(new: adapter)
expect(HTTParty::ConnectionAdapter.call(uri, options)).to be connection
end
end
describe '#connection' do
let(:uri) { URI 'http://www.google.com' }
let(:options) { Hash.new }
let(:adapter) { HTTParty::ConnectionAdapter.new(uri, options) }
describe "the resulting connection" do
subject { adapter.connection }
it { is_expected.to be_an_instance_of Net::HTTP }
context "using port 80" do
let(:uri) { URI 'http://foobar.com' }
it { is_expected.not_to use_ssl }
end
context "when dealing with ssl" do
let(:uri) { URI 'https://foobar.com' }
context "uses the system cert_store, by default" do
let!(:system_cert_store) do
system_cert_store = double('default_cert_store')
expect(system_cert_store).to receive(:set_default_paths)
expect(OpenSSL::X509::Store).to receive(:new).and_return(system_cert_store)
system_cert_store
end
it { is_expected.to use_cert_store(system_cert_store) }
end
context "should use the specified cert store, when one is given" do
let(:custom_cert_store) { double('custom_cert_store') }
let(:options) { {cert_store: custom_cert_store} }
it { is_expected.to use_cert_store(custom_cert_store) }
end
context "using port 443 for ssl" do
let(:uri) { URI 'https://api.foo.com/v1:443' }
it { is_expected.to use_ssl }
end
context "https scheme with default port" do
it { is_expected.to use_ssl }
end
context "https scheme with non-standard port" do
let(:uri) { URI 'https://foobar.com:123456' }
it { is_expected.to use_ssl }
end
context "when ssl version is set" do
let(:options) { {ssl_version: :TLSv1} }
it "sets ssl version" do
expect(subject.ssl_version).to eq(:TLSv1)
end
end if RUBY_VERSION > '1.9'
end
context "when dealing with IPv6" do
let(:uri) { URI 'http://[fd00::1]' }
it "strips brackets from the address" do
expect(subject.address).to eq('fd00::1')
end
end
context "specifying ciphers" do
let(:options) { {ciphers: 'RC4-SHA' } }
it "should set the ciphers on the connection" do
expect(subject.ciphers).to eq('RC4-SHA')
end
end if RUBY_VERSION > '1.9'
context "when timeout is not set" do
it "doesn't set the timeout" do
http = double(
"http",
:null_object => true,
:use_ssl= => false,
:use_ssl? => false
)
expect(http).not_to receive(:open_timeout=)
expect(http).not_to receive(:read_timeout=)
allow(Net::HTTP).to receive_messages(new: http)
adapter.connection
end
end
context "when setting timeout" do
context "to 5 seconds" do
let(:options) { {timeout: 5} }
describe '#open_timeout' do
subject { super().open_timeout }
it { is_expected.to eq(5) }
end
describe '#read_timeout' do
subject { super().read_timeout }
it { is_expected.to eq(5) }
end
end
context "and timeout is a string" do
let(:options) { {timeout: "five seconds"} }
it "doesn't set the timeout" do
http = double(
"http",
:null_object => true,
:use_ssl= => false,
:use_ssl? => false
)
expect(http).not_to receive(:open_timeout=)
expect(http).not_to receive(:read_timeout=)
allow(Net::HTTP).to receive_messages(new: http)
adapter.connection
end
end
end
context "when timeout is not set and read_timeout is set to 6 seconds" do
let(:options) { {read_timeout: 6} }
describe '#read_timeout' do
subject { super().read_timeout }
it { is_expected.to eq(6) }
end
it "should not set the open_timeout" do
http = double(
"http",
:null_object => true,
:use_ssl= => false,
:use_ssl? => false,
:read_timeout= => 0
)
expect(http).not_to receive(:open_timeout=)
allow(Net::HTTP).to receive_messages(new: http)
adapter.connection
end
end
context "when timeout is set and read_timeout is set to 6 seconds" do
let(:options) { {timeout: 5, read_timeout: 6} }
describe '#open_timeout' do
subject { super().open_timeout }
it { is_expected.to eq(5) }
end
describe '#read_timeout' do
subject { super().read_timeout }
it { is_expected.to eq(6) }
end
it "should override the timeout option" do
http = double(
"http",
:null_object => true,
:use_ssl= => false,
:use_ssl? => false,
:read_timeout= => 0,
:open_timeout= => 0
)
expect(http).to receive(:open_timeout=)
expect(http).to receive(:read_timeout=).twice
allow(Net::HTTP).to receive_messages(new: http)
adapter.connection
end
end
context "when timeout is not set and open_timeout is set to 7 seconds" do
let(:options) { {open_timeout: 7} }
describe '#open_timeout' do
subject { super().open_timeout }
it { is_expected.to eq(7) }
end
it "should not set the read_timeout" do
http = double(
"http",
:null_object => true,
:use_ssl= => false,
:use_ssl? => false,
:open_timeout= => 0
)
expect(http).not_to receive(:read_timeout=)
allow(Net::HTTP).to receive_messages(new: http)
adapter.connection
end
end
context "when timeout is set and open_timeout is set to 7 seconds" do
let(:options) { {timeout: 5, open_timeout: 7} }
describe '#open_timeout' do
subject { super().open_timeout }
it { is_expected.to eq(7) }
end
describe '#read_timeout' do
subject { super().read_timeout }
it { is_expected.to eq(5) }
end
it "should override the timeout option" do
http = double(
"http",
:null_object => true,
:use_ssl= => false,
:use_ssl? => false,
:read_timeout= => 0,
:open_timeout= => 0
)
expect(http).to receive(:open_timeout=).twice
expect(http).to receive(:read_timeout=)
allow(Net::HTTP).to receive_messages(new: http)
adapter.connection
end
end
context "when debug_output" do
let(:http) { Net::HTTP.new(uri) }
before do
allow(Net::HTTP).to receive_messages(new: http)
end
context "is set to $stderr" do
let(:options) { {debug_output: $stderr} }
it "has debug output set" do
expect(http).to receive(:set_debug_output).with($stderr)
adapter.connection
end
end
context "is not provided" do
it "does not set_debug_output" do
expect(http).not_to receive(:set_debug_output)
adapter.connection
end
end
end
context 'when providing proxy address and port' do
let(:options) { {http_proxyaddr: '1.2.3.4', http_proxyport: 8080} }
it { is_expected.to be_a_proxy }
describe '#proxy_address' do
subject { super().proxy_address }
it { is_expected.to eq('1.2.3.4') }
end
describe '#proxy_port' do
subject { super().proxy_port }
it { is_expected.to eq(8080) }
end
context 'as well as proxy user and password' do
let(:options) do
{
http_proxyaddr: '1.2.3.4',
http_proxyport: 8080,
http_proxyuser: 'user',
http_proxypass: 'pass'
}
end
describe '#proxy_user' do
subject { super().proxy_user }
it { is_expected.to eq('user') }
end
describe '#proxy_pass' do
subject { super().proxy_pass }
it { is_expected.to eq('pass') }
end
end
end
context 'when providing nil as proxy address' do
let(:uri) { URI 'http://noproxytest.com' }
let(:options) { {http_proxyaddr: nil} }
it { is_expected.not_to be_a_proxy }
it "does pass nil proxy parameters to the connection, this forces to not use a proxy" do
http = Net::HTTP.new("noproxytest.com")
expect(Net::HTTP).to receive(:new).once.with("noproxytest.com", 80, nil, nil, nil, nil).and_return(http)
adapter.connection
end
end
context 'when not providing a proxy address' do
let(:uri) { URI 'http://proxytest.com' }
it "does not pass any proxy parameters to the connection" do
http = Net::HTTP.new("proxytest.com")
expect(Net::HTTP).to receive(:new).once.with("proxytest.com", 80).and_return(http)
adapter.connection
end
end
context 'when providing a local bind address and port' do
let(:options) { {local_host: "127.0.0.1", local_port: 12345 } }
describe '#local_host' do
subject { super().local_host }
it { is_expected.to eq('127.0.0.1') }
end
describe '#local_port' do
subject { super().local_port }
it { is_expected.to eq(12345) }
end
end if RUBY_VERSION >= '2.0'
context "when providing PEM certificates" do
let(:pem) { :pem_contents }
let(:options) { {pem: pem, pem_password: "password"} }
context "when scheme is https" do
let(:uri) { URI 'https://google.com' }
let(:cert) { double("OpenSSL::X509::Certificate") }
let(:key) { double("OpenSSL::PKey::RSA") }
before do
expect(OpenSSL::X509::Certificate).to receive(:new).with(pem).and_return(cert)
expect(OpenSSL::PKey::RSA).to receive(:new).with(pem, "password").and_return(key)
end
it "uses the provided PEM certificate" do
expect(subject.cert).to eq(cert)
expect(subject.key).to eq(key)
end
it "will verify the certificate" do
expect(subject.verify_mode).to eq(OpenSSL::SSL::VERIFY_PEER)
end
context "when options include verify=false" do
let(:options) { {pem: pem, pem_password: "password", verify: false} }
it "should not verify the certificate" do
expect(subject.verify_mode).to eq(OpenSSL::SSL::VERIFY_NONE)
end
end
context "when options include verify_peer=false" do
let(:options) { {pem: pem, pem_password: "password", verify_peer: false} }
it "should not verify the certificate" do
expect(subject.verify_mode).to eq(OpenSSL::SSL::VERIFY_NONE)
end
end
end
context "when scheme is not https" do
let(:uri) { URI 'http://google.com' }
let(:http) { Net::HTTP.new(uri) }
before do
allow(Net::HTTP).to receive_messages(new: http)
expect(OpenSSL::X509::Certificate).not_to receive(:new).with(pem)
expect(OpenSSL::PKey::RSA).not_to receive(:new).with(pem, "password")
expect(http).not_to receive(:cert=)
expect(http).not_to receive(:key=)
end
it "has no PEM certificate " do
expect(subject.cert).to be_nil
expect(subject.key).to be_nil
end
end
end
context "when providing PKCS12 certificates" do
let(:p12) { :p12_contents }
let(:options) { {p12: p12, p12_password: "password"} }
context "when scheme is https" do
let(:uri) { URI 'https://google.com' }
let(:pkcs12) { double("OpenSSL::PKCS12", certificate: cert, key: key) }
let(:cert) { double("OpenSSL::X509::Certificate") }
let(:key) { double("OpenSSL::PKey::RSA") }
before do
expect(OpenSSL::PKCS12).to receive(:new).with(p12, "password").and_return(pkcs12)
end
it "uses the provided P12 certificate " do
expect(subject.cert).to eq(cert)
expect(subject.key).to eq(key)
end
it "will verify the certificate" do
expect(subject.verify_mode).to eq(OpenSSL::SSL::VERIFY_PEER)
end
context "when options include verify=false" do
let(:options) { {p12: p12, p12_password: "password", verify: false} }
it "should not verify the certificate" do
expect(subject.verify_mode).to eq(OpenSSL::SSL::VERIFY_NONE)
end
end
context "when options include verify_peer=false" do
let(:options) { {p12: p12, p12_password: "password", verify_peer: false} }
it "should not verify the certificate" do
expect(subject.verify_mode).to eq(OpenSSL::SSL::VERIFY_NONE)
end
end
end
context "when scheme is not https" do
let(:uri) { URI 'http://google.com' }
let(:http) { Net::HTTP.new(uri) }
before do
allow(Net::HTTP).to receive_messages(new: http)
expect(OpenSSL::PKCS12).not_to receive(:new).with(p12, "password")
expect(http).not_to receive(:cert=)
expect(http).not_to receive(:key=)
end
it "has no PKCS12 certificate " do
expect(subject.cert).to be_nil
expect(subject.key).to be_nil
end
end
end
context "when uri port is not defined" do
context "falls back to 80 port on http" do
let(:uri) { URI 'http://foobar.com' }
before { allow(uri).to receive(:port).and_return(nil) }
it { expect(subject.port).to be 80 }
end
context "falls back to 443 port on https" do
let(:uri) { URI 'https://foobar.com' }
before { allow(uri).to receive(:port).and_return(nil) }
it { expect(subject.port).to be 443 }
end
end
end
end
end