giant_client 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +22 -0
- data/README.md +264 -0
- data/lib/giant_client.rb +105 -0
- data/lib/giant_client/abstract_adapter.rb +71 -0
- data/lib/giant_client/curb_adapter.rb +56 -0
- data/lib/giant_client/error.rb +8 -0
- data/lib/giant_client/excon_adapter.rb +42 -0
- data/lib/giant_client/mock_adapter.rb +57 -0
- data/lib/giant_client/mock_request.rb +11 -0
- data/lib/giant_client/net_http_adapter.rb +55 -0
- data/lib/giant_client/patron_adapter.rb +38 -0
- data/lib/giant_client/response.rb +12 -0
- data/lib/giant_client/typhoeus_adapter.rb +40 -0
- data/lib/giant_client/version.rb +3 -0
- data/spec/examples/giant_client_spec.rb +299 -0
- data/spec/examples/mock_adapter_spec.rb +276 -0
- data/spec/examples/spec_helper.rb +7 -0
- metadata +178 -0
| @@ -0,0 +1,56 @@ | |
| 1 | 
            +
            require 'giant_client/abstract_adapter'
         | 
| 2 | 
            +
            require 'curb'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            class GiantClient
         | 
| 5 | 
            +
              class CurbAdapter < AbstractAdapter
         | 
| 6 | 
            +
                CRLF = /\r\n/
         | 
| 7 | 
            +
                HEADER_SPLIT = /:\s*/
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                def request(method, opts)
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  if BODYLESS_METHODS.include?(method)
         | 
| 12 | 
            +
                    raise GiantClient::Error::NotImplemented unless opts[:body] == ''
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  url = url_from_opts(opts)
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  if method == :post
         | 
| 18 | 
            +
                    post_body = opts[:body]
         | 
| 19 | 
            +
                  elsif method == :put
         | 
| 20 | 
            +
                    put_data = opts[:body]
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  begin
         | 
| 24 | 
            +
                    response = Curl.http( method.upcase, url, post_body, put_data ) do |curl|
         | 
| 25 | 
            +
                      curl.headers = opts[:headers]
         | 
| 26 | 
            +
                      curl.timeout = opts[:timeout]
         | 
| 27 | 
            +
                      curl.connect_timeout = opts[:timeout]
         | 
| 28 | 
            +
                    end
         | 
| 29 | 
            +
                  rescue Curl::Err::TimeoutError
         | 
| 30 | 
            +
                    raise GiantClient::Error::Timeout, "the request timed out (timeout: #{opts[:timeout]}"
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  normalize_response(response)
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                def normalize_response(response)
         | 
| 37 | 
            +
                  status_code = response.response_code
         | 
| 38 | 
            +
                  headers = parse_out_headers(response.header_str)
         | 
| 39 | 
            +
                  body = response.body_str
         | 
| 40 | 
            +
                  Response.new(status_code, headers, body)
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                def parse_out_headers(header_string)
         | 
| 44 | 
            +
                  headers = {}
         | 
| 45 | 
            +
                  pairs = header_string.split(CRLF)
         | 
| 46 | 
            +
                  pairs.shift
         | 
| 47 | 
            +
                  pairs.each do |pair|
         | 
| 48 | 
            +
                    header, value = *pair.split(HEADER_SPLIT, 2)
         | 
| 49 | 
            +
                    header = normalize_header(header)
         | 
| 50 | 
            +
                    headers[header] = value
         | 
| 51 | 
            +
                  end
         | 
| 52 | 
            +
                  headers
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
              end
         | 
| 56 | 
            +
            end
         | 
| @@ -0,0 +1,42 @@ | |
| 1 | 
            +
            require 'giant_client/abstract_adapter'
         | 
| 2 | 
            +
            require 'excon'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            class GiantClient
         | 
| 5 | 
            +
              class ExconAdapter < AbstractAdapter
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def request(method, opts)
         | 
| 8 | 
            +
                  if BODYLESS_METHODS.include?(method)
         | 
