summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--setup.py4
-rw-r--r--src/mailman/__init__.py2
-rw-r--r--src/mailman/app/docs/hooks.rst3
-rw-r--r--src/mailman/archiving/docs/__init__.py0
-rw-r--r--src/mailman/commands/docs/__init__.py0
-rw-r--r--src/mailman/docs/NEWS.rst6
-rw-r--r--src/mailman/docs/START.rst57
-rw-r--r--src/mailman/handlers/docs/__init__.py0
-rw-r--r--src/mailman/mta/docs/__init__.py0
-rw-r--r--src/mailman/rules/docs/__init__.py0
-rw-r--r--src/mailman/runners/docs/__init__.py0
-rw-r--r--src/mailman/testing/__init__.py39
-rw-r--r--src/mailman/testing/documentation.py (renamed from src/mailman/tests/test_documentation.py)63
-rw-r--r--src/mailman/testing/layers.py2
-rw-r--r--src/mailman/testing/nose.py107
-rw-r--r--unittest.cfg10
16 files changed, 152 insertions, 141 deletions
diff --git a/setup.py b/setup.py
index 3e032f46c..63cea1187 100644
--- a/setup.py
+++ b/setup.py
@@ -101,14 +101,14 @@ case second `m'. Any other spelling is incorrect.""",
'lazr.config',
'lazr.smtptest',
'mock',
+ 'nose2',
'passlib',
'restish',
'storm',
- 'zc.buildout',
'zope.component',
'zope.configuration',
'zope.event',
'zope.interface',
- 'zope.testing<4',
],
+ test_suite = 'nose2.collector.collector',
)
diff --git a/src/mailman/__init__.py b/src/mailman/__init__.py
index 8690e77bd..87a2a2100 100644
--- a/src/mailman/__init__.py
+++ b/src/mailman/__init__.py
@@ -44,7 +44,7 @@ except ImportError:
#
# Do *not* do this if we're building the documentation.
if 'build_sphinx' not in sys.argv:
- if sys.argv[0].split(os.sep)[-1] == 'test':
+ if any('nose2' in arg for arg in sys.argv):
from mailman.testing.i18n import initialize
else:
from mailman.core.i18n import initialize
diff --git a/src/mailman/app/docs/hooks.rst b/src/mailman/app/docs/hooks.rst
index 7e214f13f..a29c7ee10 100644
--- a/src/mailman/app/docs/hooks.rst
+++ b/src/mailman/app/docs/hooks.rst
@@ -52,8 +52,9 @@ script that will produce no output to force the hooks to run.
>>> import subprocess
>>> from mailman.testing.layers import ConfigLayer
>>> def call():
+ ... exe = os.path.join(os.path.dirname(sys.executable), 'mailman')
... proc = subprocess.Popen(
- ... 'bin/mailman lists --domain ignore -q'.split(),
+ ... [exe, 'lists', '--domain', 'ignore', '-q'],
... cwd=ConfigLayer.root_directory,
... env=dict(MAILMAN_CONFIG_FILE=config_path,
... PYTHONPATH=config_directory),
diff --git a/src/mailman/archiving/docs/__init__.py b/src/mailman/archiving/docs/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/mailman/archiving/docs/__init__.py
diff --git a/src/mailman/commands/docs/__init__.py b/src/mailman/commands/docs/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/mailman/commands/docs/__init__.py
diff --git a/src/mailman/docs/NEWS.rst b/src/mailman/docs/NEWS.rst
index 8faeb3074..9de710829 100644
--- a/src/mailman/docs/NEWS.rst
+++ b/src/mailman/docs/NEWS.rst
@@ -12,6 +12,12 @@ Here is a history of user visible changes to Mailman.
===============================
(2013-XX-XX)
+Development
+-----------
+ * Mailman 3 no longer uses ``zc.buildout`` and tests are now run by the
+ ``nose2`` test runner. See ``src/mailman/docs/START.rst`` for details on
+ how to build Mailman and run the test suite.
+
REST
----
* Add ``reply_to_address`` and ``first_strip_reply_to`` as writable
diff --git a/src/mailman/docs/START.rst b/src/mailman/docs/START.rst
index 85b869c2d..6c029590b 100644
--- a/src/mailman/docs/START.rst
+++ b/src/mailman/docs/START.rst
@@ -39,44 +39,43 @@ Python 2.7 is required. It can either be the default 'python' on your
If your operating system does not include Python, see http://www.python.org
downloading and installing it from source. Python 3 is not yet supported.
-In this documentation, a bare ``python`` refers to the Python executable used
-to invoke ``bootstrap.py``.
-
-Mailman 3 is now based on the `zc.buildout`_ infrastructure, which greatly
-simplifies testing Mailman. Buildout is not required for installation.
-
-During the beta program, you may need some additional dependencies, such as a
-C compiler and the Python development headers and libraries. You will need an
-internet connection.
+You may need some additional dependencies, which are either available from
+your OS vendor, or can be downloaded automatically from the `Python
+Cheeseshop`_.
Building Mailman 3
==================
-We provide several recipes for building Mailman. All should generally work,
-but some may provide a better experience for developing Mailman versus
-deploying Mailman.
-
+To build Mailman for development purposes, you will create a virtual
+environment. You need to have the `virtualenv`_ program installed.
Building for development
------------------------
-The best way to build Mailman for development is to use the `zc.buildout`_
-tools. This will download all Mailman dependencies from the `Python
-Cheeseshop`_. The dependencies will get installed locally, but isolated from
-your system Python. Here are the commands to build Mailman for development::
+First, create a virtual environment. By default ``virtualenv`` uses the
+``python`` executable it finds first on your ``$PATH``. Make sure this is
+Python 2.7. The directory you install the virtualenv into is up to you, but
+for purposes of this document, we'll install it into ``/tmp/py27``::
+
+ % virtualenv --system-site-packages /tmp/py27
+
+Now, activate the virtual environment and set it up for development::
- % python bootstrap.py
- % bin/buildout
+ % source /tmp/py27/bin/activate
+ % python setup.py develop
Sit back and have some Kombucha while you wait for everything to download and
install.
Now you can run the test suite via::
- % bin/test -vv
+ % nose2 -v
-You should see no failures.
+You should see no failures. You can also run a subset of the full test suite
+by filter tests on the module or test name using the ``-P`` option::
+
+ % nose2 -v -P user
Build the online docs by running::
@@ -91,21 +90,6 @@ doctests by looking in all the 'doc' directories under the 'mailman' package.
Doctests are documentation first, so they should give you a pretty good idea
how various components of Mailman 3 work.
-
-Building for deployment using virtualenv
-----------------------------------------
-
-`virtualenv`_ is a way to create isolated Python environments. You can use
-virtualenv as a way to deploy Mailman without installing it into your system
-Python. There are lots of ways to use virtualenv, but as described here, it
-will be default use any dependencies which are already installed in your
-system, downloading from the Cheeseshop only those which are missing. Here
-are the steps to install Mailman using virtualenv::
-
- $ virtualenv --system-site-packages /path/to/your/installation
- $ source /path/to/your/installation/bin/activate
- $ python setup.py install
-
Once everything is downloaded and installed, you can initialize Mailman and
get a display of the basic configuration settings by running::
@@ -190,7 +174,6 @@ email application that speaks LMTP or SMTP will be able to use Hyperkitty.
A `five minute guide to Hyperkitty`_ is based on Toshio Kuratomi's README.
-.. _`zc.buildout`: http://pypi.python.org/pypi/zc.buildout
.. _`Postorius`: https://launchpad.net/postorius
.. _`Hyperkitty`: https://launchpad.net/hyperkitty
.. _`Django`: http://djangoproject.org/
diff --git a/src/mailman/handlers/docs/__init__.py b/src/mailman/handlers/docs/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/mailman/handlers/docs/__init__.py
diff --git a/src/mailman/mta/docs/__init__.py b/src/mailman/mta/docs/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/mailman/mta/docs/__init__.py
diff --git a/src/mailman/rules/docs/__init__.py b/src/mailman/rules/docs/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/mailman/rules/docs/__init__.py
diff --git a/src/mailman/runners/docs/__init__.py b/src/mailman/runners/docs/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/mailman/runners/docs/__init__.py
diff --git a/src/mailman/testing/__init__.py b/src/mailman/testing/__init__.py
index e6a5047b6..e69de29bb 100644
--- a/src/mailman/testing/__init__.py
+++ b/src/mailman/testing/__init__.py
@@ -1,39 +0,0 @@
-# Copyright (C) 2011-2013 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/>.
-
-"""Set up testing.
-
-This is used as an interface to buildout.cfg's [test] section.
-zope.testrunner supports an initialization variable. It is set to import and
-run the following test initialization method.
-"""
-
-from __future__ import absolute_import, unicode_literals
-
-__metaclass__ = type
-__all__ = [
- 'initialize',
- ]
-
-
-
-def initialize(root_directory):
- """Initialize the test infrastructure."""
- from mailman.testing import layers
- layers.MockAndMonkeyLayer.testing_mode = True
- layers.ConfigLayer.enable_stderr();
- layers.ConfigLayer.set_root_directory(root_directory)
diff --git a/src/mailman/tests/test_documentation.py b/src/mailman/testing/documentation.py
index 37eb760ab..b1cc36f91 100644
--- a/src/mailman/tests/test_documentation.py
+++ b/src/mailman/testing/documentation.py
@@ -25,23 +25,16 @@ from __future__ import absolute_import, unicode_literals
__metaclass__ = type
__all__ = [
- 'test_suite',
+ 'setup',
+ 'teardown'
]
-import os
-import sys
-import doctest
-import unittest
-
from inspect import isfunction, ismethod
-import mailman
-
from mailman.app.lifecycle import create_list
from mailman.config import config
-from mailman.testing.helpers import (
- call_api, chdir, specialized_message_from_string)
+from mailman.testing.helpers import call_api, specialized_message_from_string
from mailman.testing.layers import SMTPLayer
@@ -181,53 +174,3 @@ def teardown(testobj):
cleanup()
else:
cleanup[0](*cleanup[1:])
-
-
-
-def test_suite():
- """Create test suites for all .rst documentation tests.
-
- .txt files are also tested, but .rst is highly preferred.
- """
- suite = unittest.TestSuite()
- topdir = os.path.dirname(mailman.__file__)
- packages = []
- for dirpath, dirnames, filenames in os.walk(topdir):
- if 'docs' in dirnames:
- docsdir = os.path.join(dirpath, 'docs')[len(topdir)+1:]
- packages.append(docsdir)
- # Under higher verbosity settings, report all doctest errors, not just the
- # first one.
- flags = (doctest.ELLIPSIS |
- doctest.NORMALIZE_WHITESPACE |
- doctest.REPORT_NDIFF)
- # Add all the doctests in all subpackages.
- doctest_files = {}
- with chdir(topdir):
- for docsdir in packages:
- # Look to see if the package defines a test layer, otherwise use
- # SMTPLayer.
- package_path = 'mailman.' + DOT.join(docsdir.split(os.sep))
- try:
- __import__(package_path)
- except ImportError:
- layer = SMTPLayer
- else:
- layer = getattr(sys.modules[package_path], 'layer', SMTPLayer)
- for filename in os.listdir(docsdir):
- base, extension = os.path.splitext(filename)
- if os.path.splitext(filename)[1] in ('.txt', '.rst'):
- module_path = package_path + '.' + base
- doctest_files[module_path] = (
- os.path.join(docsdir, filename), layer)
- for module_path in sorted(doctest_files):
- path, layer = doctest_files[module_path]
- test = doctest.DocFileSuite(
- path,
- package='mailman',
- optionflags=flags,
- setUp=setup,
- tearDown=teardown)
- test.layer = layer
- suite.addTest(test)
- return suite
diff --git a/src/mailman/testing/layers.py b/src/mailman/testing/layers.py
index e47d5c9e0..6d150815f 100644
--- a/src/mailman/testing/layers.py
+++ b/src/mailman/testing/layers.py
@@ -154,7 +154,7 @@ class ConfigLayer(MockAndMonkeyLayer):
continue
logger_name = 'mailman.' + sub_name
log = logging.getLogger(logger_name)
- log.propagate = True
+ #log.propagate = True
# Reopen the file to a new path that tests can get at. Instead of
# using the configuration file path though, use a path that's
# specific to the logger so that tests can find expected output
diff --git a/src/mailman/testing/nose.py b/src/mailman/testing/nose.py
new file mode 100644
index 000000000..86a3e6a01
--- /dev/null
+++ b/src/mailman/testing/nose.py
@@ -0,0 +1,107 @@
+# Copyright (C) 2013 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/>.
+
+"""nose2 test infrastructure."""
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+__metaclass__ = type
+__all__ = [
+ 'NosePlugin',
+ ]
+
+
+import os
+import re
+import doctest
+import mailman
+import importlib
+
+from mailman.testing.documentation import setup, teardown
+from mailman.testing.layers import ConfigLayer, MockAndMonkeyLayer, SMTPLayer
+from nose2.events import Plugin
+
+DOT = '.'
+FLAGS = doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE | doctest.REPORT_NDIFF
+TOPDIR = os.path.dirname(mailman.__file__)
+
+
+
+class NosePlugin(Plugin):
+ configSection = 'mailman'
+
+ def __init__(self):
+ super(NosePlugin, self).__init__()
+ self.patterns = []
+ self.addArgument(self.patterns, 'P', 'pattern',
+ 'Add a test matching pattern')
+
+ def startTestRun(self, event):
+ MockAndMonkeyLayer.testing_mode = True
+ ConfigLayer.enable_stderr()
+
+ def getTestCaseNames(self, event):
+ if len(self.patterns) == 0:
+ # No filter patterns, so everything should be tested.
+ return
+ # Does the pattern match the fully qualified class name?
+ for pattern in self.patterns:
+ full_name = '{}.{}'.format(
+ event.testCase.__module__, event.testCase.__name__)
+ if re.search(pattern, full_name):
+ # Don't suppress this test class.
+ return
+ names = filter(event.isTestMethod, dir(event.testCase))
+ for name in names:
+ for pattern in self.patterns:
+ if re.search(pattern, name):
+ break
+ else:
+ event.excludedNames.append(name)
+
+ def handleFile(self, event):
+ path = event.path[len(TOPDIR)+1:]
+ if len(self.patterns) > 0:
+ for pattern in self.patterns:
+ if re.search(pattern, path):
+ break
+ else:
+ # Skip this doctest.
+ return
+ base, ext = os.path.splitext(path)
+ if ext != '.rst':
+ return
+ # Look to see if the package defines a test layer, otherwise use the
+ # default layer. First turn the file system path into a dotted Python
+ # module path.
+ parent = os.path.dirname(path)
+ dotted = 'mailman.' + DOT.join(parent.split(os.path.sep))
+ try:
+ module = importlib.import_module(dotted)
+ except ImportError:
+ layer = SMTPLayer
+ else:
+ layer = getattr(module, 'layer', SMTPLayer)
+ test = doctest.DocFileTest(
+ path, package='mailman',
+ optionflags=FLAGS,
+ setUp=setup,
+ tearDown=teardown)
+ test.layer = layer
+ # Suppress the extra "Doctest: ..." line.
+ test.shortDescription = lambda: None
+ event.extraTests.append(test)
diff --git a/unittest.cfg b/unittest.cfg
new file mode 100644
index 000000000..d639a8ae3
--- /dev/null
+++ b/unittest.cfg
@@ -0,0 +1,10 @@
+[unittest]
+verbose = 2
+plugins = mailman.testing.nose
+ nose2.plugins.layers
+
+[mailman]
+always-on = True
+
+[log-capture]
+always-on = False