The Mailman daemon processes can be started and stopped from the command line.
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
... """
>>> 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.PID_FILE) 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
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).