| 9 | 
            +
                    raise GiantClient::Error::NotImplemented unless opts[:body] == ''
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  url = url_from_opts(opts)
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  params = {}
         | 
| 15 | 
            +
                  params[:method]  = method.to_s
         | 
| 16 | 
            +
                  params[:headers] = opts[:headers]
         | 
| 17 | 
            +
                  params[:body]  = opts[:body]
         | 
| 18 | 
            +
                  params[:read_timeout]  = opts[:timeout]
         | 
| 19 | 
            +
                  params[:connect_timeout]  = opts[:timeout]
         | 
| 20 | 
            +
                  params[:write_timeout]  = opts[:timeout]
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  begin
         | 
| 23 | 
            +
                    response = Excon.new(url).request(params)
         | 
| 24 | 
            +
                  rescue Excon::Errors::Timeout
         | 
| 25 | 
            +
                    raise GiantClient::Error::Timeout, "the request timed out (timeout: #{opts[:timeout]}"
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  normalize_response(response)
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                def normalize_response(response)
         | 
| 32 | 
            +
                  status_code = response.status
         | 
| 33 | 
            +
                  headers = normalize_header_hash(response.headers)
         | 
| 34 | 
            +
                  body = response.body
         | 
| 35 | 
            +
                  Response.new(status_code, headers, body)
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
            end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
             | 
| 41 | 
            +
             | 
| 42 | 
            +
             | 
| @@ -0,0 +1,57 @@ | |
| 1 | 
            +
            require 'giant_client/abstract_adapter'
         | 
| 2 | 
            +
            require 'giant_client/mock_request'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            class GiantClient
         | 
| 5 | 
            +
              class MockAdapter < AbstractAdapter
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                attr_accessor :requests, :responses
         | 
| 8 | 
            +
                def initialize
         | 
| 9 | 
            +
                  @requests = []
         | 
| 10 | 
            +
                  @responses = []
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def request(method, opts)
         | 
| 14 | 
            +
                  last_request = MockRequest.new
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  if BODYLESS_METHODS.include?(method)
         | 
| 17 | 
            +
                    unless opts[:body] == ''
         | 
| 18 | 
            +
                      last_request.raised_error = true
         | 
| 19 | 
            +
                      last_request.error_type = GiantClient::Error::NotImplemented
         | 
| 20 | 
            +
                    end
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  last_request.host = opts[:host]
         | 
| 24 | 
            +
                  last_request.ssl = opts[:ssl]
         | 
| 25 | 
            +
                  last_request.port = opts[:port]
         | 
| 26 | 
            +
                  last_request.path = opts[:path]
         | 
| 27 | 
            +
                  last_request.query = opts[:query]
         | 
| 28 | 
            +
                  last_request.headers = opts[:headers]
         | 
| 29 | 
            +
                  last_request.body = opts[:body]
         | 
| 30 | 
            +
                  last_request.timeout = opts[:timeout]
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  last_request.url = url_from_opts(opts)
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  last_request.querystring = stringify_query(opts[:query])
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  last_response = { :status_code => 200, :headers => {}, :body => nil }
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  @requests.unshift(last_request)
         | 
| 39 | 
            +
                  @responses.unshift(last_response)
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  self
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                def respond_with(hash)
         | 
| 45 | 
            +
                  @responses[0] = @responses[0].merge(hash)
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                def last_request
         | 
| 49 | 
            +
                  @requests[0]
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                def last_response
         | 
| 53 | 
            +
                  @responses[0]
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
              end
         | 
| 57 | 
            +
            end
         | 
| @@ -0,0 +1,55 @@ | |
| 1 | 
            +
            require 'giant_client/abstract_adapter'
         | 
| 2 | 
            +
            require 'net/http'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            class GiantClient
         | 
| 5 | 
            +
              class NetHttpAdapter < AbstractAdapter
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def request(method, opts)
         | 
| 8 | 
            +
                  if BODYLESS_METHODS.include?(method)
         | 
