The switchboard
===============

The switchboard is subsystem that moves messages between queues.  Each
instance of a switchboard is responsible for one queue directory.

    >>> msg = message_from_string("""\
    ... From: aperson@example.com
    ... To: _xtest@example.com
    ...
    ... A test message.
    ... """)

Create a switchboard by giving its queue directory.

    >>> import os
    >>> from mailman.configuration import config
    >>> queue_directory = os.path.join(config.QUEUE_DIR, 'test')
    >>> from mailman.queue import Switchboard
    >>> switchboard = Switchboard(queue_directory)
    >>> switchboard.queue_directory == queue_directory
    True

Here's a helper function for ensuring things work correctly.

    >>> def check_qfiles():
    ...     files = {}
    ...     for qfile in os.listdir(queue_directory):
    ...         root, ext = os.path.splitext(qfile)
    ...         files[ext] = files.get(ext, 0) + 1
    ...     return sorted(files.items())


Enqueing and dequeing
---------------------

The message can be enqueued with metadata specified in the passed in
dictionary.

    >>> filebase = switchboard.enqueue(msg)
    >>> check_qfiles()
    [('.pck', 1)]

To read the contents of a queue file, dequeue it.

    >>> msg, msgdata = switchboard.dequeue(filebase)
    >>> print msg.as_string()
    From: aperson@example.com
    To: _xtest@example.com
    <BLANKLINE>
    A test message.
    <BLANKLINE>
    >>> sorted(msgdata.items())
    [('_parsemsg', False), ('received_time', ...), ('version', 3)]
    >>> check_qfiles()
    [('.bak', 1)]

To complete the dequeing process, removing all traces of the message file,
finish it (without preservation).

    >>> switchboard.finish(filebase)
    >>> check_qfiles()
    []

When enqueing a file, you can provide additional metadata keys by using
keyword arguments.

    >>> filebase = switchboard.enqueue(msg, {'foo': 1}, bar=2)
    >>> msg, msgdata = switchboard.dequeue(filebase)
    >>> switchboard.finish(filebase)
    >>> sorted(msgdata.items())
    [('_parsemsg', False),
     ('bar', 2), ('foo', 1),
     ('received_time', ...), ('version', 3)]

Keyword arguments override keys from the metadata dictionary.

    >>> filebase = switchboard.enqueue(msg, {'foo': 1}, foo=2)
    >>> msg, msgdata = switchboard.dequeue(filebase)
    >>> switchboard.finish(filebase)
    >>> sorted(msgdata.items())
    [('_parsemsg', False),
     ('foo', 2),
     ('received_time', ...), ('version', 3)]


Iterating over files
--------------------

There are two ways to iterate over all the files in a switchboard's queue.
Normally, queue files end in .pck (for 'pickle') and the easiest way to
iterate over just these files is to use the .files attribute.

    >>> filebase_1 = switchboard.enqueue(msg, foo=1)
    >>> filebase_2 = switchboard.enqueue(msg, foo=2)
    >>> filebase_3 = switchboard.enqueue(msg, foo=3)
    >>> filebases = sorted((filebase_1, filebase_2, filebase_3))
    >>> sorted(switchboard.files) == filebases
    True
    >>> check_qfiles()
    [('.pck', 3)]

You can also use the .get_files() method if you want to iterate over all the
file bases for some other extension.

    >>> for filebase in switchboard.get_files():
    ...     msg, msgdata = switchboard.dequeue(filebase)
    >>> bakfiles = sorted(switchboard.get_files('.bak'))
    >>> bakfiles == filebases
    True
    >>> check_qfiles()
    [('.bak', 3)]
    >>> for filebase in switchboard.get_files('.bak'):
    ...     switchboard.finish(filebase)
    >>> check_qfiles()
    []


Recovering files
----------------

Calling .dequeue() without calling .finish() leaves .bak backup files in
place.  These can be recovered when the switchboard is instantiated.

    >>> filebase_1 = switchboard.enqueue(msg, foo=1)
    >>> filebase_2 = switchboard.enqueue(msg, foo=2)
    >>> filebase_3 = switchboard.enqueue(msg, foo=3)
    >>> for filebase in switchboard.files:
    ...     msg, msgdata = switchboard.dequeue(filebase)
    ...     # Don't call .finish()
    >>> check_qfiles()
    [('.bak', 3)]
    >>> switchboard_2 = Switchboard(queue_directory, recover=True)
    >>> check_qfiles()
    [('.pck', 3)]

Clean up

    >>> for filebase in switchboard.files:
    ...     msg, msgdata = switchboard.dequeue(filebase)
    ...     switchboard.finish(filebase)
    >>> check_qfiles()
    []


Queue slices
------------

XXX Add tests for queue slices.
