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