httpadapter 0.2.1 → 1.0.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.
@@ -0,0 +1,357 @@
1
+ # Copyright (C) 2010 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'spec_helper'
16
+ require 'spec/httpadapter/adapter_type_checking_spec'
17
+
18
+ require 'httpadapter/adapters/rack'
19
+
20
+ describe HTTPAdapter::RackAdapter do
21
+ before do
22
+ @adapter = HTTPAdapter::RackAdapter.new
23
+ end
24
+
25
+ it_should_behave_like 'adapter type-checking example'
26
+
27
+ describe 'when adapting a request' do
28
+ describe 'from Rack::Request for GET' do
29
+ before do
30
+ @body_io = StringIO.new
31
+ @env = {
32
+ # PEP333 variables
33
+ 'REQUEST_METHOD' => 'GET',
34
+ 'SERVER_NAME' => 'www.example.com',
35
+ 'SERVER_PORT' => '80',
36
+ 'SCRIPT_NAME' => '',
37
+ 'PATH_INFO' => '/path/to/resource',
38
+ 'QUERY_STRING' => '',
39
+
40
+ # Rack-specific variables
41
+ 'rack.version' => Rack::VERSION,
42
+ 'rack.input' => @body_io,
43
+ 'rack.errors' => STDERR,
44
+ 'rack.multithread' => true,
45
+ 'rack.multiprocess' => true,
46
+ 'rack.run_once' => false,
47
+ 'rack.url_scheme' => 'http',
48
+
49
+ # HTTP headers
50
+ 'HTTP_ACCEPT' => 'application/json'
51
+ }
52
+ @request = Rack::Request.new(@env)
53
+ @result = @adapter.adapt_request(@request)
54
+ @method, @uri, @headers, @body = @result
55
+ end
56
+
57
+ it 'should convert the HTTP method properly' do
58
+ @method.should == 'GET'
59
+ end
60
+
61
+ it 'should convert the URI properly' do
62
+ @uri.should == 'http://www.example.com/path/to/resource'
63
+ end
64
+
65
+ it 'should convert the headers properly' do
66
+ accept = nil
67
+ @headers.each do |header, value|
68
+ header.should be_kind_of(String)
69
+ value.should be_kind_of(String)
70
+ accept = value if header == 'Accept'
71
+ end
72
+ accept.should == 'application/json'
73
+ end
74
+
75
+ it 'should convert the body properly' do
76
+ @body.each do |chunk|
77
+ chunk.should be_kind_of(String)
78
+ end
79
+ end
80
+ end
81
+
82
+ describe 'from Rack::Request for POST' do
83
+ before do
84
+ @body_io = StringIO.new('{"three":3,"two":2,"one":1}')
85
+ @env = {
86
+ # PEP333 variables
87
+ 'REQUEST_METHOD' => 'POST',
88
+ 'SERVER_NAME' => 'www.example.com',
89
+ 'SERVER_PORT' => '80',
90
+ 'SCRIPT_NAME' => '',
91
+ 'PATH_INFO' => '/path/to/resource',
92
+ 'QUERY_STRING' => '',
93
+
94
+ # Rack-specific variables
95
+ 'rack.version' => Rack::VERSION,
96
+ 'rack.input' => @body_io,
97
+ 'rack.errors' => STDERR,
98
+ 'rack.multithread' => true,
99
+ 'rack.multiprocess' => true,
100
+ 'rack.run_once' => false,
101
+ 'rack.url_scheme' => 'http',
102
+
103
+ # HTTP headers
104
+ 'HTTP_ACCEPT' => 'application/json',
105
+ 'HTTP_CONTENT_TYPE' => 'application/json; charset=utf-8'
106
+ }
107
+ @request = Rack::Request.new(@env)
108
+ @result = @adapter.adapt_request(@request)
109
+ @method, @uri, @headers, @body = @result
110
+ end
111
+
112
+ it 'should convert the HTTP method properly' do
113
+ @method.should == 'POST'
114
+ end
115
+
116
+ it 'should convert the URI properly' do
117
+ @uri.should == 'http://www.example.com/path/to/resource'
118
+ end
119
+
120
+ it 'should convert the headers properly' do
121
+ accept = nil
122
+ content_type = nil
123
+ @headers.each do |header, value|
124
+ header.should be_kind_of(String)
125
+ value.should be_kind_of(String)
126
+ accept = value if header == 'Accept'
127
+ content_type = value if header == 'Content-Type'
128
+ end
129
+ accept.should == 'application/json'
130
+ content_type.should == 'application/json; charset=utf-8'
131
+ end
132
+
133
+ it 'should convert the body properly' do
134
+ merged_body = ""
135
+ @body.each do |chunk|
136
+ chunk.should be_kind_of(String)
137
+ merged_body += chunk
138
+ end
139
+ merged_body.should == '{"three":3,"two":2,"one":1}'
140
+ end
141
+ end
142
+ end
143
+
144
+ describe 'when specializing a request' do
145
+ it 'should raise an error for converting from an invalid tuple' do
146
+ (lambda do
147
+ @adapter.specialize_request(['GET', '/', [], [42]])
148
+ end).should raise_error(TypeError)
149
+ end
150
+
151
+ describe 'from a GET tuple' do
152
+ before do
153
+ @tuple = [
154
+ 'GET',
155
+ 'http://www.example.com/path?query',
156
+ [
157
+ ['Accept', 'application/json']
158
+ ],
159
+ []
160
+ ]
161
+ @request = @adapter.specialize_request(@tuple)
162
+ end
163
+
164
+ it 'should convert the HTTP method properly' do
165
+ @request.request_method.should == 'GET'
166
+ end
167
+
168
+ it 'should convert the URI properly' do
169
+ @request.url.should == 'http://www.example.com/path?query'
170
+ end
171
+
172
+ it 'should convert the headers properly' do
173
+ @request.env['HTTP_ACCEPT'].should == 'application/json'
174
+ end
175
+
176
+ it 'should convert the body properly' do
177
+ @request.body.read.should == ''
178
+ end
179
+ end
180
+
181
+ describe 'from a POST tuple' do
182
+ before do
183
+ @tuple = [
184
+ 'POST',
185
+ 'http://www.example.com/path?query',
186
+ [
187
+ ['Accept', 'application/json'],
188
+ ['Content-Type', 'application/json; charset=utf-8'],
189
+ ['Content-Length', '27']
190
+ ],
191
+ ['{"three":3,', '"two":2,', '"one":1}']
192
+ ]
193
+ @request = @adapter.specialize_request(@tuple)
194
+ end
195
+
196
+ it 'should convert the HTTP method properly' do
197
+ @request.request_method.should == 'POST'
198
+ end
199
+
200
+ it 'should convert the URI properly' do
201
+ @request.url.should == 'http://www.example.com/path?query'
202
+ end
203
+
204
+ it 'should convert the headers properly' do
205
+ accept = nil
206
+ content_type = nil
207
+ @request.env['HTTP_ACCEPT'].should == 'application/json'
208
+ @request.env['HTTP_CONTENT_TYPE'].should ==
209
+ 'application/json; charset=utf-8'
210
+ end
211
+
212
+ it 'should convert the body properly' do
213
+ @request.body.read.should == '{"three":3,"two":2,"one":1}'
214
+ end
215
+ end
216
+ end
217
+
218
+ describe 'when adapting a response' do
219
+ it 'should raise an error for converting from an invalid response' do
220
+ (lambda do
221
+ @adapter.adapt_response(42)
222
+ end).should raise_error(TypeError)
223
+ end
224
+
225
+ describe 'from Rack::Response' do
226
+ before do
227
+ @response = Rack::Response.new(
228
+ ['{"three":3,"two":2,"one":1}'],
229
+ 200,
230
+ {
231
+ 'Content-Type' => 'application/json; charset=utf-8',
232
+ 'Content-Length' => '27'
233
+ }
234
+ )
235
+ @result = @adapter.adapt_response(@response)
236
+ @status, @headers, @body = @result
237
+ end
238
+
239
+ it 'should convert the HTTP status properly' do
240
+ @status.should == 200
241
+ end
242
+
243
+ it 'should convert the headers properly' do
244
+ content_type = nil
245
+ @headers.each do |header, value|
246
+ header.should be_kind_of(String)
247
+ value.should be_kind_of(String)
248
+ content_type = value if header == 'Content-Type'
249
+ end
250
+ content_type.should == 'application/json; charset=utf-8'
251
+ end
252
+
253
+ it 'should convert the body properly' do
254
+ merged_body = ""
255
+ @body.each do |chunk|
256
+ merged_body += chunk
257
+ chunk.should be_kind_of(String)
258
+ end
259
+ merged_body.should == '{"three":3,"two":2,"one":1}'
260
+ end
261
+ end
262
+ end
263
+
264
+ describe 'when specializing a response' do
265
+ it 'should raise an error for converting from an invalid tuple' do
266
+ (lambda do
267
+ @adapter.specialize_response(
268
+ [200, [], [42]]
269
+ )
270
+ end).should raise_error(TypeError)
271
+ end
272
+
273
+ describe 'from a 200 tuple' do
274
+ before do
275
+ @tuple = [
276
+ 200,
277
+ [
278
+ ['Content-Type', 'application/json; charset=utf-8'],
279
+ ['Content-Length', '27']
280
+ ],
281
+ ['{"three":3,"two":2,"one":1}']
282
+ ]
283
+ @response = @adapter.specialize_response(@tuple)
284
+ end
285
+
286
+ it 'should convert the HTTP status properly' do
287
+ @response.status.to_i.should == 200
288
+ end
289
+
290
+ it 'should parse the content length properly' do
291
+ @response.length.to_i.should == 27
292
+ end
293
+
294
+ it 'should convert the headers properly' do
295
+ content_type = nil
296
+ @response.header.each do |header, value|
297
+ header.should be_kind_of(String)
298
+ value.should be_kind_of(String)
299
+ content_type = value if header == 'Content-Type'
300
+ end
301
+ content_type.should == 'application/json; charset=utf-8'
302
+ end
303
+
304
+ it 'should convert the body properly' do
305
+ merged_body = ""
306
+ @response.body.each do |chunk|
307
+ merged_body += chunk
308
+ end
309
+ merged_body.should == '{"three":3,"two":2,"one":1}'
310
+ end
311
+ end
312
+
313
+ describe 'from a 200 tuple' do
314
+ before do
315
+ @tuple = [
316
+ 500,
317
+ [
318
+ ['Content-Type', 'text/html'],
319
+ ['Content-Length', '28']
320
+ ],
321
+ ['<html><body>', '42', '</body></html>']
322
+ ]
323
+ @response = @adapter.specialize_response(@tuple)
324
+ end
325
+
326
+ it 'should convert the HTTP status properly' do
327
+ @response.status.to_i.should == 500
328
+ end
329
+
330
+ it 'should convert the headers properly' do
331
+ content_type = nil
332
+ @response.header.each do |header, value|
333
+ header.should be_kind_of(String)
334
+ value.should be_kind_of(String)
335
+ content_type = value if header == 'Content-Type'
336
+ end
337
+ content_type.should == 'text/html'
338
+ end
339
+
340
+ it 'should convert the body properly' do
341
+ merged_body = ""
342
+ @response.body.each do |chunk|
343
+ merged_body += chunk
344
+ end
345
+ merged_body.should == '<html><body>42</body></html>'
346
+ end
347
+ end
348
+ end
349
+
350
+ describe 'when transmitting a request' do
351
+ it 'should raise an error indicating that transmission is not possible' do
352
+ (lambda do
353
+ @adapter.transmit(['GET', 'http://www.google.com/', [], ['']])
354
+ end).should raise_error(NotImplementedError)
355
+ end
356
+ end
357
+ end
@@ -0,0 +1,379 @@
1
+ # Copyright (C) 2010 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'spec_helper'
16
+
17
+ require 'httpadapter/adapters/typhoeus'
18
+
19
+ describe HTTPAdapter::TyphoeusAdapter do
20
+ before do
21
+ @adapter = HTTPAdapter::TyphoeusAdapter.new
22
+ end
23
+
24
+ it_should_behave_like 'adapter type-checking example'
25
+
26
+ describe 'when adapting a request' do
27
+ describe 'from Typhoeus::Request for GET' do
28
+ before do
29
+ @request = Typhoeus::Request.new(
30
+ 'http://www.example.com/path/to/resource'
31
+ )
32
+ @request.headers['Accept'] = 'application/json'
33
+ @result = @adapter.adapt_request(@request)
34
+ @method, @uri, @headers, @body = @result
35
+ end
36
+
37
+ it 'should convert the HTTP method properly' do
38
+ @method.should == 'GET'
39
+ end
40
+
41
+ it 'should convert the URI properly' do
42
+ @uri.should == 'http://www.example.com/path/to/resource'
43
+ end
44
+
45
+ it 'should convert the headers properly' do
46
+ accept = nil
47
+ @headers.each do |header, value|
48
+ header.should be_kind_of(String)
49
+ value.should be_kind_of(String)
50
+ accept = value if header == 'Accept'
51
+ end
52
+ accept.should == 'application/json'
53
+ end
54
+
55
+ it 'should convert the body properly' do
56
+ @body.each do |chunk|
57
+ chunk.should be_kind_of(String)
58
+ end
59
+ end
60
+ end
61
+
62
+ describe 'from Typhoeus::Request for POST' do
63
+ before do
64
+ @request = Typhoeus::Request.new(
65
+ 'http://www.example.com/path/to/resource',
66
+ :method => :post
67
+ )
68
+ @request.headers['Accept'] = 'application/json'
69
+ @request.headers['Content-Type'] = 'application/json; charset=utf-8'
70
+ @request.body = '{"three":3,"two":2,"one":1}'
71
+ @result = @adapter.adapt_request(@request)
72
+ @method, @uri, @headers, @body = @result
73
+ end
74
+
75
+ it 'should convert the HTTP method properly' do
76
+ @method.should == 'POST'
77
+ end
78
+
79
+ it 'should convert the URI properly' do
80
+ @uri.should == 'http://www.example.com/path/to/resource'
81
+ end
82
+
83
+ it 'should convert the headers properly' do
84
+ accept = nil
85
+ content_type = nil
86
+ @headers.each do |header, value|
87
+ header.should be_kind_of(String)
88
+ value.should be_kind_of(String)
89
+ accept = value if header == 'Accept'
90
+ content_type = value if header == 'Content-Type'
91
+ end
92
+ accept.should == 'application/json'
93
+ content_type.should == 'application/json; charset=utf-8'
94
+ end
95
+
96
+ it 'should convert the body properly' do
97
+ merged_body = ""
98
+ @body.each do |chunk|
99
+ chunk.should be_kind_of(String)
100
+ merged_body += chunk
101
+ end
102
+ merged_body.should == '{"three":3,"two":2,"one":1}'
103
+ end
104
+ end
105
+ end
106
+
107
+ describe 'when specializing a request' do
108
+ it 'should raise an error for converting from an invalid tuple' do
109
+ (lambda do
110
+ @adapter.specialize_request(
111
+ ['GET', '/', [], [42]]
112
+ )
113
+ end).should raise_error(TypeError)
114
+ end
115
+
116
+ describe 'from a GET tuple' do
117
+ before do
118
+ @tuple = [
119
+ 'GET',
120
+ 'http://www.example.com/path?query',
121
+ [
122
+ ['Accept', 'application/json']
123
+ ],
124
+ []
125
+ ]
126
+ @request = @adapter.specialize_request(@tuple)
127
+ end
128
+
129
+ it 'should convert the HTTP method properly' do
130
+ @request.method.should == :get
131
+ end
132
+
133
+ it 'should convert the URI properly' do
134
+ @request.url.should == 'http://www.example.com/path?query'
135
+ end
136
+
137
+ it 'should convert the headers properly' do
138
+ accept = nil
139
+ @request.headers.each do |header, value|
140
+ header.should be_kind_of(String)
141
+ value.should be_kind_of(String)
142
+ accept = value if header == 'Accept'
143
+ end
144
+ accept.should == 'application/json'
145
+ end
146
+
147
+ it 'should convert the body properly' do
148
+ @request.body.should == nil
149
+ end
150
+ end
151
+
152
+ describe 'from a POST tuple' do
153
+ before do
154
+ @tuple = [
155
+ 'POST',
156
+ 'http://www.example.com/path?query',
157
+ [
158
+ ['Accept', 'application/json'],
159
+ ['Content-Type', 'application/json; charset=utf-8'],
160
+ ['Content-Length', '27']
161
+ ],
162
+ ['{"three":3,', '"two":2,', '"one":1}']
163
+ ]
164
+ @request = @adapter.specialize_request(@tuple)
165
+ end
166
+
167
+ it 'should convert the HTTP method properly' do
168
+ @request.method.should == :post
169
+ end
170
+
171
+ it 'should convert the URI properly' do
172
+ @request.url.should == 'http://www.example.com/path?query'
173
+ end
174
+
175
+ it 'should convert the headers properly' do
176
+ accept = nil
177
+ content_type = nil
178
+ @request.headers.each do |header, value|
179
+ header.should be_kind_of(String)
180
+ value.should be_kind_of(String)
181
+ accept = value if header == 'Accept'
182
+ content_type = value if header == 'Content-Type'
183
+ end
184
+ accept.should == 'application/json'
185
+ content_type.should == 'application/json; charset=utf-8'
186
+ end
187
+
188
+ it 'should convert the body properly' do
189
+ @request.body.should == '{"three":3,"two":2,"one":1}'
190
+ end
191
+ end
192
+ end
193
+
194
+ describe 'when adapting a response' do
195
+ describe 'from Typhoeus::Response' do
196
+ before do
197
+ @response = Typhoeus::Response.new(
198
+ :code => 200,
199
+ :headers => <<-HEADERS,
200
+ Content-Type: application/json; charset=utf-8
201
+ Content-Length: 27
202
+ HEADERS
203
+ :body => '{"three":3,"two":2,"one":1}'
204
+ )
205
+ @result = @adapter.adapt_response(@response)
206
+ @status, @headers, @body = @result
207
+ end
208
+
209
+ it 'should convert the HTTP status properly' do
210
+ @status.should == 200
211
+ end
212
+
213
+ it 'should convert the headers properly' do
214
+ content_type = nil
215
+ @headers.each do |header, value|
216
+ header.should be_kind_of(String)
217
+ value.should be_kind_of(String)
218
+ content_type = value if header == 'Content-Type'
219
+ end
220
+ content_type.should == 'application/json; charset=utf-8'
221
+ end
222
+
223
+ it 'should convert the body properly' do
224
+ merged_body = ""
225
+ @body.each do |chunk|
226
+ merged_body += chunk
227
+ chunk.should be_kind_of(String)
228
+ end
229
+ merged_body.should == '{"three":3,"two":2,"one":1}'
230
+ end
231
+ end
232
+ end
233
+
234
+ describe 'when specializing a response' do
235
+ it 'should raise an error for converting from an invalid tuple' do
236
+ (lambda do
237
+ @adapter.specialize_response(
238
+ [200, [], [42]]
239
+ )
240
+ end).should raise_error(TypeError)
241
+ end
242
+
243
+ describe 'from a 200 tuple' do
244
+ before do
245
+ @tuple = [
246
+ 200,
247
+ [
248
+ ['Content-Type', 'application/json; charset=utf-8'],
249
+ ['Content-Length', '27']
250
+ ],
251
+ ['{"three":3,"two":2,"one":1}']
252
+ ]
253
+ @response = @adapter.specialize_response(@tuple)
254
+ end
255
+
256
+ it 'should convert the HTTP status properly' do
257
+ @response.code.to_i.should == 200
258
+ end
259
+
260
+ it 'should convert the headers properly' do
261
+ content_type = nil
262
+ @response.headers_hash.each do |header, value|
263
+ header.should be_kind_of(String)
264
+ value.should be_kind_of(String)
265
+ content_type = value if header == 'Content-Type'
266
+ end
267
+ content_type.should == 'application/json; charset=utf-8'
268
+ end
269
+
270
+ it 'should convert the body properly' do
271
+ @response.body.should == '{"three":3,"two":2,"one":1}'
272
+ end
273
+ end
274
+
275
+ describe 'from a 200 tuple' do
276
+ before do
277
+ @tuple = [
278
+ 500,
279
+ [
280
+ ['Content-Type', 'text/html'],
281
+ ['Content-Length', '28']
282
+ ],
283
+ ['<html><body>', '42', '</body></html>']
284
+ ]
285
+ @response = @adapter.specialize_response(@tuple)
286
+ end
287
+
288
+ it 'should convert the HTTP status properly' do
289
+ @response.code.to_i.should == 500
290
+ end
291
+
292
+ it 'should convert the headers properly' do
293
+ content_type = nil
294
+ @response.headers_hash.each do |header, value|
295
+ header.should be_kind_of(String)
296
+ value.should be_kind_of(String)
297
+ content_type = value if header == 'Content-Type'
298
+ end
299
+ content_type.should == 'text/html'
300
+ end
301
+
302
+ it 'should convert the body properly' do
303
+ @response.body.should == '<html><body>42</body></html>'
304
+ end
305
+ end
306
+ end
307
+
308
+ describe 'when transmitting a request' do
309
+ describe 'with a GET tuple' do
310
+ before do
311
+ @tuple = [
312
+ 'GET',
313
+ 'http://www.google.com/',
314
+ [],
315
+ []
316
+ ]
317
+ @response = @adapter.transmit(@tuple)
318
+ @status, @headers, @chunked_body = @response
319
+ @body = ''
320
+ @chunked_body.each do |chunk|
321
+ @body += chunk
322
+ end
323
+ end
324
+
325
+ it 'should have the correct status' do
326
+ @status.should == 200
327
+ end
328
+
329
+ it 'should have response headers' do
330
+ @headers.should_not be_empty
331
+ end
332
+
333
+ it 'should have a response body' do
334
+ @body.length.should > 0
335
+ end
336
+ end
337
+
338
+ describe 'with connection' do
339
+ before do
340
+ @connection = HTTPAdapter::Connection.new(
341
+ 'www.google.com', 80,
342
+ Typhoeus::Hydra.new,
343
+ :join => [:run, [], nil]
344
+ )
345
+ @connection.open
346
+ @tuple = [
347
+ 'GET',
348
+ 'http://www.google.com/',
349
+ [],
350
+ []
351
+ ]
352
+ @response = @adapter.transmit(@tuple, @connection)
353
+ @status, @headers, @chunked_body = @response
354
+ @body = ''
355
+ @chunked_body.each do |chunk|
356
+ @body += chunk
357
+ end
358
+ end
359
+
360
+ after do
361
+ @connection.close
362
+ end
363
+
364
+ it 'should have the correct status' do
365
+ @status.should == 200
366
+ end
367
+
368
+ it 'should have response headers' do
369
+ @headers.should_not be_empty
370
+ end
371
+
372
+ it 'should have a response body' do
373
+ @body.length.should > 0
374
+ end
375
+ end
376
+ end
377
+ end
378
+
379
+