diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/mailman/__init__.py | 2 | ||||
| -rw-r--r-- | src/mailman/app/docs/hooks.rst | 3 | ||||
| -rw-r--r-- | src/mailman/archiving/docs/__init__.py | 0 | ||||
| -rw-r--r-- | src/mailman/commands/docs/__init__.py | 0 | ||||
| -rw-r--r-- | src/mailman/docs/NEWS.rst | 7 | ||||
| -rw-r--r-- | src/mailman/docs/START.rst | 57 | ||||
| -rw-r--r-- | src/mailman/handlers/docs/__init__.py | 0 | ||||
| -rw-r--r-- | src/mailman/mta/docs/__init__.py | 0 | ||||
| -rw-r--r-- | src/mailman/rules/docs/__init__.py | 0 | ||||
| -rw-r--r-- | src/mailman/runners/docs/__init__.py | 0 | ||||
| -rw-r--r-- | src/mailman/testing/__init__.py | 39 | ||||
| -rw-r--r-- | src/mailman/testing/documentation.py (renamed from src/mailman/tests/test_documentation.py) | 63 | ||||
| -rw-r--r-- | src/mailman/testing/layers.py | 2 | ||||
| -rw-r--r-- | src/mailman/testing/nose.py | 107 |
14 files changed, 141 insertions, 139 deletions
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..a2b599cbc 100644 --- a/src/mailman/docs/NEWS.rst +++ b/src/mailman/docs/NEWS.rst @@ -12,6 +12,13 @@ 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. + * Use the ``enum34`` package instead of ``flufl.enum``. + 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) |
