summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBarry Warsaw2016-01-07 18:33:01 -0500
committerBarry Warsaw2016-01-07 18:33:01 -0500
commit433ce1580295a410ebe83b731e54672c13e04e15 (patch)
tree2474a30749d66260cad28945210ee778f32436ce /src
parent4f549f8655857aef64ed8c92c3339c32f5e942db (diff)
downloadmailman-433ce1580295a410ebe83b731e54672c13e04e15.tar.gz
mailman-433ce1580295a410ebe83b731e54672c13e04e15.tar.zst
mailman-433ce1580295a410ebe83b731e54672c13e04e15.zip
Diffstat (limited to 'src')
-rw-r--r--src/mailman/app/tests/test_subscriptions.py204
-rw-r--r--src/mailman/interfaces/subscriptions.py45
-rw-r--r--src/mailman/model/docs/subscriptions.rst (renamed from src/mailman/app/docs/subscriptions.rst)23
-rw-r--r--src/mailman/model/subscriptions.py23
-rw-r--r--src/mailman/model/tests/test_subscriptions.py260
5 files changed, 339 insertions, 216 deletions
diff --git a/src/mailman/app/tests/test_subscriptions.py b/src/mailman/app/tests/test_subscriptions.py
index 229c85aa8..096b7dac6 100644
--- a/src/mailman/app/tests/test_subscriptions.py
+++ b/src/mailman/app/tests/test_subscriptions.py
@@ -27,9 +27,9 @@ import unittest
from mailman.app.lifecycle import create_list
from mailman.app.subscriptions import SubscriptionWorkflow
from mailman.interfaces.bans import IBanManager
-from mailman.interfaces.member import MemberRole, MembershipIsBannedError
+from mailman.interfaces.member import MembershipIsBannedError
from mailman.interfaces.pending import IPendings
-from mailman.interfaces.subscriptions import ISubscriptionService, TokenOwner
+from mailman.interfaces.subscriptions import TokenOwner
from mailman.testing.helpers import LogFileMark, get_queue_messages
from mailman.testing.layers import ConfigLayer
from mailman.interfaces.mailinglist import SubscriptionPolicy
@@ -641,203 +641,3 @@ approval:
self.assertIsNone(workflow.token)
self.assertEqual(workflow.token_owner, TokenOwner.no_one)
self.assertEqual(workflow.member.address, anne)
-
-
-
-class TestSubscriptionService(unittest.TestCase):
- layer = ConfigLayer
-
- def setUp(self):
- self._mlist = create_list('test@example.com')
- self._mlist.admin_immed_notify = False
- self._user_manager = getUtility(IUserManager)
- self._service = getUtility(ISubscriptionService)
-
- def test_find_member_address_no_user(self):
- # Find address-based memberships when no user is linked to the address.
- address = self._user_manager.create_address(
- 'anne@example.com', 'Anne Address')
- self._mlist.subscribe(address)
- members = self._service.find_members('anne@example.com')
- self.assertEqual(len(members), 1)
- self.assertEqual(members[0].address, address)
-
- def test_find_member_address_with_user(self):
- # Find address-based memberships when a user is linked to the address.
- user = self._user_manager.create_user(
- 'anne@example.com', 'Anne User')
- address = user.addresses[0]
- address.verified_on = now()
- user.preferred_address = address
- # Subscribe the address.
- self._mlist.subscribe(address)
- members = self._service.find_members('anne@example.com')
- self.assertEqual(len(members), 1)
- self.assertEqual(members[0].user, user)
-
- def test_find_member_user(self):
- # Find user-based memberships by address.
- user = self._user_manager.create_user(
- 'anne@example.com', 'Anne User')
- address = user.addresses[0]
- address.verified_on = now()
- user.preferred_address = address
- # Subscribe the user.
- self._mlist.subscribe(user)
- members = self._service.find_members('anne@example.com')
- self.assertEqual(len(members), 1)
- self.assertEqual(members[0].user, user)
-
- def test_find_member_user_secondary_address(self):
- # Find user-based memberships using a secondary address.
- user = self._user_manager.create_user(
- 'anne@example.com', 'Anne User')
- address = user.addresses[0]
- address.verified_on = now()
- user.preferred_address = address
- # Create a secondary address.
- address_2 = self._user_manager.create_address(
- 'anne2@example.com', 'Anne User 2')
- address_2.user = user
- # Subscribe the user.
- self._mlist.subscribe(user)
- # Search for the secondary address.
- members = self._service.find_members('anne2@example.com')
- self.assertEqual(len(members), 1)
- self.assertEqual(members[0].user, user)
-
- def test_wont_find_member_secondary_address(self):
- # A user is subscribed with one of their address, and a search is
- # performed on another of their addresses. This is not supported; the
- # subscription is not returned.
- user = self._user_manager.create_user(
- 'anne@example.com', 'Anne User')
- address = user.addresses[0]
- address.verified_on = now()
- user.preferred_address = address
- # Create a secondary address.
- address_2 = self._user_manager.create_address(
- 'anne2@example.com', 'Anne User 2')
- address_2.verified_on = now()
- address_2.user = user
- # Subscribe the secondary address.
- self._mlist.subscribe(address_2)
- # Search for the primary address.
- members = self._service.find_members('anne@example.com')
- self.assertEqual(len(members), 0)
-
- def test_find_member_user_id(self):
- # Find user-based memberships by user_id.
- user = self._user_manager.create_user(
- 'anne@example.com', 'Anne User')
- address = user.addresses[0]
- address.verified_on = now()
- user.preferred_address = address
- # Subscribe the user.
- self._mlist.subscribe(user)
- members = self._service.find_members(user.user_id)
- self.assertEqual(len(members), 1)
- self.assertEqual(members[0].user, user)
-
- def test_find_member_user_id_controlled_addresses(self):
- # Find address-based memberships by user_id when a secondary address is
- # subscribed.
- user = self._user_manager.create_user(
- 'anne@example.com', 'Anne User')
- address = user.addresses[0]
- address.verified_on = now()
- user.preferred_address = address
- # Create a secondary address.
- address_2 = self._user_manager.create_address(
- 'anne2@example.com', 'Anne User 2')
- address_2.verified_on = now()
- address_2.user = user
- # Create a third address.
- address_3 = self._user_manager.create_address(
- 'anne3@example.com', 'Anne User 3')
- address_3.verified_on = now()
- address_3.user = user
- # Subscribe the secondary address only.
- self._mlist.subscribe(address_2)
- members = self._service.find_members(user.user_id)
- self.assertEqual(len(members), 1)
- self.assertEqual(members[0].address, address_2)
-
- def test_find_member_sorting(self):
- # Check that the memberships are properly sorted.
- user = self._user_manager.create_user(
- 'anne1@example.com', 'Anne User')
- address = user.addresses[0]
- address.verified_on = now()
- user.preferred_address = address
- # Create a secondary address.
- address_2 = self._user_manager.create_address(
- 'anne2@example.com', 'Anne User 2')
- address_2.verified_on = now()
- address_2.user = user
- # Create a third address.
- address_3 = self._user_manager.create_address(
- 'anne3@example.com', 'Anne User 3')
- address_3.verified_on = now()
- address_3.user = user
- # Create three lists.
- mlist1 = create_list('test1@example.com')
- mlist1.admin_immed_notify = False
- mlist2 = create_list('test2@example.com')
- mlist2.admin_immed_notify = False
- mlist3 = create_list('test3@example.com')
- mlist3.admin_immed_notify = False
- # Subscribe the addresses in random order
- # https://www.xkcd.com/221/
- mlist3.subscribe(address_3, MemberRole.moderator)
- mlist3.subscribe(address_3, MemberRole.owner)
- mlist3.subscribe(address_3, MemberRole.member)
- mlist3.subscribe(address_2, MemberRole.member)
- mlist3.subscribe(address_2, MemberRole.owner)
- mlist3.subscribe(address_2, MemberRole.moderator)
- mlist3.subscribe(address, MemberRole.owner)
- mlist3.subscribe(address, MemberRole.member)
- mlist3.subscribe(address, MemberRole.moderator)
- mlist2.subscribe(address_2, MemberRole.moderator)
- mlist2.subscribe(address_2, MemberRole.member)
- mlist2.subscribe(address_2, MemberRole.owner)
- mlist2.subscribe(address_3, MemberRole.moderator)
- mlist2.subscribe(address_3, MemberRole.member)
- mlist2.subscribe(address_3, MemberRole.owner)
- mlist2.subscribe(address, MemberRole.owner)
- mlist2.subscribe(address, MemberRole.moderator)
- mlist2.subscribe(address, MemberRole.member)
- mlist1.subscribe(address_2, MemberRole.moderator)
- mlist1.subscribe(address, MemberRole.member)
- mlist1.subscribe(address_3, MemberRole.owner)
- # The results should be sorted first by list id, then by address, then
- # by member role.
- members = self._service.find_members(user.user_id)
- self.assertEqual(len(members), 21)
- self.assertListEqual(
- [(m.list_id.partition('.')[0],
- m.address.email.partition('@')[0],
- m.role)
- for m in members],
- [('test1', 'anne1', MemberRole.member),
- ('test1', 'anne2', MemberRole.moderator),
- ('test1', 'anne3', MemberRole.owner),
- ('test2', 'anne1', MemberRole.member),
- ('test2', 'anne1', MemberRole.owner),
- ('test2', 'anne1', MemberRole.moderator),
- ('test2', 'anne2', MemberRole.member),
- ('test2', 'anne2', MemberRole.owner),
- ('test2', 'anne2', MemberRole.moderator),
- ('test2', 'anne3', MemberRole.member),
- ('test2', 'anne3', MemberRole.owner),
- ('test2', 'anne3', MemberRole.moderator),
- ('test3', 'anne1', MemberRole.member),
- ('test3', 'anne1', MemberRole.owner),
- ('test3', 'anne1', MemberRole.moderator),
- ('test3', 'anne2', MemberRole.member),
- ('test3', 'anne2', MemberRole.owner),
- ('test3', 'anne2', MemberRole.moderator),
- ('test3', 'anne3', MemberRole.member),
- ('test3', 'anne3', MemberRole.owner),
- ('test3', 'anne3', MemberRole.moderator),
- ])
diff --git a/src/mailman/interfaces/subscriptions.py b/src/mailman/interfaces/subscriptions.py
index f9e0c44dd..d4626a1bc 100644
--- a/src/mailman/interfaces/subscriptions.py
+++ b/src/mailman/interfaces/subscriptions.py
@@ -22,13 +22,14 @@ __all__ = [
'MissingUserError',
'RequestRecord',
'TokenOwner',
+ 'TooManyMembersError',
]
from collections import namedtuple
from enum import Enum
from mailman.interfaces.errors import MailmanError
-from mailman.interfaces.member import DeliveryMode
+from mailman.interfaces.member import DeliveryMode, MembershipError
from zope.interface import Interface
@@ -37,13 +38,21 @@ class MissingUserError(MailmanError):
"""A an invalid user id was given."""
def __init__(self, user_id):
- super(MissingUserError, self).__init__()
+ super().__init__()
self.user_id = user_id
def __str__(self):
return self.user_id
+class TooManyMembersError(MembershipError):
+ def __init__(self, subscriber, list_id, role):
+ super().__init__()
+ self.subscriber = subscriber
+ self.list_id = list_id
+ self.role = role
+
+
_RequestRecord = namedtuple(
'RequestRecord',
@@ -92,12 +101,13 @@ class ISubscriptionService(Interface):
"""
def find_members(subscriber=None, list_id=None, role=None):
- """Search for and return a specific member.
+ """Search for members matching some criteria.
- The members are sorted first by fully-qualified mailing list name,
- then by subscribed email address, then by role. Because the user may
- be a member of the list under multiple roles (e.g. as an owner and as
- a digest member), the member can appear multiple times in this list.
+ The members are sorted first by list-id, then by subscribed
+ email address, then by role. Because the user may be a member
+ of the list under multiple roles (e.g. as an owner and as a
+ digest member), the member can appear multiple times in this
+ list.
:param subscriber: The email address or user id of the user getting
subscribed.
@@ -111,6 +121,27 @@ class ISubscriptionService(Interface):
:rtype: list of `IMember`
"""
+ def find_member(subscriber=None, list_id=None, role=None):
+ """Search for a member matching some criteria.
+
+ This is like find_members() but is guaranteed to return exactly
+ one member.
+
+ :param subscriber: The email address or user id of the user getting
+ subscribed.
+ :type subscriber: string or int
+ :param list_id: The list id of the mailing list to search for the
+ subscriber's memberships on.
+ :type list_id: string
+ :param role: The member role.
+ :type role: `MemberRole`
+ :return: The member matching the given criteria or None if no
+ members match the criteria.
+ :rtype: `IMember` or None
+ :raises TooManyMembersError: when the given criteria matches
+ more than one membership.
+ """
+
def __iter__():
"""See `get_members()`."""
diff --git a/src/mailman/app/docs/subscriptions.rst b/src/mailman/model/docs/subscriptions.rst
index fa5d0edfe..5d141d5a9 100644
--- a/src/mailman/app/docs/subscriptions.rst
+++ b/src/mailman/model/docs/subscriptions.rst
@@ -86,8 +86,8 @@ There is an iteration shorthand for getting all the members.
on cat@example.com as MemberRole.member>
-Finding members
-===============
+Searching for members
+=====================
The subscription service can be used to find memberships based on specific
search criteria. For example, we can find all the mailing lists that Anne is
@@ -152,6 +152,25 @@ You can also find a specific membership by all three criteria.
on bee@example.com as MemberRole.owner>
+Finding a single member
+=======================
+
+If you expect only zero or one member to match your criteria, you can use a
+the more efficient ``find_member()`` method. This takes exactly the same
+criteria as ``find_members()``.
+
+There may be no matching members.
+
+ >>> print(service.find_member('dave@example.com'))
+ None
+
+But if there is exactly one membership, it is returned.
+
+ >>> service.find_member('bperson@example.com', 'ant.example.com')
+ <Member: Bart Person <bperson@example.com>
+ on ant@example.com as MemberRole.moderator>
+
+
Removing members
================
diff --git a/src/mailman/model/subscriptions.py b/src/mailman/model/subscriptions.py
index d1b805ef1..93c7c97c2 100644
--- a/src/mailman/model/subscriptions.py
+++ b/src/mailman/model/subscriptions.py
@@ -25,7 +25,8 @@ __all__ = [
from mailman.app.membership import delete_member
from mailman.database.transaction import dbconnection
from mailman.interfaces.listmanager import IListManager, NoSuchListError
-from mailman.interfaces.subscriptions import ISubscriptionService
+from mailman.interfaces.subscriptions import (
+ ISubscriptionService, TooManyMembersError)
from mailman.interfaces.usermanager import IUserManager
from mailman.model.address import Address
from mailman.model.member import Member
@@ -76,13 +77,12 @@ class SubscriptionService:
return members[0]
@dbconnection
- def find_members(self, store, subscriber=None, list_id=None, role=None):
- """See `ISubscriptionService`."""
+ def _find_members(self, store, subscriber, list_id, role):
# If `subscriber` is a user id, then we'll search for all addresses
# which are controlled by the user, otherwise we'll just search for
# the given address.
if subscriber is None and list_id is None and role is None:
- return []
+ raise NoResultFound
order = (Member.list_id, Address.email, Member.role)
# Querying for the subscriber is the most complicated part, because
# the parameter can either be an email address or a user id. Start by
@@ -112,12 +112,25 @@ class SubscriptionService:
q_address = q_address.filter(Member.role == role)
q_user = q_user.filter(Member.role == role)
# Do a UNION of the two queries, sort the result and generate Members.
+ return q_address.union(q_user).order_by(*order).from_self(Member)
+
+ def find_members(self, subscriber=None, list_id=None, role=None):
+ """See `ISubscriptionService`."""
try:
- query = q_address.union(q_user).order_by(*order).from_self(Member)
+ query = self._find_members(subscriber, list_id, role)
except NoResultFound:
query = None
return QuerySequence(query)
+ def find_member(self, subscriber=None, list_id=None, role=None):
+ """See `ISubscriptionService`."""
+ try:
+ return self._find_members(subscriber, list_id, role).one()
+ except NoResultFound:
+ return None
+ except MultipleResultsFound:
+ raise TooManyMembersError(subscriber, list_id, role)
+
def __iter__(self):
for member in self.get_members():
yield member
diff --git a/src/mailman/model/tests/test_subscriptions.py b/src/mailman/model/tests/test_subscriptions.py
new file mode 100644
index 000000000..3e97bd427
--- /dev/null
+++ b/src/mailman/model/tests/test_subscriptions.py
@@ -0,0 +1,260 @@
+# 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/>.
+
+"""Test the subscription service."""
+
+__all__ = [
+ 'TestSubscriptionService',
+ ]
+
+
+import unittest
+
+from mailman.app.lifecycle import create_list
+from mailman.interfaces.listmanager import NoSuchListError
+from mailman.interfaces.member import MemberRole
+from mailman.interfaces.subscriptions import (
+ ISubscriptionService, TooManyMembersError)
+from mailman.interfaces.usermanager import IUserManager
+from mailman.testing.helpers import subscribe
+from mailman.testing.layers import ConfigLayer
+from mailman.utilities.datetime import now
+from zope.component import getUtility
+
+
+class TestSubscriptionService(unittest.TestCase):
+ layer = ConfigLayer
+
+ def setUp(self):
+ self._mlist = create_list('test@example.com')
+ self._mlist.admin_immed_notify = False
+ self._user_manager = getUtility(IUserManager)
+ self._service = getUtility(ISubscriptionService)
+
+ def test_find_member_address_no_user(self):
+ # Find address-based memberships when no user is linked to the address.
+ address = self._user_manager.create_address(
+ 'anne@example.com', 'Anne Address')
+ self._mlist.subscribe(address)
+ members = self._service.find_members('anne@example.com')
+ self.assertEqual(len(members), 1)
+ self.assertEqual(members[0].address, address)
+
+ def test_find_member_address_with_user(self):
+ # Find address-based memberships when a user is linked to the address.
+ user = self._user_manager.create_user(
+ 'anne@example.com', 'Anne User')
+ address = user.addresses[0]
+ address.verified_on = now()
+ user.preferred_address = address
+ # Subscribe the address.
+ self._mlist.subscribe(address)
+ members = self._service.find_members('anne@example.com')
+ self.assertEqual(len(members), 1)
+ self.assertEqual(members[0].user, user)
+
+ def test_find_member_user(self):
+ # Find user-based memberships by address.
+ user = self._user_manager.create_user(
+ 'anne@example.com', 'Anne User')
+ address = user.addresses[0]
+ address.verified_on = now()
+ user.preferred_address = address
+ # Subscribe the user.
+ self._mlist.subscribe(user)
+ members = self._service.find_members('anne@example.com')
+ self.assertEqual(len(members), 1)
+ self.assertEqual(members[0].user, user)
+
+ def test_find_member_user_secondary_address(self):
+ # Find user-based memberships using a secondary address.
+ user = self._user_manager.create_user(
+ 'anne@example.com', 'Anne User')
+ address = user.addresses[0]
+ address.verified_on = now()
+ user.preferred_address = address
+ # Create a secondary address.
+ address_2 = self._user_manager.create_address(
+ 'anne2@example.com', 'Anne User 2')
+ address_2.user = user
+ # Subscribe the user.
+ self._mlist.subscribe(user)
+ # Search for the secondary address.
+ members = self._service.find_members('anne2@example.com')
+ self.assertEqual(len(members), 1)
+ self.assertEqual(members[0].user, user)
+
+ def test_wont_find_member_secondary_address(self):
+ # A user is subscribed with one of their address, and a search is
+ # performed on another of their addresses. This is not supported; the
+ # subscription is not returned.
+ user = self._user_manager.create_user(
+ 'anne@example.com', 'Anne User')
+ address = user.addresses[0]
+ address.verified_on = now()
+ user.preferred_address = address
+ # Create a secondary address.
+ address_2 = self._user_manager.create_address(
+ 'anne2@example.com', 'Anne User 2')
+ address_2.verified_on = now()
+ address_2.user = user
+ # Subscribe the secondary address.
+ self._mlist.subscribe(address_2)
+ # Search for the primary address.
+ members = self._service.find_members('anne@example.com')
+ self.assertEqual(len(members), 0)
+
+ def test_find_member_user_id(self):
+ # Find user-based memberships by user_id.
+ user = self._user_manager.create_user(
+ 'anne@example.com', 'Anne User')
+ address = user.addresses[0]
+ address.verified_on = now()
+ user.preferred_address = address
+ # Subscribe the user.
+ self._mlist.subscribe(user)
+ members = self._service.find_members(user.user_id)
+ self.assertEqual(len(members), 1)
+ self.assertEqual(members[0].user, user)
+
+ def test_find_member_user_id_controlled_addresses(self):
+ # Find address-based memberships by user_id when a secondary address is
+ # subscribed.
+ user = self._user_manager.create_user(
+ 'anne@example.com', 'Anne User')
+ address = user.addresses[0]
+ address.verified_on = now()
+ user.preferred_address = address
+ # Create a secondary address.
+ address_2 = self._user_manager.create_address(
+ 'anne2@example.com', 'Anne User 2')
+ address_2.verified_on = now()
+ address_2.user = user
+ # Create a third address.
+ address_3 = self._user_manager.create_address(
+ 'anne3@example.com', 'Anne User 3')
+ address_3.verified_on = now()
+ address_3.user = user
+ # Subscribe the secondary address only.
+ self._mlist.subscribe(address_2)
+ members = self._service.find_members(user.user_id)
+ self.assertEqual(len(members), 1)
+ self.assertEqual(members[0].address, address_2)
+
+ def test_find_member_sorting(self):
+ # Check that the memberships are properly sorted.
+ user = self._user_manager.create_user(
+ 'anne1@example.com', 'Anne User')
+ address = user.addresses[0]
+ address.verified_on = now()
+ user.preferred_address = address
+ # Create a secondary address.
+ address_2 = self._user_manager.create_address(
+ 'anne2@example.com', 'Anne User 2')
+ address_2.verified_on = now()
+ address_2.user = user
+ # Create a third address.
+ address_3 = self._user_manager.create_address(
+ 'anne3@example.com', 'Anne User 3')
+ address_3.verified_on = now()
+ address_3.user = user
+ # Create three lists.
+ mlist1 = create_list('test1@example.com')
+ mlist1.admin_immed_notify = False
+ mlist2 = create_list('test2@example.com')
+ mlist2.admin_immed_notify = False
+ mlist3 = create_list('test3@example.com')
+ mlist3.admin_immed_notify = False
+ # Subscribe the addresses in random order
+ # https://www.xkcd.com/221/
+ mlist3.subscribe(address_3, MemberRole.moderator)
+ mlist3.subscribe(address_3, MemberRole.owner)
+ mlist3.subscribe(address_3, MemberRole.member)
+ mlist3.subscribe(address_2, MemberRole.member)
+ mlist3.subscribe(address_2, MemberRole.owner)
+ mlist3.subscribe(address_2, MemberRole.moderator)
+ mlist3.subscribe(address, MemberRole.owner)
+ mlist3.subscribe(address, MemberRole.member)
+ mlist3.subscribe(address, MemberRole.moderator)
+ mlist2.subscribe(address_2, MemberRole.moderator)
+ mlist2.subscribe(address_2, MemberRole.member)
+ mlist2.subscribe(address_2, MemberRole.owner)
+ mlist2.subscribe(address_3, MemberRole.moderator)
+ mlist2.subscribe(address_3, MemberRole.member)
+ mlist2.subscribe(address_3, MemberRole.owner)
+ mlist2.subscribe(address, MemberRole.owner)
+ mlist2.subscribe(address, MemberRole.moderator)
+ mlist2.subscribe(address, MemberRole.member)
+ mlist1.subscribe(address_2, MemberRole.moderator)
+ mlist1.subscribe(address, MemberRole.member)
+ mlist1.subscribe(address_3, MemberRole.owner)
+ # The results should be sorted first by list id, then by address, then
+ # by member role.
+ members = self._service.find_members(user.user_id)
+ self.assertEqual(len(members), 21)
+ self.assertListEqual(
+ [(m.list_id.partition('.')[0],
+ m.address.email.partition('@')[0],
+ m.role)
+ for m in members],
+ [('test1', 'anne1', MemberRole.member),
+ ('test1', 'anne2', MemberRole.moderator),
+ ('test1', 'anne3', MemberRole.owner),
+ ('test2', 'anne1', MemberRole.member),
+ ('test2', 'anne1', MemberRole.owner),
+ ('test2', 'anne1', MemberRole.moderator),
+ ('test2', 'anne2', MemberRole.member),
+ ('test2', 'anne2', MemberRole.owner),
+ ('test2', 'anne2', MemberRole.moderator),
+ ('test2', 'anne3', MemberRole.member),
+ ('test2', 'anne3', MemberRole.owner),
+ ('test2', 'anne3', MemberRole.moderator),
+ ('test3', 'anne1', MemberRole.member),
+ ('test3', 'anne1', MemberRole.owner),
+ ('test3', 'anne1', MemberRole.moderator),
+ ('test3', 'anne2', MemberRole.member),
+ ('test3', 'anne2', MemberRole.owner),
+ ('test3', 'anne2', MemberRole.moderator),
+ ('test3', 'anne3', MemberRole.member),
+ ('test3', 'anne3', MemberRole.owner),
+ ('test3', 'anne3', MemberRole.moderator),
+ ])
+
+ def test_find_members_shortcut(self):
+ members = self._service.find_members()
+ self.assertEqual(len(members), 0)
+
+ def test_find_members_no_results(self):
+ members = self._service.find_members('zack@example.com')
+ self.assertEqual(len(members), 0)
+ self.assertEqual(list(members), [])
+
+ def test_find_member_error(self):
+ # .find_member() can only return zero or one memberships. Anything
+ # else is an error.
+ subscribe(self._mlist, 'Anne')
+ subscribe(self._mlist, 'Anne', MemberRole.owner)
+ with self.assertRaises(TooManyMembersError) as cm:
+ self._service.find_member('aperson@example.com')
+ self.assertEqual(cm.exception.subscriber, 'aperson@example.com')
+ self.assertEqual(cm.exception.list_id, None)
+ self.assertEqual(cm.exception.role, None)
+
+ def test_leave_no_such_list(self):
+ # Trying to leave a nonexistent list raises an exception.
+ self.assertRaises(NoSuchListError, self._service.leave,
+ 'bogus.example.com', 'anne@example.com')