1
from cherrypy.test import test
2
from cherrypy._cptree import Application
3
test.prefer_parent_path()
7
script_names = ["", "/foo", "/users/fred/blog", "/corp/blog"]
12
return "SubSubRoot index"
15
def default(self, *args):
16
return "SubSubRoot default"
17
default.exposed = True
20
return "SubSubRoot handler"
21
handler.exposed = True
24
return "SubSubRoot dispatch"
25
dispatch.exposed = True
34
return "SubRoot index"
37
def default(self, *args):
38
return "SubRoot %s" % (args,)
39
default.exposed = True
42
return "SubRoot handler"
43
handler.exposed = True
45
def _cp_dispatch(self, vpath):
46
return subsubnodes.get(vpath[0], None)
57
def default(self, *args):
58
return "default %s" % (args,)
59
default.exposed = True
63
handler.exposed = True
65
def _cp_dispatch(self, vpath):
66
return subnodes.get(vpath[0])
68
#--------------------------------------------------------------------------
69
# DynamicNodeAndMethodDispatcher example.
70
# This example exposes a fairly naive HTTP api
72
def __init__(self, id, name):
76
def __unicode__(self):
77
return unicode(self.name)
84
def make_user(name, id=None):
86
id = max(*user_lookup.keys()) + 1
87
user_lookup[id] = User(id, name)
90
class UserContainerNode(object):
95
Allow the creation of a new Object
97
return "POST %d" % make_user(name)
100
keys = user_lookup.keys()
104
def dynamic_dispatch(self, vpath):
109
return UserInstanceNode(id)
111
class UserInstanceNode(object):
113
def __init__(self, id):
115
self.user = user_lookup.get(id, None)
117
# For all but PUT methods there MUST be a valid user identified
119
if not self.user and cherrypy.request.method != 'PUT':
120
raise cherrypy.HTTPError(404)
122
def GET(self, *args, **kwargs):
124
Return the appropriate representation of the instance.
126
return unicode(self.user)
128
def POST(self, name):
130
Update the fields of the user instance.
132
self.user.name = name
133
return "POST %d" % self.user.id
137
Create a new user with the specified id, or edit it if it already exists
140
# Edit the current user
141
self.user.name = name
142
return "PUT %d" % self.user.id
144
# Make a new user with said attributes.
145
return "PUT %d" % make_user(name, self.id)
149
Delete the user specified at the id.
152
del user_lookup[self.user.id]
154
return "DELETE %d" % id
157
Root.users = UserContainerNode()
159
md = cherrypy.dispatch.MethodDispatcher('dynamic_dispatch')
160
for url in script_names:
162
'user': (url or "/").split("/")[-2],
165
'request.dispatch': md
168
cherrypy.tree.mount(Root(), url, conf)
171
from cherrypy.test import helper
173
class DynamicObjectMappingTest(helper.CPWebCase):
175
def testObjectMapping(self):
176
for url in script_names:
177
prefix = self.script_name = url
180
self.assertBody('index')
182
self.getPage('/handler')
183
self.assertBody('handler')
185
# Dynamic dispatch will succeed here for the subnodes
186
# so the subroot gets called
188
self.assertBody('SubRoot index')
191
self.assertBody('SubRoot index')
193
self.getPage('/1/handler')
194
self.assertBody('SubRoot handler')
196
self.getPage('/2/handler')
197
self.assertBody('SubRoot handler')
199
# Dynamic dispatch will fail here for the subnodes
200
# so the default gets called
201
self.getPage('/asdf/')
202
self.assertBody("default ('asdf',)")
204
self.getPage('/asdf/asdf')
205
self.assertBody("default ('asdf', 'asdf')")
207
self.getPage('/asdf/handler')
208
self.assertBody("default ('asdf', 'handler')")
210
# Dynamic dispatch will succeed here for the subsubnodes
211
# so the subsubroot gets called
212
self.getPage('/1/1/')
213
self.assertBody('SubSubRoot index')
215
self.getPage('/2/2/')
216
self.assertBody('SubSubRoot index')
218
self.getPage('/1/1/handler')
219
self.assertBody('SubSubRoot handler')
221
self.getPage('/2/2/handler')
222
self.assertBody('SubSubRoot handler')
224
self.getPage('/2/2/dispatch')
225
self.assertBody('SubSubRoot dispatch')
227
# The exposed dispatch will not be called as a dispatch
229
self.getPage('/2/2/foo/foo')
230
self.assertBody("SubSubRoot default")
232
# Dynamic dispatch will fail here for the subsubnodes
233
# so the SubRoot gets called
234
self.getPage('/1/asdf/')
235
self.assertBody("SubRoot ('asdf',)")
237
self.getPage('/1/asdf/asdf')
238
self.assertBody("SubRoot ('asdf', 'asdf')")
240
self.getPage('/1/asdf/handler')
241
self.assertBody("SubRoot ('asdf', 'handler')")
243
def testMethodDispatch(self):
244
# GET acts like a container
245
self.getPage("/users")
246
self.assertBody("[1, 2]")
247
self.assertHeader('Allow', 'GET, HEAD, POST')
249
# POST to the container URI allows creation
250
self.getPage("/users", method="POST", body="name=baz")
251
self.assertBody("POST 3")
252
self.assertHeader('Allow', 'GET, HEAD, POST')
254
# POST to a specific instanct URI results in a 404
255
# as the resource does not exit.
256
self.getPage("/users/5", method="POST", body="name=baz")
257
self.assertStatus(404)
259
# PUT to a specific instanct URI results in creation
260
self.getPage("/users/5", method="PUT", body="name=boris")
261
self.assertBody("PUT 5")
262
self.assertHeader('Allow', 'DELETE, GET, HEAD, POST, PUT')
264
# GET acts like a container
265
self.getPage("/users")
266
self.assertBody("[1, 2, 3, 5]")
267
self.assertHeader('Allow', 'GET, HEAD, POST')
270
(1, 'foo', 'fooupdated', 'DELETE, GET, HEAD, POST, PUT'),
271
(2, 'bar', 'barupdated', 'DELETE, GET, HEAD, POST, PUT'),
272
(3, 'baz', 'bazupdated', 'DELETE, GET, HEAD, POST, PUT'),
273
(5, 'boris', 'borisupdated', 'DELETE, GET, HEAD, POST, PUT'),
275
for id, name, updatedname, headers in test_cases:
276
self.getPage("/users/%d" % id)
277
self.assertBody(name)
278
self.assertHeader('Allow', headers)
280
# Make sure POSTs update already existings resources
281
self.getPage("/users/%d" % id, method='POST', body="name=%s" % updatedname)
282
self.assertBody("POST %d" % id)
283
self.assertHeader('Allow', headers)
285
# Make sure PUTs Update already existing resources.
286
self.getPage("/users/%d" % id, method='PUT', body="name=%s" % updatedname)
287
self.assertBody("PUT %d" % id)
288
self.assertHeader('Allow', headers)
290
# Make sure DELETES Remove already existing resources.
291
self.getPage("/users/%d" % id, method='DELETE')
292
self.assertBody("DELETE %d" % id)
293
self.assertHeader('Allow', headers)
296
# GET acts like a container
297
self.getPage("/users")
298
self.assertBody("[]")
299
self.assertHeader('Allow', 'GET, HEAD, POST')
301
if __name__ == "__main__":