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

root/branches/cherrypy-3.0.x/cherrypy/test/helper.py

Revision 1712 (checked in by fumanchu, 1 year ago)

Buglets.

  • Property svn:eol-style set to native
Line 
1 """A library of helper functions for the CherryPy test suite.
2
3 The actual script that runs the entire CP test suite is called
4 "test.py" (in this folder); test.py calls this module as a library.
5
6 Usage
7 =====
8 Each individual test_*.py module imports this module (helper),
9 usually to make an instance of CPWebCase, and then call testmain().
10
11 The CP test suite script (test.py) imports this module and calls
12 run_test_suite, possibly more than once. CP applications may also
13 import test.py (to use TestHarness), which then calls helper.py.
14 """
15
16 # GREAT CARE has been taken to separate this module from test.py,
17 # because different consumers of each have mutually-exclusive import
18 # requirements. So don't go moving functions from here into test.py,
19 # or vice-versa, unless you *really* know what you're doing.
20
21 import re
22 import sys
23 import thread
24 import warnings
25
26 import cherrypy
27 from cherrypy.lib import http, profiler
28 from cherrypy.test import webtest
29
30
31 class CPWebCase(webtest.WebCase):
32    
33     script_name = ""
34     scheme = "http"
35    
36     def prefix(self):
37         return self.script_name.rstrip("/")
38    
39     def base(self):
40         if ((self.scheme == "http" and self.PORT == 80) or
41             (self.scheme == "https" and self.PORT == 443)):
42             port = ""
43         else:
44             port = ":%s" % self.PORT
45        
46         host = self.HOST
47         if not host:
48             # The empty string signifies INADDR_ANY,
49             # which should respond on localhost.
50             host = "127.0.0.1"
51        
52         return "%s://%s%s%s" % (self.scheme, host, port,
53                                 self.script_name.rstrip("/"))
54    
55     def exit(self):
56         sys.exit()
57    
58     def tearDown(self):
59         pass
60    
61     def getPage(self, url, headers=None, method="GET", body=None, protocol=None):
62         """Open the url. Return status, headers, body."""
63         if self.script_name:
64             url = http.urljoin(self.script_name, url)
65         webtest.WebCase.getPage(self, url, headers, method, body, protocol)
66    
67     def assertErrorPage(self, status, message=None, pattern=''):
68         """Compare the response body with a built in error page.
69         
70         The function will optionally look for the regexp pattern,
71         within the exception embedded in the error page."""
72        
73         # This will never contain a traceback
74         page = cherrypy._cperror.get_error_page(status, message=message)
75        
76         # First, test the response body without checking the traceback.
77         # Stick a match-all group (.*) in to grab the traceback.
78         esc = re.escape
79         epage = esc(page)
80         epage = epage.replace(esc('<pre id="traceback"></pre>'),
81                               esc('<pre id="traceback">') + '(.*)' + esc('</pre>'))
82         m = re.match(epage, self.body, re.DOTALL)
83         if not m:
84             self._handlewebError('Error page does not match\n' + page)
85             return
86        
87         # Now test the pattern against the traceback
88         if pattern is None:
89             # Special-case None to mean that there should be *no* traceback.
90             if m and m.group(1):
91                 self._handlewebError('Error page contains traceback')
92         else:
93             if (m is None) or (not re.search(re.escape(pattern), m.group(1))):
94                 msg = 'Error page does not contain %s in traceback'
95                 self._handlewebError(msg % repr(pattern))
96
97
98 CPTestLoader = webtest.ReloadingTestLoader()
99 CPTestRunner = webtest.TerseTestRunner(verbosity=2)
100
101 def setConfig(conf):
102     """Set the global config using a copy of conf."""
103     if isinstance(conf, basestring):
104         # assume it's a filename
105         cherrypy.config.update(conf)
106     else:
107         cherrypy.config.update(conf.copy())
108
109
110 def run_test_suite(moduleNames, server, conf):
111     """Run the given test modules using the given server and conf.
112     
113     The server is started and stopped once, regardless of the number
114     of test modules. The config, however, is reset for each module.
115     """
116     cherrypy.config.reset()
117     setConfig(conf)
118     cherrypy.server.quickstart(server)
119     # The Pybots automatic testing system needs the suite to exit
120     # with a non-zero value if there were any problems.
121     # Might as well stick it in the engine... :/
122     cherrypy.engine.test_success = True
123     cherrypy.engine.start_with_callback(_run_test_suite_thread,
124                                         args=(moduleNames, conf))
125     if cherrypy.engine.test_success:
126         return 0
127     else:
128         return 1
129
130 def sync_apps(profile=False, validate=False, conquer=False):
131     apps = []
132     for base, app in cherrypy.tree.apps.iteritems():
133         if base == "/":
134             base = ""
135         if profile:
136             app = profiler.make_app(app, aggregate=False)
137         if conquer:
138             try:
139                 import wsgiconq
140             except ImportError:
141                 warnings.warn("Error importing wsgiconq. pyconquer will not run.")
142             else:
143                 app = wsgiconq.WSGILogger(app)
144         if validate:
145             try:
146                 from wsgiref import validate
147             except ImportError:
148                 warnings.warn("Error importing wsgiref. The validator will not run.")
149             else:
150                 app = validate.validator(app)
151         apps.append((base, app))
152     apps.sort()
153     apps.reverse()
154     for s in cherrypy.server.httpservers:
155         s.mount_points = apps
156
157 def _run_test_suite_thread(moduleNames, conf):
158     for testmod in moduleNames:
159         # Must run each module in a separate suite,
160         # because each module uses/overwrites cherrypy globals.
161         cherrypy.tree = cherrypy._cptree.Tree()
162         cherrypy.config.reset()
163         setConfig(conf)
164        
165         m = __import__(testmod, globals(), locals())
166         setup = getattr(m, "setup_server", None)
167         if setup:
168             setup()
169        
170         # The setup functions probably mounted new apps.
171         # Tell our server about them.
172         sync_apps(profile=conf.get("profiling.on", False),
173                   validate=conf.get("validator.on", False),
174                   conquer=conf.get("conquer.on", False),
175                   )
176        
177         suite = CPTestLoader.loadTestsFromName(testmod)
178         result = CPTestRunner.run(suite)
179         cherrypy.engine.test_success &= result.wasSuccessful()
180        
181         teardown = getattr(m, "teardown_server", None)
182         if teardown:
183             teardown()
184     thread.interrupt_main()
185
186 def testmain(conf=None):
187     """Run __main__ as a test module, with webtest debugging."""
188     if conf is None:
189         conf = {'server.socket_host': '127.0.0.1'}
190     setConfig(conf)
191     try:
192         cherrypy.server.quickstart()
193         cherrypy.engine.start_with_callback(_test_main_thread)
194     except KeyboardInterrupt:
195         cherrypy.server.stop()
196         cherrypy.engine.stop()
197
198 def _test_main_thread():
199     try:
200         webtest.WebCase.PORT = cherrypy.server.socket_port
201         webtest.main()
202     finally:
203         thread.interrupt_main()
204
Note: See TracBrowser for help on using the browser.

Hosted by WebFaction

Log in as guest/cpguest to create tickets