pauldix-feedzirra 0.0.3 → 0.0.5

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