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

root/branches/cp3-wsgi-remix/test/test.py

Revision 1244 (checked in by dowski, 2 years ago)

Created a branch for some WSGI related ideas that I have implemented.

  • Property svn:eol-style set to native
Line 
1 """The actual script that runs the entire CP test suite.
2
3 There is a library of helper functions for the CherryPy test suite,
4 called "helper.py" (in this folder); this module calls that as a library.
5 """
6
7 # GREAT CARE has been taken to separate this module from helper.py,
8 # because different consumers of each have mutually-exclusive import
9 # requirements. So don't go moving functions from here into helper.py,
10 # or vice-versa, unless you *really* know what you're doing.
11
12
13 import sys
14 import os, os.path
15 import webtest
16 import getopt
17
18
19 class TestHarness(object):
20     """A test harness for the CherryPy framework and CherryPy applications."""
21    
22     def __init__(self, tests=None, server=None, protocol="HTTP/1.1", port=8000):
23         """Constructor to populate the TestHarness instance.
24         
25         tests should be a list of module names (strings).
26         """
27         self.protocol = protocol
28         self.port = port
29         self.server = server
30         self.tests = tests or []
31    
32     def run(self, conf=None):
33         """Run the test harness."""
34         import cherrypy
35         v = sys.version.split()[0]
36         print "Python version used to run this test script:", v
37         print "CherryPy version", cherrypy.__version__
38         print
39        
40         if isinstance(conf, basestring):
41             conf = cherrypy.config.dict_from_config_file(conf)
42         baseconf = {'server.socket_host': '127.0.0.1',
43                     'server.socket_port': self.port,
44                     'server.thread_pool': 10,
45                     'log_to_screen': False,
46                     'environment': "production",
47                     'show_tracebacks': True,
48                     }
49         baseconf.update(conf or {})
50        
51         baseconf['server.protocol_version'] = self.protocol
52         self._run(baseconf)
53    
54     def _run(self, conf):
55         # helper must be imported lazily so the coverage tool
56         # can run against module-level statements within cherrypy.
57         # Also, we have to do a relative import here, not
58         # "from cherrypy.test import helper", because the latter
59         # would stick a second instance of webtest in sys.modules,
60         # and we wouldn't be able to globally override the port anymore.
61         import helper
62         webtest.WebCase.PORT = self.port
63         print
64         print "Running tests:", self.server
65         helper.run_test_suite(self.tests, self.server, conf)
66
67
68 class CommandLineParser(object):
69     available_servers = {'wsgi': "cherrypy._cpwsgi.WSGIServer",
70                          'cpmodpy': "cpmodpy",
71                          'modpygw': "modpygw",
72                          }
73     default_server = "wsgi"
74    
75     def __init__(self, available_tests, args=sys.argv[1:]):
76         """Constructor to populate the TestHarness instance.
77         
78         available_tests should be a list of module names (strings).
79         
80         args defaults to sys.argv[1:], but you can provide a different
81             set of args if you like.
82         """
83         self.available_tests = available_tests
84         self.cover = False
85         self.profile = False
86         self.server = None
87         self.port = 8080
88         self.protocol = "HTTP/1.1"
89        
90         longopts = ['cover', 'profile', '1.0', 'help', 'basedir=', 'port=',
91                     'server=']
92         longopts.extend(self.available_servers)
93         longopts.extend(self.available_tests)
94         try:
95             opts, args = getopt.getopt(args, "", longopts)
96         except getopt.GetoptError:
97             # print help information and exit
98             self.help()
99             sys.exit(2)
100        
101         self.tests = []
102        
103         for o, a in opts:
104             if o == '--help':
105                 self.help()
106                 sys.exit()
107             elif o == "--cover":
108                 self.cover = True
109             elif o == "--profile":
110                 self.profile = True
111             elif o == "--1.0":
112                 self.protocol = "HTTP/1.0"
113             elif o == "--basedir":
114                 self.basedir = a
115             elif o == "--port":
116                 self.port = int(a)
117             elif o == "--server":
118                 if a in self.available_servers:
119                     a = self.available_servers[a]
120                 self.server = a
121             else:
122                 o = o[2:]
123                 if o in self.available_tests and o not in self.tests:
124                     self.tests.append(o)
125        
126         if self.cover and self.profile:
127             # Print error message and exit
128             print ('Error: you cannot run the profiler and the '
129                    'coverage tool at the same time.')
130             sys.exit(2)
131        
132         if not self.server:
133             self.server = self.available_servers[self.default_server]
134        
135         if not self.tests:
136             self.tests = self.available_tests[:]
137    
138     def help(self):
139         """Print help for test.py command-line options."""
140        
141         print """CherryPy Test Program
142     Usage:
143         test.py --server=* --1.0 --cover --basedir=path --profile --tests**
144         
145     """
146         print '    * servers:'
147         for name, val in self.available_servers.iteritems():
148             if name == self.default_server:
149                 print '        --server=%s: %s (default)' % (name, val)
150             else:
151                 print '        --server=%s: %s' % (name, val)
152        
153         print """
154     
155     --1.0: use HTTP/1.0 servers instead of default HTTP/1.1
156     
157     --cover: turn on code-coverage tool
158     --basedir=path: display coverage stats for some path other than cherrypy.
159     
160     --profile: turn on profiling tool
161     """
162        
163         print '    ** tests:'
164         for name in self.available_tests:
165             print '        --' + name
166    
167     def start_coverage(self):
168         """Start the coverage tool.
169         
170         To use this feature, you need to download 'coverage.py',
171         either Gareth Rees' original implementation:
172         http://www.garethrees.org/2001/12/04/python-coverage/
173         
174         or Ned Batchelder's enhanced version:
175         http://www.nedbatchelder.com/code/modules/coverage.html
176         
177         If neither module is found in PYTHONPATH,
178         coverage is silently(!) disabled.
179         """
180         try:
181             from coverage import the_coverage as coverage
182             c = os.path.join(os.path.dirname(__file__), "../lib/coverage.cache")
183             coverage.cache_default = c
184             if c and os.path.exists(c):
185                 os.remove(c)
186             coverage.start()
187             import cherrypy
188             from cherrypy.lib import covercp
189             cherrypy.engine.on_start_engine_list.insert(0, covercp.start)
190             cherrypy.engine.on_start_thread_list.insert(0, covercp.start)
191         except ImportError:
192             coverage = None
193         self.coverage = coverage
194    
195     def stop_coverage(self):
196         """Stop the coverage tool, save results, and report."""
197         import cherrypy
198         from cherrypy.lib import covercp
199         while covercp.start in cherrypy.engine.on_start_engine_list:
200             cherrypy.engine.on_start_engine_list.remove(covercp.start)
201         while covercp.start in cherrypy.engine.on_start_thread_list:
202             cherrypy.engine.on_start_thread_list.remove(covercp.start)
203         if self.coverage:
204             self.coverage.save()
205             self.report_coverage()
206             print ("run cherrypy/lib/covercp.py as a script to serve "
207                    "coverage results on port 8080")
208    
209     def report_coverage(self):
210         """Print a summary from the code coverage tool."""
211        
212         basedir = self.basedir
213         if basedir is None:
214             # Assume we want to cover everything in "../../cherrypy/"
215             localDir = os.path.dirname(__file__)
216             basedir = os.path.normpath(os.path.join(os.getcwd(), localDir, '../'))
217         else:
218             if not os.path.isabs(basedir):
219                 basedir = os.path.normpath(os.path.join(os.getcwd(), basedir))
220         basedir = basedir.lower()
221        
222         self.coverage.get_ready()
223         morfs = [x for x in self.coverage.cexecuted
224                  if x.lower().startswith(basedir)]
225        
226         total_statements = 0
227         total_executed = 0
228        
229         print
230         print "CODE COVERAGE (this might take a while)",
231         for morf in morfs:
232             sys.stdout.write(".")
233             sys.stdout.flush()
234             name = os.path.split(morf)[1]
235             if morf.find('test') != -1:
236                 continue
237             try:
238                 _, statements, _, missing, readable  = self.coverage.analysis2(morf)
239                 n = len(statements)
240                 m = n - len(missing)
241                 total_statements = total_statements + n
242                 total_executed = total_executed + m
243             except KeyboardInterrupt:
244                 raise
245             except:
246                 # No, really! We truly want to ignore any other errors.
247                 pass
248        
249         pc = 100.0
250         if total_statements > 0:
251             pc = 100.0 * total_executed / total_statements
252        
253         print ("\nTotal: %s Covered: %s Percent: %2d%%"
254                % (total_statements, total_executed, pc))
255    
256     def run(self, conf=None):
257         """Run the test harness."""
258         # Start the coverage tool before importing cherrypy,
259         # so module-level global statements are covered.
260         if self.cover:
261             self.start_coverage()
262        
263         if self.profile:
264             conf = conf or {}
265             conf['profiling.on'] = True
266        
267         if self.server == 'cpmodpy':
268             import modpy
269             m = modpy.ModPythonTestHarness(self.tests, self.server,
270                                            self.protocol, self.port)
271             m.use_wsgi = False
272             m.run(conf)
273         elif self.server == 'modpygw':
274             import modpy
275             m = modpy.ModPythonTestHarness(self.tests, self.server,
276                                            self.protocol, self.port)
277             m.use_wsgi = True
278             m.run(conf)
279         else:
280             TestHarness(self.tests, self.server,
281                         self.protocol, self.port).run(conf)
282        
283         if self.profile:
284             del conf['profiling.on']
285             print
286             print ("run /cherrypy/lib/profiler.py as a script to serve "
287                    "profiling results on port 8080")
288        
289         if self.cover:
290             self.stop_coverage()
291
292
293 def prefer_parent_path():
294     # Place this __file__'s grandparent (../../) at the start of sys.path,
295     # so that all cherrypy/* imports are from this __file__'s package.
296     localDir = os.path.dirname(__file__)
297     curpath = os.path.normpath(os.path.join(os.getcwd(), localDir))
298     grandparent = os.path.normpath(os.path.join(curpath, '../../'))
299     if grandparent not in sys.path:
300         sys.path.insert(0, grandparent)
301
302 def run():
303    
304     prefer_parent_path()
305    
306     testList = [
307         'test_proxy',
308         'test_caching',
309         'test_config',
310         'test_core',
311         'test_tools',
312         'test_decodingencoding',
313         'test_etags',
314         'test_gzip',
315         'test_objectmapping',
316         'test_response_headers',
317         'test_static',
318         'test_tutorials',
319         'test_virtualhost',
320         'test_session',
321         'test_sessionauthenticate',
322 ##        'test_states',
323         'test_xmlrpc',
324         'test_wsgiapps',
325     ]
326     CommandLineParser(testList).run()
327    
328     print
329     raw_input('hit enter')
330
331
332 if __name__ == '__main__':
333     run()
Note: See TracBrowser for help on using the browser.

Hosted by WebFaction

Log in as guest/cpguest to create tickets