rufus-verbs 0.1

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/auth_test.rb ADDED
@@ -0,0 +1,46 @@
1
+
2
+ #
3
+ # Testing rufus-verbs
4
+ #
5
+ # jmettraux@gmail.com
6
+ #
7
+ # Sun Jan 13 12:33:03 JST 2008
8
+ #
9
+
10
+ require 'test/unit'
11
+ require 'testbase'
12
+
13
+ require 'rufus/verbs'
14
+
15
+
16
+ class AuthTest < Test::Unit::TestCase
17
+ include TestBaseMixin
18
+
19
+ include Rufus::Verbs
20
+
21
+ #
22
+ # Using an items server with the authentication on.
23
+ #
24
+ def setup
25
+
26
+ @server = ItemServer.new :auth => true
27
+ @server.start
28
+ end
29
+
30
+
31
+ def test_0
32
+
33
+ #res = get :uri => "http://localhost:7777/items"
34
+ #assert_equal 200, res.code.to_i
35
+ #assert_equal "{}", res.body.strip
36
+ expect 401, nil, get(:uri => "http://localhost:7777/items")
37
+
38
+ expect 401, nil, get(
39
+ :uri => "http://localhost:7777/items",
40
+ :http_basic_authentication => [ "toto", "wrong" ])
41
+
42
+ expect 200, {}, get(
43
+ :uri => "http://localhost:7777/items?a",
44
+ :http_basic_authentication => [ "toto", "toto" ])
45
+ end
46
+ end
@@ -0,0 +1,49 @@
1
+
2
+ #
3
+ # Testing rufus-verbs
4
+ #
5
+ # jmettraux@gmail.com
6
+ #
7
+ # Sun Jan 13 20:02:25 JST 2008
8
+ #
9
+
10
+ require 'test/unit'
11
+ require 'testbase'
12
+
13
+ require 'rufus/verbs'
14
+
15
+
16
+ class BlockTest < Test::Unit::TestCase
17
+ include TestBaseMixin
18
+
19
+ include Rufus::Verbs
20
+
21
+
22
+ def test_0
23
+
24
+ res = post :uri => "http://localhost:7777/items/0" do
25
+ "Fedor" +
26
+ "Fedorovitch"
27
+ end
28
+ assert_equal 201, res.code.to_i
29
+ assert_equal "http://localhost:7777/items/0", res['Location']
30
+
31
+
32
+ expect(
33
+ 200,
34
+ { 0 => "FedorFedorovitch" },
35
+ get(:uri => "http://localhost:7777/things"))
36
+
37
+ res = post :uri => "http://localhost:7777/items/1" do |req|
38
+ # do whatever with the request [headers]
39
+ "John"
40
+ end
41
+ assert_equal 201, res.code.to_i
42
+ assert_equal "http://localhost:7777/items/1", res['Location']
43
+
44
+ expect(
45
+ 200,
46
+ { 0 => "FedorFedorovitch", 1 => "John" },
47
+ get(:uri => "http://localhost:7777/things"))
48
+ end
49
+ end
@@ -0,0 +1,49 @@
1
+
2
+ #
3
+ # Testing rufus-verbs
4
+ #
5
+ # jmettraux@gmail.com
6
+ #
7
+ # Wed Jan 16 13:54:36 JST 2008
8
+ #
9
+
10
+ require 'test/unit'
11
+ require 'testbase'
12
+
13
+ require 'rufus/verbs'
14
+
15
+
16
+ class ConditionalTest < Test::Unit::TestCase
17
+ include TestBaseMixin
18
+
19
+ include Rufus::Verbs
20
+
21
+
22
+ def test_1
23
+
24
+ ep = ConditionalEndPoint.new(:host => "localhost", :port => 7777)
25
+ expect 200, {}, ep.get(:resource => "items")
26
+
27
+ res = ep.put :resource => "items", :id => 0 do
28
+ "blockdata"
29
+ end
30
+ assert_equal 404, res.code.to_i
31
+
32
+ res = ep.post :resource => "items", :id => 0 do
33
+ "blockdata"
34
+ end
35
+ assert_equal 201, res.code.to_i
36
+ assert_equal "http://localhost:7777/items/0", res['Location']
37
+
38
+ res = expect 200, { 0 => "blockdata" }, ep.get(:res => "items")
39
+ assert_kind_of Net::HTTPResponse, res
40
+ assert_respond_to res, :lastmod
41
+ i = res.object_id
42
+ #p res.to_hash
43
+
44
+ res = expect 200, { 0 => "blockdata" }, ep.get(:res => "items")
45
+ assert_equal i, res.object_id
46
+
47
+ assert_equal 1, ep.cache_current_size
48
+ end
49
+ end
@@ -0,0 +1,42 @@
1
+
2
+ #
3
+ # Testing rufus-verbs
4
+ #
5
+ # jmettraux@gmail.com
6
+ #
7
+ # Tue Jan 15 09:26:45 JST 2008
8
+ #
9
+
10
+ require 'test/unit'
11
+
12
+ require 'rufus/verbs'
13
+
14
+
15
+ class DryRunTest < Test::Unit::TestCase
16
+
17
+ include Rufus::Verbs
18
+
19
+
20
+ def test_0
21
+
22
+ req = put(
23
+ :dry_run => true,
24
+ :uri => "http://localhost:7777/items/1",
25
+ :params => { "a" => "A", :b => :B })
26
+
27
+ assert "/items/1?a=A&b=B", req.path
28
+
29
+ req = put(
30
+ :dry_run => true,
31
+ :uri => "http://localhost:7777/items/1",
32
+ :query => { "a" => "A", :b => :B })
33
+
34
+ assert "/items/1?a=A&b=B", req.path
35
+
36
+ req = put(
37
+ "http://localhost:7777/items/1?a=A", :d => "toto", :dry_run => true)
38
+
39
+ assert "/items/1?a=A", req.path
40
+ assert "toto", req.body
41
+ end
42
+ end
@@ -0,0 +1,42 @@
1
+
2
+ #
3
+ # Testing rufus-verbs
4
+ #
5
+ # jmettraux@gmail.com
6
+ #
7
+ # Mon Jan 14 00:07:38 JST 2008
8
+ #
9
+
10
+ require 'test/unit'
11
+ require 'testbase'
12
+
13
+ require 'rufus/verbs'
14
+
15
+
16
+ class HttpsTest < Test::Unit::TestCase
17
+ include TestBaseMixin
18
+
19
+ include Rufus::Verbs
20
+
21
+ def setup
22
+ # no need for an items server
23
+ end
24
+
25
+ def teardown
26
+ end
27
+
28
+ def test_0
29
+
30
+ res = expect(
31
+ 200,
32
+ nil,
33
+ get(:uri => "http://jmettraux.wordpress.com/2006/03/31/cvs-down/"))
34
+
35
+ #res.each_header do |h|
36
+ # p h
37
+ #end
38
+
39
+ #puts res.body
40
+ assert res.body.match "^<!DOCTYPE html PUBLIC"
41
+ end
42
+ end
@@ -0,0 +1,68 @@
1
+
2
+ #
3
+ # Testing rufus-verbs
4
+ #
5
+ # jmettraux@gmail.com
6
+ #
7
+ # Sun Jan 13 12:33:03 JST 2008
8
+ #
9
+
10
+ require 'test/unit'
11
+ require 'testbase'
12
+
13
+ require 'rufus/verbs'
14
+
15
+
16
+ class ItemConditionalTest < Test::Unit::TestCase
17
+ include TestBaseMixin
18
+
19
+ include Rufus::Verbs
20
+
21
+
22
+ def test_0
23
+
24
+ require 'open-uri'
25
+ f = open "http://localhost:7777/items"
26
+ d = f.read
27
+ f.close
28
+
29
+ assert_equal "{}", d.strip
30
+ end
31
+
32
+ def test_1
33
+
34
+ res = get :uri => "http://localhost:7777/items"
35
+
36
+ assert_equal 200, res.code.to_i
37
+ assert_equal "{}", res.body.strip
38
+
39
+ p res['Etag']
40
+ #p res['Last-Modified']
41
+ assert res['Etag'].length > 0
42
+ assert res['Last-Modified'].length > 0
43
+ end
44
+
45
+ def test_2
46
+
47
+ res = get "http://localhost:7777/items"
48
+ assert_equal 200, res.code.to_i
49
+
50
+ lm = res['Last-Modified']
51
+ etag = res['Etag']
52
+
53
+ res = get(
54
+ "http://localhost:7777/items",
55
+ :headers => { 'If-Modified-Since' => lm })
56
+ assert_equal 304, res.code.to_i
57
+
58
+ res = get(
59
+ "http://localhost:7777/items", :h => { 'If-None-Match' => etag })
60
+ assert_equal 304, res.code.to_i
61
+
62
+ res = get(
63
+ "http://localhost:7777/items",
64
+ :h => { 'If-Modified-Since' => lm, 'If-None-Match' => etag })
65
+ assert_equal 304, res.code.to_i
66
+ end
67
+ end
68
+
data/test/items.rb ADDED
@@ -0,0 +1,262 @@
1
+
2
+ #
3
+ # an in-memory resource set for testing rufus-verbs
4
+ #
5
+ # jmettraux@gmail.com
6
+ #
7
+ # Fri Jan 11 12:36:45 JST 2008
8
+ #
9
+
10
+ require 'date'
11
+ require 'webrick'
12
+
13
+
14
+ class LastModifiedHash
15
+
16
+ def initialize
17
+
18
+ @hash = {}
19
+ touch
20
+ end
21
+
22
+ def touch (key=nil)
23
+
24
+ now = Time.now.httpdate
25
+ @hash[key] = now if key
26
+ @hash['__self'] = now
27
+ end
28
+
29
+ def delete (key)
30
+
31
+ @hash.delete key
32
+ @hash['__self'] = Time.now.httpdate
33
+ end
34
+
35
+ def last_modified (key)
36
+
37
+ key = key || '__self'
38
+ @hash[key]
39
+ end
40
+
41
+ def clear
42
+
43
+ @hash.clear
44
+ @hash['__self'] = Time.now.httpdate
45
+ end
46
+ end
47
+
48
+
49
+ #
50
+ # This servlet provides a RESTful in-memory resource "/items".
51
+ #
52
+ class ItemServlet < WEBrick::HTTPServlet::AbstractServlet
53
+
54
+ @@items = {}
55
+ @@lastmod = LastModifiedHash.new
56
+
57
+
58
+ def initialize (server, *options)
59
+
60
+ super
61
+ @auth = server.auth
62
+ end
63
+
64
+ #
65
+ # Overriding the service() method to perform a potential auth check
66
+ #
67
+ def service (req, res)
68
+
69
+ WEBrick::HTTPAuth.basic_auth(req, res, "items") do |u, p|
70
+ (u != nil and u == p)
71
+ end if @auth
72
+
73
+ super
74
+ end
75
+
76
+ def do_GET (req, res)
77
+
78
+ i = item_id req
79
+
80
+ return reply(res, 404, "no item '#{i}'") \
81
+ if i and not items[i]
82
+
83
+ representation, et, lm = fetch_representation i
84
+
85
+ since = req['If-Modified-Since']
86
+ since = DateTime.parse(since) if since
87
+ match = req['If-None-Match']
88
+
89
+ if ((not since and not match) or
90
+ (since and (since > DateTime.parse(lm))) or
91
+ (match and (match != et)))
92
+
93
+ res['Etag'] = et
94
+ res['Last-Modified'] = lm
95
+ res.body = representation.inspect + "\n"
96
+
97
+ else
98
+
99
+ reply(res, 304, "Not Modified")
100
+ end
101
+ end
102
+
103
+ def do_POST (req, res)
104
+
105
+ query = WEBrick::HTTPUtils::parse_query(req.query_string)
106
+ m = query['_method']
107
+ m = m.downcase if m
108
+ return do_PUT(req, res) if m == 'put'
109
+ return do_DELETE(req, res) if m == 'delete'
110
+
111
+ i = item_id req
112
+ items[i] = req.body
113
+ lastmod.touch i
114
+
115
+ res['Location'] = "#{@host}/items/#{i}"
116
+ reply res, 201, "item created"
117
+ end
118
+
119
+ def do_PUT (req, res)
120
+
121
+ i = item_id req
122
+
123
+ return reply(res, 404, "no item '#{i}'") unless items[i]
124
+
125
+ items[i] = req.body
126
+ lastmod.touch i
127
+
128
+ reply res, 200, "item updated"
129
+ end
130
+
131
+ def do_DELETE (req, res)
132
+
133
+ i = item_id req
134
+
135
+ return reply(res, 404, "no item '#{i}'") unless items[i]
136
+
137
+ items.delete i
138
+ lastmod.delete i
139
+
140
+ reply res, 200, "item deleted"
141
+ end
142
+
143
+ #
144
+ # clears the items
145
+ #
146
+ def self.flush
147
+
148
+ @@items.clear
149
+ @@lastmod.clear
150
+ end
151
+
152
+ protected
153
+
154
+ def items
155
+ @@items
156
+ end
157
+
158
+ def lastmod
159
+ @@lastmod
160
+ end
161
+
162
+ def is_modified (req, key)
163
+
164
+ since = req['If-Modified-Since']
165
+ match = req['If-None-Match']
166
+
167
+ return true unless since or match
168
+
169
+ puts
170
+ p [ since, match ]
171
+ puts
172
+
173
+ (since or match)
174
+ end
175
+
176
+ #
177
+ # Returns representation, etag, last_modified
178
+ #
179
+ def fetch_representation (key=nil)
180
+
181
+ representation = if key
182
+ items[key]
183
+ else
184
+ items
185
+ end
186
+
187
+ [ representation,
188
+ representation.inspect.hash.to_s,
189
+ lastmod.last_modified(key) ]
190
+ end
191
+
192
+ def reply (res, code, message)
193
+
194
+ res.status = code
195
+ res.body = message + "\n"
196
+ res['Content-type'] = "text/plain"
197
+ end
198
+
199
+ def item_id (req)
200
+
201
+ p = req.path_info[1..-1]
202
+ return nil if not p or p == ''
203
+ p.to_i
204
+ end
205
+ end
206
+
207
+ #
208
+ # just redirecting to the ItemServlet...
209
+ #
210
+ class ThingServlet < WEBrick::HTTPServlet::AbstractServlet
211
+
212
+ def do_GET (req, res)
213
+
214
+ res.set_redirect(
215
+ WEBrick::HTTPStatus[303],
216
+ "http://localhost:7777/items")
217
+ end
218
+ end
219
+
220
+ #
221
+ # Serving items, a dummy resource...
222
+ # Also serving things, which just redirect to items...
223
+ #
224
+ class ItemServer
225
+
226
+ def initialize (args={})
227
+
228
+ port = args[:port] || 7777
229
+
230
+ #al = [
231
+ # [ "", WEBrick::AccessLog::COMMON_LOG_FORMAT ],
232
+ # [ "", WEBrick::AccessLog::REFERER_LOG_FORMAT ]]
233
+
234
+ @server = WEBrick::HTTPServer.new :Port => port, :AccessLog => nil
235
+
236
+ class << @server
237
+ attr_accessor :auth
238
+ end
239
+
240
+ @server.auth = args[:auth]
241
+
242
+ @server.mount "/items", ItemServlet
243
+ @server.mount "/things", ThingServlet
244
+
245
+ [ 'INT', 'TERM' ].each do |signal|
246
+ trap(signal) { shutdown }
247
+ end
248
+ end
249
+
250
+ def start
251
+
252
+ Thread.new { @server.start }
253
+ # else the server and the test lock each other
254
+ end
255
+
256
+ def shutdown
257
+
258
+ ItemServlet.flush
259
+ @server.shutdown
260
+ end
261
+ end
262
+