# -*- encoding: utf-8 -*- import asyncio from async_generator import asynccontextmanager from bonsai import LDAPEntry import mock import pytest from phi.async_ldap.new_model import get_dn, User from phi.async_ldap.mixins import Member 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) @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()