Skip to content

Commit 6fb9fa5

Browse files
committed
Commands have a 'expected' parameter
1 parent 89639dd commit 6fb9fa5

File tree

3 files changed

+94
-25
lines changed

3 files changed

+94
-25
lines changed

CHANGES.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ and this project adheres to `Semantic Versioning <https://semver.org/spec/v2.0.0
99
Added
1010
*****
1111

12-
- Initial commit.
12+
- Initial release.

slapd/__init__.py

+80-24
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ class Slapd:
111111
:param port: The port on which the slapd server will listen to.
112112
If `None` a random available port will be chosen.
113113
114-
:param log_level: The verbosity of Slapd..
114+
:param log_level: The verbosity of Slapd.
115115
The default value is `logging.WARNING`.
116116
117117
:param suffix: The LDAP suffix for all objects. The default is
@@ -236,7 +236,7 @@ def _find_command(self, cmd, in_sbin=False):
236236
)
237237
return command
238238

239-
def setup_rundir(self):
239+
def _setup_rundir(self):
240240
"""
241241
creates rundir structure
242242
@@ -281,7 +281,7 @@ def _avail_tcpport(self):
281281
self.logger.info("Found available port %d", port)
282282
return port
283283

284-
def gen_config(self):
284+
def _gen_config(self):
285285
"""
286286
generates a slapd.conf and returns it as one string
287287
@@ -307,7 +307,7 @@ def _write_config(self):
307307
"""Loads the slapd.d configuration."""
308308
self.logger.debug("importing configuration: %s", self._slapd_conf)
309309

310-
self.slapadd(self.gen_config(), ["-n0"])
310+
self.slapadd(self._gen_config(), ["-n0"])
311311
ldif_paths = [
312312
schema if os.path.exists(schema) else os.path.join(self.SCHEMADIR, schema)
313313
for schema in self.schemas
@@ -384,7 +384,7 @@ def start(self):
384384

385385
atexit.register(self.stop)
386386
self._cleanup_rundir()
387-
self.setup_rundir()
387+
self._setup_rundir()
388388
self._write_config()
389389
self._test_config()
390390
self._start_slapd()
@@ -445,8 +445,16 @@ def _cli_auth_args(self):
445445
return authc_args
446446

447447
def _cli_popen(
448-
self, ldapcommand, extra_args=None, ldap_uri=None, stdin_data=None
448+
self,
449+
ldapcommand,
450+
extra_args=None,
451+
ldap_uri=None,
452+
stdin_data=None,
453+
expected=0,
449454
):
455+
if isinstance(expected, int):
456+
expected = [expected]
457+
450458
if ldap_uri is None:
451459
ldap_uri = self.default_ldap_uri
452460

@@ -464,74 +472,122 @@ def _cli_popen(
464472
self.logger.debug(
465473
"stdin_data=%s", stdin_data.decode("utf-8") if stdin_data else stdin_data
466474
)
475+
467476
if proc.stdout is not None:
468477
self.logger.debug("stdout=%s", proc.stdout.decode("utf-8"))
478+
469479
if proc.stderr is not None:
470480
self.logger.debug("stderr=%s", proc.stderr.decode("utf-8"))
471-
if proc.returncode != 0:
472-
raise RuntimeError("Process failed: {!r}".format(" ".join(args)))
481+
482+
if proc.returncode not in expected:
483+
raise RuntimeError(
484+
"Unexpected process return code (expected {}, got {}): {!r}".format(
485+
expected, proc.returncode, " ".join(args)
486+
)
487+
)
473488
return proc
474489

475-
def ldapwhoami(self, extra_args=None):
490+
def ldapwhoami(self, extra_args=None, expected=0):
476491
"""
477492
Runs ldapwhoami on this slapd instance
478493
479-
:return: A :class:`subprocess.CompletedProcess` with the execution data.
494+
:param extra_args: Extra argument to pass to *ldapwhoami*.
495+
:param expected: Expected return code. Defaults to `0`.
496+
:type expected: An integer or a list of integers
497+
498+
:return: A :class:`subprocess.CompletedProcess` with the *ldapwhoami* execution data.
480499
"""
481-
return self._cli_popen(self.PATH_LDAPWHOAMI, extra_args=extra_args)
500+
return self._cli_popen(
501+
self.PATH_LDAPWHOAMI, extra_args=extra_args, expected=expected
502+
)
482503

483-
def ldapadd(self, ldif, extra_args=None):
504+
def ldapadd(self, ldif, extra_args=None, expected=0):
484505
"""
485506
Runs ldapadd on this slapd instance, passing it the ldif content
486507
487-
:return: A :class:`subprocess.CompletedProcess` with the execution data.
508+
:param ldif: The ldif content to pass to the *ldapadd* standard input.
509+
:param extra_args: Extra argument to pass to *ldapadd*.
510+
:param expected: Expected return code. Defaults to `0`.
511+
:type expected: An integer or a list of integers
512+
513+
:return: A :class:`subprocess.CompletedProcess` with the *ldapadd* execution data.
488514
"""
489515
return self._cli_popen(
490-
self.PATH_LDAPADD, extra_args=extra_args, stdin_data=ldif.encode("utf-8")
516+
self.PATH_LDAPADD,
517+
extra_args=extra_args,
518+
stdin_data=ldif.encode("utf-8") if ldif else None,
519+
expected=expected,
491520
)
492521

493-
def ldapmodify(self, ldif, extra_args=None):
522+
def ldapmodify(self, ldif, extra_args=None, expected=0):
494523
"""
495524
Runs ldapadd on this slapd instance, passing it the ldif content
496525
497-
:return: A :class:`subprocess.CompletedProcess` with the execution data.
526+
:param ldif: The ldif content to pass to the *ldapmodify* standard input.
527+
:param extra_args: Extra argument to pass to *ldapmodify*.
528+
:param expected: Expected return code. Defaults to `0`.
529+
:type expected: An integer or a list of integers
530+
531+
:return: A :class:`subprocess.CompletedProcess` with the *ldapmodify* execution data.
498532
"""
499533
return self._cli_popen(
500-
self.PATH_LDAPMODIFY, extra_args=extra_args, stdin_data=ldif.encode("utf-8")
534+
self.PATH_LDAPMODIFY,
535+
extra_args=extra_args,
536+
stdin_data=ldif.encode("utf-8") if ldif else None,
537+
expected=expected,
501538
)
502539

503-
def ldapdelete(self, dn, recursive=False, extra_args=None):
540+
def ldapdelete(self, dn, recursive=False, extra_args=None, expected=0):
504541
"""
505542
Runs ldapdelete on this slapd instance, deleting 'dn'
506543
507-
:return: A :class:`subprocess.CompletedProcess` with the execution data.
544+
:param dn: The distinguished name of the element to delete.
545+
:param recursive: Whether to delete sub-elements. Defaults to `False`.
546+
:param extra_args: Extra argument to pass to *ldapdelete*.
547+
:param expected: Expected return code. Defaults to `0`.
548+
:type expected: An integer or a list of integers
549+
550+
:return: A :class:`subprocess.CompletedProcess` with the *ldapdelete* execution data.
508551
"""
509552
if extra_args is None:
510553
extra_args = []
511554
if recursive:
512555
extra_args.append("-r")
513556
extra_args.append(dn)
514-
return self._cli_popen(self.PATH_LDAPDELETE, extra_args=extra_args)
557+
return self._cli_popen(
558+
self.PATH_LDAPDELETE, extra_args=extra_args, expected=expected
559+
)
515560

516-
def slapadd(self, ldif, extra_args=None):
561+
def slapadd(self, ldif, extra_args=None, expected=0):
517562
"""
518563
Runs slapadd on this slapd instance, passing it the ldif content
519564
520-
:return: A :class:`subprocess.CompletedProcess` with the execution data.
565+
:param ldif: The ldif content to pass to the *slapadd* standard input.
566+
:param extra_args: Extra argument to pass to *slapadd*.
567+
:param expected: Expected return code. Defaults to `0`.
568+
:type expected: An integer or a list of integers
569+
570+
:return: A :class:`subprocess.CompletedProcess` with the *slapadd* execution data.
521571
"""
522572
return self._cli_popen(
523573
self.PATH_SLAPADD,
524574
stdin_data=ldif.encode("utf-8") if ldif else None,
525575
extra_args=extra_args,
576+
expected=expected,
526577
)
527578

528-
def slapcat(self, extra_args=None):
579+
def slapcat(self, extra_args=None, expected=0):
529580
"""
530581
Runs slapadd on this slapd instance, passing it the ldif content
531582
532-
:return: A :class:`subprocess.CompletedProcess` with the execution data.
583+
:param extra_args: Extra argument to pass to *slapcat*.
584+
:param expected: Expected return code. Defaults to `0`.
585+
:type expected: An integer or a list of integers
586+
587+
:return: A :class:`subprocess.CompletedProcess` with the *slapcat* execution data.
533588
"""
534589
return self._cli_popen(
535590
self.PATH_SLAPCAT,
536591
extra_args=extra_args,
592+
expected=expected,
537593
)

tests/test_slapdobject.py

+13
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import slapd
2+
import pytest
23

34

45
def test_nominal_case():
@@ -71,3 +72,15 @@ def test_commands():
7172
)
7273

7374
server.stop()
75+
76+
77+
def test_return_codes():
78+
server = slapd.Slapd()
79+
server.start()
80+
81+
with pytest.raises(RuntimeError):
82+
server.ldapadd("bad ldif")
83+
server.ldapadd("bad ldif", expected=247)
84+
server.ldapadd("bad ldif", expected=(0, 247))
85+
86+
server.stop()

0 commit comments

Comments
 (0)