thehack-atom-tools 2.0.3

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.
data/test/test_feed.rb ADDED
@@ -0,0 +1,134 @@
1
+ require "test/unit"
2
+
3
+ require "atom/feed"
4
+ require "webrick"
5
+
6
+ class AtomFeedTest < Test::Unit::TestCase
7
+ def setup
8
+ @http = Atom::HTTP.new
9
+ @port = rand(1024) + 1024
10
+ @s = WEBrick::HTTPServer.new :Port => @port,
11
+ :Logger => WEBrick::Log.new($stderr, WEBrick::Log::FATAL),
12
+ :AccessLog => []
13
+
14
+ @test_feed =<<END
15
+ <?xml version="1.0" encoding="utf-8"?>
16
+ <feed xmlns="http://www.w3.org/2005/Atom">
17
+ <title>Example Feed</title>
18
+ <link href="http://example.org/"/>
19
+ <updated>2003-12-13T18:30:02Z</updated>
20
+ <author>
21
+ <name>John Doe</name>
22
+ </author>
23
+ <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
24
+
25
+ <entry>
26
+ <title>Atom-Powered Robots Run Amok</title>
27
+ <link href="http://example.org/2003/12/13/atom03"/>
28
+ <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
29
+ <updated>2003-12-13T18:30:02Z</updated>
30
+ <summary>Some text.</summary>
31
+ </entry>
32
+ </feed>
33
+ END
34
+ end
35
+
36
+ def test_merge
37
+ feed1 = Atom::Feed.new
38
+
39
+ feed1.title = "title"
40
+
41
+ feed1.subtitle = "<br>"
42
+ feed1.subtitle["type"] = "html"
43
+
44
+ a = feed1.authors.new
45
+ a.name = "test"
46
+
47
+ feed2 = Atom::Feed.new
48
+
49
+ feed = feed1.merge(feed2)
50
+
51
+ assert_equal "text", feed.title["type"]
52
+ assert_equal "title", feed.title.to_s
53
+
54
+ assert_equal "html", feed.subtitle["type"]
55
+ assert_equal "<br>", feed.subtitle.to_s
56
+
57
+ assert_equal 1, feed.authors.length
58
+ assert_equal "test", feed.authors.first.name
59
+ end
60
+
61
+ def test_update
62
+ @s.mount_proc("/") do |req,res|
63
+ assert_equal "application/atom+xml", req["Accept"]
64
+
65
+ res.content_type = "application/atom+xml"
66
+ res.body = @test_feed
67
+
68
+ @s.stop
69
+ end
70
+
71
+ feed = Atom::Feed.new "http://localhost:#{@port}/"
72
+
73
+ assert_equal nil, feed.title
74
+ assert_equal nil, feed.id
75
+ assert_equal [], feed.entries
76
+
77
+ one_shot
78
+
79
+ feed.update!
80
+
81
+ assert_equal "Example Feed", feed.title.to_s
82
+ assert_equal "urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6", feed.id
83
+ assert_equal 1, feed.entries.length
84
+ end
85
+
86
+ def test_media_types
87
+ c = proc do |c_t|
88
+ @s.mount_proc("/") do |req,res|
89
+ res.content_type = c_t
90
+ res.body = @test_feed
91
+
92
+ @s.stop
93
+ end
94
+ # there's some kind of race condition here that will result in a
95
+ # timeout sometimes. this is a dirty fix.
96
+ sleep 0.5
97
+ one_shot
98
+ end
99
+
100
+ feed = Atom::Feed.new "http://localhost:#{@port}/"
101
+
102
+ # even if it looks like a feed, the server's word is law
103
+ c.call("text/plain")
104
+ assert_raise(Atom::WrongMimetype) { feed.update! }
105
+
106
+ # a parameter shouldn't change the type
107
+ c.call("application/atom+xml;type=feed")
108
+ assert_nothing_raised { feed.update! }
109
+
110
+ # type and subtype are case insensitive (param. attribute names too)
111
+ c.call("ApPliCatIon/ATOM+XML")
112
+ assert_nothing_raised { feed.update! }
113
+
114
+ # text/xml isn't the preferred mimetype, but we'll accept it
115
+ c.call("text/xml")
116
+ assert_nothing_raised { feed.update! }
117
+
118
+ # same goes for application/xml
119
+ c.call("application/xml")
120
+ assert_nothing_raised { feed.update! }
121
+
122
+ # nil content type
123
+ @s.mount_proc("/") do |req,res|
124
+ res.body = @test_feed
125
+
126
+ @s.stop
127
+ end
128
+ one_shot
129
+ assert_raises(Atom::HTTPException) { feed.update! }
130
+ end
131
+
132
+ # prepares the server for a single request
133
+ def one_shot; Thread.new { @s.start }; end
134
+ end
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require "test/unit"
4
+
5
+ require "atom/feed"
6
+
7
+ class AtomTest < Test::Unit::TestCase
8
+ def test_feed_duplicate_id
9
+ feed = Atom::Feed.new
10
+
11
+ entry1 = get_entry
12
+ entry1.id = "http://example.org/test"
13
+ entry1.content = "an original entry"
14
+ entry1.updated!
15
+
16
+ feed << entry1
17
+
18
+ assert_equal(1, feed.entries.length)
19
+ assert_equal("an original entry", feed.entries.first.content.to_s)
20
+
21
+ feed << entry1.dup
22
+
23
+ assert_equal(1, feed.entries.length)
24
+ assert_equal("an original entry", feed.entries.first.content.to_s)
25
+
26
+ entry2 = entry1.dup
27
+ entry2.content = "a changed entry"
28
+ entry2.updated!
29
+
30
+ feed << entry2
31
+
32
+ assert_equal(1, feed.entries.length)
33
+ assert_equal("a changed entry", feed.entries.last.content.to_s)
34
+ end
35
+
36
+ def test_tags
37
+ entry = get_entry
38
+ entry.tag_with "test tags"
39
+
40
+ xml = get_elements entry
41
+
42
+ assert_has_category(xml, "test")
43
+ assert_has_category(xml, "tags")
44
+ end
45
+
46
+ def assert_has_category xml, term
47
+ assert_not_nil(REXML::XPath.match(xml, "/entry/category[@term = #{term}]"))
48
+ end
49
+
50
+ def assert_has_content_type xml, type
51
+ assert_equal(type, xml.elements["/entry/content"].attributes["type"])
52
+ end
53
+
54
+ def get_entry
55
+ Atom::Entry.new
56
+ end
57
+
58
+ def get_elements entry
59
+ xml = entry.to_xml
60
+
61
+ assert_equal(entry.to_s, Atom::Entry.parse(xml).to_s)
62
+
63
+ base_check xml
64
+
65
+ xml
66
+ end
67
+
68
+ def base_check xml
69
+ assert_equal("entry", xml.root.name)
70
+ assert_equal("http://www.w3.org/2005/Atom", xml.root.namespace)
71
+ end
72
+ end
data/test/test_http.rb ADDED
@@ -0,0 +1,323 @@
1
+ require "test/unit"
2
+
3
+ require "atom/http"
4
+ require "webrick"
5
+
6
+ class AtomHTTPTest < Test::Unit::TestCase
7
+ REALM = "test authentication"
8
+ USER = "test_user"
9
+ PASS = "aoeuaoeu"
10
+
11
+ # for Google AuthSub authentication
12
+ TOKEN = "pq7266382__838"
13
+
14
+ SECRET_DATA = "I kissed a boy once"
15
+
16
+ def setup
17
+ @http = Atom::HTTP.new
18
+ @port = rand(1024) + 1024
19
+ @s = WEBrick::HTTPServer.new :Port => @port,
20
+ :Logger => WEBrick::Log.new($stderr, WEBrick::Log::FATAL),
21
+ :AccessLog => []
22
+ end
23
+
24
+ def test_parse_wwwauth
25
+ # a Basic WWW-Authenticate
26
+ header = 'realm="SokEvo"'
27
+
28
+ params = @http.send :parse_quoted_wwwauth, header
29
+ assert_equal "SokEvo", params[:realm]
30
+
31
+ # Digest is parsed a bit differently
32
+ header = 'opaque="07UrfUiCYac5BbWJ", algorithm=MD5-sess, qop="auth", stale=TRUE, nonce="MDAx0Mzk", realm="test authentication"'
33
+
34
+ params = @http.send :parse_wwwauth_digest, header
35
+
36
+ assert_equal "test authentication", params[:realm]
37
+ assert_equal "MDAx0Mzk", params[:nonce]
38
+ assert_equal true, params[:stale]
39
+ assert_equal "auth", params[:qop]
40
+ assert_equal "MD5-sess", params[:algorithm]
41
+ assert_equal "07UrfUiCYac5BbWJ", params[:opaque]
42
+ end
43
+
44
+ def test_GET
45
+ mount_one_shot do |req,res|
46
+ assert_equal("/", req.path)
47
+
48
+ res.content_type = "text/plain"
49
+ res.body = "Success!"
50
+ end
51
+
52
+ get_root
53
+
54
+ assert_equal "200", @res.code
55
+ assert_equal "text/plain", @res.content_type
56
+ assert_equal "Success!", @res.body
57
+ end
58
+
59
+ def test_GET_headers
60
+ mount_one_shot do |req,res|
61
+ assert_equal("tester agent", req["User-Agent"])
62
+ end
63
+
64
+ get_root("User-Agent" => "tester agent")
65
+
66
+ assert_equal "200", @res.code
67
+ end
68
+
69
+ def test_redirect
70
+ @s.mount_proc("/") do |req,res|
71
+ res.status = 302
72
+ res["Location"] = "http://localhost:#{@port}/redirected"
73
+
74
+ res.body = "ignore me."
75
+ end
76
+
77
+ @s.mount_proc("/redirected") do |req,res|
78
+ res.content_type = "text/plain"
79
+ res.body = "Success!"
80
+
81
+ @s.stop
82
+ end
83
+
84
+ one_shot; get_root
85
+
86
+ # the redirect should be transparent (to whatever extent it can be)
87
+ assert_equal "200", @res.code
88
+ assert_equal "Success!", @res.body
89
+ end
90
+
91
+ def test_redirect_loop
92
+ @s.mount_proc("/") do |req,res|
93
+ res.status = 302
94
+ res["Location"] = "http://localhost:#{@port}/redirected"
95
+ end
96
+
97
+ @s.mount_proc("/redirected") do |req,res|
98
+ res.status = 302
99
+ res["Location"] = "http://localhost:#{@port}/"
100
+ end
101
+
102
+ one_shot
103
+
104
+ assert_raises(Atom::HTTPException) { get_root }
105
+
106
+ @s.stop
107
+ end
108
+
109
+ def test_redirect_non_GET_non_HEAD
110
+ @s.mount_proc("/") do |req,res|
111
+ assert_equal "POST", req.request_method
112
+ res.status = 302
113
+ res["Location"] = "http://localhost:#{@port}/redirected"
114
+ end
115
+
116
+ @s.mount_proc("/redirected") do |req,res|
117
+ assert_equal "POST", req.request_method
118
+ assert_equal "important message", req.body
119
+ res.content_type = "text/plain"
120
+ res.body = "Success!"
121
+ end
122
+
123
+ one_shot
124
+
125
+ @res = @http.post "http://localhost:#{@port}/", "important message"
126
+
127
+ assert_equal "302", @res.code
128
+
129
+ @http.allow_all_redirects = true
130
+
131
+ one_shot
132
+
133
+ @res = @http.post "http://localhost:#{@port}/", "important message"
134
+
135
+ assert_equal "200", @res.code
136
+ assert_equal "Success!", @res.body
137
+
138
+ @s.stop
139
+ end
140
+
141
+ def test_basic_auth
142
+ mount_one_shot do |req,res|
143
+ WEBrick::HTTPAuth.basic_auth(req, res, REALM) do |u,p|
144
+ u == USER and p == PASS
145
+ end
146
+
147
+ res.body = SECRET_DATA
148
+ end
149
+
150
+ # no credentials
151
+ assert_raises(Atom::Unauthorized) { get_root }
152
+
153
+ # incorrect credentials
154
+ @http.user = USER
155
+ @http.pass = "incorrect_password"
156
+
157
+ one_shot
158
+
159
+ assert_raises(Atom::Unauthorized) { get_root }
160
+
161
+ # no credentials, fancy block
162
+ @http.when_auth do nil end
163
+
164
+ one_shot
165
+
166
+ assert_raises(Atom::Unauthorized) { get_root }
167
+
168
+ # correct credentials, fancy block
169
+ @http.when_auth do |abs_url,realm|
170
+ assert_equal "http://localhost:#{@port}/", abs_url
171
+ assert_equal REALM, realm
172
+
173
+ [USER, PASS]
174
+ end
175
+
176
+ one_shot
177
+
178
+ assert_authenticates
179
+ end
180
+
181
+ def test_digest_auth
182
+ # a dummy userdb (saves me creating a file)
183
+ userdb = {}
184
+ # with a single entry
185
+ userdb[USER] = PASS
186
+
187
+ # HTTPAuth::DigestAuth#authenticate uses this
188
+ def userdb.get_passwd(realm, user, reload)
189
+ Digest::MD5::hexdigest([user, realm, self[user]].join(":"))
190
+ end
191
+
192
+ authenticator = WEBrick::HTTPAuth::DigestAuth.new(
193
+ :UserDB => userdb,
194
+ :Realm => REALM,
195
+ :Algorithm => "MD5"
196
+ )
197
+
198
+ @s.mount_proc("/") do |req,res|
199
+ authenticator.authenticate(req, res)
200
+ res.body = SECRET_DATA
201
+ end
202
+
203
+ one_shot
204
+
205
+ # no credentials
206
+ assert_raises(Atom::Unauthorized) { get_root }
207
+
208
+ @http.user = USER
209
+ @http.pass = PASS
210
+
211
+ # correct credentials
212
+ assert_authenticates
213
+
214
+ @s.stop
215
+ end
216
+
217
+ def test_wsse_auth
218
+ mount_one_shot do |req,res|
219
+ assert_equal 'WSSE profile="UsernameToken"', req["Authorization"]
220
+
221
+ xwsse = req["X-WSSE"]
222
+
223
+ p = @http.send :parse_quoted_wwwauth, xwsse
224
+
225
+ assert_equal USER, p[:Username]
226
+ assert_match /^UsernameToken /, xwsse
227
+
228
+ # Base64( SHA1( Nonce + CreationTimestamp + Password ) )
229
+ pd_string = p[:Nonce].unpack("m").first + p[:Created] + PASS
230
+ password_digest = [Digest::SHA1.digest(pd_string)].pack("m").chomp
231
+
232
+ assert_equal password_digest, p[:PasswordDigest]
233
+
234
+ res.body = SECRET_DATA
235
+ end
236
+
237
+ @http.always_auth = :wsse
238
+ @http.user = USER
239
+ @http.pass = PASS
240
+
241
+ assert_authenticates
242
+ end
243
+
244
+ def test_authsub_auth
245
+ mount_one_shot do |req,res|
246
+ assert_equal %{AuthSub token="#{TOKEN}"}, req["Authorization"]
247
+
248
+ res.body = SECRET_DATA
249
+ end
250
+
251
+ @http.always_auth = :authsub
252
+ @http.token = TOKEN
253
+
254
+ assert_authenticates
255
+ end
256
+
257
+ def test_multiple_auth
258
+ mount_one_shot do |req,res|
259
+ # WEBrick doesn't seem to support sending multiple headers, so this is the best we can do
260
+ res["WWW-Authenticate"] = %{NonexistantAuth parameter="yes", qop="auth", Basic realm="#{REALM}", something="true"}
261
+
262
+ if req["Authorization"]
263
+ res.body = SECRET_DATA
264
+ else
265
+ res.status = 401
266
+ end
267
+ end
268
+
269
+ @http.user = USER
270
+ @http.pass = PASS
271
+
272
+ assert_authenticates
273
+ end
274
+
275
+ def test_https
276
+ require 'webrick/https'
277
+
278
+ @s = WEBrick::HTTPServer.new(
279
+ :Port => (@port + 1),
280
+ :DocumentRoot => Dir::pwd + "/htdocs",
281
+ :Logger => WEBrick::Log.new($stderr, WEBrick::Log::FATAL),
282
+ :AccessLog => [],
283
+ :SSLEnable => true,
284
+ :SSLVerifyClient => ::OpenSSL::SSL::VERIFY_NONE,
285
+ :SSLCertName => [ ["C","CA"], ["O","localhost"], ["CN", "WWW"] ]
286
+ )
287
+
288
+ mount_one_shot do |req,res|
289
+ res.body = SECRET_DATA
290
+ end
291
+
292
+ res = @http.get("https://localhost:#{@port + 1}/")
293
+
294
+ assert_equal "200", res.code
295
+ assert_equal SECRET_DATA, res.body
296
+ end
297
+
298
+ # mount a block on the test server, shutting the server down after a
299
+ # single request
300
+ def mount_one_shot &block
301
+ @s.mount_proc("/") do |req,res|
302
+ block.call req, res
303
+ @s.stop
304
+ end
305
+
306
+ one_shot
307
+ end
308
+
309
+ # test that we authenticated properly
310
+ def assert_authenticates
311
+ get_root
312
+ assert_equal "200", @res.code
313
+ assert_equal SECRET_DATA, @res.body
314
+ end
315
+
316
+ # performs a GET on the test server
317
+ def get_root(*args)
318
+ @res = @http.get("http://localhost:#{@port}/", *args)
319
+ end
320
+
321
+ # sets up the server for a single request
322
+ def one_shot; Thread.new { @s.start }; end
323
+ end