ratom-instructure 0.6.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/History.txt +135 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +293 -0
  4. data/Rakefile +59 -0
  5. data/VERSION.yml +5 -0
  6. data/lib/atom.rb +796 -0
  7. data/lib/atom/configuration.rb +24 -0
  8. data/lib/atom/pub.rb +251 -0
  9. data/lib/atom/version.rb +7 -0
  10. data/lib/atom/xml/parser.rb +413 -0
  11. data/ratom.gemspec +95 -0
  12. data/spec/app/member_entry.atom +31 -0
  13. data/spec/app/service.xml +36 -0
  14. data/spec/app/service_xml_base.xml +37 -0
  15. data/spec/atom/pub_spec.rb +517 -0
  16. data/spec/atom_spec.rb +1385 -0
  17. data/spec/conformance/baseuri.atom +19 -0
  18. data/spec/conformance/divtest.atom +32 -0
  19. data/spec/conformance/linktests.xml +103 -0
  20. data/spec/conformance/nondefaultnamespace-baseline.atom +25 -0
  21. data/spec/conformance/nondefaultnamespace-xhtml.atom +25 -0
  22. data/spec/conformance/nondefaultnamespace.atom +25 -0
  23. data/spec/conformance/ordertest.xml +112 -0
  24. data/spec/conformance/title/html-cdata.atom +22 -0
  25. data/spec/conformance/title/html-entity.atom +22 -0
  26. data/spec/conformance/title/html-ncr.atom +22 -0
  27. data/spec/conformance/title/text-cdata.atom +22 -0
  28. data/spec/conformance/title/text-entity.atom +21 -0
  29. data/spec/conformance/title/text-ncr.atom +21 -0
  30. data/spec/conformance/title/xhtml-entity.atom +21 -0
  31. data/spec/conformance/title/xhtml-ncr.atom +21 -0
  32. data/spec/conformance/unknown-namespace.atom +25 -0
  33. data/spec/conformance/xmlbase.atom +133 -0
  34. data/spec/fixtures/complex_single_entry.atom +45 -0
  35. data/spec/fixtures/created_entry.atom +31 -0
  36. data/spec/fixtures/entry.atom +30 -0
  37. data/spec/fixtures/entry_with_custom_extensions.atom +8 -0
  38. data/spec/fixtures/entry_with_simple_extensions.atom +31 -0
  39. data/spec/fixtures/entry_with_single_custom_extension.atom +6 -0
  40. data/spec/fixtures/multiple_entry.atom +0 -0
  41. data/spec/fixtures/simple_single_entry.atom +21 -0
  42. data/spec/fixtures/with_stylesheet.atom +8 -0
  43. data/spec/paging/first_paged_feed.atom +21 -0
  44. data/spec/paging/last_paged_feed.atom +21 -0
  45. data/spec/paging/middle_paged_feed.atom +22 -0
  46. data/spec/property.rb +31 -0
  47. data/spec/spec.opts +1 -0
  48. data/spec/spec_helper.rb +46 -0
  49. metadata +147 -0
