Package cherrypy :: Package test :: Module test_objectmapping
[hide private]
[frames] | no frames]

Source Code for Module cherrypy.test.test_objectmapping

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