Fixed python_path problem.
[smonitor.git] / lib / cherrypy / test / test_objectmapping.py
blob46816fcbfdfbc701c4a967504e9726fdecd51b53
1 import cherrypy
2 from cherrypy._cptree import Application
3 from cherrypy.test import helper
5 script_names = ["", "/foo", "/users/fred/blog", "/corp/blog"]
8 class ObjectMappingTest(helper.CPWebCase):
10 def setup_server():
11 class Root:
12 def index(self, name="world"):
13 return name
14 index.exposed = True
16 def foobar(self):
17 return "bar"
18 foobar.exposed = True
20 def default(self, *params, **kwargs):
21 return "default:" + repr(params)
22 default.exposed = True
24 def other(self):
25 return "other"
26 other.exposed = True
28 def extra(self, *p):
29 return repr(p)
30 extra.exposed = True
32 def redirect(self):
33 raise cherrypy.HTTPRedirect('dir1/', 302)
34 redirect.exposed = True
36 def notExposed(self):
37 return "not exposed"
39 def confvalue(self):
40 return cherrypy.request.config.get("user")
41 confvalue.exposed = True
43 def redirect_via_url(self, path):
44 raise cherrypy.HTTPRedirect(cherrypy.url(path))
45 redirect_via_url.exposed = True
47 def translate_html(self):
48 return "OK"
49 translate_html.exposed = True
51 def mapped_func(self, ID=None):
52 return "ID is %s" % ID
53 mapped_func.exposed = True
54 setattr(Root, "Von B\xfclow", mapped_func)
57 class Exposing:
58 def base(self):
59 return "expose works!"
60 cherrypy.expose(base)
61 cherrypy.expose(base, "1")
62 cherrypy.expose(base, "2")
64 class ExposingNewStyle(object):
65 def base(self):
66 return "expose works!"
67 cherrypy.expose(base)
68 cherrypy.expose(base, "1")
69 cherrypy.expose(base, "2")
72 class Dir1:
73 def index(self):
74 return "index for dir1"
75 index.exposed = True
77 def myMethod(self):
78 return "myMethod from dir1, path_info is:" + repr(cherrypy.request.path_info)
79 myMethod.exposed = True
80 myMethod._cp_config = {'tools.trailing_slash.extra': True}
82 def default(self, *params):
83 return "default for dir1, param is:" + repr(params)
84 default.exposed = True
87 class Dir2:
88 def index(self):
89 return "index for dir2, path is:" + cherrypy.request.path_info
90 index.exposed = True
92 def script_name(self):
93 return cherrypy.tree.script_name()
94 script_name.exposed = True
96 def cherrypy_url(self):
97 return cherrypy.url("/extra")
98 cherrypy_url.exposed = True
100 def posparam(self, *vpath):
101 return "/".join(vpath)
102 posparam.exposed = True
105 class Dir3:
106 def default(self):
107 return "default for dir3, not exposed"
109 class Dir4:
110 def index(self):
111 return "index for dir4, not exposed"
113 class DefNoIndex:
114 def default(self, *args):
115 raise cherrypy.HTTPRedirect("contact")
116 default.exposed = True
118 # MethodDispatcher code
119 class ByMethod:
120 exposed = True
122 def __init__(self, *things):
123 self.things = list(things)
125 def GET(self):
126 return repr(self.things)
128 def POST(self, thing):
129 self.things.append(thing)
131 class Collection:
132 default = ByMethod('a', 'bit')
134 Root.exposing = Exposing()
135 Root.exposingnew = ExposingNewStyle()
136 Root.dir1 = Dir1()
137 Root.dir1.dir2 = Dir2()
138 Root.dir1.dir2.dir3 = Dir3()
139 Root.dir1.dir2.dir3.dir4 = Dir4()
140 Root.defnoindex = DefNoIndex()
141 Root.bymethod = ByMethod('another')
142 Root.collection = Collection()
144 d = cherrypy.dispatch.MethodDispatcher()
145 for url in script_names:
146 conf = {'/': {'user': (url or "/").split("/")[-2]},
147 '/bymethod': {'request.dispatch': d},
148 '/collection': {'request.dispatch': d},
150 cherrypy.tree.mount(Root(), url, conf)
153 class Isolated:
154 def index(self):
155 return "made it!"
156 index.exposed = True
158 cherrypy.tree.mount(Isolated(), "/isolated")
160 class AnotherApp:
162 exposed = True
164 def GET(self):
165 return "milk"
167 cherrypy.tree.mount(AnotherApp(), "/app", {'/': {'request.dispatch': d}})
168 setup_server = staticmethod(setup_server)
171 def testObjectMapping(self):
172 for url in script_names:
173 prefix = self.script_name = url
175 self.getPage('/')
176 self.assertBody('world')
178 self.getPage("/dir1/myMethod")
179 self.assertBody("myMethod from dir1, path_info is:'/dir1/myMethod'")
181 self.getPage("/this/method/does/not/exist")
182 self.assertBody("default:('this', 'method', 'does', 'not', 'exist')")
184 self.getPage("/extra/too/much")
185 self.assertBody("('too', 'much')")
187 self.getPage("/other")
188 self.assertBody('other')
190 self.getPage("/notExposed")
191 self.assertBody("default:('notExposed',)")
193 self.getPage("/dir1/dir2/")
194 self.assertBody('index for dir2, path is:/dir1/dir2/')
196 # Test omitted trailing slash (should be redirected by default).
197 self.getPage("/dir1/dir2")
198 self.assertStatus(301)
199 self.assertHeader('Location', '%s/dir1/dir2/' % self.base())
201 # Test extra trailing slash (should be redirected if configured).
202 self.getPage("/dir1/myMethod/")
203 self.assertStatus(301)
204 self.assertHeader('Location', '%s/dir1/myMethod' % self.base())
206 # Test that default method must be exposed in order to match.
207 self.getPage("/dir1/dir2/dir3/dir4/index")
208 self.assertBody("default for dir1, param is:('dir2', 'dir3', 'dir4', 'index')")
210 # Test *vpath when default() is defined but not index()
211 # This also tests HTTPRedirect with default.
212 self.getPage("/defnoindex")
213 self.assertStatus((302, 303))
214 self.assertHeader('Location', '%s/contact' % self.base())
215 self.getPage("/defnoindex/")
216 self.assertStatus((302, 303))
217 self.assertHeader('Location', '%s/defnoindex/contact' % self.base())
218 self.getPage("/defnoindex/page")
219 self.assertStatus((302, 303))
220 self.assertHeader('Location', '%s/defnoindex/contact' % self.base())
222 self.getPage("/redirect")
223 self.assertStatus('302 Found')
224 self.assertHeader('Location', '%s/dir1/' % self.base())
226 if not getattr(cherrypy.server, "using_apache", False):
227 # Test that we can use URL's which aren't all valid Python identifiers
228 # This should also test the %XX-unquoting of URL's.
229 self.getPage("/Von%20B%fclow?ID=14")
230 self.assertBody("ID is 14")
232 # Test that %2F in the path doesn't get unquoted too early;
233 # that is, it should not be used to separate path components.
234 # See ticket #393.
235 self.getPage("/page%2Fname")
236 self.assertBody("default:('page/name',)")
238 self.getPage("/dir1/dir2/script_name")
239 self.assertBody(url)
240 self.getPage("/dir1/dir2/cherrypy_url")
241 self.assertBody("%s/extra" % self.base())
243 # Test that configs don't overwrite each other from diferent apps
244 self.getPage("/confvalue")
245 self.assertBody((url or "/").split("/")[-2])
247 self.script_name = ""
249 # Test absoluteURI's in the Request-Line
250 self.getPage('http://%s:%s/' % (self.interface(), self.PORT))
251 self.assertBody('world')
253 self.getPage('http://%s:%s/abs/?service=http://192.168.0.1/x/y/z' %
254 (self.interface(), self.PORT))
255 self.assertBody("default:('abs',)")
257 self.getPage('/rel/?service=http://192.168.120.121:8000/x/y/z')
258 self.assertBody("default:('rel',)")
260 # Test that the "isolated" app doesn't leak url's into the root app.
261 # If it did leak, Root.default() would answer with
262 # "default:('isolated', 'doesnt', 'exist')".
263 self.getPage("/isolated/")
264 self.assertStatus("200 OK")
265 self.assertBody("made it!")
266 self.getPage("/isolated/doesnt/exist")
267 self.assertStatus("404 Not Found")
269 # Make sure /foobar maps to Root.foobar and not to the app
270 # mounted at /foo. See http://www.cherrypy.org/ticket/573
271 self.getPage("/foobar")
272 self.assertBody("bar")
274 def test_translate(self):
275 self.getPage("/translate_html")
276 self.assertStatus("200 OK")
277 self.assertBody("OK")
279 self.getPage("/translate.html")
280 self.assertStatus("200 OK")
281 self.assertBody("OK")
283 self.getPage("/translate-html")
284 self.assertStatus("200 OK")
285 self.assertBody("OK")
287 def test_redir_using_url(self):
288 for url in script_names:
289 prefix = self.script_name = url
291 # Test the absolute path to the parent (leading slash)
292 self.getPage('/redirect_via_url?path=./')
293 self.assertStatus(('302 Found', '303 See Other'))
294 self.assertHeader('Location', '%s/' % self.base())
296 # Test the relative path to the parent (no leading slash)
297 self.getPage('/redirect_via_url?path=./')
298 self.assertStatus(('302 Found', '303 See Other'))
299 self.assertHeader('Location', '%s/' % self.base())
301 # Test the absolute path to the parent (leading slash)
302 self.getPage('/redirect_via_url/?path=./')
303 self.assertStatus(('302 Found', '303 See Other'))
304 self.assertHeader('Location', '%s/' % self.base())
306 # Test the relative path to the parent (no leading slash)
307 self.getPage('/redirect_via_url/?path=./')
308 self.assertStatus(('302 Found', '303 See Other'))
309 self.assertHeader('Location', '%s/' % self.base())
311 def testPositionalParams(self):
312 self.getPage("/dir1/dir2/posparam/18/24/hut/hike")
313 self.assertBody("18/24/hut/hike")
315 # intermediate index methods should not receive posparams;
316 # only the "final" index method should do so.
317 self.getPage("/dir1/dir2/5/3/sir")
318 self.assertBody("default for dir1, param is:('dir2', '5', '3', 'sir')")
320 # test that extra positional args raises an 404 Not Found
321 # See http://www.cherrypy.org/ticket/733.
322 self.getPage("/dir1/dir2/script_name/extra/stuff")
323 self.assertStatus(404)
325 def testExpose(self):
326 # Test the cherrypy.expose function/decorator
327 self.getPage("/exposing/base")
328 self.assertBody("expose works!")
330 self.getPage("/exposing/1")
331 self.assertBody("expose works!")
333 self.getPage("/exposing/2")
334 self.assertBody("expose works!")
336 self.getPage("/exposingnew/base")
337 self.assertBody("expose works!")
339 self.getPage("/exposingnew/1")
340 self.assertBody("expose works!")
342 self.getPage("/exposingnew/2")
343 self.assertBody("expose works!")
345 def testMethodDispatch(self):
346 self.getPage("/bymethod")
347 self.assertBody("['another']")
348 self.assertHeader('Allow', 'GET, HEAD, POST')
350 self.getPage("/bymethod", method="HEAD")
351 self.assertBody("")
352 self.assertHeader('Allow', 'GET, HEAD, POST')
354 self.getPage("/bymethod", method="POST", body="thing=one")
355 self.assertBody("")
356 self.assertHeader('Allow', 'GET, HEAD, POST')
358 self.getPage("/bymethod")
359 self.assertBody("['another', u'one']")
360 self.assertHeader('Allow', 'GET, HEAD, POST')
362 self.getPage("/bymethod", method="PUT")
363 self.assertErrorPage(405)
364 self.assertHeader('Allow', 'GET, HEAD, POST')
366 # Test default with posparams
367 self.getPage("/collection/silly", method="POST")
368 self.getPage("/collection", method="GET")
369 self.assertBody("['a', 'bit', 'silly']")
371 # Test custom dispatcher set on app root (see #737).
372 self.getPage("/app")
373 self.assertBody("milk")
375 def testTreeMounting(self):
376 class Root(object):
377 def hello(self):
378 return "Hello world!"
379 hello.exposed = True
381 # When mounting an application instance,
382 # we can't specify a different script name in the call to mount.
383 a = Application(Root(), '/somewhere')
384 self.assertRaises(ValueError, cherrypy.tree.mount, a, '/somewhereelse')
386 # When mounting an application instance...
387 a = Application(Root(), '/somewhere')
388 # ...we MUST allow in identical script name in the call to mount...
389 cherrypy.tree.mount(a, '/somewhere')
390 self.getPage('/somewhere/hello')
391 self.assertStatus(200)
392 # ...and MUST allow a missing script_name.
393 del cherrypy.tree.apps['/somewhere']
394 cherrypy.tree.mount(a)
395 self.getPage('/somewhere/hello')
396 self.assertStatus(200)
398 # In addition, we MUST be able to create an Application using
399 # script_name == None for access to the wsgi_environ.
400 a = Application(Root(), script_name=None)
401 # However, this does not apply to tree.mount
402 self.assertRaises(TypeError, cherrypy.tree.mount, a, None)