| 9 | 
            +
                    raise GiantClient::Error::NotImplemented unless opts[:body] == ''
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
                  query = encode_query(opts[:query])
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  http = Net::HTTP.new( opts[:host], opts[:port] )
         | 
| 14 | 
            +
                  http.use_ssl = opts[:ssl]
         | 
| 15 | 
            +
                  http.read_timeout = opts[:timeout]
         | 
| 16 | 
            +
                  http.open_timeout = opts[:timeout]
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  request_class =
         | 
| 19 | 
            +
                    case method
         | 
| 20 | 
            +
                      when :get then Net::HTTP::Get
         | 
| 21 | 
            +
                      when :post then Net::HTTP::Post
         | 
| 22 | 
            +
                      when :put then Net::HTTP::Put
         | 
| 23 | 
            +
                      when :delete then Net::HTTP::Delete
         | 
| 24 | 
            +
                      when :head then Net::HTTP::Head
         | 
| 25 | 
            +
                    end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  request = request_class.new( opts[:path] + query, opts[:headers] )
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  if request.request_body_permitted?
         | 
| 30 | 
            +
                    request.body = opts[:body]
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  begin
         | 
| 34 | 
            +
                    response = http.start {|http| http.request(request)}
         | 
| 35 | 
            +
                  rescue Timeout::Error
         | 
| 36 | 
            +
                    raise GiantClient::Error::Timeout, "the request timed out (timeout: #{opts[:timeout]}"
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  # make response object
         | 
| 40 | 
            +
                  normalize_response(response)
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                def normalize_response(response)
         | 
| 44 | 
            +
                  status_code = response.code.to_i
         | 
| 45 | 
            +
                  headers = {}
         | 
| 46 | 
            +
                  response.each_header do |header, value|
         | 
| 47 | 
            +
                    header = normalize_header(header)
         | 
| 48 | 
            +
                    headers[header] = value
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
                  body = response.body
         | 
| 51 | 
            +
                  Response.new(status_code, headers, body)
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
              end
         | 
| 55 | 
            +
            end
         | 
| @@ -0,0 +1,38 @@ | |
| 1 | 
            +
            require 'giant_client/abstract_adapter'
         | 
| 2 | 
            +
            require 'patron'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            class GiantClient
         | 
| 5 | 
            +
              class PatronAdapter < AbstractAdapter
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def request(method, opts)
         | 
| 8 | 
            +
                  if BODYLESS_METHODS.include?(method)
         | 
| 9 | 
            +
                    raise GiantClient::Error::NotImplemented unless opts[:body] == ''
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  url = url_from_opts(opts)
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  http = Patron::Session.new
         | 
| 15 | 
            +
                  http.timeout = opts[:timeout]
         | 
| 16 | 
            +
                  http.connect_timeout = opts[:timeout]
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  # TODO support all extra options
         | 
| 19 | 
            +
                  extra_opts = {}
         | 
| 20 | 
            +
                  extra_opts[:data] = opts[:body]
         | 
| 21 | 
            +
                  begin
         | 
| 22 | 
            +
                    response = http.request(method, url, opts[:headers], extra_opts)
         | 
| 23 | 
            +
                  rescue Patron::TimeoutError
         | 
| 24 | 
            +
                    raise GiantClient::Error::Timeout, "the request timed out (timeout: #{opts[:timeout]}"
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  normalize_response(response)
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                def normalize_response(response)
         | 
| 31 | 
            +
                   status_code = response.status
         | 
| 32 | 
            +
                   headers = normalize_header_hash(response.headers)
         | 
| 33 | 
            +
                   body = response.body
         | 
| 34 | 
            +
                   Response.new(status_code, headers, body)
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
            end
         | 
| @@ -0,0 +1,40 @@ | |
| 1 | 
            +
            require 'giant_client/abstract_adapter'
         | 
| 2 | 
            +
            require 'typhoeus'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            class GiantClient
         | 
