Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

root/trunk/cherrypy/test/modwsgi.py

Revision 2017 (checked in by fumanchu, 2 months ago)

More updates to mod_wsgi test harness.

  • Property svn:eol-style set to native
Line 
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         from cherrypy.test import webtest
120         webtest.WebCase.PORT = self.port
121         webtest.WebCase.harness = self
122         webtest.WebCase.scheme = "http"
123         webtest.WebCase.interactive = self.interactive
124         print
125         print "Running tests:", self.server
126        
127         conf_template = conf_modwsgi
128        
129         # mod_wsgi, since it runs in the Apache process, must be
130         # started separately for each test, and then *that* process
131         # must run the setup_server() function for the test.
132         # Then our process can run the actual test.
133         success = True
134         for testmod in self.tests:
135             try:
136                 start(testmod, self.port, conf_template)
137                 cherrypy._cpserver.wait_for_occupied_port("127.0.0.1", self.port)
138                 suite = webtest.ReloadingTestLoader().loadTestsFromName(testmod)
139                 # Make a request so mod_wsgi starts up our app.
140                 # If we don't, concurrent initial requests will 404.
141                 webtest.openURL('/ihopetheresnodefault', port=self.port)
142                 time.sleep(1)
143                 result = webtest.TerseTestRunner(verbosity=2).run(suite)
144                 success &= result.wasSuccessful()
145             finally:
146                 stop()
147         if success:
148             return 0
149         else:
150             return 1
151
152
153 loaded = False
154 def application(environ, start_response):
155     import cherrypy
156     global loaded
157     if not loaded:
158         loaded = True
159         modname = "cherrypy.test." + environ['testmod']
160         mod = __import__(modname, globals(), locals(), [''])
161         mod.setup_server()
162        
163         cherrypy.config.update({
164             "log.error_file": os.path.join(curdir, "test.error.log"),
165             "log.access_file": os.path.join(curdir, "test.access.log"),
166             "environment": "test_suite",
167             "engine.SIGHUP": None,
168             "engine.SIGTERM": None,
169             })
170     return cherrypy.tree(environ, start_response)
171
Note: See TracBrowser for help on using the browser.

Hosted by WebFaction

Log in as guest/cpguest to create tickets