require "spec_helper" require "integration/support/server" # find out why httpi doesn't load these automatically. [dh, 2012-12-15] require "excon" require "net/http/persistent" require "http" unless RUBY_VERSION < "1.9" require "em-synchrony" require "em-http-request" end unless RUBY_PLATFORM =~ /java/ require "curb" end describe HTTPI do let(:client) { HTTPI } let(:httpclient) { HTTPI::Adapter.load(:httpclient) } let(:net_http) { HTTPI::Adapter.load(:net_http) } let(:net_http_persistent) { HTTPI::Adapter.load(:net_http_persistent) } before(:all) do HTTPI::Adapter::Rack.mount('example.com', IntegrationServer::Application) end after(:all) do HTTPI::Adapter::Rack.unmount('example.com') end describe ".adapter=" do it "sets the default adapter to use" do HTTPI::Adapter.expects(:use=).with(:net_http) HTTPI.adapter = :net_http end end describe ".query_builder" do it "gets flat builder by default" do expect(client.query_builder).to eq(HTTPI::QueryBuilder::Flat) end context "setter" do after { client.query_builder = HTTPI::QueryBuilder::Flat } it "looks up for class if symbol" do client.query_builder = :nested expect(client.query_builder).to eq(HTTPI::QueryBuilder::Nested) end it "validates if symbol is a valid option" do expect do client.query_builder = :xxx end.to raise_error(ArgumentError) end it "validates if value respond to build" do expect do client.query_builder = nil end.to raise_error(ArgumentError) end it "accepts valid class" do client.query_builder = HTTPI::QueryBuilder::Nested expect(client.query_builder).to eq(HTTPI::QueryBuilder::Nested) end end end describe ".get(request)" do it "executes a GET request using the default adapter" do request = HTTPI::Request.new("http://example.com") httpclient.any_instance.expects(:request).with(:get) client.get(request) end end describe ".get(request, adapter)" do it "executes a GET request using the given adapter" do request = HTTPI::Request.new("http://example.com") net_http.any_instance.expects(:request).with(:get) client.get(request, :net_http) end end describe ".get(url)" do it "executes a GET request using the default adapter" do httpclient.any_instance.expects(:request).with(:get) client.get("http://example.com") end end describe ".get(url, adapter)" do it "executes a GET request using the given adapter" do net_http.any_instance.expects(:request).with(:get) client.get("http://example.com", :net_http) end end describe ".post(request)" do it "executes a POST request using the default adapter" do request = HTTPI::Request.new("http://example.com") httpclient.any_instance.expects(:request).with(:post) client.post(request) end end describe ".post(request, adapter)" do it "executes a POST request using the given adapter" do request = HTTPI::Request.new("http://example.com") net_http.any_instance.expects(:request).with(:post, anything) client.post(request, :net_http) end end describe ".post(url, body)" do it "executes a POST request using the default adapter" do httpclient.any_instance.expects(:request).with(:post) client.post("http://example.com", "xml") end end describe ".post(url, body, adapter)" do it "executes a POST request using the given adapter" do net_http.any_instance.expects(:request).with(:post) client.post("http://example.com", "xml", :net_http) end end describe ".head(request)" do it "executes a HEAD request using the default adapter" do request = HTTPI::Request.new("http://example.com") httpclient.any_instance.expects(:request).with(:head, anything) client.head(request) end end describe ".head(request, adapter)" do it "executes a HEAD request using the given adapter" do request = HTTPI::Request.new("http://example.com") net_http.any_instance.expects(:request).with(:head, anything) client.head(request, :net_http) end end describe ".head(url)" do it "executes a HEAD request using the default adapter" do httpclient.any_instance.expects(:request).with(:head) client.head("http://example.com") end end describe ".head(url, adapter)" do it "executes a HEAD request using the given adapter" do net_http.any_instance.expects(:request).with(:head) client.head("http://example.com", :net_http) end end describe ".put(request)" do it "executes a PUT request using the default adapter" do request = HTTPI::Request.new("http://example.com") httpclient.any_instance.expects(:request).with(:put, anything) client.put(request) end end describe ".put(request, adapter)" do it "executes a PUT request using the given adapter" do request = HTTPI::Request.new("http://example.com") net_http.any_instance.expects(:request).with(:put, anything) client.put(request, :net_http) end end describe ".put(url, body)" do it "executes a PUT request using the default adapter" do httpclient.any_instance.expects(:request).with(:put) client.put("http://example.com", "xml") end end describe ".put(url, body, adapter)" do it "executes a PUT request using the given adapter" do net_http.any_instance.expects(:request).with(:put) client.put("http://example.com", "xml", :net_http) end end describe ".delete(request)" do it "executes a DELETE request using the default adapter" do request = HTTPI::Request.new("http://example.com") httpclient.any_instance.expects(:request).with(:delete, anything) client.delete(request) end end describe ".delete(request, adapter)" do it "executes a DELETE request using the given adapter" do request = HTTPI::Request.new("http://example.com") net_http.any_instance.expects(:request).with(:delete, anything) client.delete(request, :net_http) end end describe ".delete(url)" do it "executes a DELETE request using the default adapter" do httpclient.any_instance.expects(:request).with(:delete) client.delete("http://example.com") end end describe ".delete(url, adapter)" do it "executes a DELETE request using the given adapter" do net_http.any_instance.expects(:request).with(:delete) client.delete("http://example.com", :net_http) end end describe ".request" do let(:request) { HTTPI::Request.new('http://example.com/foo/') } it "allows custom HTTP methods" do httpclient.any_instance.expects(:request).with(:custom) client.request(:custom, request, :httpclient) end it 'follows redirects' do request.follow_redirect = true redirect_location = 'http://foo.bar' redirect = HTTPI::Response.new(302, {'location' => redirect_location}, 'Moved') response = HTTPI::Response.new(200, {}, 'success') httpclient.any_instance.expects(:request).twice.with(:custom).returns(redirect, response) request.expects(:url=).with(URI.parse(redirect_location)) client.request(:custom, request, :httpclient) end it 'follows redirects with absolute path' do request.follow_redirect = true redirect_location = '/bar/foo' redirect = HTTPI::Response.new(302, {'location' => redirect_location}, 'Moved') response = HTTPI::Response.new(200, {}, 'success') httpclient.any_instance.expects(:request).twice.with(:custom).returns(redirect, response) request.expects(:url=).with(URI.parse('http://example.com/bar/foo')) client.request(:custom, request, :httpclient) end it 'follows redirects with relative path' do request.follow_redirect = true redirect_location = 'bar/foo' redirect = HTTPI::Response.new(302, {'location' => redirect_location}, 'Moved') response = HTTPI::Response.new(200, {}, 'success') httpclient.any_instance.expects(:request).twice.with(:custom).returns(redirect, response) request.expects(:url=).with(URI.parse('http://example.com/foo/bar/foo')) client.request(:custom, request, :httpclient) end it 'follows redirects at maximum of the redirect limit' do request.follow_redirect = true request.redirect_limit = 2 redirect_location = 'http://foo.bar' redirect = HTTPI::Response.new(302, {'location' => redirect_location}, 'Moved') response = HTTPI::Response.new(200, {}, 'success') httpclient.any_instance.expects(:request).times(2).with(:custom).returns(redirect, response) request.expects(:url=).with(URI.parse(redirect_location)) client.request(:custom, request, :httpclient) end end HTTPI::REQUEST_METHODS.each do |method| describe ".#{method}" do let(:request) { HTTPI::Request.new("http://example.com") } it "raises an ArgumentError in case of an invalid adapter" do expect { client.request method, request, :invalid }.to raise_error(ArgumentError) end HTTPI::Adapter::ADAPTERS.each do |adapter, opts| unless (adapter == :em_http && RUBY_VERSION =~ /1\.8/) || (adapter == :curb && RUBY_PLATFORM =~ /java/) client_class = { :httpclient => lambda { HTTPClient }, :curb => lambda { Curl::Easy }, :net_http => lambda { Net::HTTP }, :net_http_persistent => lambda { Net::HTTP::Persistent }, :em_http => lambda { EventMachine::HttpConnection }, :rack => lambda { Rack::MockRequest }, :excon => lambda { Excon::Connection }, :http => lambda { ::HTTP::Client } } context "using #{adapter}" do before { opts[:class].any_instance.expects(:request).with(method) } it "#request yields the HTTP client instance" do expect { |b| client.request(method, request, adapter, &b) }.to yield_with_args(client_class[adapter].call) end it "##{method} yields the HTTP client instance" do expect { |b| client.send(method, request, adapter, &b) }.to yield_with_args(client_class[adapter].call) end end end end end end context "(with reset)" do before { HTTPI.reset_config! } after do HTTPI.reset_config! HTTPI.log = false # disable for specs end describe ".log" do it "defaults to true" do expect(HTTPI.log?).to be_truthy end end describe ".logger" do it "defaults to Logger writing to STDOUT" do expect(HTTPI.logger).to be_a(Logger) end end describe ".log_level" do it "defaults to :debug" do expect(HTTPI.log_level).to eq(:debug) end end describe ".log" do it "logs the given messages" do HTTPI.log_level = :info HTTPI.logger.expects(:info).with("Log this") HTTPI.log "Log this" end end end end