| 5 | 
            +
              class TyphoeusAdapter < AbstractAdapter
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def request(method, opts)
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  if BODYLESS_METHODS.include?(method)
         | 
| 10 | 
            +
                    raise GiantClient::Error::NotImplemented unless opts[:body] == ''
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  url = url_from_opts(opts)
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  params = {}
         | 
| 16 | 
            +
                  params[:method] = method
         | 
| 17 | 
            +
                  params[:headers] = opts[:headers]
         | 
| 18 | 
            +
                  params[:body] = opts[:body]
         | 
| 19 | 
            +
                  params[:timeout] = 1000 * opts[:timeout] # typhoeus does milliseconds
         | 
| 20 | 
            +
                  params[:connect_timeout] = 1000 * opts[:timeout]
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  response = Typhoeus::Request.run(url, params)
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  if response.curl_return_code == 28 # timeout
         | 
| 25 | 
            +
                    raise GiantClient::Error::Timeout, "the request timed out (timeout: #{opts[:timeout]}"
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  normalize_response(response)
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                def normalize_response(response)
         | 
| 33 | 
            +
                  status_code = response.code
         | 
| 34 | 
            +
                  headers = normalize_header_hash(response.headers_hash)
         | 
| 35 | 
            +
                  body = response.body
         | 
| 36 | 
            +
                  Response.new(status_code, headers, body)
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
            end
         | 
| @@ -0,0 +1,299 @@ | |
| 1 | 
            +
            require File.expand_path( '../spec_helper', __FILE__ )
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe 'GiantClient' do
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              shared_examples "an adapter" do
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                context 'GET requests' do
         | 
| 8 | 
            +
                  let(:client) { GiantClient.new( :host => 'example.com', :adapter => adapter ) }
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  it 'should perform a simple GET request' do
         | 
| 11 | 
            +
                    stub = stub_request(:get, 'example.com')
         | 
| 12 | 
            +
                    client.get( :path => '/' )
         | 
| 13 | 
            +
                    stub.should have_been_requested
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  it 'should treat a string argument as a path' do
         | 
| 17 | 
            +
                    stub = stub_request(:get, 'example.com')
         | 
| 18 | 
            +
                    client.get( '/' )
         | 
| 19 | 
            +
                    stub.should have_been_requested
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  it 'should respond with 200' do
         | 
| 23 | 
            +
                    stub = stub_request(:get, 'example.com')
         | 
| 24 | 
            +
                                  .to_return(:status => [200, 'OK'])
         | 
| 25 | 
            +
                    client.get( :path => '/' ).status_code.should == 200
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  it 'should respond with a success header' do
         | 
| 29 | 
            +
                    stub = stub_request(:get, 'example.com')
         | 
| 30 | 
            +
                                   .to_return(:headers => {'Success' => 'true'})
         | 
| 31 | 
            +
                    client.get( :path => '/' ).headers.should == {'Success' => 'true'}
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  it 'should respond with a multiple headers' do
         | 
| 35 | 
            +
                    stub = stub_request(:get, 'example.com')
         | 
| 36 | 
            +
                                   .to_return(:headers =>
         | 
| 37 | 
            +
                                              {'Success' => 'true', 'doodle' => 'kaboodle'})
         | 
| 38 | 
            +
                    client.get( :path => '/' ).headers.should ==
         | 
| 39 | 
            +
                                                  {'Success' => 'true', 'Doodle' => 'kaboodle'}
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                  it 'should respond with a header and status, and should capitalize status' do
         | 
| 43 | 
            +
                    stub = stub_request(:get, 'example.com')
         | 
| 44 | 
            +
                                   .to_return(:status => 1700, :headers => {'success' => 'true'})
         | 
| 45 | 
            +
                    client.get( :path => '/' ).headers.should == {'Success' => 'true'}
         | 
| 46 | 
            +
                    client.get( :path => '/' ).status_code.should == 1700
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  it 'should respond with a body' do
         | 
