add tests for Group class

This commit is contained in:
Max Erenberg 2021-08-04 06:33:50 +00:00
parent e7bfe36c0b
commit 3ecf43731f
5 changed files with 91 additions and 37 deletions

View File

@ -2,15 +2,13 @@ from typing import Dict, List
from zope.interface import Interface, Attribute from zope.interface import Interface, Attribute
from .IUser import IUser
class IGroup(Interface): class IGroup(Interface):
"""Represents a Unix group.""" """Represents a Unix group."""
cn = Attribute('common name') cn = Attribute('common name')
gid_number = Attribute('gid number') gid_number = Attribute('gid number')
unique_members = Attribute('DNs of group members') members = Attribute('usernames of group members')
dn = Attribute('distinguished name') dn = Attribute('distinguished name')
def add_to_ldap(): def add_to_ldap():
@ -22,9 +20,6 @@ class IGroup(Interface):
def remove_member(username: str): def remove_member(username: str):
"""Remove the member from this group in LDAP.""" """Remove the member from this group in LDAP."""
def get_members() -> List[IUser]:
"""Get a list of the members in this group."""
def serialize_for_ldap() -> Dict[str, List[bytes]]: def serialize_for_ldap() -> Dict[str, List[bytes]]:
""" """
Serialize this group into a dict to be passed to Serialize this group into a dict to be passed to
@ -37,3 +32,6 @@ class IGroup(Interface):
:returns: IGroup :returns: IGroup
""" """
def to_dict():
"""Serialize this group as JSON."""

View File

@ -1,11 +1,12 @@
import copy import copy
import json
from typing import List, Dict, Union from typing import List, Dict, Union
from zope import component from zope import component
from zope.interface import implementer from zope.interface import implementer
from .utils import strings_to_bytes, bytes_to_strings, dn_to_uid from .utils import strings_to_bytes, bytes_to_strings, dn_to_uid
from ceo_common.interfaces import ILDAPService, IGroup, IConfig, IUser from ceo_common.interfaces import ILDAPService, IGroup, IConfig
@implementer(IGroup) @implementer(IGroup)
@ -16,8 +17,8 @@ class Group:
): ):
self.cn = cn self.cn = cn
self.gid_number = gid_number self.gid_number = gid_number
# this is a list of the DNs of the members in this group # this is a list of the usernames of the members in this group
self.member_DNs = members or [] self.members = members or []
cfg = component.getUtility(IConfig) cfg = component.getUtility(IConfig)
self.dn = f'cn={cn},{cfg.get("ldap_groups_base")}' self.dn = f'cn={cn},{cfg.get("ldap_groups_base")}'
@ -25,17 +26,15 @@ class Group:
self.ldap_srv = component.getUtility(ILDAPService) self.ldap_srv = component.getUtility(ILDAPService)
def __repr__(self) -> str: def __repr__(self) -> str:
lines = [ return json.dumps(self.to_dict(), indent=2)
'dn: ' + self.dn,
'cn: ' + self.cn, def to_dict(self):
'gidNumber: ' + str(self.gid_number), return {
'objectClass: top', 'dn': self.dn,
'objectClass: group', 'cn': self.cn,
'objectClass: posixGroup', 'gid_number': self.gid_number,
] 'members': self.members,
for member_dn in self.member_DNs: }
lines.append('uniqueMember: ' + member_dn)
return '\n'.join(lines)
def add_to_ldap(self): def add_to_ldap(self):
self.ldap_srv.add_group(self) self.ldap_srv.add_group(self)
@ -53,8 +52,11 @@ class Group:
'posixGroup', 'posixGroup',
], ],
} }
if self.member_DNs: if self.members:
data['uniqueMember'] = self.member_DNs data['uniqueMember'] = [
f'uid={member},{self.ldap_users_base}'
for member in self.members
]
return strings_to_bytes(data) return strings_to_bytes(data)
@staticmethod @staticmethod
@ -63,25 +65,21 @@ class Group:
return Group( return Group(
cn=data['cn'][0], cn=data['cn'][0],
gid_number=int(data['gidNumber'][0]), gid_number=int(data['gidNumber'][0]),
members=data.get('uniqueMember'), members=[
dn_to_uid(dn) for dn in data.get('uniqueMember', [])
],
) )
def add_member(self, username: str): def add_member(self, username: str):
new_group = copy.copy(self) new_group = copy.copy(self)
new_group.member_DNs = self.member_DNs.copy() new_group.members = self.members.copy()
new_group.member_DNs.append(f'uid={username},{self.ldap_users_base}') new_group.members.append(username)
self.ldap_srv.modify_group(self, new_group) self.ldap_srv.modify_group(self, new_group)
self.member_DNs = new_group.member_DNs self.members = new_group.members
def remove_member(self, username: str): def remove_member(self, username: str):
new_group = copy.copy(self) new_group = copy.copy(self)
new_group.member_DNs = self.member_DNs.copy() new_group.members = self.members.copy()
new_group.member_DNs.remove(f'uid={username},{self.ldap_users_base}') new_group.members.remove(username)
self.ldap_srv.modify_group(self, new_group) self.ldap_srv.modify_group(self, new_group)
self.member_DNs = new_group.member_DNs self.members = new_group.members
def get_members(self) -> List[IUser]:
members = []
for dn in self.member_DNs:
members.append(self.ldap_srv.get_user(dn_to_uid(dn)))
return members

