httparty 0.4.5 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of httparty might be problematic. Click here for more details.

@@ -18,7 +18,20 @@ describe HTTParty::Request do
18
18
  before do
19
19
  @request = HTTParty::Request.new(Net::HTTP::Get, 'http://api.foo.com/v1', :format => :xml)
20
20
  end
21
-
21
+
22
+ describe "initialization" do
23
+ it "sets parser to HTTParty::Parser" do
24
+ request = HTTParty::Request.new(Net::HTTP::Get, 'http://google.com')
25
+ request.parser.should == HTTParty::Parser
26
+ end
27
+
28
+ it "sets parser to the optional parser" do
29
+ my_parser = lambda {}
30
+ request = HTTParty::Request.new(Net::HTTP::Get, 'http://google.com', :parser => my_parser)
31
+ request.parser.should == my_parser
32
+ end
33
+ end
34
+
22
35
  describe "#format" do
23
36
  it "should return the correct parsing format" do
24
37
  @request.format.should == :xml
@@ -30,17 +43,76 @@ describe HTTParty::Request do
30
43
  request = HTTParty::Request.new(Net::HTTP::Get, 'https://api.foo.com/v1:443')
31
44
  request.send(:http).use_ssl?.should == true
32
45
  end
33
-
46
+
34
47
  it 'should not use ssl for port 80' do
35
48
  request = HTTParty::Request.new(Net::HTTP::Get, 'http://foobar.com')
36
49
  request.send(:http).use_ssl?.should == false
37
50
  end
38
-
39
- it "should use ssl for https scheme" do
51
+
52
+ it "uses ssl for https scheme with default port" do
40
53
  request = HTTParty::Request.new(Net::HTTP::Get, 'https://foobar.com')
41
54
  request.send(:http).use_ssl?.should == true
42
55
  end
43
56
 
57
+ it "uses ssl for https scheme regardless of port" do
58
+ request = HTTParty::Request.new(Net::HTTP::Get, 'https://foobar.com:123456')
59
+ request.send(:http).use_ssl?.should == true
60
+ end
61
+
62
+ context "PEM certificates" do
63
+ before do
64
+ OpenSSL::X509::Certificate.stub(:new)
65
+ OpenSSL::PKey::RSA.stub(:new)
66
+ end
67
+
68
+ context "when scheme is https" do
69
+ before do
70
+ @request.stub!(:uri).and_return(URI.parse("https://google.com"))
71
+ pem = :pem_contents
72
+ @cert = mock("OpenSSL::X509::Certificate")
73
+ @key = mock("OpenSSL::PKey::RSA")
74
+ OpenSSL::X509::Certificate.should_receive(:new).with(pem).and_return(@cert)
75
+ OpenSSL::PKey::RSA.should_receive(:new).with(pem).and_return(@key)
76
+
77
+ @request.options[:pem] = pem
78
+ @pem_http = @request.send(:http)
79
+ end
80
+
81
+ it "should use a PEM certificate when provided" do
82
+ @pem_http.cert.should == @cert
83
+ @pem_http.key.should == @key
84
+ end
85
+
86
+ it "should verify the certificate when provided" do
87
+ @pem_http = @request.send(:http)
88
+ @pem_http.verify_mode.should == OpenSSL::SSL::VERIFY_PEER
89
+ end
90
+ end
91
+
92
+ context "when scheme is not https" do
93
+ it "does not assign a PEM" do
94
+ http = Net::HTTP.new('google.com')
95
+ http.should_not_receive(:cert=)
96
+ http.should_not_receive(:key=)
97
+ Net::HTTP.stub(:new => http)
98
+
99
+ request = HTTParty::Request.new(Net::HTTP::Get, 'http://google.com')
100
+ request.options[:pem] = :pem_contents
101
+ request.send(:http)
102
+ end
103
+
104
+ it "should not verify a certificate if scheme is not https" do
105
+ http = Net::HTTP.new('google.com')
106
+ Net::HTTP.stub(:new => http)
107
+
108
+ request = HTTParty::Request.new(Net::HTTP::Get, 'http://google.com')
109
+ request.options[:pem] = :pem_contents
110
+ http = request.send(:http)
111
+ http.verify_mode.should == OpenSSL::SSL::VERIFY_NONE
112
+ end
113
+ end
114
+ end
115
+
44
116
  it "should use basic auth when configured" do
