Merge authors:
  Aurélien Bompard (abompard)
Related merge proposals:
  
https://code.launchpad.net/~abompard/mailman.client/mockingclient/+merge/242185
  proposed by: Aurélien Bompard (abompard)
------------------------------------------------------------
revno: 58 [merge]
committer: Florian Fuchs <[email protected]>
branch nick: mailman.client
timestamp: Mon 2014-11-24 11:25:10 +0100
message:
  Addedd an improved test harness using WebTest. Contributed by Aurélien 
Abompard.
added:
  src/mailmanclient/tests/utils.py
modified:
  bin/test
  setup.py
  src/mailmanclient/NEWS.txt
  src/mailmanclient/docs/using.txt
  src/mailmanclient/tests/test_docs.py


--
lp:mailman.client
https://code.launchpad.net/~mailman-coders/mailman.client/trunk

Your team Mailman Coders is subscribed to branch lp:mailman.client.
To unsubscribe from this branch go to 
https://code.launchpad.net/~mailman-coders/mailman.client/trunk/+edit-subscription
=== modified file 'bin/test'
--- bin/test	2013-03-15 23:02:04 +0000
+++ bin/test	2014-11-24 10:25:10 +0000
@@ -30,10 +30,6 @@
 
 
 if __name__ == '__main__':
-    if len(sys.argv) == 1:
-        print 'Please provide the path to your mailman bin directory.'
-        sys.exit(1)
-    os.environ['MAILMAN_TEST_BINDIR'] = sys.argv[1]
     suite = additional_tests()
     runner = unittest.TextTestRunner(verbosity=2)
     runner.run(suite)

=== modified file 'setup.py'
--- setup.py	2014-04-22 14:38:40 +0000
+++ setup.py	2014-11-19 11:03:32 +0000
@@ -44,5 +44,5 @@
     # Auto-conversion to Python 3.
     use_2to3=True,
     convert_2to3_doctests=find_doctests(),
-    install_requires=['httplib2', 'mock', ],
+    install_requires=['httplib2', 'mock', 'WebTest', ],
 )

=== modified file 'src/mailmanclient/NEWS.txt'
--- src/mailmanclient/NEWS.txt	2014-03-15 20:43:52 +0000
+++ src/mailmanclient/NEWS.txt	2014-11-24 10:25:10 +0000
@@ -2,6 +2,12 @@
 NEWS for mailman.client
 =======================
 
+1.0.0b1 (xxxx-xx-xx)
+
+* Addedd an improved test harness using WebTest. Contributed by Aurélien Abompard.
+
+
 1.0.0a1 (2014-03-15)
 ====================
+
  * Initial release.

