diff --git a/src/ims/directory/clubhouse_db/_directory.py b/src/ims/directory/clubhouse_db/_directory.py index 0d3eea0ff..979e44dce 100644 --- a/src/ims/directory/clubhouse_db/_directory.py +++ b/src/ims/directory/clubhouse_db/_directory.py @@ -27,7 +27,7 @@ from ims.directory import IMSDirectory, IMSGroupID, IMSTeamID, IMSUser, userFromRanger from ims.model import Ranger -from ._dms import DutyManagementSystem +from ._dms import DutyManagementSystem, Position, Team __all__ = () @@ -48,22 +48,37 @@ async def personnel(self) -> Iterable[Ranger]: async def lookupUser(self, searchTerm: str) -> IMSUser | None: dms = self._dms + # call out to a more easily testable static method + return DMSDirectory._lookupUser( + searchTerm, + tuple(await dms.personnel()), + tuple(await dms.positions()), + tuple(await dms.teams()), + ) - # FIXME: a hash would be better (eg. rangersByHandle) - rangers = tuple(await dms.personnel()) - - for ranger in rangers: - if ranger.handle == searchTerm: + @staticmethod + def _lookupUser( + searchTerm: str, + rangers: tuple[Ranger, ...], + positions: tuple[Position, ...], + teams: tuple[Team, ...], + ) -> IMSUser | None: + searchLower = searchTerm.lower() + + ranger = None + + for r in rangers: + if r.handle.lower() == searchLower: + ranger = r + for email in r.email: + if email.lower() == searchLower: + ranger = r + if ranger is not None: break else: - for ranger in rangers: - if searchTerm in ranger.email: - break - else: - return None - - positions = tuple(await dms.positions()) - teams = tuple(await dms.teams()) + return None + + assert ranger is not None groups = tuple( IMSGroupID(position.name) diff --git a/src/ims/directory/clubhouse_db/test/test_directory.py b/src/ims/directory/clubhouse_db/test/test_directory.py index c331c8b12..4af46f927 100644 --- a/src/ims/directory/clubhouse_db/test/test_directory.py +++ b/src/ims/directory/clubhouse_db/test/test_directory.py @@ -18,12 +18,52 @@ Tests for L{ims.directory.clubhouse_db._directory}. """ +from ims.directory import IMSUser +from ims.directory.clubhouse_db import DMSDirectory +from ims.directory.clubhouse_db._dms import Position, Team from ims.ext.trial import TestCase +from ims.model import Ranger, RangerStatus __all__ = () +def _ranger_alpha() -> Ranger: + return Ranger( + handle="Alpha", + status=RangerStatus.active, + email=frozenset(["alpha@example.com"]), + onsite=False, + directoryID=None, + ) + + +def _ranger_beta() -> Ranger: + return Ranger( + handle="Beta", + status=RangerStatus.active, + email=frozenset(["beta@example.com"]), + onsite=True, + directoryID=None, + ) + + +def _position_delta() -> Position: + return Position( + positionID="ddd", + name="Delta", + members={_ranger_alpha()}, + ) + + +def _team_upsilon() -> Team: + return Team( + teamID="uuu", + name="Upsilon", + members={_ranger_beta()}, + ) + + class DMSDirectoryTests(TestCase): """ Tests for :class:`DMSDirectory` @@ -35,6 +75,39 @@ def test_personnel(self) -> None: test_personnel.todo = "unimplemented" # type: ignore[attr-defined] def test_lookupUser(self) -> None: - raise NotImplementedError() + def lookup(search: str) -> IMSUser | None: + return DMSDirectory._lookupUser( + search, + (_ranger_alpha(), _ranger_beta()), + (_position_delta(),), + (_team_upsilon(),), + ) + + # Case-insensitive matching against handles and email addresses + self.assertIsNotNone(lookup("alpha")) + self.assertIsNotNone(lookup("Alpha")) + self.assertIsNotNone(lookup("beta@example.com")) + self.assertIsNotNone(lookup("ALPHA@exAMple.com")) + + # Failures to match against handle or email address + self.assertIsNone(lookup("NotARanger@example.com")) + self.assertIsNone(lookup("BetaWithSuffix")) - test_lookupUser.todo = "unimplemented" # type: ignore[attr-defined] + # Now check the various fields that come back, including + # positions and teams set up at the top of this test file. + alpha = lookup("alpha") + beta = lookup("BETA@EXAMPLE.COM") + self.assertIsNotNone(alpha) + # to appease mypy + assert alpha is not None + self.assertEqual(alpha.uid, "Alpha") + self.assertEqual(alpha.shortNames, ("Alpha",)) + self.assertEqual(alpha.onsite, False) + self.assertEqual(alpha.groups, ("Delta",)) + self.assertEqual(alpha.teams, ()) + self.assertIsNotNone(beta) + # to appease mypy + assert beta is not None + self.assertEqual(beta.onsite, True) + self.assertEqual(beta.groups, ()) + self.assertEqual(beta.teams, ("Upsilon",))