Robert Brewer avatar Robert Brewer committed 02a5b68

Some test_states love. Also, cherryd grew an --import option.

Comments (0)

Files changed (3)

 #! /usr/bin/env python
 """The CherryPy daemon."""
 
+import sys
+
 import cherrypy
 from cherrypy.process import plugins, servers
 
 
 def start(configfiles=None, daemonize=False, environment=None,
-          fastcgi=False, pidfile=None):
+          fastcgi=False, pidfile=None, imports=None):
     """Subscribe all engine plugins and start the engine."""
+    for i in imports:
+        exec "import %s" % i
+    
     for c in configfiles or []:
         cherrypy.config.update(c)
     
         s.subscribe()
     
     # Always start the engine; this will start all other services
-    engine.start()
-    engine.block()
+    try:
+        engine.start()
+    except:
+        # Assume the error has been logged already via bus.log.
+        sys.exit(1)
+    else:
+        engine.block()
 
 
 if __name__ == '__main__':
                  help="apply the given config environment")
     p.add_option('-f', action="store_true", dest='fastcgi',
                  help="start a fastcgi server instead of the default HTTP server")
+    p.add_option('-i', '--import', action="append", dest='imports',
+                 help="specify modules to import")
     p.add_option('-p', '--pidfile', dest='pidfile', default=None,
                  help="store the process id in the given file")
     options, args = p.parse_args()
     
     start(options.config, options.daemonize,
-          options.environment, options.fastcgi, options.pidfile)
+          options.environment, options.fastcgi, options.pidfile,
+          options.imports)
 

cherrypy/test/test_states.py

 PID_file_path = os.path.join(thisdir, 'pid_for_test_daemonize')
 
 
+def write_conf(scheme='http', starterror=False):
+    if scheme.lower() == 'https':
+        serverpem = os.path.join(thisdir, 'test.pem')
+        ssl = """
+server.ssl_certificate: r'%s'
+server.ssl_private_key: r'%s'
+""" % (serverpem, serverpem)
+    else:
+        ssl = ""
+    
+    if starterror:
+        starterror = "starterror: True"
+    else:
+        starterror = ""
+    
+    conffile = open(os.path.join(thisdir, 'test_states.conf'), 'wb')
+    conffile.write("""[global]
+server.socket_host: '%(host)s'
+server.socket_port: %(port)s
+log.screen: False
+log.error_file: r'%(error_log)s'
+log.access_file: r'%(access_log)s'
+%(ssl)s
+%(starterror)s
+""" % {'host': host,
+       'port': port,
+       'error_log': os.path.join(thisdir, 'test_states_demo.error.log'),
+       'access_log': os.path.join(thisdir, 'test_states_demo.access.log'),
+       'ssl': ssl,
+       'starterror': starterror,
+       })
+    conffile.close()
+
+
+def spawn_cp(configfile=os.path.join(thisdir, 'test_states.conf'),
+             wait=False, daemonize=False):
+    """Start cherryd in a subprocess."""
+    host = cherrypy.server.socket_host
+    port = cherrypy.server.socket_port
+    cherrypy._cpserver.wait_for_free_port(host, port)
+    
+    args = [sys.executable, os.path.join(thisdir, '..', 'cherryd'),
+            '-c', configfile, '-i', 'cherrypy.test.test_states_demo']
+    
+    if sys.platform != 'win32':
+        args.append('-p')
+        args.append(PID_file_path)
+    
+    # Spawn the process and wait, when this returns, the original process
+    # is finished.  If it daemonized properly, we should still be able
+    # to access pages.
+    if daemonize:
+        args.append('-d')
+    
+    if wait:
+        result = os.spawnl(os.P_WAIT, sys.executable, *args)
+    else:
+        result = os.spawnl(os.P_NOWAIT, sys.executable, *args)
+        cherrypy._cpserver.wait_for_occupied_port(host, port)
+    
+    return result
+
+def wait(pid):
+    """Wait for the process with the given pid to exit."""
+    try:
+        try:
+            # Mac, UNIX
+            os.wait()
+        except AttributeError:
+            # Windows
+            os.waitpid(pid, 0)
+    except OSError, x:
+        if x.args != (10, 'No child processes'):
+            raise
+
+
 class Root:
     def index(self):
         return "Hello World"
             return
         
         # Start the demo script in a new process
-        demoscript = os.path.join(os.getcwd(), os.path.dirname(__file__),
-                                  "test_states_demo.py")
-        host = cherrypy.server.socket_host
-        port = cherrypy.server.socket_port
-        cherrypy._cpserver.wait_for_free_port(host, port)
-        
-        args = [sys.executable, demoscript, host, str(port)]
-        if self.scheme == "https":
-            args.append('-ssl')
-        pid = os.spawnl(os.P_NOWAIT, sys.executable, *args)
-        cherrypy._cpserver.wait_for_occupied_port(host, port)
-        
+        write_conf(scheme=self.scheme)
+        pid = spawn_cp()
         try:
             self.getPage("/start")
             start = float(self.body)
             time.sleep(2)
             
             # Touch the file
-            os.utime(demoscript, None)
+            os.utime(os.path.join(thisdir, "test_states_demo.py"), None)
             
             # Give the autoreloader time to re-exec the process
             time.sleep(2)
         finally:
             # Shut down the spawned process
             self.getPage("/exit")
