summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mailman/rest/configuration.py3
-rw-r--r--src/mailman/rest/docs/domains.txt4
-rw-r--r--src/mailman/rest/docs/lists.txt2
-rw-r--r--src/mailman/testing/helpers.py60
-rw-r--r--src/mailman/testing/layers.py21
-rw-r--r--src/mailman/testing/smtplistener.py97
6 files changed, 24 insertions, 163 deletions
diff --git a/src/mailman/rest/configuration.py b/src/mailman/rest/configuration.py
index 1c7378010..c7099d5b1 100644
--- a/src/mailman/rest/configuration.py
+++ b/src/mailman/rest/configuration.py
@@ -27,6 +27,7 @@ __all__ = [
from lazr.config import as_boolean
from lazr.restful.interfaces import IWebServiceConfiguration
+from lazr.restful.wsgi import BaseWSGIWebServiceConfiguration
from zope.interface import implements
from mailman import version
@@ -35,7 +36,7 @@ from mailman.config import config
# pylint: disable-msg=W0232,R0201
-class AdminWebServiceConfiguration:
+class AdminWebServiceConfiguration(BaseWSGIWebServiceConfiguration):
"""A configuration object for the Mailman admin web service."""
implements(IWebServiceConfiguration)
diff --git a/src/mailman/rest/docs/domains.txt b/src/mailman/rest/docs/domains.txt
index 32491cb6f..76710ddb2 100644
--- a/src/mailman/rest/docs/domains.txt
+++ b/src/mailman/rest/docs/domains.txt
@@ -127,7 +127,7 @@ directly to the URL.
... })
URL: http://localhost:8001/3.0/domains
content-length: 0
- content-type: text/plain
+ content-type: text/plain;charset=utf-8
date: ...
location: http://localhost:8001/3.0/domains/lists.example.com
server: WSGIServer/... Python/...
@@ -168,7 +168,7 @@ address.
... })
URL: http://localhost:8001/3.0/domains
content-length: 0
- content-type: text/plain
+ content-type: text/plain;charset=utf-8
date: ...
location: http://localhost:8001/3.0/domains/my.example.com
server: WSGIServer/... Python/...
diff --git a/src/mailman/rest/docs/lists.txt b/src/mailman/rest/docs/lists.txt
index 9fb2f81d2..f4e2ed9ce 100644
--- a/src/mailman/rest/docs/lists.txt
+++ b/src/mailman/rest/docs/lists.txt
@@ -45,7 +45,7 @@ instead of posting directly to the URL.
... })
URL: http://localhost:8001/3.0/lists
content-length: 0
- content-type: text/plain
+ content-type: text/plain;charset=utf-8
date: ...
location: http://localhost:8001/3.0/lists/test-two@example.com
server: WSGIServer/... Python/...
diff --git a/src/mailman/testing/helpers.py b/src/mailman/testing/helpers.py
index a54e26c82..a10898d5d 100644
--- a/src/mailman/testing/helpers.py
+++ b/src/mailman/testing/helpers.py
@@ -40,11 +40,8 @@ import smtplib
import datetime
import threading
-from Queue import Empty, Queue
-
from mailman.bin.master import Loop as Master
from mailman.config import config
-from mailman.testing.smtplistener import Server
from mailman.utilities.mailbox import Mailbox
@@ -191,63 +188,6 @@ class TestableMaster(Master):
-class SMTPServer:
- """An smtp server for testing."""
-
- def __init__(self):
- self._messages = []
- self._queue = Queue()
- self.host = config.mta.smtp_host
- self.port = int(config.mta.smtp_port)
- self._server = Server((self.host, self.port), self._queue)
- self._thread = threading.Thread(target=self._server.start)
- self._thread.daemon = True
-
- def start(self):
- """Start the smtp server in a thread."""
- log.info('test SMTP server starting')
- self._thread.start()
- smtpd = smtplib.SMTP()
- log.info('connecting to %s:%s', self.host, self.port)
- smtpd.connect(self.host, self.port)
- response = smtpd.helo('test.localhost')
- smtpd.quit()
- log.info('SMTP server is running: %s', response)
-
- def stop(self):
- """Stop the smtp server."""
- smtpd = smtplib.SMTP()
- smtpd.connect(self.host, self.port)
- smtpd.docmd('EXIT')
- self.clear()
- # Wait for the thread to exit.
- self._thread.join()
- log.info('test SMTP server stopped')
-
- @property
- def messages(self):
- """Return all the messages received by the smtp server."""
- # Look at the thread queue and append any messages from there to our
- # internal list of messages.
- while True:
- try:
- message = self._queue.get_nowait()
- except Empty:
- break
- else:
- self._messages.append(message)
- # Now return all the messages we know about.
- for message in self._messages:
- yield message
-
- def clear(self):
- """Clear all messages from the queue."""
- # Just throw these away.
- list(self._messages)
- self._messages = []
-
-
-
class LMTP(smtplib.SMTP):
"""Like a normal SMTP client, but for LMTP."""
def lhlo(self, name=''):
diff --git a/src/mailman/testing/layers.py b/src/mailman/testing/layers.py
index c4968ca40..d4db9ebf2 100644
--- a/src/mailman/testing/layers.py
+++ b/src/mailman/testing/layers.py
@@ -35,6 +35,7 @@ import logging
import datetime
import tempfile
+from lazr.smtptest.controller import QueueController
from pkg_resources import resource_string
from textwrap import dedent
from urllib2 import urlopen, URLError
@@ -46,7 +47,7 @@ from mailman.core.logging import get_handler
from mailman.i18n import _
from mailman.interfaces.domain import IDomainManager
from mailman.interfaces.messages import IMessageStore
-from mailman.testing.helpers import SMTPServer, TestableMaster
+from mailman.testing.helpers import TestableMaster
from mailman.utilities.datetime import factory
from mailman.utilities.string import expand
@@ -209,6 +210,20 @@ class ConfigLayer(MockAndMonkeyLayer):
+class ExtendedQueueController(QueueController):
+ """QueueController with a little extra API."""
+
+ @property
+ def messages(self):
+ """Return all the messages received by the SMTP server."""
+ for message in self:
+ yield message
+
+ def clear(self):
+ """Clear all the messages from the queue."""
+ list(self)
+
+
class SMTPLayer(ConfigLayer):
"""Layer for starting, stopping, and accessing a test SMTP server."""
@@ -217,7 +232,9 @@ class SMTPLayer(ConfigLayer):
@classmethod
def setUp(cls):
assert cls.smtpd is None, 'Layer already set up'
- cls.smtpd = SMTPServer()
+ host = config.mta.smtp_host
+ port = int(config.mta.smtp_port)
+ cls.smtpd = ExtendedQueueController(host, port)
cls.smtpd.start()
@classmethod
diff --git a/src/mailman/testing/smtplistener.py b/src/mailman/testing/smtplistener.py
deleted file mode 100644
index 2094e20de..000000000
--- a/src/mailman/testing/smtplistener.py
+++ /dev/null
@@ -1,97 +0,0 @@
-# Copyright (C) 2007-2009 by the Free Software Foundation, Inc.
-#
-# This file is part of GNU Mailman.
-#
-# GNU Mailman is free software: you can redistribute it and/or modify it under
-# the terms of the GNU General Public License as published by the Free
-# Software Foundation, either version 3 of the License, or (at your option)
-# any later version.
-#
-# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
-# more details.
-#
-# You should have received a copy of the GNU General Public License along with
-# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
-
-"""A test SMTP listener."""
-
-from __future__ import absolute_import, unicode_literals
-
-__metaclass__ = type
-__all__ = [
- 'Server',
- ]
-
-
-import smtpd
-import socket
-import logging
-import asyncore
-
-from email import message_from_string
-
-
-COMMASPACE = ', '
-log = logging.getLogger('mailman.debug')
-
-
-
-class Channel(smtpd.SMTPChannel):
- """A channel that can reset the mailbox."""
-
- def __init__(self, server, conn, addr):
- smtpd.SMTPChannel.__init__(self, server, conn, addr)
- # Stash this here since the subclass uses private attributes. :(
- self._server = server
-
- def smtp_EXIT(self, arg):
- """Respond to a new command EXIT by exiting the server."""
- self.push('250 Ok')
- self._server.stop()
-
- def send(self, data):
- """Silence the bloody asynchat/asyncore broken pipe errors!"""
- try:
- return smtpd.SMTPChannel.send(self, data)
- except socket.error:
- # Nothing here can affect the outcome, and these messages are just
- # plain annoying! So ignore them.
- pass
-
-
-
-class Server(smtpd.SMTPServer):
- """An SMTP server that stores messages to a mailbox."""
-
- def __init__(self, localaddr, queue):
- smtpd.SMTPServer.__init__(self, localaddr, None)
- log.info('[SMTPServer] listening: %s', localaddr)
- self._queue = queue
-
- def handle_accept(self):
- """Handle connections by creating our own Channel object."""
- conn, addr = self.accept()
- log.info('[SMTPServer] accepted: %s', addr)
- Channel(self, conn, addr)
-
- def process_message(self, peer, mailfrom, rcpttos, data):
- """Process a message by adding it to the mailbox."""
- message = message_from_string(data)
- message['X-Peer'] = '{0}:{1}'.format(*peer)
- message['X-MailFrom'] = mailfrom
- message['X-RcptTo'] = COMMASPACE.join(rcpttos)
- log.info('[SMTPServer] processed message: %s',
- message.get('message-id', 'n/a'))
- self._queue.put(message)
-
- def start(self):
- """Start the asyncore loop."""
- asyncore.loop()
-
- def stop(self):
- """Stop the asyncore loop."""
- asyncore.socket_map.clear()
- asyncore.close_all()
- self.close()