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