Spectives-feedzirra 0.0.28

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/README.rdoc +169 -0
  2. data/README.textile +205 -0
  3. data/Rakefile +56 -0
  4. data/lib/core_ext/date.rb +21 -0
  5. data/lib/core_ext/string.rb +9 -0
  6. data/lib/feedzirra/feed.rb +334 -0
  7. data/lib/feedzirra/feed_entry_utilities.rb +45 -0
  8. data/lib/feedzirra/feed_utilities.rb +71 -0
  9. data/lib/feedzirra/parser/atom.rb +35 -0
  10. data/lib/feedzirra/parser/atom_entry.rb +41 -0
  11. data/lib/feedzirra/parser/itunes_category.rb +12 -0
  12. data/lib/feedzirra/parser/mrss_category.rb +11 -0
  13. data/lib/feedzirra/parser/mrss_content.rb +48 -0
  14. data/lib/feedzirra/parser/mrss_copyright.rb +10 -0
  15. data/lib/feedzirra/parser/mrss_credit.rb +11 -0
  16. data/lib/feedzirra/parser/mrss_group.rb +37 -0
  17. data/lib/feedzirra/parser/mrss_hash.rb +10 -0
  18. data/lib/feedzirra/parser/mrss_player.rb +11 -0
  19. data/lib/feedzirra/parser/mrss_rating.rb +10 -0
  20. data/lib/feedzirra/parser/mrss_restriction.rb +11 -0
  21. data/lib/feedzirra/parser/mrss_text.rb +13 -0
  22. data/lib/feedzirra/parser/mrss_thumbnail.rb +11 -0
  23. data/lib/feedzirra/parser/rss.rb +83 -0
  24. data/lib/feedzirra/parser/rss_entry.rb +83 -0
  25. data/lib/feedzirra/parser/rss_image.rb +15 -0
  26. data/lib/feedzirra.rb +44 -0
  27. data/spec/benchmarks/feed_benchmarks.rb +98 -0
  28. data/spec/benchmarks/feedzirra_benchmarks.rb +40 -0
  29. data/spec/benchmarks/fetching_benchmarks.rb +28 -0
  30. data/spec/benchmarks/parsing_benchmark.rb +30 -0
  31. data/spec/benchmarks/updating_benchmarks.rb +33 -0
  32. data/spec/feedzirra/feed_entry_utilities_spec.rb +52 -0
  33. data/spec/feedzirra/feed_spec.rb +546 -0
  34. data/spec/feedzirra/feed_utilities_spec.rb +149 -0
  35. data/spec/feedzirra/parser/atom_entry_spec.rb +49 -0
  36. data/spec/feedzirra/parser/atom_feed_burner_entry_spec.rb +42 -0
  37. data/spec/feedzirra/parser/atom_feed_burner_spec.rb +39 -0
  38. data/spec/feedzirra/parser/atom_spec.rb +43 -0
  39. data/spec/feedzirra/parser/mrss_content_spec.rb +32 -0
  40. data/spec/feedzirra/parser/rss_entry_spec.rb +154 -0
  41. data/spec/feedzirra/parser/rss_spec.rb +93 -0
  42. data/spec/sample_feeds/run_against_sample.rb +20 -0
  43. data/spec/spec_helper.rb +62 -0
  44. metadata +154 -0
@@ -0,0 +1,546 @@
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 == 4
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
+ it 'should initiate the fetching and parsing using multicurl'
508
+ it "should pass any request options through to add_url_to_multi"
509
+ it 'should slice the feeds into groups of thirty for processing'
510
+ it "should return a feed object if a single feed is passed in"
511
+ it "should return an return an array of feed objects if multiple feeds are passed in"
512
+ end
513
+
514
+ describe "#decode_content" do
515
+ before(:each) do
516
+ @curl_easy = mock('curl_easy', :body_str => '<xml></xml>')
517
+ end
518
+
519
+ it 'should decode the response body using gzip if the Content-Encoding: is gzip' do
520
+ @curl_easy.stub!(:header_str).and_return('Content-Encoding: gzip')
521
+ string_io = mock('stringio', :read => @curl_easy.body_str, :close => true)
522
+ StringIO.should_receive(:new).and_return(string_io)
523
+ Zlib::GzipReader.should_receive(:new).with(string_io).and_return(string_io)
524
+ Feedzirra::Feed.decode_content(@curl_easy)
525
+ end
526
+
527
+ it 'should deflate the response body using inflate if the Content-Encoding: is deflate' do
528
+ @curl_easy.stub!(:header_str).and_return('Content-Encoding: deflate')
529
+ Zlib::Inflate.should_receive(:inflate).with(@curl_easy.body_str)
530
+ Feedzirra::Feed.decode_content(@curl_easy)
531
+ end
532
+
533
+ it 'should return the response body if it is not encoded' do
534
+ @curl_easy.stub!(:header_str).and_return('')
535
+ Feedzirra::Feed.decode_content(@curl_easy).should == '<xml></xml>'
536
+ end
537
+ end
538
+
539
+ describe "#update" do
540
+ it 'should perform the updating using multicurl'
541
+ it "should pass any request options through to add_feed_to_multi"
542
+ it "should return a feed object if a single feed is passed in"
543
+ it "should return an return an array of feed objects if multiple feeds are passed in"
544
+ end
545
+ end
546
+ end