| 50 | 
            +
                    stub = stub_request(:get, 'example.com')
         | 
| 51 | 
            +
                                   .to_return(:body => 'Chucky Cheese')
         | 
| 52 | 
            +
                    client.get( :path => '/' ).body.should == 'Chucky Cheese'
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                  it 'should pass on the port' do
         | 
| 56 | 
            +
                    stub = stub_request(:get, 'example.com:8080')
         | 
| 57 | 
            +
                    client.get( :path => '/', :port => '8080' )
         | 
| 58 | 
            +
                    stub.should have_been_requested
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                  it 'should pass on the request headers' do
         | 
| 62 | 
            +
                    stub = stub_request(:get, 'example.com').with( :headers => { 'Content-Type' => 'text/special' } )
         | 
| 63 | 
            +
                    client.get( :path => '/', :headers => { 'Content-Type' => 'text/special' } )
         | 
| 64 | 
            +
                    stub.should have_been_requested
         | 
| 65 | 
            +
                  end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                  it 'should pass on the request params' do
         | 
| 68 | 
            +
                    stub = stub_request(:get, 'example.com').with( :query => { 'a' => 'b' } )
         | 
| 69 | 
            +
                    client.get( :path => '/', :query => { 'a' => 'b' } )
         | 
| 70 | 
            +
                    stub.should have_been_requested
         | 
| 71 | 
            +
                  end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                  it 'should allow a query in the url path' do
         | 
| 74 | 
            +
                    stub = stub_request(:get, 'example.com').with( :query => { 'z' => 'me' } )
         | 
| 75 | 
            +
                    client.get( :path => '/?z=me' )
         | 
| 76 | 
            +
                    stub.should have_been_requested
         | 
| 77 | 
            +
                  end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                  it 'should raise an error if there is a request body' do
         | 
| 80 | 
            +
                    stub = stub_request(:get, 'example.com').with( :body => 'hey yo' )
         | 
| 81 | 
            +
                    expect{ client.get( :path => '/', :body => 'hey yo' ) }.to raise_error( GiantClient::Error::NotImplemented )
         | 
| 82 | 
            +
                  end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                  context 'timing out' do
         | 
| 85 | 
            +
                    let(:client) { GiantClient.new( :host => 'example.com', :adapter => adapter, :timeout => 1 ) }
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                    it 'should raise a timeout error if there is a timeout' do
         | 
| 88 | 
            +
                      stub = stub_request(:get, 'example.com').to_timeout
         | 
| 89 | 
            +
                      expect{ client.get( :path => '/' ) }.to raise_error( GiantClient::Error::Timeout )
         | 
| 90 | 
            +
                    end
         | 
| 91 | 
            +
                  end
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                  context 'ssl' do
         | 
| 94 | 
            +
                    let(:client) { GiantClient.new( :host => 'example.com', :ssl => true, :adapter => adapter ) }
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                    it 'should perform a simple get request' do
         | 
| 97 | 
            +
                      stub = stub_request(:get, 'https://example.com')
         | 
| 98 | 
            +
                      client.get( :path => '/' )
         | 
| 99 | 
            +
                      stub.should have_been_requested
         | 
| 100 | 
            +
                    end
         | 
| 101 | 
            +
                  end
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                  context 'custom port' do
         | 
| 104 | 
            +
                    let(:client) { GiantClient.new( :host => 'example.com', :ssl => true, :port => 8080, :adapter => adapter ) }
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                    it 'should perform a simple GET request' do
         | 
| 107 | 
            +
                      stub = stub_request(:get, 'https://example.com:8080')
         | 
| 108 | 
            +
                      client.get( :path => '/' )
         | 
| 109 | 
            +
                      stub.should have_been_requested
         | 
| 110 | 
            +
                    end
         | 
| 111 | 
            +
                  end
         | 
| 112 | 
            +
                end
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                context 'POST requests' do
         | 