@@ -0,0 +1,95 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{ratom-instructure}
8
+ s.version = "0.6.9"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Peerworks", "Sean Geoghegan", "Jacob Fugal"]
12
+ s.date = %q{2011-07-13}
13
+ s.description = %q{A fast Atom Syndication and Publication API based on libxml}
14
+ s.email = %q{seangeo@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ "History.txt",
21
+ "LICENSE",
22
+ "README.rdoc",
23
+ "Rakefile",
24
+ "VERSION.yml",
25
+ "lib/atom.rb",
26
+ "lib/atom/configuration.rb",
27
+ "lib/atom/pub.rb",
28
+ "lib/atom/version.rb",
29
+ "lib/atom/xml/parser.rb",
30
+ "ratom.gemspec",
31
+ "spec/app/member_entry.atom",
32
+ "spec/app/service.xml",
33
+ "spec/app/service_xml_base.xml",
34
+ "spec/atom/pub_spec.rb",
35
+ "spec/atom_spec.rb",
36
+ "spec/conformance/baseuri.atom",
37
+ "spec/conformance/divtest.atom",
38
+ "spec/conformance/linktests.xml",
39
+ "spec/conformance/nondefaultnamespace-baseline.atom",
40
+ "spec/conformance/nondefaultnamespace-xhtml.atom",
41
+ "spec/conformance/nondefaultnamespace.atom",
42
+ "spec/conformance/ordertest.xml",
43
+ "spec/conformance/title/html-cdata.atom",
44
+ "spec/conformance/title/html-entity.atom",
45
+ "spec/conformance/title/html-ncr.atom",
46
+ "spec/conformance/title/text-cdata.atom",
47
+ "spec/conformance/title/text-entity.atom",
48
+ "spec/conformance/title/text-ncr.atom",
49
+ "spec/conformance/title/xhtml-entity.atom",
50
+ "spec/conformance/title/xhtml-ncr.atom",
51
+ "spec/conformance/unknown-namespace.atom",
52
+ "spec/conformance/xmlbase.atom",
53
+ "spec/fixtures/complex_single_entry.atom",
54
+ "spec/fixtures/created_entry.atom",
55
+ "spec/fixtures/entry.atom",
56
+ "spec/fixtures/entry_with_custom_extensions.atom",
57
+ "spec/fixtures/entry_with_simple_extensions.atom",
58
+ "spec/fixtures/entry_with_single_custom_extension.atom",
59
+ "spec/fixtures/multiple_entry.atom",
60
+ "spec/fixtures/simple_single_entry.atom",
61
+ "spec/fixtures/with_stylesheet.atom",
62
+ "spec/paging/first_paged_feed.atom",
63
+ "spec/paging/last_paged_feed.atom",
64
+ "spec/paging/middle_paged_feed.atom",
65
+ "spec/property.rb",
66
+ "spec/spec.opts",
67
+ "spec/spec_helper.rb"
68
+ ]
69
+ s.homepage = %q{http://github.com/lukfugl/ratom}
70
+ s.require_paths = ["lib"]
71
+ s.rubygems_version = %q{1.6.2}
72
+ s.summary = %q{Atom Syndication and Publication API}
73
+ s.test_files = [
74
+ "spec/atom/pub_spec.rb",
75
+ "spec/atom_spec.rb",
76
+ "spec/property.rb",
77
+ "spec/spec_helper.rb"
78
+ ]
79
+
80
+ if s.respond_to? :specification_version then
81
+ s.specification_version = 3
82
+
83
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
84
+ s.add_development_dependency(%q<rspec>, [">= 0"])
85
+ s.add_runtime_dependency(%q<libxml-ruby>, [">= 1.1.2"])
86
+ else
87
+ s.add_dependency(%q<rspec>, [">= 0"])
88
+ s.add_dependency(%q<libxml-ruby>, [">= 1.1.2"])
89
+ end
90
+ else
91
+ s.add_dependency(%q<rspec>, [">= 0"])
92
+ s.add_dependency(%q<libxml-ruby>, [">= 1.1.2"])
93
+ end
94
+ end
95
+
@@ -0,0 +1,31 @@
1
+ <?xml version="1.0" ?>
2
+ <entry xmlns="http://www.w3.org/2005/Atom">
3
+ <title>Atom draft-07 snapshot</title>
4
+ <link rel="alternate" type="text/html"
5
+ href="http://example.org/2005/04/02/atom"/>
6
+ <link rel="edit" href="http://example.org/member_entry.atom"/>
7
+ <link rel="enclosure" type="audio/mpeg" length="1337"
8
+ href="http://example.org/audio/ph34r_my_podcast.mp3"/>
9
+ <id>tag:example.org,2003:3.2397</id>
10
+ <updated>2005-07-31T12:29:29Z</updated>
11
+ <published>2003-12-13T08:29:29-04:00</published>
12
+ <author>
13
+ <name>Mark Pilgrim</name>
14
+ <uri>http://example.org/</uri>
15
+ <email>f8dy@example.com</email>
16
+ </author>
17
+ <contributor>
18
+ <name>Sam Ruby</name>
19
+ </contributor>
20
+ <contributor>
21
+ <name>Joe Gregorio</name>
22
+ </contributor>
23
+ <content type="xhtml" xml:lang="en"
24
+ xml:base="http://diveintomark.org/">
25
+ <div xmlns="http://www.w3.org/1999/xhtml">
26
+ <p>
27
+ <i>[Update: The Atom draft is finished.]</i>
28
+ </p>
29
+ </div>
30
+ </content>
31
+ </entry>
@@ -0,0 +1,36 @@
1
+ <?xml version="1.0" encoding='utf-8'?>
2
+ <service xmlns="http://www.w3.org/2007/app"
3
+ xmlns:atom="http://www.w3.org/2005/Atom">
4
+ <workspace>
5
+ <atom:title>Main Site</atom:title>
6
+ <collection
7
+ href="http://example.org/blog/main" >
8
+ <atom:title>My Blog Entries</atom:title>
9
+ <categories
10
+ href="http://example.org/cats/forMain.cats" />
11
+ </collection>
12
+ <collection
13
+ href="http://example.org/blog/pic" >
14
+ <atom:title>Pictures</atom:title>
15
+ <accept>image/png</accept>
16
+ <accept>image/jpeg</accept>
17
+ <accept>image/gif</accept>
18
+ </collection>
19
+ </workspace>
20
+ <workspace>
21
+ <atom:title>Sidebar Blog</atom:title>
22
+ <collection
23
+ href="http://example.org/sidebar/list" >
24
+ <atom:title>Remaindered Links</atom:title>
25
+ <accept>application/atom+xml;type=entry</accept>
26
+ <categories fixed="yes">
27
+ <atom:category
28
+ scheme="http://example.org/extra-cats/"
29
+ term="joke" />
30
+ <atom:category
31
+ scheme="http://example.org/extra-cats/"
32
+ term="serious" />
33
+ </categories>
34
+ </collection>
35
+ </workspace>
36
+ </service>
@@ -0,0 +1,37 @@
1
+ <?xml version="1.0" encoding='utf-8'?>
2
+ <service xmlns="http://www.w3.org/2007/app"
3
+ xmlns:atom="http://www.w3.org/2005/Atom"
4
+ xml:base="http://example.org/">
5
+ <workspace>
6
+ <atom:title>Main Site</atom:title>
7
+ <collection
8
+ href="/blog/main" >
9
+ <atom:title>My Blog Entries</atom:title>
10
+ <categories
11
+ href="/cats/forMain.cats" />
12
+ </collection>
13
+ <collection
14
+ href="http://example.org/blog/pic" >
15
+ <atom:title>Pictures</atom:title>
16
+ <accept>image/png</accept>
17
+ <accept>image/jpeg</accept>
18
+ <accept>image/gif</accept>
19
+ </collection>
20
+ </workspace>
21
+ <workspace>
22
+ <atom:title>Sidebar Blog</atom:title>
23
+ <collection
24
+ href="http://example.org/sidebar/list" >
25
+ <atom:title>Remaindered Links</atom:title>
26
+ <accept>application/atom+xml;type=entry</accept>
27
+ <categories fixed="yes">
28
+ <atom:category
29
+ scheme="http://example.org/extra-cats/"
30
+ term="joke" />
31
+ <atom:category
32
+ scheme="http://example.org/extra-cats/"
33
+ term="serious" />
34
+ </categories>
35
+ </collection>
36
+ </workspace>
37
+ </service>
@@ -0,0 +1,517 @@
1
+ # Copyright (c) 2008 The Kaphan Foundation
2
+ #
3
+ # For licensing information see LICENSE.
4
+ #
5
+ # Please visit http://www.peerworks.org/contact for further information.
6
+ #
7
+
8
+ require File.dirname(__FILE__) + '/../spec_helper'
9
+ require 'atom'
10
+ require 'atom/pub'
11
+ require 'atom/version'
12
+ require 'uri'
13
+ require 'net/http'
14
+
15
+ shared_examples_for 'parser of spec/app/service.xml' do
16
+ it "should have 2 workspaces" do
17
+ @service.should have(2).workspaces
18
+ end
19
+
20
+ it "should have a title" do
21
+ @workspace.title.should == "Main Site"
22
+ end
23
+
24
+ it "should have 2 collections" do
25
+ @workspace.should have(2).collections
26
+ end
27
+
28
+ it "should have the right href" do
29
+ @collection1.href.should == 'http://example.org/blog/main'
30
+ end
31
+
32
+ it "should have categories" do
33
+ @collection1.categories.should_not be_nil
34
+ end
35
+
36
+ it "should have a href on categories" do
37
+ @collection1.categories.href.should == "http://example.org/cats/forMain.cats"
38
+ @collection1.categories.fixed?.should be_false
39
+ end
40
+
41
+ it "should have a title" do
42
+ @collection1.title.should == 'My Blog Entries'
43
+ end
44
+
45
+ it "should have a title" do
46
+ @collection2.title.should == 'Pictures'
47
+ end
48
+
49
+ it "should have the right href" do
50
+ @collection2.href.should == 'http://example.org/blog/pic'
51
+ end
52
+
53
+ it "should not have categories" do
54
+ @collection2.categories.should be_nil
55
+ end
56
+
57
+ it "should have 3 accepts" do
58
+ @collection2.should have(3).accepts
59
+ end
60
+
61
+ it "should accept 'image/png'" do
62
+ @collection2.accepts.should include('image/png')
63
+ end
64
+
65
+ it "should accept 'image/jpeg'" do
66
+ @collection2.accepts.should include('image/jpeg')
67
+ end
68
+
69
+ it "should accept 'image/gif'" do
70
+ @collection2.accepts.should include('image/gif')
71
+ end
72
+
73
+ it "should have a title on workspace 2" do
74
+ @workspace2.title.should == 'Sidebar Blog'
75
+ end
76
+
77
+ it "should have 1 collection on workspace 2" do
78
+ @workspace2.should have(1).collections
79
+ end
80
+
81
+ it "should have a title on collection 3" do
82
+ @collection3.title.should == 'Remaindered Links'
83
+ end
84
+
85
+ it "should have 1 accept on collection 3" do
86
+ @collection3.should have(1).accepts
87
+ end
88
+
89
+ it "should accept 'application/atom+xml;type=entry'" do
90
+ @collection3.accepts.should include('application/atom+xml;type=entry')
91
+ end
92
+
93
+ it "should have categories" do
94
+ @collection3.categories.should_not be_nil
95
+ end
96
+
97
+ it "should have fixed == 'yes' on categories" do
98
+ @collection3.categories.fixed.should == "yes"
99
+ end
100
+
101
+ it "should have fixed? == true on categories" do
102
+ @collection3.categories.fixed?.should be_true
103
+ end
104
+ end
105
+
106
+ describe Atom::Pub do
107
+ describe Atom::Pub::Service do
108
+ it "should load from a URL" do
109
+ uri = URI.parse('http://example.com/service.xml')
110
+ response = Net::HTTPSuccess.new(nil, nil, nil)
111
+ response.stub!(:body).and_return(File.read('spec/app/service.xml'))
112
+ mock_http_get(uri, response)
113
+
114
+ Atom::Pub::Service.load_service(uri).should be_an_instance_of(Atom::Pub::Service)
115
+ end
116
+
117
+ it "should raise ArgumentError with a non-http URL" do
118
+ lambda { Atom::Pub::Service.load_service(URI.parse('file:/tmp')) }.should raise_error(ArgumentError)
119
+ end
120
+
121
+ it "should be able to be created without xml" do
122
+ lambda { Atom::Pub::Service.new }.should_not raise_error
123
+ end
124
+
125
+ it "should yield in the initializer" do
126
+ yielded = false
127
+ Atom::Pub::Service.new do
128
+ yielded = true
129
+ end
130
+
131
+ yielded.should be_true
132
+ end
133
+
134
+ it "should parse it's output" do
135
+ orig = File.read('spec/app/service.xml')
136
+ svc = Atom::Pub::Service.load_service(orig)
137
+ xml = svc.to_xml
138
+ lambda do
139
+ Atom::Pub::Service.load_service(xml)
140
+ end.should_not raise_error
141
+ end
142
+
143
+ describe "load_service" do
144
+ before(:all) do
145
+ @service = Atom::Pub::Service.load_service(File.open('spec/app/service.xml'))
146
+ @workspace = @service.workspaces.first
147
+ @workspace2 = @service.workspaces[1]
148
+ @collection1 = @workspace.collections.first
149
+ @collection2 = @workspace.collections[1]
150
+ @collection3 = @workspace2.collections.first
151
+ end
152
+
153
+ it_should_behave_like 'parser of spec/app/service.xml'
154
+ end
155
+
156
+ describe "load service with xml:base" do
157
+ before(:all) do
158
+ @service = Atom::Pub::Service.load_service(File.open('spec/app/service_xml_base.xml'))
159
+ @workspace = @service.workspaces.first
160
+ @workspace2 = @service.workspaces[1]
161
+ @collection1 = @workspace.collections.first
162
+ @collection2 = @workspace.collections[1]
163
+ @collection3 = @workspace2.collections.first
164
+ end
165
+
166
+ it_should_behave_like 'parser of spec/app/service.xml'
167
+ end
168
+
169
+ describe "load_service with authentication" do
170
+ it "should pass credentials to the server" do
171
+ uri = URI.parse('http://example.com/service.xml')
172
+ response = Net::HTTPSuccess.new(nil, nil, nil)
173
+ response.stub!(:body).and_return(File.read('spec/app/service.xml'))
174
+ mock_http_get(uri, response, 'user', 'pass')
175
+ Atom::Pub::Service.load_service(uri, :user => 'user', :pass => 'pass')
176
+ end
177
+
178
+ it "should pass credentials on to the collections" do
179
+ uri = URI.parse('http://example.com/service.xml')
180
+ response = Net::HTTPSuccess.new(nil, nil, nil)
181
+ response.stub!(:body).and_return(File.read('spec/app/service.xml'))
182
+ mock_http_get(uri, response, 'user', 'pass')
183
+ pub = Atom::Pub::Service.load_service(uri, :user => 'user', :pass => 'pass')
184
+
185
+ uri2 = URI.parse('http://example.org/blog/main')
186
+ response2 = Net::HTTPSuccess.new(nil, nil, nil)
187
+ response2.stub!(:body).and_return(File.read('spec/fixtures/simple_single_entry.atom'))
188
+ mock_http_get(uri2, response2, 'user', 'pass')
189
+ pub.workspaces.first.collections.first.feed(:user => 'user', :pass => 'pass')
190
+ end
191
+ end
192
+
193
+ describe "#to_xml" do
194
+ before(:each) do
195
+ @svc = Atom::Pub::Service.load_service(File.read('spec/app/service.xml'))
196
+ @xml = @svc.to_xml
197
+ @service = Atom::Pub::Service.load_service(@xml)
198
+ @workspace = @service.workspaces.first
199
+ @workspace2 = @service.workspaces[1]
200
+ @collection1 = @workspace.collections.first
201
+ @collection2 = @workspace.collections[1]
202
+ @collection3 = @workspace2.collections.first
203
+ end
204
+
205
+ it "should put title in Atom namespace" do
206
+ @xml.should match(%r{atom:title})
207
+ end
208
+
209
+ it_should_behave_like 'parser of spec/app/service.xml'
210
+ end
211
+ end
212
+
213
+ describe Atom::Pub::Collection do
214
+ describe '.new' do
215
+ it "should set the href from the hash" do
216
+ collection = Atom::Pub::Collection.new(:href => 'http://example.org/blog')
217
+ collection.href.should == 'http://example.org/blog'
218
+ end
219
+
220
+ it "should set the href from a block" do
221
+ collection = Atom::Pub::Collection.new do |c|
222
+ c.href = "http://example.org/blog"
223
+ end
224
+ collection.href.should == 'http://example.org/blog'
225
+ end
226
+ end
227
+
228
+ it "should return the feed" do
229
+ collection = Atom::Pub::Collection.new(:href => 'http://example.org/blog')
230
+ response = Net::HTTPSuccess.new(nil, nil, nil)
231
+ response.stub!(:body).and_return(File.read('spec/fixtures/simple_single_entry.atom'))
232
+ mock_http_get(URI.parse(collection.href), response)
233
+ collection.feed.should be_an_instance_of(Atom::Feed)
234
+ end
235
+
236
+ describe '#publish' do
237
+ before(:each) do
238
+ @collection = Atom::Pub::Collection.new(:href => 'http://example.org/blog')
239
+ @request_headers = {'Accept' => 'application/atom+xml',
240
+ 'Content-Type' => 'application/atom+xml;type=entry',
241
+ 'User-Agent' => "rAtom #{Atom::VERSION::STRING}"
242
+ }
243
+ end
244
+
245
+ it "should send a POST request when an entry is published" do
246
+ entry = Atom::Entry.load_entry(File.open('spec/fixtures/entry.atom'))
247
+
248
+ response = mock_response(Net::HTTPCreated, entry.to_xml.to_s)
249
+
250
+ request = mock('request')
251
+ Net::HTTP::Post.should_receive(:new).with('/blog', @request_headers).and_return(request)
252
+
253
+ http = mock('http')
254
+ http.should_receive(:request).with(request, entry.to_xml.to_s).and_return(response)
255
+ Net::HTTP.should_receive(:start).with('example.org', 80).and_yield(http)
256
+
257
+ created = @collection.publish(entry)
258
+ created.should == entry
259
+ end
260
+
261
+ it "should send a POST with basic auth request when an entry is published" do
262
+ entry = Atom::Entry.load_entry(File.open('spec/fixtures/entry.atom'))
263
+
264
+ response = mock_response(Net::HTTPCreated, entry.to_xml.to_s)
265
+
266
+ request = mock('request')
267
+ request.should_receive(:basic_auth).with('user', 'pass')
268
+ Net::HTTP::Post.should_receive(:new).with('/blog', @request_headers).and_return(request)
269
+
270
+ http = mock('http')
271
+ http.should_receive(:request).with(request, entry.to_xml.to_s).and_return(response)
272
+ Net::HTTP.should_receive(:start).with('example.org', 80).and_yield(http)
273
+
274
+ created = @collection.publish(entry, :user => 'user', :pass => 'pass')
275
+ created.should == entry
276
+ end
277
+
278
+ if Atom::Configuration.auth_hmac_enabled?
279
+ it "should send a POST with hmac authentication when an entry is published" do
280
+ entry = Atom::Entry.load_entry(File.open('spec/fixtures/entry.atom'))
281
+
282
+ response = mock_response(Net::HTTPCreated, entry.to_xml.to_s)
283
+
284
+ http = mock('http')
285
+ http.should_receive(:request) do |request, entry_xml|
286
+ request['Authorization'].should match(/^AuthHMAC access_id:[a-zA-Z0-9\/+]+=*/)
287
+ response
288
+ end
289
+
290
+ Net::HTTP.should_receive(:start).with('example.org', 80).and_yield(http)
291
+
292
+ created = @collection.publish(entry, :hmac_access_id => 'access_id', :hmac_secret_key => 'secret')
293
+ created.should == entry
294
+ end
295
+ else
296
+ xit "should send a POST with hmac authentication when an entry is published"
297
+ end
298
+
299
+ it "should behave well when no content is returned" do
300
+ entry = Atom::Entry.load_entry(File.open('spec/fixtures/entry.atom'))
301
+
302
+ response = mock_response(Net::HTTPCreated, " ")
303
+
304
+ request = mock('request')
305
+ Net::HTTP::Post.should_receive(:new).with('/blog', @request_headers).and_return(request)
306
+
307
+ http = mock('http')
308
+ http.should_receive(:request).with(request, entry.to_xml.to_s).and_return(response)
309
+ Net::HTTP.should_receive(:start).with('example.org', 80).and_yield(http)
310
+
311
+ created = @collection.publish(entry)
312
+ created.should == entry
313
+ end
314
+
315
+ it "should raise error when response is not HTTPCreated" do
316
+ entry = Atom::Entry.load_entry(File.open('spec/fixtures/entry.atom'))
317
+ response = mock_response(Net::HTTPPreconditionFailed, "")
318
+
319
+ request = mock('request')
320
+ Net::HTTP::Post.should_receive(:new).with('/blog', @request_headers).and_return(request)
321
+
322
+ http = mock('http')
323
+ http.should_receive(:request).with(request, entry.to_xml.to_s).and_return(response)
324
+ Net::HTTP.should_receive(:start).with('example.org', 80).and_yield(http)
325
+
326
+ lambda { @collection.publish(entry) }.should raise_error(Atom::Pub::ProtocolError)
327
+ end
328
+
329
+ it "should copy Location into edit link of entry" do
330
+ entry = Atom::Entry.load_entry(File.open('spec/fixtures/entry.atom'))
331
+
332
+ response = mock_response(Net::HTTPCreated, entry.to_xml.to_s, 'Location' => 'http://example.org/edit/entry1.atom')
333
+
334
+ request = mock('request')
335
+ Net::HTTP::Post.should_receive(:new).with('/blog', @request_headers).and_return(request)
336
+
337
+ http = mock('http')
338
+ http.should_receive(:request).with(request, entry.to_xml.to_s).and_return(response)
339
+ Net::HTTP.should_receive(:start).with('example.org', 80).and_yield(http)
340
+
341
+ created = @collection.publish(entry)
342
+ created.edit_link.should_not be_nil
343
+ created.edit_link.href.should == 'http://example.org/edit/entry1.atom'
344
+ end
345
+
346
+ it "should update the entry when response is different" do
347
+ entry = Atom::Entry.load_entry(File.open('spec/fixtures/entry.atom'))
348
+ response = mock_response(Net::HTTPCreated, File.read('spec/fixtures/created_entry.atom'),
349
+ 'Location' => 'http://example.org/edit/atom')
350
+
351
+ request = mock('request')
352
+ Net::HTTP::Post.should_receive(:new).with('/blog', @request_headers).and_return(request)
353
+
354
+ http = mock('http')
355
+ http.should_receive(:request).with(request, entry.to_xml.to_s).and_return(response)
356
+ Net::HTTP.should_receive(:start).with('example.org', 80).and_yield(http)
357
+
358
+ created = @collection.publish(entry)
359
+ created.should == Atom::Entry.load_entry(File.open('spec/fixtures/created_entry.atom'))
360
+ end
361
+ end
362
+ end
363
+
364
+ describe Atom::Pub::Workspace do
365
+ it "should do the block initialization thing" do
366
+ workspace = Atom::Pub::Workspace.new do |w|
367
+ w.title = "Title"
368
+ end
369
+
370
+ workspace.title.should == "Title"
371
+ end
372
+
373
+ it "should do the hash initialization thing" do
374
+ workspace = Atom::Pub::Workspace.new(:title => 'Title')
375
+ workspace.title.should == "Title"
376
+ end
377
+ end
378
+
379
+ describe Atom::Entry do
380
+ before(:each) do
381
+ @request_headers = {'Accept' => 'application/atom+xml',
382
+ 'Content-Type' => 'application/atom+xml;type=entry',
383
+ 'User-Agent' => "rAtom #{Atom::VERSION::STRING}"
384
+ }
385
+ end
386
+
387
+ it "should send a PUT to the edit link on save!" do
388
+ entry = Atom::Entry.load_entry(File.open('spec/app/member_entry.atom'))
389
+ response = mock_response(Net::HTTPSuccess, nil)
390
+
391
+ request = mock('request')
392
+ Net::HTTP::Put.should_receive(:new).with('/member_entry.atom', @request_headers).and_return(request)
393
+
394
+ http = mock('http')
395
+ http.should_receive(:request).with(request, entry.to_xml.to_s).and_return(response)
396
+ Net::HTTP.should_receive(:start).with('example.org', 80).and_yield(http)
397
+
398
+ entry.save!
399
+ end
400
+
401
+ it "should send a PUT with auth to the edit link on save!" do
402
+ entry = Atom::Entry.load_entry(File.open('spec/app/member_entry.atom'))
403
+ response = mock_response(Net::HTTPSuccess, nil)
404
+
405
+ request = mock('request')
406
+ request.should_receive(:basic_auth).with('user', 'pass')
407
+ Net::HTTP::Put.should_receive(:new).with('/member_entry.atom', @request_headers).and_return(request)
408
+
409
+ http = mock('http')
410
+ http.should_receive(:request).with(request, entry.to_xml.to_s).and_return(response)
411
+ Net::HTTP.should_receive(:start).with('example.org', 80).and_yield(http)
412
+
413
+ entry.save!(:user => 'user', :pass => 'pass')
414
+ end
415
+
416
+ if Atom::Configuration.auth_hmac_enabled?
417
+ it "should send a PUT with hmac auth to the edit link on save!" do
418
+ entry = Atom::Entry.load_entry(File.open('spec/app/member_entry.atom'))
419
+ response = mock_response(Net::HTTPSuccess, nil)
420
+
421
+ http = mock('http')
422
+ http.should_receive(:request) do |request, entry_xml|
423
+ request['Authorization'].should match(/^AuthHMAC access_id:[a-zA-Z0-9\/+]+=*$/)
424
+ response
425
+ end
426
+
427
+ Net::HTTP.should_receive(:start).with('example.org', 80).and_yield(http)
428
+
429
+ entry.save!(:hmac_access_id => 'access_id', :hmac_secret_key => 'secret')
430
+ end
431
+ end
432
+
433
+ it "should send a DELETE to the edit link on delete!" do
434
+ entry = Atom::Entry.load_entry(File.open('spec/app/member_entry.atom'))
435
+ response = mock_response(Net::HTTPSuccess, nil)
436
+
437
+ request = mock('request')
438
+ Net::HTTP::Delete.should_receive(:new).with('/member_entry.atom', an_instance_of(Hash)).and_return(request)
439
+
440
+ http = mock('http')
441
+ http.should_receive(:request).with(request).and_return(response)
442
+ Net::HTTP.should_receive(:start).with('example.org', 80).and_yield(http)
443
+
444
+ entry.destroy!
445
+ end
446
+
447
+ it "should send a DELETE with basic auth to the edit link on delete!" do
448
+ entry = Atom::Entry.load_entry(File.open('spec/app/member_entry.atom'))
449
+ response = mock_response(Net::HTTPSuccess, nil)
450
+
451
+ request = mock('request')
452
+ request.should_receive(:basic_auth).with('user', 'pass')
453
+ Net::HTTP::Delete.should_receive(:new).with('/member_entry.atom', an_instance_of(Hash)).and_return(request)
454
+
455
+ http = mock('http')
456
+ http.should_receive(:request).with(request).and_return(response)
457
+ Net::HTTP.should_receive(:start).with('example.org', 80).and_yield(http)
458
+
459
+ entry.destroy!(:user => 'user', :pass => 'pass')
460
+ end
461
+
462
+ if Atom::Configuration.auth_hmac_enabled?
463
+ it "should send a DELETE with hmac auth to the edit link on delete!" do
464
+ entry = Atom::Entry.load_entry(File.open('spec/app/member_entry.atom'))
465
+ response = mock_response(Net::HTTPSuccess, nil)
466
+
467
+ http = mock('http')
468
+ http.should_receive(:request) do |request|
469
+ request['Authorization'].should match(/^AuthHMAC access_id:[a-zA-Z0-9\/+]+=*$/)
470
+ response
471
+ end
472
+
473
+ Net::HTTP.should_receive(:start).with('example.org', 80).and_yield(http)
474
+
475
+ entry.destroy!(:hmac_access_id => 'access_id', :hmac_secret_key => 'secret')
476
+ end
477
+ end
478
+
479
+ it "should raise exception on save! without an edit link" do
480
+ entry = Atom::Entry.load_entry(File.open('spec/fixtures/entry.atom'))
481
+ lambda { entry.save! }.should raise_error(Atom::Pub::NotSupported)
482
+ end
483
+
484
+ it "should raise exception on save failure" do
485
+ entry = Atom::Entry.load_entry(File.open('spec/app/member_entry.atom'))
486
+ response = mock_response(Net::HTTPClientError, nil)
487
+
488
+ request = mock('request')
489
+ Net::HTTP::Put.should_receive(:new).with('/member_entry.atom', @request_headers).and_return(request)
490
+
491
+ http = mock('http')
492
+ http.should_receive(:request).with(request, entry.to_xml.to_s).and_return(response)
493
+ Net::HTTP.should_receive(:start).with('example.org', 80).and_yield(http)
494
+
495
+ lambda { entry.save! }.should raise_error(Atom::Pub::ProtocolError)
496
+ end
497
+
498
+ it "should raise exception on destroy! without an edit link" do
499
+ entry = Atom::Entry.load_entry(File.open('spec/fixtures/entry.atom'))
500
+ lambda { entry.destroy! }.should raise_error(Atom::Pub::NotSupported)
501
+ end
502
+
503
+ it "should raise exception on destroy failure" do
504
+ entry = Atom::Entry.load_entry(File.open('spec/app/member_entry.atom'))
505
+ response = mock_response(Net::HTTPClientError, nil)
506
+
507
+ request = mock('request')
508
+ Net::HTTP::Delete.should_receive(:new).with('/member_entry.atom', an_instance_of(Hash)).and_return(request)
509
+
510
+ http = mock('http')
511
+ http.should_receive(:request).with(request).and_return(response)
512
+ Net::HTTP.should_receive(:start).with('example.org', 80).and_yield(http)
513
+
514
+ lambda { entry.destroy! }.should raise_error(Atom::Pub::ProtocolError)
515
+ end
516
+ end
517
+ end