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

Source Code for Module cherrypy.test.modwsgi

  1  """Wrapper for mod_wsgi, for use as a CherryPy HTTP server. 
  2   
  3  To autostart modwsgi, the "apache" executable or script must be 
  4  on your system path, or you must override the global APACHE_PATH. 
  5  On some platforms, "apache" may be called "apachectl" or "apache2ctl"-- 
  6  create a symlink to them if needed. 
  7   
  8   
  9  KNOWN BUGS 
 10  ========== 
 11   
 12  ##1. Apache processes Range headers automatically; CherryPy's truncated 
 13  ##    output is then truncated again by Apache. See test_core.testRanges. 
 14  ##    This was worked around in http://www.cherrypy.org/changeset/1319. 
 15  2. Apache does not allow custom HTTP methods like CONNECT as per the spec. 
 16      See test_core.testHTTPMethods. 
 17  3. Max request header and body settings do not work with Apache. 
 18  ##4. Apache replaces status "reason phrases" automatically. For example, 
 19  ##    CherryPy may set "304 Not modified" but Apache will write out 
 20  ##    "304 Not Modified" (capital "M"). 
 21  ##5. Apache does not allow custom error codes as per the spec. 
 22  ##6. Apache (or perhaps modpython, or modpython_gateway) unquotes %xx in the 
 23  ##    Request-URI too early. 
 24  7. mod_wsgi will not read request bodies which use the "chunked" 
 25      transfer-coding (it passes REQUEST_CHUNKED_ERROR to ap_setup_client_block 
 26      instead of REQUEST_CHUNKED_DECHUNK, see Apache2's http_protocol.c and 
 27      mod_python's requestobject.c). 
 28  8. When responding with 204 No Content, mod_wsgi adds a Content-Length 
 29      header for you. 
 30  9. When an error is raised, mod_wsgi has no facility for printing a 
 31      traceback as the response content (it's sent to the Apache log instead). 
 32  10. Startup and shutdown of Apache when running mod_wsgi seems slow. 
 33  """ 
 34   
 35  import os 
 36  curdir = os.path.join(os.getcwd(), os.path.dirname(__file__)) 
 37  import re 
 38  import time 
 39   
 40  from cherrypy.test import test 
 41   
 42   
43 -def read_process(cmd, args=""):
44 pipein, pipeout = os.popen4("%s %s" % (cmd, args)) 45 try: 46 firstline = pipeout.readline() 47 if (re.search(r"(not recognized|No such file|not found)", firstline, 48 re.IGNORECASE)): 49 raise IOError('%s must be on your system path.' % cmd) 50 output = firstline + pipeout.read() 51 finally: 52 pipeout.close() 53 return output
54 55 56 APACHE_PATH = "apache" 57 CONF_PATH = "test_mw.conf" 58 59 conf_modwsgi = """ 60 # Apache2 server conf file for testing CherryPy with modpython_gateway. 61 62 DocumentRoot "/" 63 Listen %%s 64 LoadModule wsgi_module modules/mod_wsgi.so 65 LoadModule env_module modules/mod_env.so 66 67 WSGIScriptAlias / %s 68 SetEnv testmod %%s 69 """ % os.path.join(curdir, 'modwsgi.py') 70 71
72 -def start(testmod, port, conf_template):
73 mpconf = CONF_PATH 74 if not os.path.isabs(mpconf): 75 mpconf = os.path.join(curdir, mpconf) 76 77 f = open(mpconf, 'wb') 78 try: 79 f.write(conf_template % (port, testmod)) 80 finally: 81 f.close() 82 83 result = read_process(APACHE_PATH, "-k start -f %s" % mpconf) 84 if result: 85 print result
86
87 -def stop():
88 """Gracefully shutdown a server that is serving forever.""" 89 read_process(APACHE_PATH, "-k stop")
90 91
92 -class ModWSGITestHarness(test.TestHarness):
93 """TestHarness for ModWSGI and CherryPy.""" 94 95 use_wsgi = True 96
97 - def _run(self, conf):
98 from cherrypy.test import webtest 99 webtest.WebCase.PORT = self.port 100 webtest.WebCase.harness = self 101 webtest.WebCase.scheme = "http" 102 webtest.WebCase.interactive = self.interactive 103 print 104 print "Running tests:", self.server 105 106 conf_template = conf_modwsgi 107 108 # mod_wsgi, since it runs in the Apache process, must be 109 # started separately for each test, and then *that* process 110 # must run the setup_server() function for the test. 111 # Then our process can run the actual test. 112 success = True 113 for testmod in self.tests: 114 try: 115 start(testmod, self.port, conf_template) 116 suite = webtest.ReloadingTestLoader().loadTestsFromName(testmod) 117 result = webtest.TerseTestRunner(verbosity=2).run(suite) 118 success &= result.wasSuccessful() 119 finally: 120 stop() 121 if success: 122 return 0 123 else: 124 return 1
125 126 127 loaded = False
128 -def application(environ, start_response):
129 import cherrypy 130 global loaded 131 if not loaded: 132 loaded = True 133 modname = "cherrypy.test." + environ['testmod'] 134 mod = __import__(modname, globals(), locals(), ['']) 135 mod.setup_server() 136 137 cherrypy.config.update({ 138 "log.error_file": os.path.join(curdir, "test.log"), 139 "environment": "test_suite", 140 "engine.SIGHUP": None, 141 "engine.SIGTERM": None, 142 }) 143 cherrypy.engine.start(blocking=False) 144 return cherrypy.tree(environ, start_response)
145