-        
-        try:
-            try:
-                # Mac, UNIX
-                print os.wait()
-            except AttributeError:
-                # Windows
-                print os.waitpid(pid, 0)
-        except OSError, x:
-            if x.args != (10, 'No child processes'):
-                raise
+        wait(pid)
     
     def test_5_Start_Error(self):
         if not self.server_class:
             print "skipped (no server) ",
             return
         
-        # Start the demo script in a new process
-        demoscript = os.path.join(os.getcwd(), os.path.dirname(__file__),
-                                  "test_states_demo.py")
-        host = cherrypy.server.socket_host
-        port = cherrypy.server.socket_port
-        
         # If a process errors during start, it should stop the engine
         # and exit with a non-zero exit code.
-        args = [sys.executable, demoscript, host, str(port), '-starterror']
-        if self.scheme == "https":
-            args.append('-ssl')
-        exit_code = os.spawnl(os.P_WAIT, sys.executable, *args)
+        write_conf(scheme=self.scheme, starterror=True)
+        exit_code = spawn_cp(wait=True)
         if exit_code == 0:
             self.fail("Process failed to return nonzero exit code.")
 
 
 class DaemonizeTests(helper.CPWebCase):
     
-    def test_1_Daemonize(self):
+    def test_daemonize(self):
         if not self.server_class:
             print "skipped (no server) ",
             return
             return
         
         # Start the demo script in a new process
-        demoscript = os.path.join(os.getcwd(), os.path.dirname(__file__),
-                                  "test_states_demo.py")
-        host = cherrypy.server.socket_host
-        port = cherrypy.server.socket_port
-        cherrypy._cpserver.wait_for_free_port(host, port)
-        
-        args = [sys.executable, demoscript, host, str(port), '-daemonize']
-        if self.scheme == "https":
-            args.append('-ssl')
         # Spawn the process and wait, when this returns, the original process
         # is finished.  If it daemonized properly, we should still be able
         # to access pages.
-        exit_code = os.spawnl(os.P_WAIT, sys.executable, *args)
-        cherrypy._cpserver.wait_for_occupied_port(host, port)
+        write_conf(scheme=self.scheme)
+        exit_code = spawn_cp(wait=True, daemonize=True)
         
         # Give the server some time to start up
         time.sleep(2)
         finally:
             # Shut down the spawned process
             self.getPage("/exit")
-        
-        try:
-            print os.waitpid(pid, 0)
-        except OSError, x:
-            if x.args != (10, 'No child processes'):
-                raise
+        wait(pid)
         
         # Wait until here to test the exit code because we want to ensure
         # that we wait for the daemon to finish running before we fail.
         if exit_code != 0:
-            self.fail("Daemonized process failed to exit cleanly")
+            self.fail("Daemonized parent process failed to exit cleanly.")
 
 
 def run(server, conf):

cherrypy/test/test_states_demo.py

 starttime = time.time()
 
 import cherrypy
-from cherrypy.process import plugins
-thisdir = os.path.join(os.getcwd(), os.path.dirname(__file__))
-PID_file_path = os.path.join(thisdir, 'pid_for_test_daemonize')
 
 
 class Root:
         cherrypy.engine.exit()
     exit.exposed = True
 
+def starterror():
+    if cherrypy.config.get('starterror', False):
+        zerodiv = 1 / 0
+cherrypy.engine.subscribe('start', starterror, priority=6)
 
-if __name__ == '__main__':
-    conf = {"server.socket_host": sys.argv[1],
-            "server.socket_port": int(sys.argv[2]),
-            "log.screen": False,
-            "log.error_file": os.path.join(thisdir, 'test_states_demo.error.log'),
-            "log.access_file": os.path.join(thisdir, 'test_states_demo.access.log'),
-            }
-    
-    if '-ssl' in sys.argv[3:]:
-        localDir = os.path.dirname(__file__)
-        serverpem = os.path.join(os.getcwd(), localDir, 'test.pem')
-        conf['server.ssl_certificate'] = serverpem
-        conf['server.ssl_private_key'] = serverpem
-    
-    if '-daemonize' in sys.argv[3:]:
-        # Sometimes an exception happens during exit;
-        # try to make sure we get a non_zero exit code.
-        old_exitfunc = sys.exitfunc
-        def exitfunc():
-            try:
-                old_exitfunc()
-            except SystemExit:
-                raise
-            except:
-                raise SystemExit(1)
-        sys.exitfunc = exitfunc
-        
-        plugins.Daemonizer(cherrypy.engine).subscribe()
-        plugins.PIDFile(cherrypy.engine, PID_file_path).subscribe()
-    
-    if '-starterror' in sys.argv[3:]:
-        cherrypy.engine.subscribe('start', lambda: 1/0, priority=6)
-    
-    # This is in a special order for a reason:
-    # it allows test_states to wait_for_occupied_port
-    # and then immediately call getPage without getting 503.
-    cherrypy.config.update(conf)
-    cherrypy.tree.mount(Root(), config={'global': conf})
-    try:
-        cherrypy.engine.start()
-    except ZeroDivisionError:
-        sys.exit(1)
-    cherrypy.engine.block()
+cherrypy.tree.mount(Root(), '/', {'/': {}})
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.