| 115 | 
            +
                  let(:client) { GiantClient.new( :host => 'example.com', :adapter => adapter ) }
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                  it 'should perform a simple POST request' do
         | 
| 118 | 
            +
                    stub = stub_request(:post, 'example.com')
         | 
| 119 | 
            +
                    client.post( :path => '/' )
         | 
| 120 | 
            +
                    stub.should have_been_requested
         | 
| 121 | 
            +
                  end
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                  it 'should post the body as well' do
         | 
| 124 | 
            +
                    stub = stub_request(:post, 'example.com').with( :body => 'woohoo' )
         | 
| 125 | 
            +
                    client.post( :path => '/', :body => 'woohoo' )
         | 
| 126 | 
            +
                    stub.should have_been_requested
         | 
| 127 | 
            +
                  end
         | 
| 128 | 
            +
                end
         | 
| 129 | 
            +
             | 
| 130 | 
            +
                context 'PUT requests' do
         | 
| 131 | 
            +
                  let(:client) { GiantClient.new( :host => 'example.com', :adapter => adapter ) }
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                  it 'should perform a simple PUT request' do
         | 
| 134 | 
            +
                    stub = stub_request(:put, 'example.com')
         | 
| 135 | 
            +
                    client.put( :path => '/' )
         | 
| 136 | 
            +
                    stub.should have_been_requested
         | 
| 137 | 
            +
                  end
         | 
| 138 | 
            +
             | 
| 139 | 
            +
                  it 'should perform a PUT request to a specific path' do
         | 
| 140 | 
            +
                    stub = stub_request(:put, 'example.com/heyyy')
         | 
| 141 | 
            +
                    client.put( :path => '/heyyy' )
         | 
| 142 | 
            +
                    stub.should have_been_requested
         | 
| 143 | 
            +
                  end
         | 
| 144 | 
            +
             | 
| 145 | 
            +
                  it 'should put the body as well' do
         | 
| 146 | 
            +
                    stub = stub_request(:put, 'example.com').with( :body => 'woohoo' )
         | 
| 147 | 
            +
                    client.put( :path => '/', :body => 'woohoo' )
         | 
| 148 | 
            +
                    stub.should have_been_requested
         | 
| 149 | 
            +
                  end
         | 
| 150 | 
            +
                end
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                context 'DELETE requests' do
         | 
| 153 | 
            +
                  let(:client) { GiantClient.new( :host => 'example.com', :adapter => adapter ) }
         | 
| 154 | 
            +
             | 
| 155 | 
            +
                  it 'should perform a simple DELETE request' do
         | 
| 156 | 
            +
                    stub = stub_request(:delete, 'example.com')
         | 
| 157 | 
            +
                    client.delete( :path => '/' )
         | 
| 158 | 
            +
                    stub.should have_been_requested
         | 
| 159 | 
            +
                  end
         | 
| 160 | 
            +
             | 
| 161 | 
            +
                  it 'should perform a DELETE request to a specific path' do
         | 
| 162 | 
            +
                    stub = stub_request(:delete, 'example.com/heyyy/how/ya/doin')
         | 
| 163 | 
            +
                    client.delete( :path => '/heyyy/how/ya/doin' )
         | 
| 164 | 
            +
                    stub.should have_been_requested
         | 
| 165 | 
            +
                  end
         | 
| 166 | 
            +
             | 
| 167 | 
            +
                  it 'should raise an error if there is a request body' do
         | 
| 168 | 
            +
                    stub = stub_request(:delete, 'example.com').with( :body => 'woohoo' )
         | 
| 169 | 
            +
                    expect{ client.delete( :path => '/', :body => 'woohoo' ) }.to raise_error( GiantClient::Error::NotImplemented )
         | 
| 170 | 
            +
                  end
         | 
| 171 | 
            +
                end
         | 
| 172 | 
            +
             | 
| 173 | 
            +
                context 'HEAD requests' do
         | 
| 174 | 
            +
                  let(:client) { GiantClient.new( :host => 'example.com', :adapter => adapter ) }
         | 
