Changeset 2004
- Timestamp:
- 06/30/08 12:00:35
- Files:
-
- trunk/cherrypy/test/helper.py (modified) (5 diffs)
- trunk/cherrypy/test/test_states.py (modified) (12 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/cherrypy/test/helper.py
r2002 r2004 19 19 # or vice-versa, unless you *really* know what you're doing. 20 20 21 import os 22 thisdir = os.path.abspath(os.path.dirname(__file__)) 21 23 import re 22 24 import sys 23 25 import thread 26 import time 24 27 import warnings 25 28 … … 180 183 def testmain(conf=None): 181 184 """Run __main__ as a test module, with webtest debugging.""" 185 engine = cherrypy.engine 182 186 if '--server' in sys.argv: 183 187 # Run the test module server-side only; wait for Ctrl-C to break. … … 185 189 conf['server.socket_host'] = '0.0.0.0' 186 190 setConfig(conf) 187 cherrypy.engine.start() 188 cherrypy.engine.block() 191 if hasattr(engine, "signal_handler"): 192 engine.signal_handler.subscribe() 193 if hasattr(engine, "console_control_handler"): 194 engine.console_control_handler.subscribe() 195 engine.start() 196 engine.block() 189 197 else: 190 198 for arg in sys.argv: … … 204 212 conf['server.socket_host'] = '127.0.0.1' 205 213 setConfig(conf) 206 cherrypy.engine.start_with_callback(_test_main_thread)207 cherrypy.engine.block()214 engine.start_with_callback(_test_main_thread) 215 engine.block() 208 216 209 217 def _test_main_thread(): … … 214 222 cherrypy.engine.exit() 215 223 224 225 226 # --------------------------- Spawning helpers --------------------------- # 227 228 229 class CPProcess(object): 230 231 pid_file = os.path.join(thisdir, 'test.pid') 232 config_file = os.path.join(thisdir, 'test.conf') 233 config_template = """[global] 234 server.socket_host: '%(host)s' 235 server.socket_port: %(port)s 236 log.screen: False 237 log.error_file: r'%(error_log)s' 238 log.access_file: r'%(access_log)s' 239 %(ssl)s 240 %(extra)s 241 """ 242 error_log = os.path.join(thisdir, 'test.error.log') 243 access_log = os.path.join(thisdir, 'test.access.log') 244 245 def __init__(self, wait=False, daemonize=False, ssl=False): 246 self.wait = wait 247 self.daemonize = daemonize 248 self.ssl = ssl 249 self.host = cherrypy.server.socket_host 250 self.port = cherrypy.server.socket_port 251 252 def write_conf(self, extra=""): 253 if self.ssl: 254 serverpem = os.path.join(thisdir, 'test.pem') 255 ssl = """ 256 server.ssl_certificate: r'%s' 257 server.ssl_private_key: r'%s' 258 """ % (serverpem, serverpem) 259 else: 260 ssl = "" 261 262 f = open(self.config_file, 'wb') 263 f.write(self.config_template % 264 {'host': self.host, 265 'port': self.port, 266 'error_log': self.error_log, 267 'access_log': self.access_log, 268 'ssl': ssl, 269 'extra': extra, 270 }) 271 f.close() 272 273 def start(self, imports=None): 274 """Start cherryd in a subprocess.""" 275 cherrypy._cpserver.wait_for_free_port(self.host, self.port) 276 277 args = [sys.executable, os.path.join(thisdir, '..', 'cherryd'), 278 '-c', self.config_file, '-p', self.pid_file] 279 280 if not isinstance(imports, (list, tuple)): 281 imports = [imports] 282 for i in imports: 283 if i: 284 args.append('-i') 285 args.append(i) 286 287 if self.daemonize: 288 args.append('-d') 289 290 if self.wait: 291 self.exit_code = os.spawnl(os.P_WAIT, sys.executable, *args) 292 else: 293 os.spawnl(os.P_NOWAIT, sys.executable, *args) 294 cherrypy._cpserver.wait_for_occupied_port(self.host, self.port) 295 296 # Give the engine a wee bit more time to finish STARTING 297 if self.daemonize: 298 time.sleep(2) 299 else: 300 time.sleep(1) 301 302 def get_pid(self): 303 return int(open(self.pid_file, 'rb').read()) 304 305 def join(self): 306 """Wait for the process to exit.""" 307 try: 308 try: 309 # Mac, UNIX 310 os.wait() 311 except AttributeError: 312 # Windows 313 try: 314 pid = self.get_pid() 315 except IOError: 316 # Assume the subprocess deleted the pidfile on shutdown. 317 pass 318 else: 319 os.waitpid(pid, 0) 320 except OSError, x: 321 if x.args != (10, 'No child processes'): 322 raise 323 trunk/cherrypy/test/test_states.py
r1999 r2004 13 13 engine = cherrypy.engine 14 14 thisdir = os.path.join(os.getcwd(), os.path.dirname(__file__)) 15 PID_file_path = os.path.join(thisdir, 'pid_for_test_daemonize')16 17 18 def write_conf(scheme='http', extra=""):19 if scheme.lower() == 'https':20 serverpem = os.path.join(thisdir, 'test.pem')21 ssl = """22 server.ssl_certificate: r'%s'23 server.ssl_private_key: r'%s'24 """ % (serverpem, serverpem)25 else:26 ssl = ""27 28 conffile = open(os.path.join(thisdir, 'test_states.conf'), 'wb')29 conffile.write("""[global]30 server.socket_host: '%(host)s'31 server.socket_port: %(port)s32 log.screen: False33 log.error_file: r'%(error_log)s'34 log.access_file: r'%(access_log)s'35 %(ssl)s36 %(extra)s37 """ % {'host': host,38 'port': port,39 'error_log': os.path.join(thisdir, 'test_states_demo.error.log'),40 'access_log': os.path.join(thisdir, 'test_states_demo.access.log'),41 'ssl': ssl,42 'extra': extra,43 })44 conffile.close()45 46 47 def spawn_cp(configfile=os.path.join(thisdir, 'test_states.conf'),48 wait=False, daemonize=False):49 """Start cherryd in a subprocess."""50 host = cherrypy.server.socket_host51 port = cherrypy.server.socket_port52 cherrypy._cpserver.wait_for_free_port(host, port)53 54 args = [sys.executable, os.path.join(thisdir, '..', 'cherryd'),55 '-c', configfile, '-i', 'cherrypy.test.test_states_demo']56 57 if sys.platform != 'win32':58 args.append('-p')59 args.append(PID_file_path)60 61 # Spawn the process and wait, when this returns, the original process62 # is finished. If it daemonized properly, we should still be able63 # to access pages.64 if daemonize:65 args.append('-d')66 67 if wait:68 result = os.spawnl(os.P_WAIT, sys.executable, *args)69 else:70 result = os.spawnl(os.P_NOWAIT, sys.executable, *args)71 cherrypy._cpserver.wait_for_occupied_port(host, port)72 73 # Give the engine a wee bit more time to finish STARTING74 if daemonize:75 time.sleep(2)76 else:77 time.sleep(1)78 79 return result80 81 def wait(pid):82 """Wait for the process with the given pid to exit."""83 try:84 try:85 # Mac, UNIX86 os.wait()87 except AttributeError:88 # Windows89 os.waitpid(pid, 0)90 except OSError, x:91 if x.args != (10, 'No child processes'):92 raise93 15 94 16 … … 342 264 343 265 # Start the demo script in a new process 344 write_conf(scheme=self.scheme) 345 pid = spawn_cp() 266 p = helper.CPProcess(ssl=(self.scheme.lower()=='https')) 267 p.write_conf() 268 p.start(imports='cherrypy.test.test_states_demo') 346 269 try: 347 270 self.getPage("/start") … … 357 280 time.sleep(2) 358 281 cherrypy._cpserver.wait_for_occupied_port(host, port) 359 360 self.getPage("/pid")361 pid = int(self.body)362 282 363 283 self.getPage("/start") … … 366 286 # Shut down the spawned process 367 287 self.getPage("/exit") 368 wait(pid)288 p.join() 369 289 370 290 def test_5_Start_Error(self): … … 375 295 # If a process errors during start, it should stop the engine 376 296 # and exit with a non-zero exit code. 377 write_conf(scheme=self.scheme, extra="starterror: True") 378 exit_code = spawn_cp(wait=True) 379 if exit_code == 0: 297 p = helper.CPProcess(ssl=(self.scheme.lower()=='https'), 298 wait=True) 299 p.write_conf(extra="starterror: True") 300 p.start(imports='cherrypy.test.test_states_demo') 301 if p.exit_code == 0: 380 302 self.fail("Process failed to return nonzero exit code.") 381 303 … … 394 316 # is finished. If it daemonized properly, we should still be able 395 317 # to access pages. 396 write_conf(scheme=self.scheme) 397 exit_code = spawn_cp(wait=True, daemonize=True) 398 399 # Get the PID from the file. 400 pid = int(open(PID_file_path).read()) 318 p = helper.CPProcess(ssl=(self.scheme.lower()=='https'), 319 wait=True, daemonize=True) 320 p.write_conf() 321 p.start(imports='cherrypy.test.test_states_demo') 401 322 try: 402 323 # Just get the pid of the daemonization process. … … 404 325 self.assertStatus(200) 405 326 page_pid = int(self.body) 406 self.assertEqual(page_pid, p id)327 self.assertEqual(page_pid, p.get_pid()) 407 328 finally: 408 329 # Shut down the spawned process 409 330 self.getPage("/exit") 410 wait(pid)331 p.join() 411 332 412 333 # Wait until here to test the exit code because we want to ensure 413 334 # that we wait for the daemon to finish running before we fail. 414 if exit_code != 0:335 if p.exit_code != 0: 415 336 self.fail("Daemonized parent process failed to exit cleanly.") 416 337 … … 431 352 432 353 # Spawn the process. 433 write_conf(scheme=self.scheme) 434 pid = spawn_cp(wait=False, daemonize=False) 354 p = helper.CPProcess(ssl=(self.scheme.lower()=='https')) 355 p.write_conf() 356 p.start(imports='cherrypy.test.test_states_demo') 435 357 # Send a SIGHUP 436 os.kill(p id, SIGHUP)358 os.kill(p.get_pid(), SIGHUP) 437 359 # This might hang if things aren't working right, but meh. 438 wait(pid)360 p.join() 439 361 440 362 def test_SIGHUP_daemonized(self): … … 457 379 # is finished. If it daemonized properly, we should still be able 458 380 # to access pages. 459 write_conf(scheme=self.scheme) 460 exit_code = spawn_cp(wait=True, daemonize=True) 461 462 # Get the PID from the file. 463 pid = int(open(PID_file_path).read()) 381 p = helper.CPProcess(ssl=(self.scheme.lower()=='https'), 382 wait=True, daemonize=True) 383 p.write_conf() 384 p.start(imports='cherrypy.test.test_states_demo') 385 386 pid = p.get_pid() 464 387 try: 465 388 # Send a SIGHUP … … 474 397 # Shut down the spawned process 475 398 self.getPage("/exit") 476 wait(new_pid)399 p.join() 477 400 478 401 def test_SIGTERM(self): … … 495 418 496 419 # Spawn a normal, undaemonized process. 497 write_conf(scheme=self.scheme) 498 pid = spawn_cp(wait=False, daemonize=False) 420 p = helper.CPProcess(ssl=(self.scheme.lower()=='https')) 421 p.write_conf() 422 p.start(imports='cherrypy.test.test_states_demo') 499 423 # Send a SIGTERM 500 os.kill(p id, SIGTERM)424 os.kill(p.get_pid(), SIGTERM) 501 425 # This might hang if things aren't working right, but meh. 502 wait(pid)426 p.join() 503 427 504 428 if os.name in ['posix']: 505 429 # Spawn a daemonized process and test again. 506 exit_code = spawn_cp(wait=True, daemonize=True) 430 p = helper.CPProcess(ssl=(self.scheme.lower()=='https'), 431 wait=True, daemonize=True) 432 p.write_conf() 433 p.start(imports='cherrypy.test.test_states_demo') 507 434 # Send a SIGTERM 508 pid = int(open(PID_file_path).read()) 509 os.kill(pid, SIGTERM) 435 os.kill(p.get_pid(), SIGTERM) 510 436 # This might hang if things aren't working right, but meh. 511 wait(pid)437 p.join() 512 438 513 439 def test_signal_handler_unsubscribe(self): … … 529 455 530 456 # Spawn a normal, undaemonized process. 531 write_conf(scheme=self.scheme, extra="unsubsig: True") 532 pid = spawn_cp(wait=False, daemonize=False) 533 os.kill(pid, SIGTERM) 534 wait(pid) 457 p = helper.CPProcess(ssl=(self.scheme.lower()=='https')) 458 p.write_conf(extra="unsubsig: True") 459 p.start(imports='cherrypy.test.test_states_demo') 460 # Send a SIGTERM 461 os.kill(p.get_pid(), SIGTERM) 462 # This might hang if things aren't working right, but meh. 463 p.join() 464 535 465 # Assert the old handler ran. 536 errlog = os.path.join(thisdir, 'test_states_demo.error.log') 537 target_line = open(errlog, 'rb').readlines()[-10] 466 target_line = open(p.error_log, 'rb').readlines()[-10] 538 467 if not "I am an old SIGTERM handler." in target_line: 539 468 self.fail("Old SIGTERM handler did not run.\n%r" % target_line)

