mwilliams-feedzirra 0.0.14

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,578 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Feedzirra::Feed do
4
+ describe "#add_common_feed_entry_element" do
5
+ before(:all) do
6
+ Feedzirra::Feed.add_common_feed_entry_element("wfw:commentRss", :as => :comment_rss)
7
+ end
8
+
9
+ it "should parse the added element out of Atom feeds" do
10
+ Feedzirra::Feed.parse(sample_wfw_feed).entries.first.comment_rss.should == "this is the new val"
11
+ end
12
+
13
+ it "should parse the added element out of Atom Feedburner feeds" do
14
+ Feedzirra::Parser::AtomEntry.new.should respond_to(:comment_rss)
15
+ end
16
+
17
+ it "should parse the added element out of RSS feeds" do
18
+ Feedzirra::Parser::RSSEntry.new.should respond_to(:comment_rss)
19
+ end
20
+ end
21
+
22
+ describe "#parse" do # many of these tests are redundant with the specific feed type tests, but I put them here for completeness
23
+ context "when there's an available parser" do
24
+ it "should parse an rdf feed" do
25
+ feed = Feedzirra::Feed.parse(sample_rdf_feed)
26
+ feed.title.should == "HREF Considered Harmful"
27
+ feed.entries.first.published.to_s.should == "Tue Sep 02 19:50:07 UTC 2008"
28
+ feed.entries.size.should == 10
29
+ end
30
+
31
+ it "should parse an rss feed" do
32
+ feed = Feedzirra::Feed.parse(sample_rss_feed)
33
+ feed.title.should == "Tender Lovemaking"
34
+ feed.entries.first.published.to_s.should == "Thu Dec 04 17:17:49 UTC 2008"
35
+ feed.entries.size.should == 10
36
+ end
37
+
38
+ it "should parse an atom feed" do
39
+ feed = Feedzirra::Feed.parse(sample_atom_feed)
40
+ feed.title.should == "Amazon Web Services Blog"
41
+ feed.entries.first.published.to_s.should == "Fri Jan 16 18:21:00 UTC 2009"
42
+ feed.entries.size.should == 10
43
+ end
44
+
45
+ it "should parse an feedburner atom feed" do
46
+ feed = Feedzirra::Feed.parse(sample_feedburner_atom_feed)
47
+ feed.title.should == "Paul Dix Explains Nothing"
48
+ feed.entries.first.published.to_s.should == "Thu Jan 22 15:50:22 UTC 2009"
49
+ feed.entries.size.should == 5
50
+ end
51
+
52
+ it "should parse an itunes feed as a standard RSS feed" do
53
+ feed = Feedzirra::Feed.parse(sample_itunes_feed)
54
+ feed.title.should == "All About Everything"
55
+ feed.entries.first.published.should == Time.parse("Wed, 15 Jun 2005 19:00:00 GMT")
56
+
57
+ # Since the commit 621957879, iTunes feeds will be parsed as standard RSS, so this
58
+ # entry should now not have a method for itunes_author.
59
+ feed.entries.first.should_not respond_to(:itunes_author)
60
+ feed.entries.size.should == 3
61
+ end
62
+ end
63
+
64
+ context "when there's no available parser" do
65
+ it "raises Feedzirra::NoParserAvailable" do
66
+ proc {
67
+ Feedzirra::Feed.parse("I'm an invalid feed")
68
+ }.should raise_error(Feedzirra::NoParserAvailable)
69
+ end
70
+ end
71
+
72
+ it "should parse an feedburner rss feed" do
73
+ feed = Feedzirra::Feed.parse(sample_rss_feed_burner_feed)
74
+ feed.title.should == "Sam Harris: Author, Philosopher, Essayist, Atheist"
75
+ feed.entries.first.published.to_s.should == "Tue Jan 13 17:20:28 UTC 2009"
76
+ feed.entries.size.should == 10
77
+ end
78
+ end
79
+
80
+ describe "#determine_feed_parser_for_xml" do
81
+ it "should return the Feedzirra::Parser::Atom class for an atom feed" do
82
+ Feedzirra::Feed.determine_feed_parser_for_xml(sample_atom_feed).should == Feedzirra::Parser::Atom
83
+ end
84
+
85
+ it "should return the Feedzirra::Parser::AtomFeedBurner class for an atom feedburner feed" do
86
+ Feedzirra::Feed.determine_feed_parser_for_xml(sample_feedburner_atom_feed).should == Feedzirra::Parser::AtomFeedBurner
87
+ end
88
+
89
+ it "should return the Feedzirra::Parser::RSS class for an rdf/rss 1.0 feed" do
90
+ Feedzirra::Feed.determine_feed_parser_for_xml(sample_rdf_feed).should == Feedzirra::Parser::RSS
91
+ end
92
+
93
+ it "should return the Feedzirra::Parser::RSS class for an rss feedburner feed" do
94
+ Feedzirra::Feed.determine_feed_parser_for_xml(sample_rss_feed_burner_feed).should == Feedzirra::Parser::RSS
95
+ end
96
+
97
+ it "should return the Feedzirra::Parser::RSS object for an rss 2.0 feed" do
98
+ Feedzirra::Feed.determine_feed_parser_for_xml(sample_rss_feed).should == Feedzirra::Parser::RSS
99
+ end
100
+
101
+ it "should return a Feedzirra::Parser::RSS object for an itunes feed" do
102
+ Feedzirra::Feed.determine_feed_parser_for_xml(sample_itunes_feed).should == Feedzirra::Parser::RSS
103
+ end
104
+
105
+ end
106
+
107
+ describe "when adding feed types" do
108
+ it "should prioritize added types over the built in ones" do
109
+ feed_text = "Atom asdf"
110
+ Feedzirra::Parser::Atom.should be_able_to_parse(feed_text)
111
+ new_feed_type = Class.new do
112
+ def self.able_to_parse?(val)
113
+ true
114
+ end
115
+ end
116
+
117
+ new_feed_type.should be_able_to_parse(feed_text)
118
+ Feedzirra::Feed.add_feed_class(new_feed_type)
119
+ Feedzirra::Feed.determine_feed_parser_for_xml(feed_text).should == new_feed_type
120
+
121
+ # this is a hack so that this doesn't break the rest of the tests
122
+ Feedzirra::Feed.feed_classes.reject! {|o| o == new_feed_type }
123
+ end
124
+ end
125
+
126
+ describe '#etag_from_header' do
127
+ before(:each) do
128
+ @header = "HTTP/1.0 200 OK\r\nDate: Thu, 29 Jan 2009 03:55:24 GMT\r\nServer: Apache\r\nX-FB-Host: chi-write6\r\nLast-Modified: Wed, 28 Jan 2009 04:10:32 GMT\r\nETag: ziEyTl4q9GH04BR4jgkImd0GvSE\r\nP3P: CP=\"ALL DSP COR NID CUR OUR NOR\"\r\nConnection: close\r\nContent-Type: text/xml;charset=utf-8\r\n\r\n"
129
+ end
130
+
131
+ it "should return the etag from the header if it exists" do
132
+ Feedzirra::Feed.etag_from_header(@header).should == "ziEyTl4q9GH04BR4jgkImd0GvSE"
133
+ end
134
+
135
+ it "should return nil if there is no etag in the header" do
136
+ Feedzirra::Feed.etag_from_header("foo").should be_nil
137
+ end
138
+
139
+ end
140
+
141
+ describe '#last_modified_from_header' do
142
+ before(:each) do
143
+ @header = "HTTP/1.0 200 OK\r\nDate: Thu, 29 Jan 2009 03:55:24 GMT\r\nServer: Apache\r\nX-FB-Host: chi-write6\r\nLast-Modified: Wed, 28 Jan 2009 04:10:32 GMT\r\nETag: ziEyTl4q9GH04BR4jgkImd0GvSE\r\nP3P: CP=\"ALL DSP COR NID CUR OUR NOR\"\r\nConnection: close\r\nContent-Type: text/xml;charset=utf-8\r\n\r\n"
144
+ end
145
+
146
+ it "should return the last modified date from the header if it exists" do
147
+ Feedzirra::Feed.last_modified_from_header(@header).should == Time.parse("Wed, 28 Jan 2009 04:10:32 GMT")
148
+ end
149
+
150
+ it "should return nil if there is no last modified date in the header" do
151
+ Feedzirra::Feed.last_modified_from_header("foo").should be_nil
152
+ end
153
+ end
154
+
155
+ describe "fetching feeds" do
156
+ before(:each) do
157
+ @paul_feed = { :xml => load_sample("PaulDixExplainsNothing.xml"), :url => "http://feeds.feedburner.com/PaulDixExplainsNothing" }
158
+ @trotter_feed = { :xml => load_sample("TrotterCashionHome.xml"), :url => "http://feeds2.feedburner.com/trottercashion" }
159
+ end
160
+
161
+ describe "#fetch_raw" do
162
+ before(:each) do
163
+ @cmock = stub('cmock', :header_str => '', :body_str => @paul_feed[:xml] )
164
+ @multi = stub('curl_multi', :add => true, :perform => true)
165
+ @curl_easy = stub('curl_easy')
166
+ @curl = stub('curl', :headers => {}, :follow_location= => true, :on_failure => true)
167
+ @curl.stub!(:on_success).and_yield(@cmock)
168
+
169
+ Curl::Multi.stub!(:new).and_return(@multi)
170
+ Curl::Easy.stub!(:new).and_yield(@curl).and_return(@curl_easy)
171
+ end
172
+
173
+ it "should set user agent if it's passed as an option" do
174
+ Feedzirra::Feed.fetch_raw(@paul_feed[:url], :user_agent => 'Custom Useragent')
175
+ @curl.headers['User-Agent'].should == 'Custom Useragent'
176
+ end
177
+
178
+ it "should set user agent to default if it's not passed as an option" do
179
+ Feedzirra::Feed.fetch_raw(@paul_feed[:url])
180
+ @curl.headers['User-Agent'].should == Feedzirra::Feed::USER_AGENT
181
+ end
182
+
183
+ it "should set if modified since as an option if passed" do
184
+ Feedzirra::Feed.fetch_raw(@paul_feed[:url], :if_modified_since => Time.parse("Wed, 28 Jan 2009 04:10:32 GMT"))
185
+ @curl.headers["If-Modified-Since"].should == 'Wed, 28 Jan 2009 04:10:32 GMT'
186
+ end
187
+
188
+ it "should set if none match as an option if passed" do
189
+ Feedzirra::Feed.fetch_raw(@paul_feed[:url], :if_none_match => 'ziEyTl4q9GH04BR4jgkImd0GvSE')
190
+ @curl.headers["If-None-Match"].should == 'ziEyTl4q9GH04BR4jgkImd0GvSE'
191
+ end
192
+
193
+ it 'should set userpwd for http basic authentication if :http_authentication is passed' do
194
+ @curl.should_receive(:userpwd=).with('username:password')
195
+ Feedzirra::Feed.fetch_raw(@paul_feed[:url], :http_authentication => ['username', 'password'])
196
+ end
197
+
198
+ it 'should set accepted encodings' do
199
+ Feedzirra::Feed.fetch_raw(@paul_feed[:url], :compress => true)
200
+ @curl.headers["Accept-encoding"].should == 'gzip, deflate'
201
+ end
202
+
203
+ it "should return raw xml" do
204
+ Feedzirra::Feed.fetch_raw(@paul_feed[:url]).should =~ /^#{Regexp.escape('<?xml version="1.0" encoding="UTF-8"?>')}/
205
+ end
206
+
207
+ it "should take multiple feed urls and return a hash of urls and response xml" do
208
+ multi = stub('curl_multi', :add => true, :perform => true)
209
+ Curl::Multi.stub!(:new).and_return(multi)
210
+
211
+ paul_response = stub('paul_response', :header_str => '', :body_str => @paul_feed[:xml] )
212
+ trotter_response = stub('trotter_response', :header_str => '', :body_str => @trotter_feed[:xml] )
213
+
214
+ paul_curl = stub('paul_curl', :headers => {}, :follow_location= => true, :on_failure => true)
215
+ paul_curl.stub!(:on_success).and_yield(paul_response)
216
+
217
+ trotter_curl = stub('trotter_curl', :headers => {}, :follow_location= => true, :on_failure => true)
218
+ trotter_curl.stub!(:on_success).and_yield(trotter_response)
219
+
220
+ Curl::Easy.should_receive(:new).with(@paul_feed[:url]).ordered.and_yield(paul_curl)
221
+ Curl::Easy.should_receive(:new).with(@trotter_feed[:url]).ordered.and_yield(trotter_curl)
222
+
223
+ results = Feedzirra::Feed.fetch_raw([@paul_feed[:url], @trotter_feed[:url]])
224
+ results.keys.should include(@paul_feed[:url])
225
+ results.keys.should include(@trotter_feed[:url])
226
+ results[@paul_feed[:url]].should =~ /Paul Dix/
227
+ results[@trotter_feed[:url]].should =~ /Trotter Cashion/
228
+ end
229
+
230
+ it "should always return a hash when passed an array" do
231
+ results = Feedzirra::Feed.fetch_raw([@paul_feed[:url]])
232
+ results.class.should == Hash
233
+ end
234
+ end
235
+
236
+ describe "#add_url_to_multi" do
237
+ before(:each) do
238
+ @multi = Curl::Multi.new(@paul_feed[:url])
239
+ @multi.stub!(:add)
240
+ @easy_curl = Curl::Easy.new(@paul_feed[:url])
241
+
242
+ Curl::Easy.should_receive(:new).and_yield(@easy_curl)
243
+ end
244
+
245
+ it "should set user agent if it's passed as an option" do
246
+ Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, :user_agent => 'My cool application')
247
+ @easy_curl.headers["User-Agent"].should == 'My cool application'
248
+ end
249
+
250
+ it "should set user agent to default if it's not passed as an option" do
251
+ Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, {})
252
+ @easy_curl.headers["User-Agent"].should == Feedzirra::Feed::USER_AGENT
253
+ end
254
+
255
+ it "should set if modified since as an option if passed" do
256
+ Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, :if_modified_since => Time.parse("Jan 25 2009 04:10:32 GMT"))
257
+ @easy_curl.headers["If-Modified-Since"].should == 'Sun, 25 Jan 2009 04:10:32 GMT'
258
+ end
259
+
260
+ it 'should set follow location to true' do
261
+ @easy_curl.should_receive(:follow_location=).with(true)
262
+ Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, {})
263
+ end
264
+
265
+ it 'should set userpwd for http basic authentication if :http_authentication is passed' do
266
+ Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, :http_authentication => ['myusername', 'mypassword'])
267
+ @easy_curl.userpwd.should == 'myusername:mypassword'
268
+ end
269
+
270
+ it 'should set accepted encodings' do
271
+ Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, {:compress => true})
272
+ @easy_curl.headers["Accept-encoding"].should == 'gzip, deflate'
273
+ end
274
+
275
+ it "should set if_none_match as an option if passed" do
276
+ Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, :if_none_match => 'ziEyTl4q9GH04BR4jgkImd0GvSE')
277
+ @easy_curl.headers["If-None-Match"].should == 'ziEyTl4q9GH04BR4jgkImd0GvSE'
278
+ end
279
+
280
+ describe 'on success' do
281
+ before(:each) do
282
+ @feed = mock('feed', :feed_url= => true, :etag= => true, :last_modified= => true)
283
+ Feedzirra::Feed.stub!(:decode_content).and_return(@paul_feed[:xml])
284
+ Feedzirra::Feed.stub!(:determine_feed_parser_for_xml).and_return(Feedzirra::Parser::AtomFeedBurner)
285
+ Feedzirra::Parser::AtomFeedBurner.stub!(:parse).and_return(@feed)
286
+ Feedzirra::Feed.stub!(:etag_from_header).and_return('ziEyTl4q9GH04BR4jgkImd0GvSE')
287
+ Feedzirra::Feed.stub!(:last_modified_from_header).and_return('Wed, 28 Jan 2009 04:10:32 GMT')
288
+ end
289
+
290
+ it 'should decode the response body' do
291
+ Feedzirra::Feed.should_receive(:decode_content).with(@easy_curl).and_return(@paul_feed[:xml])
292
+ Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, {})
293
+ @easy_curl.on_success.call(@easy_curl)
294
+ end
295
+
296
+ it 'should determine the xml parser class' do
297
+ Feedzirra::Feed.should_receive(:determine_feed_parser_for_xml).with(@paul_feed[:xml]).and_return(Feedzirra::Parser::AtomFeedBurner)
298
+ Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, {})
299
+ @easy_curl.on_success.call(@easy_curl)
300
+ end
301
+
302
+ it 'should parse the xml' do
303
+ Feedzirra::Parser::AtomFeedBurner.should_receive(:parse).with(@paul_feed[:xml]).and_return(@feed)
304
+ Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, {})
305
+ @easy_curl.on_success.call(@easy_curl)
306
+ end
307
+
308
+ describe 'when a compatible xml parser class is found' do
309
+ it 'should set the last effective url to the feed url' do
310
+ @easy_curl.should_receive(:last_effective_url).and_return(@paul_feed[:url])
311
+ @feed.should_receive(:feed_url=).with(@paul_feed[:url])
312
+ Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, {})
313
+ @easy_curl.on_success.call(@easy_curl)
314
+ end
315
+
316
+ it 'should set the etags on the feed' do
317
+ @feed.should_receive(:etag=).with('ziEyTl4q9GH04BR4jgkImd0GvSE')
318
+ Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, {})
319
+ @easy_curl.on_success.call(@easy_curl)
320
+ end
321
+
322
+ it 'should set the last modified on the feed' do
323
+ @feed.should_receive(:last_modified=).with('Wed, 28 Jan 2009 04:10:32 GMT')
324
+ Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, {})
325
+ @easy_curl.on_success.call(@easy_curl)
326
+ end
327
+
328
+ it 'should add the feed to the responses' do
329
+ responses = {}
330
+ Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], responses, {})
331
+ @easy_curl.on_success.call(@easy_curl)
332
+
333
+ responses.length.should == 1
334
+ responses['http://feeds.feedburner.com/PaulDixExplainsNothing'].should == @feed
335
+ end
336
+
337
+ it 'should call proc if :on_success option is passed' do
338
+ success = lambda { |url, feed| }
339
+ success.should_receive(:call).with(@paul_feed[:url], @feed)
340
+ Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, { :on_success => success })
341
+ @easy_curl.on_success.call(@easy_curl)
342
+ end
343
+ end
344
+
345
+ describe 'when no compatible xml parser class is found' do
346
+ it 'should raise a NoParserAvailable exception'
347
+ end
348
+ end
349
+
350
+ describe 'on failure' do
351
+ before(:each) do
352
+ @headers = "HTTP/1.0 404 Not Found\r\nDate: Thu, 29 Jan 2009 03:55:24 GMT\r\nServer: Apache\r\nX-FB-Host: chi-write6\r\nLast-Modified: Wed, 28 Jan 2009 04:10:32 GMT\r\n"
353
+ @body = 'Page could not be found.'
354
+
355
+ @easy_curl.stub!(:response_code).and_return(404)
356
+ @easy_curl.stub!(:header_str).and_return(@headers)
357
+ @easy_curl.stub!(:body_str).and_return(@body)
358
+ end
359
+
360
+ it 'should call proc if :on_failure option is passed' do
361
+ failure = lambda { |url, feed| }
362
+ failure.should_receive(:call).with(@paul_feed[:url], 404, @headers, @body)
363
+ Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], {}, { :on_failure => failure })
364
+ @easy_curl.on_failure.call(@easy_curl)
365
+ end
366
+
367
+ it 'should return the http code in the responses' do
368
+ responses = {}
369
+ Feedzirra::Feed.add_url_to_multi(@multi, @paul_feed[:url], [], responses, {})
370
+ @easy_curl.on_failure.call(@easy_curl)
371
+
372
+ responses.length.should == 1
373
+ responses[@paul_feed[:url]].should == 404
374
+ end
375
+ end
376
+ end
377
+
378
+ describe "#add_feed_to_multi" do
379
+ before(:each) do
380
+ @multi = Curl::Multi.new(@paul_feed[:url])
381
+ @multi.stub!(:add)
382
+ @easy_curl = Curl::Easy.new(@paul_feed[:url])
383
+ @feed = Feedzirra::Feed.parse(sample_feedburner_atom_feed)
384
+
385
+ Curl::Easy.should_receive(:new).and_yield(@easy_curl)
386
+ end
387
+
388
+ it "should set user agent if it's passed as an option" do
389
+ Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, :user_agent => 'My cool application')
390
+ @easy_curl.headers["User-Agent"].should == 'My cool application'
391
+ end
392
+
393
+ it "should set user agent to default if it's not passed as an option" do
394
+ Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, {})
395
+ @easy_curl.headers["User-Agent"].should == Feedzirra::Feed::USER_AGENT
396
+ end
397
+
398
+ it "should set if modified since as an option if passed"
399
+
400
+ it 'should set follow location to true' do
401
+ @easy_curl.should_receive(:follow_location=).with(true)
402
+ Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, {})
403
+ end
404
+
405
+ it 'should set userpwd for http basic authentication if :http_authentication is passed' do
406
+ Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, :http_authentication => ['myusername', 'mypassword'])
407
+ @easy_curl.userpwd.should == 'myusername:mypassword'
408
+ end
409
+
410
+ it "should set if_none_match as an option if passed" do
411
+ @feed.etag = 'ziEyTl4q9GH04BR4jgkImd0GvSE'
412
+ Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, {})
413
+ @easy_curl.headers["If-None-Match"].should == 'ziEyTl4q9GH04BR4jgkImd0GvSE'
414
+ end
415
+
416
+ describe 'on success' do
417
+ before(:each) do
418
+ @new_feed = @feed.clone
419
+ @feed.stub!(:update_from_feed)
420
+ Feedzirra::Feed.stub!(:decode_content).and_return(@paul_feed[:xml])
421
+ Feedzirra::Feed.stub!(:determine_feed_parser_for_xml).and_return(Feedzirra::Parser::AtomFeedBurner)
422
+ Feedzirra::Parser::AtomFeedBurner.stub!(:parse).and_return(@new_feed)
423
+ Feedzirra::Feed.stub!(:etag_from_header).and_return('ziEyTl4q9GH04BR4jgkImd0GvSE')
424
+ Feedzirra::Feed.stub!(:last_modified_from_header).and_return('Wed, 28 Jan 2009 04:10:32 GMT')
425
+ end
426
+
427
+ it 'should process the next feed in the queue'
428
+
429
+ it 'should parse the updated feed' do
430
+ Feedzirra::Parser::AtomFeedBurner.should_receive(:parse).and_return(@new_feed)
431
+ Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, {})
432
+ @easy_curl.on_success.call(@easy_curl)
433
+ end
434
+
435
+ it 'should set the last effective url to the feed url' do
436
+ @easy_curl.should_receive(:last_effective_url).and_return(@paul_feed[:url])
437
+ @new_feed.should_receive(:feed_url=).with(@paul_feed[:url])
438
+ Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, {})
439
+ @easy_curl.on_success.call(@easy_curl)
440
+ end
441
+
442
+ it 'should set the etags on the feed' do
443
+ @new_feed.should_receive(:etag=).with('ziEyTl4q9GH04BR4jgkImd0GvSE')
444
+ Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, {})
445
+ @easy_curl.on_success.call(@easy_curl)
446
+ end
447
+
448
+ it 'should set the last modified on the feed' do
449
+ @new_feed.should_receive(:last_modified=).with('Wed, 28 Jan 2009 04:10:32 GMT')
450
+ Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, {})
451
+ @easy_curl.on_success.call(@easy_curl)
452
+ end
453
+
454
+ it 'should add the feed to the responses' do
455
+ responses = {}
456
+ Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], responses, {})
457
+ @easy_curl.on_success.call(@easy_curl)
458
+
459
+ responses.length.should == 1
460
+ responses['http://feeds.feedburner.com/PaulDixExplainsNothing'].should == @feed
461
+ end
462
+
463
+ it 'should call proc if :on_success option is passed' do
464
+ success = lambda { |feed| }
465
+ success.should_receive(:call).with(@feed)
466
+ Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, { :on_success => success })
467
+ @easy_curl.on_success.call(@easy_curl)
468
+ end
469
+
470
+ it 'should call update from feed on the old feed with the updated feed' do
471
+ @feed.should_receive(:update_from_feed).with(@new_feed)
472
+ Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, {})
473
+ @easy_curl.on_success.call(@easy_curl)
474
+ end
475
+ end
476
+
477
+ describe 'on failure' do
478
+ before(:each) do
479
+ @headers = "HTTP/1.0 404 Not Found\r\nDate: Thu, 29 Jan 2009 03:55:24 GMT\r\nServer: Apache\r\nX-FB-Host: chi-write6\r\nLast-Modified: Wed, 28 Jan 2009 04:10:32 GMT\r\n"
480
+ @body = 'Page could not be found.'
481
+
482
+ @easy_curl.stub!(:response_code).and_return(404)
483
+ @easy_curl.stub!(:header_str).and_return(@headers)
484
+ @easy_curl.stub!(:body_str).and_return(@body)
485
+ end
486
+
487
+ it 'should call on success callback if the response code is 304' do
488
+ success = lambda { |feed| }
489
+ success.should_receive(:call).with(@feed)
490
+ @easy_curl.should_receive(:response_code).and_return(304)
491
+ Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], {}, { :on_success => success })
492
+ @easy_curl.on_failure.call(@easy_curl)
493
+ end
494
+
495
+ it 'should return the http code in the responses' do
496
+ responses = {}
497
+ Feedzirra::Feed.add_feed_to_multi(@multi, @feed, [], responses, {})
498
+ @easy_curl.on_failure.call(@easy_curl)
499
+
500
+ responses.length.should == 1
501
+ responses['http://www.pauldix.net/'].should == 404
502
+ end
503
+ end
504
+ end
505
+
506
+ describe "#fetch_and_parse" do
507
+ describe "with curl" do
508
+ before(:each) do
509
+ Feedzirra.should_receive(:use_curb?).and_return(true)
510
+ end
511
+ it 'should initiate the fetching and parsing using multicurl' do
512
+ @curl_multi = mock('curl_multi')
513
+ @curl_multi.should_receive(:perform)
514
+ Curl::Multi.should_receive(:new).and_return(@curl_multi)
515
+ Feedzirra::Feed.fetch_and_parse('')
516
+ end
517
+ it "should pass any request options through to add_url_to_multi"
518
+ it 'should slice the feeds into groups of thirty for processing'
519
+ it "should return a feed object if a single feed is passed in"
520
+ it "should return an return an array of feed objects if multiple feeds are passed in"
521
+ end
522
+ describe "without curl" do
523
+ before(:each) do
524
+ Feedzirra.should_receive(:use_curb?).and_return(false)
525
+ end
526
+ it 'should initiate the fetching and parsing using Net::HTTP' do
527
+ url = 'http://engadget.com/rss.xml'
528
+ responses = Feedzirra::Feed.fetch_and_parse(url)
529
+ responses.should_not == nil
530
+ end
531
+ it "should return a feed object if a single feed is passed in" do
532
+ url = 'http://engadget.com/rss.xml'
533
+ responses = Feedzirra::Feed.fetch_and_parse(url)
534
+ responses.title.should == 'Engadget'
535
+ responses.entries.length.should == 40
536
+ end
537
+ it "should return an return an hash of feed objects if multiple feeds are passed in" do
538
+ responses = Feedzirra::Feed.fetch_and_parse(
539
+ ['http://engadget.com/rss.xml', 'http://gizmodo.com/index.xml']
540
+ )
541
+ responses.length.should == 2
542
+ end
543
+ end
544
+ end
545
+
546
+ describe "#decode_content" do
547
+ before(:each) do
548
+ @curl_easy = mock('curl_easy', :body_str => '<xml></xml>')
549
+ end
550
+
551
+ it 'should decode the response body using gzip if the Content-Encoding: is gzip' do
552
+ @curl_easy.stub!(:header_str).and_return('Content-Encoding: gzip')
553
+ string_io = mock('stringio', :read => @curl_easy.body_str, :close => true)
554
+ StringIO.should_receive(:new).and_return(string_io)
555
+ Zlib::GzipReader.should_receive(:new).with(string_io).and_return(string_io)
556
+ Feedzirra::Feed.decode_content(@curl_easy)
557
+ end
558
+
559
+ it 'should deflate the response body using inflate if the Content-Encoding: is deflate' do
560
+ @curl_easy.stub!(:header_str).and_return('Content-Encoding: deflate')
561
+ Zlib::Inflate.should_receive(:inflate).with(@curl_easy.body_str)
562
+ Feedzirra::Feed.decode_content(@curl_easy)
563
+ end
564
+
565
+ it 'should return the response body if it is not encoded' do
566
+ @curl_easy.stub!(:header_str).and_return('')
567
+ Feedzirra::Feed.decode_content(@curl_easy).should == '<xml></xml>'
568
+ end
569
+ end
570
+
571
+ describe "#update" do
572
+ it 'should perform the updating using multicurl'
573
+ it "should pass any request options through to add_feed_to_multi"
574
+ it "should return a feed object if a single feed is passed in"
575
+ it "should return an return an array of feed objects if multiple feeds are passed in"
576
+ end
577
+ end
578
+ end