| 175 | 
            +
             | 
| 176 | 
            +
                  it 'should perform a simple HEAD request' do
         | 
| 177 | 
            +
                    stub = stub_request(:head, 'example.com')
         | 
| 178 | 
            +
                    client.head( :path => '/' )
         | 
| 179 | 
            +
                    stub.should have_been_requested
         | 
| 180 | 
            +
                  end
         | 
| 181 | 
            +
             | 
| 182 | 
            +
                  it 'should perform a HEAD request to a specific path' do
         | 
| 183 | 
            +
                    stub = stub_request(:head, 'example.com/heyyy/how/ya/doin')
         | 
| 184 | 
            +
                    client.head( :path => '/heyyy/how/ya/doin' )
         | 
| 185 | 
            +
                    stub.should have_been_requested
         | 
| 186 | 
            +
                  end
         | 
| 187 | 
            +
             | 
| 188 | 
            +
                  it 'should raise an error if there is a request body' do
         | 
| 189 | 
            +
                    stub = stub_request(:head, 'example.com').with( :body => 'woohoo' )
         | 
| 190 | 
            +
                    expect{ client.head( :path => '/', :body => 'woohoo' ) }.to raise_error( GiantClient::Error::NotImplemented )
         | 
| 191 | 
            +
                  end
         | 
| 192 | 
            +
                end
         | 
| 193 | 
            +
              end
         | 
| 194 | 
            +
             | 
| 195 | 
            +
              describe 'NetHttpAdapter' do
         | 
| 196 | 
            +
                it_behaves_like 'an adapter' do
         | 
| 197 | 
            +
                  let(:adapter){ :net_http }
         | 
| 198 | 
            +
                end
         | 
| 199 | 
            +
              end
         | 
| 200 | 
            +
             | 
| 201 | 
            +
              describe 'PatronAdapter' do
         | 
| 202 | 
            +
                it_behaves_like 'an adapter' do
         | 
| 203 | 
            +
                  let(:adapter){ :patron }
         | 
| 204 | 
            +
                end
         | 
| 205 | 
            +
              end
         | 
| 206 | 
            +
             | 
| 207 | 
            +
              describe 'Curb' do
         | 
| 208 | 
            +
                it_behaves_like 'an adapter' do
         | 
| 209 | 
            +
                  let(:adapter){ :curb }
         | 
| 210 | 
            +
                end
         | 
| 211 | 
            +
              end
         | 
| 212 | 
            +
             | 
| 213 | 
            +
              describe 'Excon' do
         | 
| 214 | 
            +
                it_behaves_like 'an adapter' do
         | 
| 215 | 
            +
                  let(:adapter){ :excon }
         | 
| 216 | 
            +
                end
         | 
| 217 | 
            +
              end
         | 
| 218 | 
            +
             | 
| 219 | 
            +
              describe 'Typhoeus' do
         | 
| 220 | 
            +
                it_behaves_like 'an adapter' do
         | 
| 221 | 
            +
                  let(:adapter){ :typhoeus }
         | 
| 222 | 
            +
                end
         | 
| 223 | 
            +
              end
         | 
| 224 | 
            +
             | 
| 225 | 
            +
             | 
| 226 | 
            +
              describe 'AbstractAdapter' do
         | 
| 227 | 
            +
             | 
| 228 | 
            +
                let(:adapter){ GiantClient::AbstractAdapter.new }
         | 
| 229 | 
            +
             | 
| 230 | 
            +
                describe '#normalize_header' do
         | 
| 231 | 
            +
             | 
| 232 | 
            +
                  it 'should not touch a header that is already title case' do
         | 
| 233 | 
            +
                    adapter.normalize_header('Content-Type').should == 'Content-Type'
         | 
| 234 | 
            +
                  end
         | 
| 235 | 
            +
             | 
| 236 | 
            +
                  it 'should convert a header to title case' do
         | 
| 237 | 
            +
                    adapter.normalize_header('content-type').should == 'Content-Type'
         | 