View File

@ -0,0 +1,43 @@
import pytest
from ceo_common.errors import GroupNotFoundError
def test_group_add_to_ldap(simple_group, ldap_srv):
group = simple_group
group.add_to_ldap()
retrieved_group = ldap_srv.get_group(group.cn)
assert retrieved_group.cn == group.cn
group.remove_from_ldap()
with pytest.raises(GroupNotFoundError):
ldap_srv.get_group(group.cn)
def test_group_members(ldap_group, ldap_srv):
group = ldap_group
group.add_member('member1')
assert group.members == ['member1']
assert ldap_srv.get_group(group.cn).members == group.members
group.add_member('member2')
assert group.members == ['member1', 'member2']
assert ldap_srv.get_group(group.cn).members == group.members
group.remove_member('member1')
assert group.members == ['member2']
assert ldap_srv.get_group(group.cn).members == group.members
def test_group_to_dict(simple_group):
group = simple_group
expected = {
'dn': group.dn,
'cn': group.cn,
'gid_number': group.gid_number,
'members': group.members,
}
assert group.to_dict() == expected

View File

@ -2,4 +2,4 @@
ignore = ignore =
# line too long # line too long
E501 E501
exclude = .git,.vscode,venv,__pycache__,__init__.py,build,dist exclude = .git,.vscode,venv,__pycache__,__init__.py,conftest.py,build,dist

View File

@ -11,7 +11,7 @@ from ceo_common.interfaces import IConfig, IKerberosService, ILDAPService, \
IFileService, IMailmanService, IHTTPClient IFileService, IMailmanService, IHTTPClient
from ceo_common.model import Config, RemoteMailmanService, HTTPClient from ceo_common.model import Config, RemoteMailmanService, HTTPClient
from ceod.model import KerberosService, LDAPService, FileService, User, \ from ceod.model import KerberosService, LDAPService, FileService, User, \
MailmanService MailmanService, Group
@pytest.fixture(autouse=True, scope='session') @pytest.fixture(autouse=True, scope='session')
@ -138,3 +138,18 @@ def mailman_srv(cfg, http_client):
mailman = RemoteMailmanService() mailman = RemoteMailmanService()
component.provideUtility(mailman, IMailmanService) component.provideUtility(mailman, IMailmanService)
return mailman return mailman
@pytest.fixture
def simple_group():
return Group(
cn='group1',
gid_number=21000,
)
@pytest.fixture
def ldap_group(simple_group):
simple_group.add_to_ldap()
yield simple_group
simple_group.remove_from_ldap()