rufus-verbs 0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+