=============================
Starting and stopping Mailman
=============================

The Mailman daemon processes can be started and stopped from the command
line.


Set up
======

All we care about is the master process; normally it starts a bunch of
qrunners, but we don't care about any of them, so write a test configuration
file for the master that disables all the qrunners.

    >>> import shutil
    >>> from os.path import dirname, join
    >>> config_file = join(dirname(config.filename), 'no-qrunners.cfg')
    >>> shutil.copyfile(config.filename, config_file)
    >>> with open(config_file, 'a') as fp:
    ...     print >> fp, """\
    ... [qrunner.archive]
    ... start: no
    ... [qrunner.bounces]
    ... start: no
    ... [qrunner.command]
    ... start: no
    ... [qrunner.in]
    ... start: no
    ... [qrunner.lmtp]
    ... start: no
    ... [qrunner.news]
    ... start: no
    ... [qrunner.out]
    ... start: no
    ... [qrunner.pipeline]
    ... start: no
    ... [qrunner.rest]
    ... start: no
    ... [qrunner.retry]
    ... start: no
    ... [qrunner.virgin]
    ... start: no
    ... [qrunner.digest]
    ... start: no
    ... """


Starting
========

    >>> from mailman.commands.cli_control import Start
    >>> start = Start()

    >>> class FakeArgs:
    ...     force = False
    ...     run_as_user = True
    ...     quiet = False
    ...     config = config_file
    >>> args = FakeArgs()

Starting the daemons prints a useful message and starts the master qrunner
watcher process in the background.

    >>> start.process(args)
    Starting Mailman's master queue runner

    >>> import errno, os, time
    >>> from datetime import timedelta, datetime
    >>> def find_master():
    ...     until = timedelta(seconds=10) + datetime.now()
    ...     while datetime.now() < until:
    ...         time.sleep(0.1)
    ...         try:
    ...             with open(config.PIDFILE) as fp:
    ...                 pid = int(fp.read().strip())
    ...             os.kill(pid, 0)
    ...         except IOError as error:
    ...             if error.errno != errno.ENOENT:
    ...                 raise
    ...         except ValueError:
    ...             pass
    ...         except OSError as error:
    ...             if error.errno != errno.ESRCH:
    ...                 raise
    ...         else:
    ...             print 'Master process found'
    ...             return pid
    ...     else:
    ...         raise AssertionError('No master process')

The process exists, and its pid is available in a run time file.

    >>> pid = find_master()
    Master process found


Stopping
========

You can also stop the master watcher process from the command line, which
stops all the child processes too.

    >>> from mailman.commands.cli_control import Stop
    >>> stop = Stop()
    >>> stop.process(args)
    Shutting down Mailman's master queue runner

    >>> def bury_master():
    ...     until = timedelta(seconds=10) + datetime.now()
    ...     while datetime.now() < until:
    ...         time.sleep(0.1)
    ...         try:
    ...             import sys
    ...             os.kill(pid, 0)
    ...             os.waitpid(pid, os.WNOHANG)
    ...         except OSError as error:
    ...             if error.errno == errno.ESRCH:
    ...                 # The process has exited.
    ...                 print 'Master process went bye bye'
    ...                 return
    ...             else:
    ...                 raise
    ...     else:
    ...         raise AssertionError('Master process lingered')

    >>> bury_master()
    Master process went bye bye


XXX We need tests for restart (SIGUSR1) and reopen (SIGHUP).
