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
|