# -*- encoding: utf-8 -*- import asyncio from async_generator import asynccontextmanager from bonsai import LDAPEntry import mock import pytest from phi.async_ldap.model import get_dn, User from phi.async_ldap.mixins import Member from phi.exceptions import PhiCannotExecute BASE_DN = "dc=test,dc=domain,dc=tld" class MockClient(object): def __init__(self, *args, **kwargs): self.return_value = kwargs.get("return_value") self.connect_called = False self.conn = mock.MagicMock() self.search_event = asyncio.Event() self.add_event = asyncio.Event() self.delete_event = asyncio.Event() async def connect_called_with_search(self): return await self.search_event.wait() async def connect_called_with_add(self): return await self.add_event.wait() async def connect_called_with_delete(self): return await self.delete_event.wait() @property def base_dn(self): return BASE_DN @asynccontextmanager async def connect(self, *args, **kwargs): self.connect_called = True async def _search(*a, **kw): self.search_event.set() return self.return_value async def _add(*a, **kw): self.add_event.set() return self.return_value async def _modify(*a, **kw): return self.return_value async def _delete(*a, **kw): self.delete_event.set() return self.return_value self.conn.search = mock.MagicMock(side_effect=_search) self.conn.add = mock.MagicMock(side_effect=_add) self.conn.modify = mock.MagicMock(side_effect=_modify) self.conn.delete = mock.MagicMock(side_effect=_delete) yield self.conn cl = mock.MagicMock() cl.base_dn = BASE_DN @pytest.mark.parametrize( "input_obj, expected_result", [ (User(cl, "test_user"), f"uid=test_user,ou=Hackers,{BASE_DN}"), ( LDAPEntry(f"uid=test_user,ou=Hackers,{BASE_DN}"), f"uid=test_user,ou=Hackers,{BASE_DN}", ), (f"uid=test_user,ou=Hackers,{BASE_DN}", f"uid=test_user,ou=Hackers,{BASE_DN}"), ], ) def test_get_dn(input_obj, expected_result): assert get_dn(input_obj) == expected_result def test_get_dn_raises(): with pytest.raises(ValueError) as e: _ = get_dn(object) assert "Unacceptable input:" in str(e.value) def test_repr(): _cl = MockClient(return_value=None) u = User(_cl, "test_user") assert repr(u) == f"" def test_str(): _cl = MockClient(return_value=None) u = User(_cl, "test_user") assert str(u) == f"" @pytest.mark.parametrize( "input_obj", [ User(cl, "test_user"), LDAPEntry(f"uid=test_user,ou=Hackers,{BASE_DN}"), f"uid=test_user,ou=Hackers,{BASE_DN}", ], ) def test_eq(input_obj): u = User(cl, "test_user") assert u == input_obj @pytest.mark.asyncio async def test_User_add(): _cl = MockClient(return_value=None) u = User(_cl, "test_user") assert u.dn == f"uid=test_user,ou=Hackers,{BASE_DN}" _ = await u.save() assert _cl.connect_called assert await _cl.connect_called_with_add() @pytest.mark.asyncio async def test_User_modify(): """ This test does not use the MockClient check facilities because of implementation details of the Entry class. """ _cl = MockClient( return_value=[ LDAPEntry(f"uid=test_user,ou=Hackers,{BASE_DN}"), ] ) u = User(_cl, "test_user") # This is the asyncio equivalent of a semaphore modified = asyncio.Event() async def _mock_modify(): modified.set() u._entry = mock.MagicMock() u._entry.modify = mock.MagicMock(side_effect=_mock_modify) u["cn"] = "random_cn" _ = await u.modify() assert _cl.connect_called assert await _cl.connect_called_with_search() # The `wait()` call here is needed to wait for `_mock_modify` # to end its async execution assert await modified.wait() @pytest.mark.asyncio async def test_User_delete(): _cl = MockClient(return_value=None) u = User(_cl, "test_user") _ = await u.delete() assert _cl.connect_called assert await _cl.connect_called_with_delete() @pytest.mark.asyncio async def test_User_get_invalid_attr_raises(): _cl = MockClient(return_value=None) u = User(_cl, "test_user") with pytest.raises(PhiCannotExecute) as ex: _ = u["iDoNotExist"] assert "iDoNotExist" in str(ex.value) assert "is not an allowed ldap attribute" in str(ex.value) @pytest.mark.asyncio async def test_User_set_invalid_attr_raises(): _cl = MockClient(return_value=None) u = User(_cl, "test_user") with pytest.raises(PhiCannotExecute) as ex: u["iDoNotExist"] = "hello" assert "iDoNotExist" in str(ex.value) assert "is not an allowed ldap attribute" in str(ex.value)