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.abspath(os.path.dirname(__file__)) 
 37  import re 
 38  import sys 
 39  import time 
 40   
 41  import cherrypy 
 42  from cherrypy.test import test, webtest 
 43   
 44   
45 -def read_process(cmd, args=""):
46 pipein, pipeout = os.popen4("%s %s" % (cmd, args)) 47 try: 48 firstline = pipeout.readline() 49 if (re.search(r"(not recognized|No such file|not found)", firstline, 50 re.IGNORECASE)): 51 raise IOError('%s must be on your system path.' % cmd) 52 output = firstline + pipeout.read() 53 finally: 54 pipeout.close() 55 return output
56 57 58 if sys.platform == 'win32': 59 APACHE_PATH = "httpd" 60 else: 61 APACHE_PATH = "apache" 62 63 CONF_PATH = "test_mw.conf" 64 65 conf_modwsgi = r""" 66 # Apache2 server conf file for testing CherryPy with modpython_gateway. 67 68 ServerName 127.0.0.1 69 DocumentRoot "/" 70 Listen %(port)s 71 72 AllowEncodedSlashes On 73 LoadModule rewrite_module modules/mod_rewrite.so 74 RewriteEngine on 75 RewriteMap escaping int:escape 76 77 LoadModule log_config_module modules/mod_log_config.so 78 LogFormat "%%h %%l %%u %%t \"%%r\" %%>s %%b \"%%{Referer}i\" \"%%{User-agent}i\"" combined 79 CustomLog "%(curdir)s/apache.access.log" combined 80 ErrorLog "%(curdir)s/apache.error.log" 81 LogLevel debug 82 83 LoadModule wsgi_module modules/mod_wsgi.so 84 LoadModule env_module modules/mod_env.so 85 86 WSGIScriptAlias / "%(curdir)s/modwsgi.py" 87 SetEnv testmod %(testmod)s 88 """ 89 90
91 -def start(testmod, port, conf_template):
92 mpconf = CONF_PATH 93 if not os.path.isabs(mpconf): 94 mpconf = os.path.join(curdir, mpconf) 95 96 f = open(mpconf, 'wb') 97 try: 98 output = (conf_template % 99 {'port': port, 'testmod': testmod, 'curdir': curdir}) 100 f.write(output) 101 finally: 102 f.close() 103 104 result = read_process(APACHE_PATH, "-k start -f %s" % mpconf) 105 if result: 106 print result
107
108 -def stop():
109 """Gracefully shutdown a server that is serving forever.""" 110 read_process(APACHE_PATH, "-k stop")
111 112
113 -class ModWSGITestHarness(test.TestHarness):
114 """TestHarness for ModWSGI and CherryPy.""" 115 116 use_wsgi = True 117
118 - def _run(self, conf):
119 cherrypy.server.using_wsgi = True 120 cherrypy.server.using_apache = True 121 122 from cherrypy.test import webtest 123 webtest.WebCase.PORT = self.port 124 webtest.WebCase.harness = self 125 webtest.WebCase.scheme = "http" 126 webtest.WebCase.interactive = self.interactive 127 print 128 print "Running tests:", self.server 129 130 conf_template = conf_modwsgi 131 132 # mod_wsgi, since it runs in the Apache process, must be 133 # started separately for each test, and then *that* process 134 # must run the setup_server() function for the test. 135 # Then our process can run the actual test. 136 success = True 137 for testmod in self.tests: 138 try: 139 start(testmod, self.port, conf_template) 140 cherrypy._cpserver.wait_for_occupied_port("127.0.0.1", self.port) 141 suite = webtest.ReloadingTestLoader().loadTestsFromName(testmod) 142 # Make a request so mod_wsgi starts up our app. 143 # If we don't, concurrent initial requests will 404. 144 webtest.openURL('/ihopetheresnodefault', port=self.port) 145 time.sleep(1) 146 result = webtest.TerseTestRunner(verbosity=2).run(suite) 147 success &= result.wasSuccessful() 148 finally: 149 stop() 150 if success: 151 return 0 152 else: 153 return 1
154 155 156 loaded = False
157 -def application(environ, start_response):
158 import cherrypy 159 global loaded 160 if not loaded: 161 loaded = True 162 modname = "cherrypy.test." + environ['testmod'] 163 mod = __import__(modname, globals(), locals(), ['']) 164 mod.setup_server() 165 166 cherrypy.config.update({ 167 "log.error_file": os.path.join(curdir, "test.error.log"), 168 "log.access_file": os.path.join(curdir, "test.access.log"), 169 "environment": "test_suite", 170 "engine.SIGHUP": None, 171 "engine.SIGTERM": None, 172 }) 173 return cherrypy.tree(environ, start_response)
174