=== modified file 'src/mailmanclient/docs/using.txt'
--- src/mailmanclient/docs/using.txt	2014-04-22 12:47:00 +0000
+++ src/mailmanclient/docs/using.txt	2014-11-18 15:08:41 +0000
@@ -640,12 +640,7 @@
     ... Some text.
     ... 
     ... """
-    >>> server = smtplib.LMTP('localhost', 8024)
-    >>> server.sendmail('[email protected]', '[email protected]', msg)
-    {}
-    >>> server.quit()
-    (221, 'Bye')
-    >>> time.sleep(2)
+    >>> inject_message('[email protected]', msg)
 
 Messages held for moderation can be listed on a per list basis.
 

=== modified file 'src/mailmanclient/tests/test_docs.py'
--- src/mailmanclient/tests/test_docs.py	2014-03-15 20:43:52 +0000
+++ src/mailmanclient/tests/test_docs.py	2014-11-19 10:58:36 +0000
@@ -17,7 +17,7 @@
 
 """Test harness for doctests."""
 
-from __future__ import absolute_import, unicode_literals
+from __future__ import absolute_import, unicode_literals, print_function
 
 __metaclass__ = type
 __all__ = [
@@ -33,11 +33,16 @@
 import tempfile
 import unittest
 import subprocess
+from textwrap import dedent
 
+from mock import patch
 # pylint: disable-msg=F0401
 from pkg_resources import (
     resource_filename, resource_exists, resource_listdir, cleanup_resources)
 
+from mailman.config import config
+from mailmanclient.tests.utils import FakeMailmanClient, inject_message
+
 
 COMMASPACE = ', '
 DOT = '.'
@@ -50,17 +55,17 @@
 
 def dump(results):
     if results is None:
-        print None
+        print(None)
         return
     for key in sorted(results):
         if key == 'entries':
             for i, entry in enumerate(results[key]):
                 # entry is a dictionary.
-                print 'entry %d:' % i
+                print('entry %d:' % i)
                 for entry_key in sorted(entry):
-                    print '    {0}: {1}'.format(entry_key, entry[entry_key])
+                    print('    {0}: {1}'.format(entry_key, entry[entry_key]))
         else:
-            print '{0}: {1}'.format(key, results[key])
+            print('{0}: {1}'.format(key, results[key]))
 
 
 
@@ -74,69 +79,33 @@
 
 
 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
-[webservice]
-port: 9001
-[runner.archive]
-start: no
-[runner.bounces]
-start: no
-[runner.command]
-start: yes
-[runner.in]
-start: yes
-[runner.lmtp]
-start: yes
-[runner.news]
-start: no
-[runner.out]
-start: yes
-[runner.pipeline]
-start: no
-[runner.retry]
-start: no
-[runner.virgin]
-start: yes
-[runner.digest]
-start: no
-""".format(vardir=vardir)
-    mailman = os.path.join(testobj._bindir, 'mailman')
-    subprocess.call([mailman, '-C', cfgfile, 'start', '-q'])
-    time.sleep(3)
-    # 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.
-    try:
-        testobj.globs['absolute_import'] = absolute_import
-        testobj.globs['unicode_literals'] = unicode_literals
-    except NameError:
-        pass
     testobj.globs['stop'] = stop
     testobj.globs['dump'] = dump
-
-
+    testobj.globs['inject_message'] = inject_message
+    FakeMailmanClient.setUp()
+    # In unit tests, passwords aren't encrypted. Don't show this in the doctests
+    passlib_cfg = os.path.join(config.VAR_DIR, 'passlib.cfg')
+    with open(passlib_cfg, 'w') as fp:
+        print(dedent("""
+            [passlib]
+            schemes = sha512_crypt
+            """), file=fp)
+    conf_hash_pw = dedent("""
+    [passwords]
+    configuration: {}
+    """.format(passlib_cfg))
+    config.push('conf_hash_pw', conf_hash_pw)
+    # Use the FakeMailmanClient
+    testobj.patcher = patch("mailmanclient.Client", FakeMailmanClient)
+    fmc = testobj.patcher.start()
+
+
+
 def teardown(testobj):
     """Test teardown."""
-    mailman = os.path.join(testobj._bindir, 'mailman')
-    subprocess.call([mailman, '-C', testobj._cfgfile, 'stop', '-q'])
-    shutil.rmtree(testobj._vardir)
-    time.sleep(3)
+    testobj.patcher.stop()
+    config.pop('conf_hash_pw')
+    FakeMailmanClient.tearDown()
 
 
 

