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

Source Code for Module cherrypy.test.test_core

   1  """Basic tests for the CherryPy core: request handling.""" 
   2   
   3  from cherrypy.test import test 
   4  test.prefer_parent_path() 
   5   
   6  import cherrypy 
   7  from cherrypy import _cptools, tools 
   8  from cherrypy.lib import http, static 
   9  import types 
  10   
  11  import os 
  12  localDir = os.path.dirname(__file__) 
  13  log_file = os.path.join(localDir, "test.log") 
  14  log_access_file = os.path.join(localDir, "access.log") 
  15  favicon_path = os.path.join(os.getcwd(), localDir, "../favicon.ico") 
  16   
  17  defined_http_methods = ("OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE", 
  18                          "TRACE", "CONNECT", "PROPFIND") 
  19   
  20   
21 -def setup_server():
22 class Root: 23 24 def index(self): 25 return "hello"
26 index.exposed = True 27 28 favicon_ico = tools.staticfile.handler(filename=favicon_path) 29 30 def andnow(self): 31 return "the larch" 32 andnow.exposed = True 33 34 def global_(self): 35 pass 36 global_.exposed = True 37 38 def delglobal(self): 39 del self.__class__.__dict__['global_'] 40 delglobal.exposed = True 41 42 def defct(self, newct): 43 newct = "text/%s" % newct 44 cherrypy.config.update({'tools.response_headers.on': True, 45 'tools.response_headers.headers': 46 [('Content-Type', newct)]}) 47 defct.exposed = True 48 49 def upload(self, file): 50 return "Size: %s" % len(file.file.read()) 51 upload.exposed = True 52 53 root = Root() 54 55 56 class TestType(type): 57 """Metaclass which automatically exposes all functions in each subclass, 58 and adds an instance of the subclass as an attribute of root. 59 """ 60 def __init__(cls, name, bases, dct): 61 type.__init__(name, bases, dct) 62 for value in dct.itervalues(): 63 if isinstance(value, types.FunctionType): 64 value.exposed = True 65 setattr(root, name.lower(), cls()) 66 class Test(object): 67 __metaclass__ = TestType 68 69 70 class URL(Test): 71 72 _cp_config = {'tools.trailing_slash.on': False} 73 74 def index(self, path_info, relative=None): 75 return cherrypy.url(path_info, relative=bool(relative)) 76 77 def leaf(self, path_info, relative=None): 78 return cherrypy.url(path_info, relative=bool(relative)) 79 80 81 class Params(Test): 82 83 def index(self, thing): 84 return repr(thing) 85 86 def ismap(self, x, y): 87 return "Coordinates: %s, %s" % (x, y) 88 89 def default(self, *args, **kwargs): 90 return "args: %s kwargs: %s" % (args, kwargs) 91 92 93 class Status(Test): 94 95 def index(self): 96 return "normal" 97 98 def blank(self): 99 cherrypy.response.status = "" 100 101 # According to RFC 2616, new status codes are OK as long as they 102 # are between 100 and 599. 103 104 # Here is an illegal code... 105 def illegal(self): 106 cherrypy.response.status = 781 107 return "oops" 108 109 # ...and here is an unknown but legal code. 110 def unknown(self): 111 cherrypy.response.status = "431 My custom error" 112 return "funky" 113 114 # Non-numeric code 115 def bad(self): 116 cherrypy.response.status = "error" 117 return "bad news" 118 119 120 class Redirect(Test): 121 122 class Error: 123 _cp_config = {"tools.err_redirect.on": True, 124 "tools.err_redirect.url": "/errpage", 125 "tools.err_redirect.internal": False, 126 } 127 128 def index(self): 129 raise NameError("redirect_test") 130 index.exposed = True 131 error = Error() 132 133 def index(self): 134 return "child" 135 136 def by_code(self, code): 137 raise cherrypy.HTTPRedirect("somewhere else", code) 138 by_code._cp_config = {'tools.trailing_slash.extra': True} 139 140 def nomodify(self): 141 raise cherrypy.HTTPRedirect("", 304) 142 143 def proxy(self): 144 raise cherrypy.HTTPRedirect("proxy", 305) 145 146 def stringify(self): 147 return str(cherrypy.HTTPRedirect("/")) 148 149 def fragment(self, frag): 150 raise cherrypy.HTTPRedirect("/some/url#%s" % frag) 151 152 def login_redir(): 153 if not getattr(cherrypy.request, "login", None): 154 raise cherrypy.InternalRedirect("/internalredirect/login") 155 tools.login_redir = _cptools.Tool('before_handler', login_redir) 156 157 def redir_custom(): 158 raise cherrypy.InternalRedirect("/internalredirect/custom_err") 159 160 class InternalRedirect(Test): 161 162 def index(self): 163 raise cherrypy.InternalRedirect("/") 164 165 def relative(self, a, b): 166 raise cherrypy.InternalRedirect("cousin?t=6") 167 168 def cousin(self, t): 169 assert cherrypy.request.prev.closed 170 return cherrypy.request.prev.query_string 171 172 def petshop(self, user_id): 173 if user_id == "parrot": 174 # Trade it for a slug when redirecting 175 raise cherrypy.InternalRedirect('/image/getImagesByUser?user_id=slug') 176 elif user_id == "terrier": 177 # Trade it for a fish when redirecting 178 raise cherrypy.InternalRedirect('/image/getImagesByUser?user_id=fish') 179 else: 180 # This should pass the user_id through to getImagesByUser 181 raise cherrypy.InternalRedirect('/image/getImagesByUser?user_id=%s' % user_id) 182 183 # We support Python 2.3, but the @-deco syntax would look like this: 184 # @tools.login_redir() 185 def secure(self): 186 return "Welcome!" 187 secure = tools.login_redir()(secure) 188 # Since calling the tool returns the same function you pass in, 189 # you could skip binding the return value, and just write: 190 # tools.login_redir()(secure) 191 192 def login(self): 193 return "Please log in" 194 login._cp_config = {'hooks.before_error_response': redir_custom} 195 196 def custom_err(self): 197 return "Something went horribly wrong." 198 199 def early_ir(self, arg): 200 return "whatever" 201 early_ir._cp_config = {'hooks.before_request_body': redir_custom} 202 203 class Image(Test): 204 205 def getImagesByUser(self, user_id): 206 return "0 images for %s" % user_id 207 208 209 class Flatten(Test): 210 211 def as_string(self): 212 return "content" 213 214 def as_list(self): 215 return ["con", "tent"] 216 217 def as_yield(self): 218 yield "content" 219 220 def as_dblyield(self): 221 yield self.as_yield() 222 as_dblyield._cp_config = {'tools.flatten.on': True} 223 224 def as_refyield(self): 225 for chunk in self.as_yield(): 226 yield chunk 227 228 229 class Error(Test): 230 231 _cp_config = {'tools.log_tracebacks.on': True, 232 } 233 234 def custom(self): 235 raise cherrypy.HTTPError(404, "No, <b>really</b>, not found!") 236 custom._cp_config = {'error_page.404': os.path.join(localDir, "static/index.html")} 237 238 def noexist(self): 239 raise cherrypy.HTTPError(404, "No, <b>really</b>, not found!") 240 noexist._cp_config = {'error_page.404': "nonexistent.html"} 241 242 def page_method(self): 243 raise ValueError() 244 245 def page_yield(self): 246 yield "howdy" 247 raise ValueError() 248 249 def page_streamed(self): 250 yield "word up" 251 raise ValueError() 252 yield "very oops" 253 page_streamed._cp_config = {"response.stream": True} 254 255 def cause_err_in_finalize(self): 256 # Since status must start with an int, this should error. 257 cherrypy.response.status = "ZOO OK" 258 cause_err_in_finalize._cp_config = {'request.show_tracebacks': False} 259 260 def rethrow(self): 261 """Test that an error raised here will be thrown out to the server.""" 262 raise ValueError() 263 rethrow._cp_config = {'request.throw_errors': True} 264 265 266 class Ranges(Test): 267 268 def get_ranges(self, bytes): 269 return repr(http.get_ranges('bytes=%s' % bytes, 8)) 270 271 def slice_file(self): 272 path = os.path.join(os.getcwd(), os.path.dirname(__file__)) 273 return static.serve_file(os.path.join(path, "static/index.html")) 274 275 276 class Expect(Test): 277 278 def expectation_failed(self): 279 expect = cherrypy.request.headers.elements("Expect") 280 if expect and expect[0].value != '100-continue': 281 raise cherrypy.HTTPError(400) 282 raise cherrypy.HTTPError(417, 'Expectation Failed') 283 284 class Headers(Test): 285 286 def default(self, headername): 287 """Spit back out the value for the requested header.""" 288 return cherrypy.request.headers[headername] 289 290 def doubledheaders(self): 291 # From http://www.cherrypy.org/ticket/165: 292 # "header field names should not be case sensitive sayes the rfc. 293 # if i set a headerfield in complete lowercase i end up with two 294 # header fields, one in lowercase, the other in mixed-case." 295 296 # Set the most common headers 297 hMap = cherrypy.response.headers 298 hMap['content-type'] = "text/html" 299 hMap['content-length'] = 18 300 hMap['server'] = 'CherryPy headertest' 301 hMap['location'] = ('%s://%s:%s/headers/' 302 % (cherrypy.request.local.ip, 303 cherrypy.request.local.port, 304 cherrypy.request.scheme)) 305 306 # Set a rare header for fun 307 hMap['Expires'] = 'Thu, 01 Dec 2194 16:00:00 GMT' 308 309 return "double header test" 310 311 def ifmatch(self): 312 val = cherrypy.request.headers['If-Match'] 313 cherrypy.response.headers['ETag'] = val 314 return repr(val) 315 316 317 class HeaderElements(Test): 318 319 def get_elements(self, headername): 320 e = cherrypy.request.headers.elements(headername) 321 return "\n".join([unicode(x) for x in e]) 322 323 324 class Method(Test): 325 326 def index(self): 327 m = cherrypy.request.method 328 if m in defined_http_methods: 329 return m 330 331 if m == "LINK": 332 raise cherrypy.HTTPError(405) 333 else: 334 raise cherrypy.HTTPError(501) 335 336 def parameterized(self, data): 337 return data 338 339 def request_body(self): 340 # This should be a file object (temp file), 341 # which CP will just pipe back out if we tell it to. 342 return cherrypy.request.body 343 344 def reachable(self): 345 return "success" 346 347 class Divorce: 348 """HTTP Method handlers shouldn't collide with normal method names. 349 For example, a GET-handler shouldn't collide with a method named 'get'. 350 351 If you build HTTP method dispatching into CherryPy, rewrite this class 352 to use your new dispatch mechanism and make sure that: 353 "GET /divorce HTTP/1.1" maps to divorce.index() and 354 "GET /divorce/get?ID=13 HTTP/1.1" maps to divorce.get() 355 """ 356 357 documents = {} 358 359 def index(self): 360 yield "<h1>Choose your document</h1>\n" 361 yield "<ul>\n" 362 for