import unittest
from unittest.mock import patch, MagicMock

import ldap

from rhodecode.authentication.plugins.services.ldap_dao import LdapDao
from rhodecode.lib.diff_match_patch import patch_obj


@patch("rhodecode.authentication.plugins.services.ldap_dao.ldap")
class TestLdapDao(unittest.TestCase):
    def setUp(self):
        self._server_list = "test_srv1,test_srv2,test_srv3"
        self._base_dn = "test_dn"
        self.ldap_dao = LdapDao(
            server=self._server_list,
            base_dn=self._base_dn,
        )

    @patch.object(LdapDao, "_get_ldap_conn")
    def test_fetch_all_from_ldap_server(self, _get_ldap_conn_mock, ldap_mock):
        conn = MagicMock()
        no_objects_in_ldap_server = []
        conn.search_ext_s.return_value = no_objects_in_ldap_server

        _get_ldap_conn_mock.return_value = conn

        returned_value = self.ldap_dao.fetch_all()

        conn.search_ext_s.assert_called_once_with(self._base_dn, 2, "(objectClass=*)", attrlist=["*", "+"])

        assert returned_value == no_objects_in_ldap_server

    @patch.object(LdapDao, "_get_ldap_conn")
    def test_fetch_all_release_connection(self, _get_ldap_conn_mock, ldap_mock):
        conn = MagicMock()
        _get_ldap_conn_mock.return_value = conn

        self.ldap_dao.fetch_all()

        conn.unbind_s.assert_called_once()

    @patch.object(LdapDao, "_get_ldap_conn")
    def test_fetch_all_release_connection_on_error(self, _get_ldap_conn_mock, ldap_mock):
        conn = MagicMock()
        _get_ldap_conn_mock.return_value = conn
        conn.search_ext_s.side_effect = Exception("Test exception")

        res = self.ldap_dao.fetch_all()

        assert res is None
        conn.unbind_s.assert_called_once()