=== added file 'src/mailmanclient/tests/utils.py'
--- src/mailmanclient/tests/utils.py	1970-01-01 00:00:00 +0000
+++ src/mailmanclient/tests/utils.py	2014-11-20 09:25:13 +0000
@@ -0,0 +1,144 @@
+# Copyright (C) 2010-2014 by The Free Software Foundation, Inc.
+#
+# This file is part of mailman.client.
+#
+# mailman.client is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by the
+# Free Software Foundation, either version 3 of the License, or (at your
+# option) any later version.
+#
+# mailman.client 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 Lesser General Public License
+# for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with mailman.client.  If not, see <http://www.gnu.org/licenses/>.
+
+"""Test tools."""
+
+from __future__ import absolute_import, unicode_literals, print_function
+
+import os
+from urllib2 import HTTPError
+from urlparse import urljoin
+
+from zope.component import getUtility
+from webtest import TestApp
+
+from mailman.config import config
+from mailman.core.chains import process
+from mailman.interfaces.listmanager import IListManager
+from mailman.interfaces.usermanager import IUserManager
+from mailman.testing.helpers import specialized_message_from_string
+from mailman.testing.layers import ConfigLayer
+import mailmanclient
+
+__metaclass__ = type
+__all__ = [
+    "inject_message",
+    "FakeMailmanClient",
+    ]
+
+
+
+def inject_message(fqdn_listname, msg):
+    mlist = getUtility(IListManager).get(fqdn_listname)
+    user_manager = getUtility(IUserManager)
+    msg = specialized_message_from_string(msg)
+    for sender in msg.senders:
+        if user_manager.get_address(sender) is None:
+            user_manager.create_address(sender)
+    process(mlist, msg, {})
+
+
+#
+# Mocking mailman client
+#
+
+
+class FakeConnection(mailmanclient._client._Connection):
+    """
+    Looks for information inside a dict instead of making HTTP requests.
+    Also, logs the called URLs as called_paths.
+    Very incomplete at the moment.
+    """
+
+    def __init__(self, baseurl, name=None, password=None):
+        super(FakeConnection, self).__init__(baseurl, name, password)
+        self.called_paths = []
+        from mailman.rest.wsgiapp import make_application
+        self.app = TestApp(make_application())
+        if self.basic_auth:
+            self.app.authorization = ('Basic', (self.name, self.password))
+        super(FakeConnection, self).__init__(baseurl, name, password)
+
+    def call(self, path, data=None, method=None):
+        self.called_paths.append(
+                { "path": path, "data": data, "method": method })
+        if method is None:
+            if data is None:
+                method = 'GET'
+            else:
+                method = 'POST'
+        method_fn = getattr(self.app, method.lower())
+        url = urljoin(self.baseurl, path)
+        try:
+            kw = {"expect_errors": True}
+            if data:
+                kw["params"] = data
+            response = method_fn(url, **kw)
+            headers = response.headers
+            headers["status"] = response.status_int
+            content = unicode(response.body)
+            # If we did not get a 2xx status code, make this look like a
+            # urllib2 exception, for backward compatibility.
+            if response.status_int // 100 != 2:
+                raise HTTPError(url, response.status_int, content, headers, None)
+            if len(content) == 0:
+                return headers, None
+            # XXX Work around for http://bugs.python.org/issue10038
+            return headers, response.json
+        except HTTPError:
+            raise
+        except IOError:
+            raise mailmanclient.MailmanConnectionError(
+                'Could not connect to Mailman API')
+
+
+
+class FakeMailmanClient(mailmanclient.Client):
+    """
+    Subclass of mailmanclient.Client to instantiate a FakeConnection object
+    instead of the real connection.
+    """
+
+    def __init__(self, baseurl, name=None, password=None):
+        self._connection = FakeConnection(baseurl, name, password)
+
+    @property
+    def called_paths(self):
+        return self._connection.called_paths
+
+    @classmethod
+    def setUp(self):
+        ConfigLayer.setUp()
+
+    @classmethod
+    def tearDown(self):
+        config.create_paths = False # or ConfigLayer.tearDown will create them
+        ConfigLayer.testTearDown()
+        ConfigLayer.tearDown()
+        reset_mailman_config()
+
+def reset_mailman_config():
+    # This is necessary because ConfigLayer.setup/tearDown was designed to be
+    # run only once for the whole test suite, and thus does not reset
+    # everything afterwards
+    for prop in ("switchboards", "rules", "chains", "handlers",
+                 "pipelines", "commands"):
+        getattr(config, prop).clear()
+    from mailman.model.user import uid_factory
+    uid_factory._lockobj = None
+    from mailman.model.member import uid_factory
+    uid_factory._lockobj = None

_______________________________________________
Mailman-coders mailing list
[email protected]
https://mail.python.org/mailman/listinfo/mailman-coders

Reply via email to