From 29c3a53e0be6bf09e4d98c1008343a56a4569c75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Kuzn=C3=ADk?= Date: Wed, 29 Oct 2025 13:31:06 +0000 Subject: [PATCH 1/2] Switch to using slapd + -T for tool use Using a locally compiled OpenLDAP impossible without this as libtool wrappers eat argv[0] of the symlinked binaries. Using a locally compiled OpenLDAP still often needs changes to the configuration, this should be a reasonably easy step forward. --- Lib/slapdtest/_slapdtest.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Lib/slapdtest/_slapdtest.py b/Lib/slapdtest/_slapdtest.py index 4110d945..f9333139 100644 --- a/Lib/slapdtest/_slapdtest.py +++ b/Lib/slapdtest/_slapdtest.py @@ -259,7 +259,6 @@ def _find_commands(self): self.PATH_LDAPDELETE = self._find_command('ldapdelete') self.PATH_LDAPMODIFY = self._find_command('ldapmodify') self.PATH_LDAPWHOAMI = self._find_command('ldapwhoami') - self.PATH_SLAPADD = self._find_command('slapadd') self.PATH_SLAPD = os.environ.get('SLAPD', None) if not self.PATH_SLAPD: @@ -276,7 +275,7 @@ def _find_command(self, cmd, in_sbin=False): if command is None: raise ValueError( "Command '{}' not found. Set the {} environment variable to " - "override slapdtest's search path.".format(cmd, var_name) + "override slapdtest's search path: {}.".format(cmd, var_name, path) ) return command @@ -347,6 +346,7 @@ def gen_config(self): 'cafile': self.cafile, 'servercert': self.servercert, 'serverkey': self.serverkey, + 'slapd_path': self.SBIN_PATH, } return self.slapd_conf_template % config_dict @@ -508,14 +508,17 @@ def _cli_auth_args(self): # no cover to avoid spurious coverage changes def _cli_popen(self, ldapcommand, extra_args=None, ldap_uri=None, - stdin_data=None): # pragma: no cover + stdin_data=None, tool=None): # pragma: no cover if ldap_uri is None: ldap_uri = self.default_ldap_uri if ldapcommand.split("/")[-1].startswith("ldap"): args = [ldapcommand, '-H', ldap_uri] + self._cli_auth_args() else: - args = [ldapcommand, '-F', self._slapd_conf] + if tool: + args = [ldapcommand, '-T', tool, '-F', self._slapd_conf] + else: + args = [ldapcommand, '-F', self._slapd_conf] args += (extra_args or []) @@ -574,9 +577,10 @@ def slapadd(self, ldif, extra_args=None): Runs slapadd on this slapd instance, passing it the ldif content """ self._cli_popen( - self.PATH_SLAPADD, + self.PATH_SLAPD, stdin_data=ldif.encode("utf-8") if ldif else None, extra_args=extra_args, + tool='add' ) def __enter__(self): From 1a4d7274e37c974ac03ae7bebd1bbca2f7c18af1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Kuzn=C3=ADk?= Date: Wed, 29 Oct 2025 13:40:10 +0000 Subject: [PATCH 2/2] Store logs and keep failed run data on failure --- Lib/slapdtest/_slapdtest.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/Lib/slapdtest/_slapdtest.py b/Lib/slapdtest/_slapdtest.py index f9333139..970a05a6 100644 --- a/Lib/slapdtest/_slapdtest.py +++ b/Lib/slapdtest/_slapdtest.py @@ -407,12 +407,17 @@ def _start_slapd(self): '-F', self._slapd_conf, '-h', ' '.join(urls), ] + stderr = None if self._log.isEnabledFor(logging.DEBUG): slapd_args.extend(['-d', '-1']) + stderr = os.open(os.path.join(self.testrundir, 'slapd.log'), os.O_WRONLY|os.O_CREAT) else: slapd_args.extend(['-d', '0']) self._log.info('starting slapd: %r', ' '.join(slapd_args)) - self._proc = subprocess.Popen(slapd_args) + self._proc = subprocess.Popen(slapd_args, stderr=stderr) + if stderr is not None: + os.close(stderr) + stderr = None # Waits until the LDAP server socket is open, or slapd crashed deadline = time.monotonic() + 10 # no cover to avoid spurious coverage changes, see @@ -452,7 +457,7 @@ def start(self): self._proc.pid, self.ldap_uri, self.ldapi_uri ) - def stop(self): + def stop(self, cleanup=True): """ Stops the slapd server, and waits for it to terminate and cleans up """ @@ -460,7 +465,8 @@ def stop(self): self._log.debug('stopping slapd with pid %d', self._proc.pid) self._proc.terminate() self.wait() - self._cleanup_rundir() + if cleanup: + self._cleanup_rundir() atexit.unregister(self.stop) def restart(self): @@ -588,7 +594,7 @@ def __enter__(self): return self def __exit__(self, exc_type, exc_value, traceback): - self.stop() + self.stop(exc_type is None) class SlapdTestCase(unittest.TestCase): @@ -617,4 +623,4 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): - cls.server.stop() + cls.server.stop(False)