Package cherrypy :: Package test :: Module test
[hide private]
[frames] | no frames]

Source Code for Module cherrypy.test.test

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