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

root/trunk/cherrypy/test/modpy.py

Revision 1824 (checked in by fumanchu, 8 months ago)

Trunk fix for #752 (Return cherrypy.server to a single-server model):

  1. Change restsrv.servers.ServerManager? (multiple httpservers) to ServerAdapter? (one httpserver).
  2. cherrypy.server is now a subclass of ServerAdapter?, and is subscribed by default.
  3. Made several plugin methods idempotent that weren't before.
  4. Added names to win32 bus state events. Also fixed a buglet in win32 block().
  5. Added repr to wspbus.states.State objects.
  6. Did not change any callers of cherrypy.server other than what was necessary, to help prove the fixes work without breaking compatibility. Future changesets will be used to modify docs and tutorials n such.
  • Property svn:eol-style set to native
Line 
1 """Wrapper for mod_python, for use as a CherryPy HTTP server when testing.
2
3 To autostart modpython, 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 If you wish to test the WSGI interface instead of our _cpmodpy interface,
9 you also need the 'modpython_gateway' module at:
10 http://projects.amor.org/misc/wiki/ModPythonGateway
11
12
13 KNOWN BUGS
14 ==========
15
16 1. Apache processes Range headers automatically; CherryPy's truncated
17     output is then truncated again by Apache. See test_core.testRanges.
18     This was worked around in http://www.cherrypy.org/changeset/1319.
19 2. Apache does not allow custom HTTP methods like CONNECT as per the spec.
20     See test_core.testHTTPMethods.
21 3. Max request header and body settings do not work with Apache.
22 4. Apache replaces status "reason phrases" automatically. For example,
23     CherryPy may set "304 Not modified" but Apache will write out
24     "304 Not Modified" (capital "M").
25 5. Apache does not allow custom error codes as per the spec.
26 6. Apache (or perhaps modpython, or modpython_gateway) unquotes %xx in the
27     Request-URI too early.
28 7. mod_python will not read request bodies which use the "chunked"
29     transfer-coding (it passes REQUEST_CHUNKED_ERROR to ap_setup_client_block
30     instead of REQUEST_CHUNKED_DECHUNK, see Apache2's http_protocol.c and
31     mod_python's requestobject.c).
32 8. Apache will output a "Content-Length: 0" response header even if there's
33     no response entity body. This isn't really a bug; it just differs from
34     the CherryPy default.
35 """
36
37 import os
38 curdir = os.path.join(os.getcwd(), os.path.dirname(__file__))
39 import re
40 import time
41
42 from cherrypy.test import test
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 APACHE_PATH = "httpd"
59 CONF_PATH = "test_mp.conf"
60
61 conf_modpython_gateway = """
62 # Apache2 server conf file for testing CherryPy with modpython_gateway.
63
64 DocumentRoot "/"
65 Listen %s
66 LoadModule python_module modules/mod_python.so
67
68 SetHandler python-program
69 PythonFixupHandler cherrypy.test.modpy::wsgisetup
70 PythonOption testmod %s
71 PythonHandler modpython_gateway::handler
72 PythonOption wsgi.application cherrypy::tree
73 PythonOption socket_host %s
74 PythonDebug On
75 """
76
77 conf_cpmodpy = """
78 # Apache2 server conf file for testing CherryPy with _cpmodpy.
79
80 DocumentRoot "/"
81 Listen %s
82 LoadModule python_module modules/mod_python.so
83
84 SetHandler python-program
85 PythonFixupHandler cherrypy.test.modpy::cpmodpysetup
86 PythonHandler cherrypy._cpmodpy::handler
87 PythonOption cherrypy.setup cherrypy.test.%s::setup_server
88 PythonOption socket_host %s
89 PythonDebug On
90 """
91
92 def start(testmod, host, port, conf_template):
93     mpconf = CONF_PATH
94     if not os.path.isabs(mpconf):
95         mpconf = os.path.join(curdir, mpconf)
96    
97     f = open(mpconf, 'wb')
98     try:
99         f.write(conf_template % (port, testmod, host))
100     finally:
101         f.close()
102    
103     result = read_process(APACHE_PATH, "-k start -f %s" % mpconf)
104     if result:
105         print result
106
107 def stop():
108     """Gracefully shutdown a server that is serving forever."""
109     read_process(APACHE_PATH, "-k stop")
110
111
112 loaded = False
113 def wsgisetup(req):
114     global loaded
115     if not loaded:
116         loaded = True
117         options = req.get_options()
118        
119         import cherrypy
120         cherrypy.config.update({
121             "log.error_file": os.path.join(curdir, "test.log"),
122             "environment": "test_suite",
123             "server.socket_host": options['socket_host'],
124             })
125        
126         modname = options['testmod']
127         mod = __import__(modname, globals(), locals(), [''])
128         mod.setup_server()
129        
130         cherrypy.server.unsubscribe()
131         cherrypy.engine.start()
132     from mod_python import apache
133     return apache.OK
134
135
136 def cpmodpysetup(req):
137     global loaded
138     if not loaded:
139         loaded = True
140         options = req.get_options()
141        
142         import cherrypy
143         cherrypy.config.update({
144             "log.error_file": os.path.join(curdir, "test.log"),
145             "environment": "test_suite",
146             "server.socket_host": options['socket_host'],
147             })
148     from mod_python import apache
149     return apache.OK
150
151
152 class ModPythonTestHarness(test.TestHarness):
153     """TestHarness for ModPython and CherryPy."""
154    
155     use_wsgi = False
156    
157     def _run(self, conf):
158         from cherrypy.test import webtest
159         webtest.WebCase.PORT = self.port
160         webtest.WebCase.harness = self
161         webtest.WebCase.scheme = "http"
162         webtest.WebCase.interactive = self.interactive
163         print
164         print "Running tests:", self.server
165        
166         if self.use_wsgi:
167             conf_template = conf_modpython_gateway
168         else:
169             conf_template = conf_cpmodpy
170        
171         # mod_python, since it runs in the Apache process, must be
172         # started separately for each test, and then *that* process
173         # must run the setup_server() function for the test.
174         # Then our process can run the actual test.
175         success = True
176         for testmod in self.tests:
177             try:
178                 start(testmod, self.host, self.port, conf_template)
179                 suite = webtest.ReloadingTestLoader().loadTestsFromName(testmod)
180                 result = webtest.TerseTestRunner(verbosity=2).run(suite)
181                 success &= result.wasSuccessful()
182             finally:
183                 stop()
184         if success:
185             return 0
186         else:
187             return 1
188
Note: See TracBrowser for help on using the browser.

Hosted by WebFaction

Log in as guest/cpguest to create tickets