| 238 | 
            +
                  end
         | 
| 239 | 
            +
             | 
| 240 | 
            +
                  it 'should only capitalize the first letter of words' do
         | 
| 241 | 
            +
                    adapter.normalize_header('CONTENT-type').should == 'Content-Type'
         | 
| 242 | 
            +
                  end
         | 
| 243 | 
            +
             | 
| 244 | 
            +
                  it 'should work for one word' do
         | 
| 245 | 
            +
                    adapter.normalize_header('acCEPTS').should == 'Accepts'
         | 
| 246 | 
            +
                  end
         | 
| 247 | 
            +
             | 
| 248 | 
            +
                  it 'should downcase appropriately' do
         | 
| 249 | 
            +
                    adapter.normalize_header('CONTENT-LENGTH').should == 'Content-Length'
         | 
| 250 | 
            +
                  end
         | 
| 251 | 
            +
             | 
| 252 | 
            +
                  it 'should handle a another, similar situation' do
         | 
| 253 | 
            +
                    adapter.normalize_header('x-Forwarded-for').should == 'X-Forwarded-For'
         | 
| 254 | 
            +
                  end
         | 
| 255 | 
            +
                end
         | 
| 256 | 
            +
             | 
| 257 | 
            +
                describe '#encode_query' do
         | 
| 258 | 
            +
             | 
| 259 | 
            +
                  it 'should return empty string from empty hash' do
         | 
| 260 | 
            +
                    adapter.encode_query({}).should == ''
         | 
| 261 | 
            +
                  end
         | 
| 262 | 
            +
             | 
| 263 | 
            +
                  it 'should prefix string argument with ?' do
         | 
| 264 | 
            +
                    adapter.encode_query('parsnips').should == '?parsnips'
         | 
| 265 | 
            +
                  end
         | 
| 266 | 
            +
             | 
| 267 | 
            +
                  it 'should correctly convert hash to query string with ?' do
         | 
| 268 | 
            +
                    adapter.encode_query({ :tra => "lala", :ha => "za"} )
         | 
| 269 | 
            +
                                                  .should == '?tra=lala&ha=za'
         | 
| 270 | 
            +
                  end
         | 
| 271 | 
            +
                end
         | 
| 272 | 
            +
             | 
| 273 | 
            +
                describe '#url_from_opts' do
         | 
| 274 | 
            +
                  let(:opts){{
         | 
| 275 | 
            +
                    :path => '/', :host => 'example.com',
         | 
| 276 | 
            +
                    :ssl => false, :port => 80,
         | 
| 277 | 
            +
                    :query => {}, :body => '',
         | 
| 278 | 
            +
                    :headers => {}
         | 
| 279 | 
            +
                  }}
         | 
| 280 | 
            +
             | 
| 281 | 
            +
                  it 'should not have the correct url' do
         | 
| 282 | 
            +
                    adapter.url_from_opts(opts).should == "http://example.com/"
         | 
| 283 | 
            +
                  end
         | 
| 284 | 
            +
             | 
| 285 | 
            +
                  it 'should use ssl if we tell it to' do
         | 
| 286 | 
            +
                    opts[:ssl] = true
         | 
| 287 | 
            +
                    adapter.url_from_opts(opts)[0...8].should == "https://"
         | 
| 288 | 
            +
                  end
         | 
| 289 | 
            +
             | 
| 290 | 
            +
                  it 'should work with a custom port' do
         | 
| 291 | 
            +
                    opts[:ssl] = true
         | 
| 292 | 
            +
                    opts[:port] = 8080
         | 
| 293 | 
            +
                    adapter.url_from_opts(opts)[19...24].should == ":8080"
         | 
| 294 | 
            +
                  end
         | 
| 295 | 
            +
             | 
| 296 | 
            +
                end
         | 
| 297 | 
            +
              end
         | 
| 298 | 
            +
             | 
| 299 | 
            +
            end
         |