Skip to content

Commit

Permalink
Fix error reporting of LDAPObject.set_option()
Browse files Browse the repository at this point in the history
Fix error reporting of LDAPObject.set_option()

The method LDAPObject.set_option() did not signal an exception in case
the set option failed. The bug was caused by checking for the wrong
error value. The internal C function LDAP_set_option() returns ``1`` for
sucess and ``0`` for error, but LDAPObject.set_option() was checking for
``-1``.

Add some tests for LDAPObject.set_option() and LDAPObject.get_option().

https://github.com/python-ldap/python-ldap/pull/101
Closes: https://github.com/python-ldap/python-ldap/issues/100
Signed-off-by: Christian Heimes <cheimes@redhat.com>
  • Loading branch information
Christian Heimes authored and Petr Viktorin committed Dec 5, 2017
1 parent c4bcf1d commit eb9dbc1
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 27 deletions.
2 changes: 1 addition & 1 deletion Modules/LDAPObject.c
Original file line number Diff line number Diff line change
Expand Up @@ -1273,7 +1273,7 @@ l_ldap_set_option(PyObject* self, PyObject *args)

if (!PyArg_ParseTuple(args, "iO:set_option", &option, &value))
return NULL;
if (LDAP_set_option((LDAPObject *)self, option, value) == -1)
if (!LDAP_set_option((LDAPObject *)self, option, value))
return NULL;
Py_INCREF(Py_None);
return Py_None;
Expand Down
110 changes: 84 additions & 26 deletions Tests/t_ldap_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
from ldap.controls import RequestControlTuples
from ldap.controls.pagedresults import SimplePagedResultsControl
from ldap.controls.openldap import SearchNoOpControl
from slapdtest import requires_tls

from ldap.ldapobject import SimpleLDAPObject
from slapdtest import SlapdTestCase, requires_tls

SENTINEL = object()

Expand All @@ -26,54 +26,68 @@
]


class TestGlobalOptions(unittest.TestCase):
class BaseTestOptions(object):
"""Common tests for getting/setting options
Used in subclasses below
"""

def get_option(self, option):
raise NotImplementedError()

def set_option(self, option, value):
raise NotImplementedError()

def _check_option(self, option, value, expected=SENTINEL,
nonevalue=None):
old = ldap.get_option(option)
old = self.get_option(option)
try:
ldap.set_option(option, value)
new = ldap.get_option(option)
self.set_option(option, value)
new = self.get_option(option)
if expected is SENTINEL:
self.assertEqual(new, value)
else:
self.assertEqual(new, expected)
finally:
ldap.set_option(option, old if old is not None else nonevalue)
self.assertEqual(ldap.get_option(option), old)
self.set_option(
option,
old if old is not None else nonevalue
)
self.assertEqual(self.get_option(option), old)

def test_invalid(self):
with self.assertRaises(ValueError):
ldap.get_option(-1)
self.get_option(-1)
with self.assertRaises(ValueError):
ldap.set_option(-1, '')
self.set_option(-1, '')

def test_timeout(self):
self._check_option(ldap.OPT_TIMEOUT, 0, nonevalue=-1)
self._check_option(ldap.OPT_TIMEOUT, 10.5, nonevalue=-1)
def _test_timeout(self, option):
self._check_option(option, 10.5, nonevalue=-1)
self._check_option(option, 0, nonevalue=-1)
with self.assertRaises(ValueError):
self._check_option(ldap.OPT_TIMEOUT, -5, nonevalue=-1)
self._check_option(option, -5, nonevalue=-1)
with self.assertRaises(TypeError):
ldap.set_option(ldap.OPT_TIMEOUT, object)
self.set_option(option, object)

def test_timeout(self):
self._test_timeout(ldap.OPT_TIMEOUT)

def test_network_timeout(self):
self._check_option(ldap.OPT_NETWORK_TIMEOUT, 0, nonevalue=-1)
self._check_option(ldap.OPT_NETWORK_TIMEOUT, 10.5, nonevalue=-1)
with self.assertRaises(ValueError):
self._check_option(ldap.OPT_NETWORK_TIMEOUT, -5, nonevalue=-1)
self._test_timeout(ldap.OPT_NETWORK_TIMEOUT)

def _test_controls(self, option):
self._check_option(option, [])
self._check_option(option, TEST_CTRL, TEST_CTRL_EXPECTED)
self._check_option(option, tuple(TEST_CTRL), TEST_CTRL_EXPECTED)
with self.assertRaises(TypeError):
ldap.set_option(option, object)
self.set_option(option, object)

with self.assertRaises(TypeError):
# must contain a tuple
ldap.set_option(option, [list(TEST_CTRL[0])])
self.set_option(option, [list(TEST_CTRL[0])])
with self.assertRaises(TypeError):
# data must be bytes or None
ldap.set_option(
self.set_option(
option,
[TEST_CTRL[0][0], TEST_CTRL[0][1], u'data']
)
Expand All @@ -87,20 +101,64 @@ def test_server_controls(self):
def test_uri(self):
self._check_option(ldap.OPT_URI, "ldapi:///path/to/socket")
with self.assertRaises(TypeError):
ldap.set_option(ldap.OPT_URI, object)
self.set_option(ldap.OPT_URI, object)

@requires_tls()
def test_cafile(self):
# None or a distribution or OS-specific path
ldap.get_option(ldap.OPT_X_TLS_CACERTFILE)
self.get_option(ldap.OPT_X_TLS_CACERTFILE)

def test_readonly(self):
value = ldap.get_option(ldap.OPT_API_INFO)
value = self.get_option(ldap.OPT_API_INFO)
self.assertIsInstance(value, dict)
with self.assertRaises(ValueError) as e:
ldap.set_option(ldap.OPT_API_INFO, value)
self.set_option(ldap.OPT_API_INFO, value)
self.assertIn('read-only', str(e.exception))


class TestGlobalOptions(BaseTestOptions, unittest.TestCase):
"""Test setting/getting options globally
"""

def get_option(self, option):
return ldap.get_option(option)

def set_option(self, option, value):
return ldap.set_option(option, value)


class TestLDAPObjectOptions(BaseTestOptions, SlapdTestCase):
"""Test setting/getting connection-specific options
"""

ldap_object_class = SimpleLDAPObject

def setUp(self):
self.conn = self._open_ldap_conn(
who=self.server.root_dn,
cred=self.server.root_pw
)

def tearDown(self):
self.conn.unbind_s()
self.conn = None

def get_option(self, option):
return self.conn.get_option(option)

def set_option(self, option, value):
return self.conn.set_option(option, value)

# test is failing with:
# pyasn1.error.SubstrateUnderrunError: Short octet stream on tag decoding
@unittest.expectedFailure
def test_client_controls(self):
self._test_controls(ldap.OPT_CLIENT_CONTROLS)

@unittest.expectedFailure
def test_server_controls(self):
self._test_controls(ldap.OPT_SERVER_CONTROLS)


if __name__ == '__main__':
unittest.main()

0 comments on commit eb9dbc1

Please sign in to comment.