Barry Warsaw pushed to branch master at mailman / Mailman

Commits:
ff31bf58 by Barry Warsaw at 2016-01-03T21:59:35Z
Boost coverage.

Use coverage.ini to ignore a few common idioms, so as to reduce code clutter.

Invoke coverage slightly differently in the tox.ini.

- - - - -
e93affa9 by Barry Warsaw at 2016-01-04T08:24:12Z
More coverage.

- - - - -


10 changed files:

- coverage.ini
- src/mailman/app/commands.py
- src/mailman/chains/base.py
- src/mailman/rest/helpers.py
- src/mailman/rest/members.py
- src/mailman/rest/sub_moderation.py
- + src/mailman/rest/tests/test_helpers.py
- src/mailman/rest/tests/test_moderation.py
- src/mailman/utilities/uid.py
- tox.ini


Changes:

=====================================
coverage.ini
=====================================
--- a/coverage.ini
+++ b/coverage.ini
@@ -7,6 +7,12 @@ omit =
     .tox/coverage/lib/python3.5/site-packages/*
     */test_*.py
 
+[report]
+exclude_lines =
+    pragma: no cover
+    raise NotImplementedError
+    assert\s
+
 [paths]
 source =
     mailman


=====================================
src/mailman/app/commands.py
=====================================
--- a/src/mailman/app/commands.py
+++ b/src/mailman/app/commands.py
@@ -35,6 +35,6 @@ def initialize():
         command = command_class()
         verifyObject(IEmailCommand, command)
         assert command_class.name not in config.commands, (
-            'Duplicate email command "{0}" found in {1}'.format(
+            'Duplicate email command "{}" found in {}'.format(
                 command_class.name, command_class.__module__))
         config.commands[command_class.name] = command_class()


=====================================
src/mailman/chains/base.py
=====================================
--- a/src/mailman/chains/base.py
+++ b/src/mailman/chains/base.py
@@ -71,7 +71,7 @@ class TerminalChainBase:
         :param msg: The message.
         :param msgdata: The message metadata.
         """
-        raise NotImplementedError                   # pragma: no cover
+        raise NotImplementedError
 
     def get_links(self, mlist, msg, msgdata):
         """See `IChain`."""


=====================================
src/mailman/rest/helpers.py
=====================================
--- a/src/mailman/rest/helpers.py
+++ b/src/mailman/rest/helpers.py
@@ -86,7 +86,7 @@ class ExtendedEncoder(json.JSONEncoder):
             # It's up to the decoding validator to associate this name with
             # the right Enum class.
             return obj.name
-        return json.JSONEncoder.default(self, obj)
+        return super().default(obj)
 
 
 def etag(resource):
@@ -130,7 +130,7 @@ class CollectionMixin:
         :return: The representation of the resource.
         :rtype: dict
         """
-        raise NotImplementedError                   # pragma: no cover
+        raise NotImplementedError
 
     def _resource_as_json(self, resource):
         """Return the JSON formatted representation of the resource."""
@@ -147,7 +147,7 @@ class CollectionMixin:
         :return: The collection
         :rtype: list
         """
-        raise NotImplementedError                   # pragma: no cover
+        raise NotImplementedError
 
     def _paginate(self, request, collection):
         """Method to paginate through collection result lists.


=====================================
src/mailman/rest/members.py
=====================================
--- a/src/mailman/rest/members.py
+++ b/src/mailman/rest/members.py
@@ -100,7 +100,7 @@ class MemberCollection(_MemberBase):
     """
     def _get_collection(self, request):
         """See `CollectionMixin`."""
-        raise NotImplementedError                   # pragma: no cover
+        raise NotImplementedError
 
     def on_get(self, request, response):
         """roster/[members|owners|moderators]"""


=====================================
src/mailman/rest/sub_moderation.py
=====================================
--- a/src/mailman/rest/sub_moderation.py
+++ b/src/mailman/rest/sub_moderation.py
@@ -79,7 +79,7 @@ class IndividualRequest(_ModerationBase):
             bad_request(response, str(error))
             return
         action = arguments['action']
-        if action is Action.defer:
+        if action in (Action.defer, Action.hold):
             # At least see if the token is in the database.
             pendable = self._pendings.confirm(self._token, expunge=False)
             if pendable is None:
@@ -100,7 +100,8 @@ class IndividualRequest(_ModerationBase):
                 not_found(response)
             else:
                 no_content(response)
-        elif action is Action.reject:
+        else:
+            assert action is Action.reject, action
             # Like discard but sends a rejection notice to the user.
             pendable = self._pendings.confirm(self._token, expunge=True)
             if pendable is None:


=====================================
src/mailman/rest/tests/test_helpers.py
=====================================
--- /dev/null
+++ b/src/mailman/rest/tests/test_helpers.py
@@ -0,0 +1,82 @@
+# Copyright (C) 2016 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/>.
+
+"""Additional tests for helpers."""
+
+__all__ = [
+    'TestHelpers',
+    ]
+
+
+import unittest
+
+from datetime import timedelta
+from mailman.rest import helpers
+from mailman.testing.layers import ConfigLayer
+
+
+class FakeResponse:
+    def __init__(self):
+        self.body = 'not set'
+
+
+class Unserializable:
+    pass
+
+
+
+class TestHelpers(unittest.TestCase):
+    layer = ConfigLayer
+
+    def test_not_found_body_is_none(self):
+        response = FakeResponse()
+        helpers.not_found(response, body=None)
+        self.assertEqual(response.body, 'not set')
+
+    def test_accepted_body_is_not_none(self):
+        response = FakeResponse()
+        helpers.accepted(response, body='set')
+        self.assertEqual(response.body, 'set')
+
+    def test_bad_request_body_is_none(self):
+        response = FakeResponse()
+        helpers.bad_request(response, body=None)
+        self.assertEqual(response.body, 'not set')
+
+    def test_conflict_body_is_none(self):
+        response = FakeResponse()
+        helpers.conflict(response, body=None)
+        self.assertEqual(response.body, 'not set')
+
+    def test_forbidden_body_is_none(self):
+        response = FakeResponse()
+        helpers.forbidden(response, body=None)
+        self.assertEqual(response.body, 'not set')
+
+    def test_json_encoding_datetime_seconds(self):
+        resource = dict(interval=timedelta(seconds=2))
+        unjson = eval(helpers.etag(resource))
+        self.assertEqual(unjson['interval'], '0d2.0s')
+
+    def test_json_encoding_datetime_microseconds(self):
+        resource = dict(interval=timedelta(microseconds=2))
+        unjson = eval(helpers.etag(resource))
+        self.assertEqual(unjson['interval'], '0d2e-06s')
+
+    def test_json_encoding_default(self):
+        resource = dict(interval=Unserializable())
+        self.assertRaises(TypeError, helpers.etag, resource)


=====================================
src/mailman/rest/tests/test_moderation.py
=====================================
--- a/src/mailman/rest/tests/test_moderation.py
+++ b/src/mailman/rest/tests/test_moderation.py
@@ -341,3 +341,25 @@ class TestSubscriptionModeration(unittest.TestCase):
                      '/requests/bogus',
                      dict(action='reject'))
         self.assertEqual(cm.exception.code, 404)
+
+    def test_hold_keeps_holding(self):
+        # POST to the request to continue holding it.
+        with transaction():
+            token, token_owner, member = self._registrar.register(self._anne)
+        # Anne's subscription request got held.
+        self.assertIsNone(member)
+        # Clear out the virgin queue, which currently contains the
+        # confirmation message sent to Anne.
+        get_queue_messages('virgin')
+        url = 'http://localhost:9001/3.0/lists/a...@example.com/requests/{}'
+        content, response = call_api(url.format(token), dict(
+            action='hold',
+            ))
+        self.assertEqual(response.status, 204)
+        # Anne is not a member.
+        self.assertIsNone(self._mlist.members.get_member('a...@example.com'))
+        # The request URL still exists.
+        content, response = call_api(url.format(token), dict(
+                action='defer',
+                ))
+        self.assertEqual(response.status, 204)


=====================================
src/mailman/utilities/uid.py
=====================================
--- a/src/mailman/utilities/uid.py
+++ b/src/mailman/utilities/uid.py
@@ -89,7 +89,7 @@ class _PredictableIDGenerator:
         The type of the returned id is intended to be the type that
         makes sense for the subclass overriding this method.
         """
-        raise NotImplementedError                   # pragma: no cover
+        raise NotImplementedError
 
     def _next_predictable_id(self):
         """Generate a predictable id for when Mailman being tested.
@@ -97,7 +97,7 @@ class _PredictableIDGenerator:
         The type of the returned id is intended to be the type that
         makes sense for the subclass overriding this method.
         """
-        raise NotImplementedError                   # pragma: no cover
+        raise NotImplementedError
 
     def _next_id(self):
         with self._lock:


=====================================
tox.ini
=====================================
--- a/tox.ini
+++ b/tox.ini
@@ -24,9 +24,10 @@ rc = --rcfile={[coverage]rcfile}
 [testenv:coverage]
 basepython = python3.5
 commands =
-    coverage run {[coverage]rc} -m nose2 -v
-    coverage combine {[coverage]rc}
-    coverage html {[coverage]rc}
+    python -m coverage run {[coverage]rc} -m nose2 -v
+    python -m coverage combine {[coverage]rc}
+    python -m coverage html {[coverage]rc}
+    python -m coverage report -m {[coverage]rc}
 #sitepackages = True
 usedevelop = True
 whitelist_externals = python-coverage



View it on GitLab: 
https://gitlab.com/mailman/mailman/compare/f390e08c31477c476e1312d03771b68e22b42675...e93affa947002959138cf8a45f33bea5fa06d3f7
_______________________________________________
Mailman-checkins mailing list
Mailman-checkins@python.org
Unsubscribe: 
https://mail.python.org/mailman/options/mailman-checkins/archive%40jab.org

Reply via email to