dinsley-feedzirra 0.0.8

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