45
117
  @request.options[:basic_auth] = {:username => 'foobar', :password => 'secret'}
46
118
  @request.send(:setup_raw_request)
@@ -102,6 +174,15 @@ describe HTTParty::Request do
102
174
  @request.send(:format_from_mimetype, ct).should == :json
103
175
  end
104
176
  end
177
+
178
+ it "returns nil for an unrecognized mimetype" do
179
+ @request.send(:format_from_mimetype, "application/atom+xml").should be_nil
180
+ end
181
+
182
+ it "returns nil when using a default parser" do
183
+ @request.options[:parser] = lambda {}
184
+ @request.send(:format_from_mimetype, "text/json").should be_nil
185
+ end
105
186
  end
106
187
 
107
188
  describe 'parsing responses' do
@@ -110,7 +191,7 @@ describe HTTParty::Request do
110
191
  @request.options[:format] = :xml
111
192
  @request.send(:parse_response, xml).should == {'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}}
112
193
  end
113
-
194
+
114
195
  it 'should handle json automatically' do
115
196
  json = %q[{"books": {"book": {"name": "Foo Bar!", "id": "1234"}}}]
116
197
  @request.options[:format] = :json
@@ -130,7 +211,7 @@ describe HTTParty::Request do
130
211
 
131
212
  @request.perform.headers.should == { "key" => ["value"] }
132
213
  end
133
-
214
+
134
215
  describe 'with non-200 responses' do
135
216
  it 'should return a valid object for 4xx response' do
136
217
  stub_response '<foo><bar>yes</bar></foo>', 401
@@ -156,7 +237,7 @@ describe HTTParty::Request do
156
237
  @request.options[:format] = :xml
157
238
  @request.perform.should be_nil
158
239
  end
159
-
240
+
160
241
  it "should not fail for missing mime type" do
161
242
  stub_response "Content for you"
162
243
  @request.options[:format] = :html
@@ -194,28 +275,38 @@ describe HTTParty::Request do
194
275
  @request.http_method = Net::HTTP::Put
195
276
  @request.perform.should == {"hash" => {"foo" => "bar"}}
196
277
  end
197
-
278
+
279
+ it "should be handled by HEAD transparently" do
280
+ @request.http_method = Net::HTTP::Head
281
+ @request.perform.should == {"hash" => {"foo" => "bar"}}
282
+ end
283
+
284
+ it "should be handled by OPTIONS transparently" do
285
+ @request.http_method = Net::HTTP::Options
286
+ @request.perform.should == {"hash" => {"foo" => "bar"}}
287
+ end
288
+
198
289
  it "should keep track of cookies between redirects" do
199
290
  @redirect['Set-Cookie'] = 'foo=bar; name=value; HTTPOnly'
200
291
  @request.perform
201
292
  @request.options[:headers]['Cookie'].should match(/foo=bar/)
202
293
  @request.options[:headers]['Cookie'].should match(/name=value/)
203
294
  end
204
-
295
+
205
296
  it 'should update cookies with rediects' do
206
297
  @request.options[:headers] = {'Cookie'=> 'foo=bar;'}
207
298
  @redirect['Set-Cookie'] = 'foo=tar;'
208
299
  @request.perform
209
300
  @request.options[:headers]['Cookie'].should match(/foo=tar/)
210
301
  end
211
-
302
+
212
303
  it 'should keep cookies between rediects' do
213
304
  @request.options[:headers] = {'Cookie'=> 'keep=me'}
214
305
  @redirect['Set-Cookie'] = 'foo=tar;'
215
306
  @request.perform
216
307
  @request.options[:headers]['Cookie'].should match(/keep=me/)
217
308
  end
218
-
309
+
219
310
  it 'should make resulting request a get request if it not already' do
220
311
  @request.http_method = Net::HTTP::Delete
221
312
  @request.perform.should == {"hash" => {"foo" => "bar"}}
@@ -1,11 +1,31 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
2
 
3
+ class CustomParser
4
+ def self.parse(body)
5
+ return {:sexy => true}
6
+ end
7
+ end
8
+
3
9
  describe HTTParty do
4
10
  before(:each) do
5
11
  @klass = Class.new
6
12
  @klass.instance_eval { include HTTParty }
7
13
  end
8
14
 
15
+ describe "AllowedFormats deprecated" do
16
+ before do
17
+ Kernel.stub(:warn)
18
+ end
19
+ it "warns with a deprecation message" do
20
+ Kernel.should_receive(:warn).with("Deprecated: Use HTTParty::Parser::SupportedFormats")
21
+ HTTParty::AllowedFormats
22
+ end
23
+
24
+ it "returns HTTPart::Parser::SupportedFormats" do
25
+ HTTParty::AllowedFormats.should == HTTParty::Parser::SupportedFormats
26
+ end
27
+ end
28
+
9
29
  describe "base uri" do
10
30
  before(:each) do
11
31
  @klass.base_uri('api.foo.com/v1')
@@ -14,7 +34,7 @@ describe HTTParty do
14
34
  it "should have reader" do
15
35
  @klass.base_uri.should == 'http://api.foo.com/v1'
16
36
  end
17
-
37
+
18
38
  it 'should have writer' do
19
39
  @klass.base_uri('http://api.foobar.com')
20
40
  @klass.base_uri.should == 'http://api.foobar.com'
@@ -26,18 +46,18 @@ describe HTTParty do
26
46
  uri.should == 'http://api.foobar.com'
27
47
  end
28
48
  end
29
-
49
+
30
50
  describe "#normalize_base_uri" do
31
51
  it "should add http if not present for non ssl requests" do
32
52
  uri = HTTParty.normalize_base_uri('api.foobar.com')
33
53
  uri.should == 'http://api.foobar.com'
34
54
  end
35
-
55
+
36
56
  it "should add https if not present for ssl requests" do
37
57
  uri = HTTParty.normalize_base_uri('api.foo.com/v1:443')
38
58
  uri.should == 'https://api.foo.com/v1:443'
39
59
  end
40
-
60
+
41
61
  it "should not remove https for ssl requests" do
42
62
  uri = HTTParty.normalize_base_uri('https://api.foo.com/v1:443')
43
63
  uri.should == 'https://api.foo.com/v1:443'
@@ -49,7 +69,7 @@ describe HTTParty do
49
69
  uri.should == 'http://api.foobar.com'
50
70
  end
51
71
  end
52
-
72
+
53
73
  describe "headers" do
54
74
  def expect_headers(header={})
55
75
  HTTParty::Request.should_receive(:new) \
@@ -170,47 +190,82 @@ describe HTTParty do
170
190
  end
171
191
  end
172
192
  end
173
-
193
+
174
194
  describe "default params" do
175
195
  it "should default to empty hash" do
176
196
  @klass.default_params.should == {}
177
197
  end
178
-
198
+
179
199
  it "should be able to be updated" do
180
200
  new_defaults = {:foo => 'bar', :baz => 'spax'}
181
201
  @klass.default_params new_defaults
182
202
  @klass.default_params.should == new_defaults
183
203
  end
184
204
  end
185
-
205
+
186
206
  describe "basic http authentication" do
187
207
  it "should work" do
188
208
  @klass.basic_auth 'foobar', 'secret'
189
209
  @klass.default_options[:basic_auth].should == {:username => 'foobar', :password => 'secret'}
190
210
  end
191
211
  end
192
-
212
+
213
+ describe "parser" do
214
+ let(:parser) do
215
+ Proc.new{ |data, format| CustomParser.parse(data) }
216
+ end
217
+
218
+ it "should set parser options" do
219
+ @klass.parser parser
220
+ @klass.default_options[:parser].should == parser
221
+ end
222
+
223
+ it "should be able parse response with custom parser" do
224
+ @klass.parser parser
225
+ FakeWeb.register_uri(:get, 'http://twitter.com/statuses/public_timeline.xml', :body => 'tweets')
226
+ custom_parsed_response = @klass.get('http://twitter.com/statuses/public_timeline.xml')
227
+ custom_parsed_response[:sexy].should == true
228
+ end
229
+
230
+ it "raises UnsupportedFormat when the parser cannot handle the format" do
231
+ @klass.format :json
232
+ class MyParser < HTTParty::Parser
233
+ SupportedFormats = {}
234
+ end
235
+ expect do
236
+ @klass.parser MyParser
237
+ end.to raise_error(HTTParty::UnsupportedFormat)
238
+ end
239
+
240
+ it 'does not validate format whe custom parser is a proc' do
241
+ expect do
242
+ @klass.format :json
243
+ @klass.parser lambda {|body, format|}
244
+ end.to_not raise_error(HTTParty::UnsupportedFormat)
245
+ end
246
+ end
247
+
193
248
  describe "format" do
194
249
  it "should allow xml" do
195
250
  @klass.format :xml
196
251
  @klass.default_options[:format].should == :xml
197
252
  end
198
-
253
+
199
254
  it "should allow json" do
200
255
  @klass.format :json
201
256
  @klass.default_options[:format].should == :json
202
257
  end
203
-
258
+
204
259
  it "should allow yaml" do
205
260
  @klass.format :yaml
206
261
  @klass.default_options[:format].should == :yaml
207
262
  end
208
-
263
+
209
264
  it "should allow plain" do
210
265
  @klass.format :plain
211
266
  @klass.default_options[:format].should == :plain
212
267
  end
213
-
268
+
214
269
  it 'should not allow funky format' do
215
270
  lambda do
216
271
  @klass.format :foobar
@@ -220,9 +275,21 @@ describe HTTParty do
220
275
  it 'should only print each format once with an exception' do
221
276
  lambda do
222
277
  @klass.format :foobar
223
- end.should raise_error(HTTParty::UnsupportedFormat, "Must be one of: html, json, plain, xml, yaml")
278
+ end.should raise_error(HTTParty::UnsupportedFormat, "':foobar' Must be one of: html, json, plain, xml, yaml")
224
279
  end
225
280
 
281
+ it 'sets the default parser' do
282
+ @klass.default_options[:parser].should be_nil
283
+ @klass.format :json
284
+ @klass.default_options[:parser].should == HTTParty::Parser
285
+ end
286
+
287
+ it 'does not reset parser to the default parser' do
288
+ my_parser = lambda {}
289
+ @klass.parser my_parser
290
+ @klass.format :json
291
+ @klass.parser.should == my_parser
292
+ end
226
293
  end
227
294
 
228
295
  describe "with explicit override of automatic redirect handling" do
@@ -250,8 +317,20 @@ describe HTTParty do
250
317
  @klass.put('/foo', :no_follow => true)
251
318
  end.should raise_error(HTTParty::RedirectionTooDeep)
252
319
  end
320
+
321
+ it "should fail with redirected HEAD" do
322
+ lambda do
323
+ @klass.head('/foo', :no_follow => true)
324
+ end.should raise_error(HTTParty::RedirectionTooDeep)
325
+ end
326
+
327
+ it "should fail with redirected OPTIONS" do
328
+ lambda do
329
+ @klass.options('/foo', :no_follow => true)
330
+ end.should raise_error(HTTParty::RedirectionTooDeep)
331
+ end
253
332
  end
254
-
333
+
255
334
  describe "with multiple class definitions" do
256
335
  before(:each) do
257
336
  @klass.instance_eval do
@@ -272,57 +351,104 @@ describe HTTParty do
272
351
  @additional_klass.default_options.should == { :base_uri => 'http://second.com', :default_params => { :two => 2 } }
273
352
  end
274
353
  end
275
-
354
+
355
+ describe "two child classes inheriting from one parent" do
356
+ before(:each) do
357
+ @parent = Class.new do
358
+ include HTTParty
359
+ end
360
+
361
+ @child1 = Class.new(@parent)
362
+ @child2 = Class.new(@parent)
363
+ end
364
+
365
+ it "does not modify each others inherited attributes" do
366
+ @child1.default_params :joe => "alive"
367
+ @child2.default_params :joe => "dead"
368
+
369
+ @child1.default_options.should == { :default_params => {:joe => "alive"} }
370
+ @child2.default_options.should == { :default_params => {:joe => "dead"} }
371
+
372
+ @parent.default_options.should == { }
373
+ end
374
+ end
375
+
276
376
  describe "#get" do
277
377
  it "should be able to get html" do
278
378
  stub_http_response_with('google.html')
279
379
  HTTParty.get('http://www.google.com').should == file_fixture('google.html')
280
380
  end
281
-
381
+
282
382
  it "should be able parse response type json automatically" do
283
383
  stub_http_response_with('twitter.json')
284
384
  tweets = HTTParty.get('http://twitter.com/statuses/public_timeline.json')
285
385
  tweets.size.should == 20
286
386
  tweets.first['user'].should == {
287
- "name" => "Pyk",
288
- "url" => nil,
289
- "id" => "7694602",
290
- "description" => nil,
291
- "protected" => false,
292
- "screen_name" => "Pyk",
293
- "followers_count" => 1,
294
- "location" => "Opera Plaza, California",
387
+ "name" => "Pyk",
388
+ "url" => nil,
389
+ "id" => "7694602",
390
+ "description" => nil,
391
+ "protected" => false,
392
+ "screen_name" => "Pyk",
393
+ "followers_count" => 1,
394
+ "location" => "Opera Plaza, California",
295
395
  "profile_image_url" => "http://static.twitter.com/images/default_profile_normal.png"
296
396
  }
297
397
  end
298
-
398
+
299
399
  it "should be able parse response type xml automatically" do
300
400
  stub_http_response_with('twitter.xml')
301
401
  tweets = HTTParty.get('http://twitter.com/statuses/public_timeline.xml')
302
402
  tweets['statuses'].size.should == 20
303
403
  tweets['statuses'].first['user'].should == {
304
- "name" => "Magic 8 Bot",
305
- "url" => nil,
306
- "id" => "17656026",
307
- "description" => "ask me a question",
308
- "protected" => "false",
309
- "screen_name" => "magic8bot",
310
- "followers_count" => "90",
311
- "profile_image_url" => "http://s3.amazonaws.com/twitter_production/profile_images/65565851/8ball_large_normal.jpg",
404
+ "name" => "Magic 8 Bot",
405
+ "url" => nil,
406
+ "id" => "17656026",
407
+ "description" => "ask me a question",
408
+ "protected" => "false",
409
+ "screen_name" => "magic8bot",
410
+ "followers_count" => "90",
411
+ "profile_image_url" => "http://s3.amazonaws.com/twitter_production/profile_images/65565851/8ball_large_normal.jpg",
312
412
  "location" => nil
313
413
  }
314
414
  end
315
-
415
+
316
416
  it "should not get undefined method add_node for nil class for the following xml" do
317
417
  stub_http_response_with('undefined_method_add_node_for_nil.xml')
318
418
  result = HTTParty.get('http://foobar.com')
319
419
  result.should == {"Entities"=>{"href"=>"https://s3-sandbox.parature.com/api/v1/5578/5633/Account", "results"=>"0", "total"=>"0", "page_size"=>"25", "page"=>"1"}}
320
420
  end
321
-
421
+
322
422
  it "should parse empty response fine" do
323
423
  stub_http_response_with('empty.xml')
324
424
  result = HTTParty.get('http://foobar.com')
325
- result.should == nil
425
+ result.should be_nil
426
+ end
427
+
428
+ it "should accept http URIs" do
429
+ stub_http_response_with('google.html')
430
+ lambda do
431
+ HTTParty.get('http://google.com')
432
+ end.should_not raise_error(HTTParty::UnsupportedURIScheme)
433
+ end
434
+
435
+ it "should accept https URIs" do
436
+ stub_http_response_with('google.html')
437
+ lambda do
438
+ HTTParty.get('https://google.com')
439
+ end.should_not raise_error(HTTParty::UnsupportedURIScheme)
440
+ end
441
+
442
+ it "should raise an ArgumentError on URIs that are not http or https" do
443
+ lambda do
444
+ HTTParty.get("file:///there_is_no_party_on/my/filesystem")
445
+ end.should raise_error(HTTParty::UnsupportedURIScheme)
446
+ end
447
+
448
+ it "should raise an InvalidURIError on URIs that can't be parsed at all" do
449
+ lambda do
450
+ HTTParty.get("It's the one that says 'Bad URI'")
451
+ end.should raise_error(URI::InvalidURIError)
326
452
  end
327
453
  end
328
- end
454
+ end