Commit 2f1b0422 authored by Barry Warsaw's avatar Barry Warsaw

Mailing lists. Also, a very crappy interface for automatically starting and

stopping Mailman for the tests.  This will do for now, but must eventually be
rewritten as race conditions and test delays abound.
parent ef9a4827
......@@ -135,14 +135,18 @@ class Client:
response, content = self._connection.call('lists')
if 'entries' not in content:
return []
return sorted(content['entries'], key=itemgetter('fqdn_listname'))
return [_List(self._connection, entry['self_link'])
for entry in sorted (content['entries'],
key=itemgetter('fqdn_listname'))]
@property
def domains(self):
response, content = self._connection.call('domains')
if 'entries' not in content:
return []
return sorted(content['entries'], key=itemgetter('url_host'))
return [_Domain(self._connection, entry['self_link'])
for entry in sorted(content['entries'],
key=itemgetter('url_host'))]
def create_domain(self, email_host, base_url=None,
description=None, contact_address=None):
......@@ -161,18 +165,90 @@ class Client:
'domains/{0}'.format(email_host))
return _Domain(self._connection, content['self_link'])
def get_list(self, fqdn_listname):
response, content = self._connection.call(
'lists/{0}'.format(fqdn_listname))
return _List(self._connection, content['self_link'])
class _Domain:
def __init__(self, connection, url):
self._connection = connection
self._url = url
response, content = self._connection.call(url)
self.base_url = content['base_url']
self.contact_address = content['contact_address']
self.description = content['description']
self.email_host = content['email_host']
self.url_host = content['url_host']
self._info = None
def __repr__(self):
return '<Domain "{0}">'.format(self.email_host)
def _get_info(self):
if self._info is None:
response, content = self._connection.call(self._url)
self._info = content
@property
def base_url(self):
self._get_info()
return self._info['base_url']
@property
def contact_address(self):
self._get_info()
return self._info['contact_address']
@property
def description(self):
self._get_info()
return self._info['description']
@property
def email_host(self):
self._get_info()
return self._info['email_host']
@property
def url_host(self):
self._get_info()
return self._info['url_host']
def create_list(self, list_name):
fqdn_listname = '{0}@{1}'.format(list_name, self.email_host)
response, content = self._connection.call(
'lists', dict(fqdn_listname=fqdn_listname))
return _List(self._connection, response['location'])
class _List:
def __init__(self, connection, url):
self._connection = connection
self._url = url
self._info = None
def __repr__(self):
return '<List "{0}">'.format(self.fqdn_listname)
def _get_info(self):
if self._info is None:
response, content = self._connection.call(self._url)
self._info = content
@property
def fqdn_listname(self):
self._get_info()
return self._info['fqdn_listname']
@property
def host_name(self):
self._get_info()
return self._info['host_name']
@property
def list_name(self):
self._get_info()
return self._info['list_name']
@property
def real_name(self):
self._get_info()
return self._info['real_name']
......@@ -64,3 +64,57 @@ But you cannot retrieve a non-existent domain.
Traceback (most recent call last):
...
HTTPError: HTTP Error 404: 404 Not Found
After creating a few more domains, we can print the list of all domains.
>>> client.create_domain('example.net')
<Domain "example.net">
>>> client.create_domain('example.org')
<Domain "example.org">
>>> for email_host in client.domains:
... print email_host
<Domain "example.com">
<Domain "example.net">
<Domain "example.org">
Mailing lists
=============
Once you have a domain, you can create mailing lists in that domain.
>>> test_one = example.create_list('test-one')
>>> test_one
<List "test-one@example.com">
>>> print test_one.fqdn_listname
test-one@example.com
>>> print test_one.host_name
example.com
>>> print test_one.list_name
test-one
>>> print test_one.real_name
Test-one
You can also retrieve the mailing list after the fact.
>>> my_list = client.get_list('test-one@example.com')
>>> my_list
<List "test-one@example.com">
And you can print all the known mailing lists.
::
>>> example.create_list('test-two')
<List "test-two@example.com">
>>> domain = client.get_domain('example.net')
>>> domain.create_list('test-three')
<List "test-three@example.net">
>>> example.create_list('test-three')
<List "test-three@example.com">
>>> for mlist in client.lists:
... print mlist
<List "test-one@example.com">
<List "test-three@example.com">
<List "test-three@example.net">
<List "test-two@example.com">
......@@ -26,9 +26,13 @@ __all__ = [
import os
import time
import atexit
import shutil
import doctest
import tempfile
import unittest
import subprocess
# pylint: disable-msg=F0401
from pkg_resources import (
......@@ -71,6 +75,26 @@ def stop():
def setup(testobj):
"""Test setup."""
# Create a unique database for the running version of Mailman, then start
# it up. It should not yet be running. This environment variable must be
# set to find the installation of Mailman we can run. Yes, this should be
# fixed.
testobj._bindir = os.environ.get('MAILMAN_TEST_BINDIR')
if testobj._bindir is None:
raise RuntimeError('Must set $MAILMAN_TEST_BINDIR to run tests')
vardir = testobj._vardir = tempfile.mkdtemp()
cfgfile = testobj._cfgfile = os.path.join(vardir, 'client_test.cfg')
with open(cfgfile, 'w') as fp:
print >> fp, """\
[mailman]
layout: tmpdir
[paths.tmpdir]
var_dir: {vardir}
log_dir: /tmp/mmclient/logs
""".format(vardir=vardir)
mailman = os.path.join(testobj._bindir, 'mailman')
subprocess.call([mailman, '-C', cfgfile, 'start', '-q'])
time.sleep(5)
# Make sure future statements in our doctests match the Python code. When
# run with 2to3, the future import gets removed and these names are not
# defined.
......@@ -85,7 +109,10 @@ def setup(testobj):
def teardown(testobj):
"""Test teardown."""
pass
mailman = os.path.join(testobj._bindir, 'mailman')
subprocess.call([mailman, '-C', testobj._cfgfile, 'stop', '-q'])
shutil.rmtree(testobj._vardir)
time.sleep(5)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment