Skip to content

Commit 48c1c87

Browse files
committed
test: Implement test cases for reconnection handling
test_106_reconnect_restore() handles a SERVER_DOWN exception manually and tries to re-use the connection afterwards again. This established the connection again but did not bind(), so it now raises ldap.INSUFFICIENT_ACCESS. test_107_reconnect_restore() restarts the LDAP server during searches, which causes a UNAVAILABLE exception.
1 parent 72c1b5e commit 48c1c87

File tree

1 file changed

+69
-0
lines changed

1 file changed

+69
-0
lines changed

Tests/t_ldapobject.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,12 @@
99
import os
1010
import re
1111
import socket
12+
import threading
13+
import time
1214
import unittest
1315
import pickle
1416

17+
1518
# Switch off processing .ldaprc or ldap.conf before importing _ldap
1619
os.environ['LDAPNOINIT'] = '1'
1720

@@ -643,6 +646,72 @@ def test105_reconnect_restore(self):
643646
self.server._start_slapd()
644647
self.assertEqual(l1.whoami_s(), 'dn:'+bind_dn)
645648

649+
def test106_reconnect_restore(self):
650+
"""
651+
The idea of this test is to stop the LDAP server, make a search and ignore the `SERVER_DOWN` exception which happens after the reconnect timeout
652+
and then re-use the same connection when the LDAP server is available again.
653+
After starting the server the LDAP connection can be re-used again as it will reconnect on the next operation.
654+
Prior to fixing PR !267 the connection was reestablished but no `bind()` was done resulting in a anonymous search which caused `INSUFFICIENT_ACCESS` when anonymous seach is disallowed.
655+
"""
656+
lo = self.ldap_object_class(self.server.ldap_uri, retry_max=2, retry_delay=1)
657+
bind_dn = 'cn=user1,' + self.server.suffix
658+
lo.simple_bind_s(bind_dn, 'user1_pw')
659+
660+
dn = lo.whoami_s()[3:]
661+
662+
self.server._proc.terminate()
663+
self.server.wait()
664+
665+
# do a search, wait for the timeout, ignore SERVER_DOWN
666+
with self.assertRaises(ldap.SERVER_DOWN):
667+
lo.search_s(dn, ldap.SCOPE_BASE, '(objectClass=*)')
668+
669+
self.server._start_slapd()
670+
671+
# try to use the connection again
672+
lo.search_s(dn, ldap.SCOPE_BASE, '(objectClass=*)')
673+
674+
def test107_reconnect_restore(self):
675+
"""
676+
The idea of this test is to restart the LDAP-Server while there are ongoing searches.
677+
This causes :class:`ldap.UNAVAILABLE` to be raised (with |OpenLDAP|) for a short time.
678+
To increase the chance of triggering this bug we are starting multiple threads
679+
with a large number of retry attempts in a short amount of time.
680+
"""
681+
# TODO: refactor this test
682+
excs = []
683+
684+
def _reconnect_search_thread():
685+
lo = self.ldap_object_class(self.server.ldap_uri)
686+
bind_dn = 'cn=user1,' + self.server.suffix
687+
lo.simple_bind_s(bind_dn, 'user1_pw')
688+
lo._retry_max = 10E4
689+
lo._retry_delay = .001
690+
lo.search_ext_s(self.server.suffix, ldap.SCOPE_SUBTREE, "cn=user1", attrlist=["cn"])
691+
s = time.time()
692+
while (time.time() - s) < run_time:
693+
lo.search_ext_s(self.server.suffix, ldap.SCOPE_SUBTREE, filterstr="cn=user1", attrlist=["cn"])
694+
695+
def reconnect_search_thread():
696+
try:
697+
_reconnect_search_thread()
698+
except Exception as exc:
699+
excs.append(exc)
700+
701+
thread_count = 100
702+
run_time = 10.0
703+
my_thread = [None] * thread_count
704+
for i in range(0, thread_count):
705+
my_thread[i] = threading.Thread(target=reconnect_search_thread)
706+
for t in my_thread:
707+
t.start()
708+
time.sleep(3)
709+
self.server.restart()
710+
for t in my_thread:
711+
t.join()
712+
713+
self.assertEqual(excs, [])
714+
646715

647716
@requires_init_fd()
648717
class Test03_SimpleLDAPObjectWithFileno(Test00_SimpleLDAPObject):

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy