python-ldap-faker


Namepython-ldap-faker JSON
Version 1.3.4 PyPI version JSON
download
home_pageNone
SummaryFake python-ldap functions, objects and methods for use in testing.
upload_time2025-07-25 00:56:44
maintainerNone
docs_urlNone
authorNone
requires_python>=3.10
licenseNone
keywords ldap testing
VCS
bugtrack_url
requirements alabaster asn1 babel case-insensitive-dictionary certifi charset-normalizer coverage docutils enum-compat idna imagesize iniconfig jinja2 ldap-filter markupsafe nose packaging pluggy pyasn1 pyasn1-modules pygments pytest python-ldap requests snowballstemmer sphinx sphinx-rtd-theme sphinxcontrib-applehelp sphinxcontrib-devhelp sphinxcontrib-htmlhelp sphinxcontrib-jsmath sphinxcontrib-qthelp sphinxcontrib-serializinghtml urllib3
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # python-ldap-faker

**Documentation**: https://python-ldap-faker.readthedocs.org

Fakes are objects that have working implementations. while mocks are objects that have predefined behavior.  `python-ldap-faker` provides a fake `python-ldap` interface and "server" that can be used for automated testing of code that uses `python-ldap`.

Managing an actual LDAP server during our tests is usually out of the question, so typically we revert to patching the `python-ldap` code to use mock objects instead, but this is very verbose and can lead to test code errors in practice.

## Installation

`python-ldap-faker` supports Python 3.7+.

To install from PyPI:

```shell
pip install python-ldap-faker
```

If you want, you can run the tests:

```shell
python -m unittest discover
```

## Features

* These `python-ldap` global functions are faked:

    * `ldap.initialize`
    * `ldap.set_option`
    * `ldap.get_option`

* These `ldap.ldapobject.LDAPObject` methods are faked:

    * `set_option`
    * `get_option`
    * `start_tls_s`
    * `simple_bind_s`
    * `unbind_s`
    * `search_s`
    * `search_ext`
    * `result3`
    * `compare_s`
    * `add_s`
    * `modify_s`
    * `rename_s`
    * `delete_s`

* For `search_ext` and `search_s`, your filter string will be validated as a valid LDAP filter, and your filter will be applied directly to your objects in our fake "server" to generate the result list.  No canned searches!
* Inspect your call history for all calls (name, arguments), and test the order in which they were made
* Simulate multiple fake LDAP "servers" with different sets of objects that correspond to different LDAP URIs.
* Ease your test setup with :py:class:`LDAPFakerMixin`, a mixin for :py:class:`unittest.TestCase`

    * Automatically manages patching `python-ldap` for the code under test
    * Allows you to populate objects into one or more LDAP "servers" with fixture files
    * Provides the following test instrumentation for inspecting state after the test:

        * Access to the full object store for each LDAP uri accessed
        * All connections made
        * All `python-ldap` API calls made
        * All `python-ldap` LDAP options set

    * Provides test isolation: object store changes, connections, call history, option changes are all reset between tests
    * Use handy LDAP specific asserts to ease your testing

* Define your own hooks to change the behavior of your fake "servers"
* Support behavior for specific LDAP implementations:

    * Redhat Directory Server/389 implementation support: have your test believe it's talking to an RHDS/389 server.

## Quickstart

The easiest way to use `python-ldap-faker` in your `unittest` based tests is to use the `ldap_faker.LDAPFakerMixin` mixin for `unittest.TestCase`.

This will patch `ldap.initialize`, `ldap.set_option` and `ldap.get_option` to use our `FakeLDAP` interface, and load fixtures in from JSON files to use as test data.

Let's say we have a class `App` in our `myapp` module that does LDAP work that we want to test.

First, prepare a file named `data.json` with the objects you want loaded into your fake LDAP server.   Let's say you want your data to consist of some `posixAccount` objects.  If we make `data.json` look like this:

```json
[
    [
        "uid=foo,ou=bar,o=baz,c=country",
        {
            "uid": ["foo"],
            "cn": ["Foo Bar"],
            "uidNumber": ["123"],
            "gidNumber": ["123"],
            "homeDirectory": ["/home/foo"],
            "userPassword": ["the password"],
            "objectclass": [
                "posixAccount",
                "top"
            ]
        }
    ],
    [
        "uid=fred,ou=bar,o=baz,c=country",
        {
            "uid": ["fred"],
            "cn": ["Fred Flintstone"],
            "uidNumber": ["124"],
            "gidNumber": ["124"],
            "homeDirectory": ["/home/fred"],
            "userPassword": ["the fredpassword"],
            "objectclass": [
                "posixAccount",
                "top"
            ]
        }
    ],
    [
        "uid=barney,ou=bar,o=baz,c=country",
        {
            "uid": ["barney"],
            "cn": ["Barney Rubble"],
            "uidNumber": ["125"],
            "gidNumber": ["125"],
            "homeDirectory": ["/home/barney"],
            "userPassword": ["the barneypassword"],
            "objectclass": [
                "posixAccount",
                "top"
            ]
        }
    ]
]
```

Then we can write a `TestCase` that looks like this:

```python
    import unittest

    import ldap
    from ldap_faker import LDAPFakerMixin

    from myapp import App

    class YourTestCase(LDAPFakerMixin, unittest.TestCase):

        ldap_modules = ['myapp']
        ldap_fixtures = 'data.json'

        def test_auth_works(self):
            app = App()
            # A method that does a `simple_bind_s`
            app.auth('fred', 'the fredpassword')
            conn = self.get_connections()[0]
            self.assertLDAPConnectionMethodCalled(
                conn, 'simple_bind_s',
                {'who': 'uid=fred,ou=bar,o=baz,c=country', 'cred': 'the fredpassword'}
            )

        def test_correct_connection_options_were_set(self):
            app = App()
            app.auth('fred', 'the fredpassword')
            conn = self.get_connections()[0]
            self.assertLDAPConnectionOptionSet(conn, ldap.OPT_X_TLX_NEWCTX, 0)

        def test_tls_was_used_before_auth(self):
            app = App()
            app.auth('fred', 'the fredpassword')
            conn = self.get_connections()[0]
            self.assertLDAPConnectiontMethodCalled(conn, 'start_tls_s')
            self.assertLDAPConnectionMethodCalledAfter(conn, 'simple_bind_s', 'start_tls_s')
```

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "python-ldap-faker",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": "ldap, testing",
    "author": null,
    "author_email": "Caltech IMSS ADS <cmalek@caltech.edu>",
    "download_url": "https://files.pythonhosted.org/packages/e9/b2/4e65ad176bded46ba231da20633f27c3663df5dc6a2c983bab60a6cbf001/python_ldap_faker-1.3.4.tar.gz",
    "platform": null,
    "description": "# python-ldap-faker\n\n**Documentation**: https://python-ldap-faker.readthedocs.org\n\nFakes are objects that have working implementations. while mocks are objects that have predefined behavior.  `python-ldap-faker` provides a fake `python-ldap` interface and \"server\" that can be used for automated testing of code that uses `python-ldap`.\n\nManaging an actual LDAP server during our tests is usually out of the question, so typically we revert to patching the `python-ldap` code to use mock objects instead, but this is very verbose and can lead to test code errors in practice.\n\n## Installation\n\n`python-ldap-faker` supports Python 3.7+.\n\nTo install from PyPI:\n\n```shell\npip install python-ldap-faker\n```\n\nIf you want, you can run the tests:\n\n```shell\npython -m unittest discover\n```\n\n## Features\n\n* These `python-ldap` global functions are faked:\n\n    * `ldap.initialize`\n    * `ldap.set_option`\n    * `ldap.get_option`\n\n* These `ldap.ldapobject.LDAPObject` methods are faked:\n\n    * `set_option`\n    * `get_option`\n    * `start_tls_s`\n    * `simple_bind_s`\n    * `unbind_s`\n    * `search_s`\n    * `search_ext`\n    * `result3`\n    * `compare_s`\n    * `add_s`\n    * `modify_s`\n    * `rename_s`\n    * `delete_s`\n\n* For `search_ext` and `search_s`, your filter string will be validated as a valid LDAP filter, and your filter will be applied directly to your objects in our fake \"server\" to generate the result list.  No canned searches!\n* Inspect your call history for all calls (name, arguments), and test the order in which they were made\n* Simulate multiple fake LDAP \"servers\" with different sets of objects that correspond to different LDAP URIs.\n* Ease your test setup with :py:class:`LDAPFakerMixin`, a mixin for :py:class:`unittest.TestCase`\n\n    * Automatically manages patching `python-ldap` for the code under test\n    * Allows you to populate objects into one or more LDAP \"servers\" with fixture files\n    * Provides the following test instrumentation for inspecting state after the test:\n\n        * Access to the full object store for each LDAP uri accessed\n        * All connections made\n        * All `python-ldap` API calls made\n        * All `python-ldap` LDAP options set\n\n    * Provides test isolation: object store changes, connections, call history, option changes are all reset between tests\n    * Use handy LDAP specific asserts to ease your testing\n\n* Define your own hooks to change the behavior of your fake \"servers\"\n* Support behavior for specific LDAP implementations:\n\n    * Redhat Directory Server/389 implementation support: have your test believe it's talking to an RHDS/389 server.\n\n## Quickstart\n\nThe easiest way to use `python-ldap-faker` in your `unittest` based tests is to use the `ldap_faker.LDAPFakerMixin` mixin for `unittest.TestCase`.\n\nThis will patch `ldap.initialize`, `ldap.set_option` and `ldap.get_option` to use our `FakeLDAP` interface, and load fixtures in from JSON files to use as test data.\n\nLet's say we have a class `App` in our `myapp` module that does LDAP work that we want to test.\n\nFirst, prepare a file named `data.json` with the objects you want loaded into your fake LDAP server.   Let's say you want your data to consist of some `posixAccount` objects.  If we make `data.json` look like this:\n\n```json\n[\n    [\n        \"uid=foo,ou=bar,o=baz,c=country\",\n        {\n            \"uid\": [\"foo\"],\n            \"cn\": [\"Foo Bar\"],\n            \"uidNumber\": [\"123\"],\n            \"gidNumber\": [\"123\"],\n            \"homeDirectory\": [\"/home/foo\"],\n            \"userPassword\": [\"the password\"],\n            \"objectclass\": [\n                \"posixAccount\",\n                \"top\"\n            ]\n        }\n    ],\n    [\n        \"uid=fred,ou=bar,o=baz,c=country\",\n        {\n            \"uid\": [\"fred\"],\n            \"cn\": [\"Fred Flintstone\"],\n            \"uidNumber\": [\"124\"],\n            \"gidNumber\": [\"124\"],\n            \"homeDirectory\": [\"/home/fred\"],\n            \"userPassword\": [\"the fredpassword\"],\n            \"objectclass\": [\n                \"posixAccount\",\n                \"top\"\n            ]\n        }\n    ],\n    [\n        \"uid=barney,ou=bar,o=baz,c=country\",\n        {\n            \"uid\": [\"barney\"],\n            \"cn\": [\"Barney Rubble\"],\n            \"uidNumber\": [\"125\"],\n            \"gidNumber\": [\"125\"],\n            \"homeDirectory\": [\"/home/barney\"],\n            \"userPassword\": [\"the barneypassword\"],\n            \"objectclass\": [\n                \"posixAccount\",\n                \"top\"\n            ]\n        }\n    ]\n]\n```\n\nThen we can write a `TestCase` that looks like this:\n\n```python\n    import unittest\n\n    import ldap\n    from ldap_faker import LDAPFakerMixin\n\n    from myapp import App\n\n    class YourTestCase(LDAPFakerMixin, unittest.TestCase):\n\n        ldap_modules = ['myapp']\n        ldap_fixtures = 'data.json'\n\n        def test_auth_works(self):\n            app = App()\n            # A method that does a `simple_bind_s`\n            app.auth('fred', 'the fredpassword')\n            conn = self.get_connections()[0]\n            self.assertLDAPConnectionMethodCalled(\n                conn, 'simple_bind_s',\n                {'who': 'uid=fred,ou=bar,o=baz,c=country', 'cred': 'the fredpassword'}\n            )\n\n        def test_correct_connection_options_were_set(self):\n            app = App()\n            app.auth('fred', 'the fredpassword')\n            conn = self.get_connections()[0]\n            self.assertLDAPConnectionOptionSet(conn, ldap.OPT_X_TLX_NEWCTX, 0)\n\n        def test_tls_was_used_before_auth(self):\n            app = App()\n            app.auth('fred', 'the fredpassword')\n            conn = self.get_connections()[0]\n            self.assertLDAPConnectiontMethodCalled(conn, 'start_tls_s')\n            self.assertLDAPConnectionMethodCalledAfter(conn, 'simple_bind_s', 'start_tls_s')\n```\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "Fake python-ldap functions, objects and methods for use in testing.",
    "version": "1.3.4",
    "project_urls": {
        "Documentation": "https://python-ldap-faker.readthedocs.io/en/latest/",
        "Homepage": "https://github.com/caltechads/python-ldap-faker",
        "Issues": "https://github.com/caltechads/python-ldap-faker/issues",
        "Source": "https://github.com/caltechads/python-ldap-faker"
    },
    "split_keywords": [
        "ldap",
        " testing"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "7c765584e6d271fee8eae306f52d210e55b301d240dbce5f0e0d5be2f9022b6d",
                "md5": "4c0d9f6c452978e0df4e42bea2116d76",
                "sha256": "60685cbbd8488eb8f3e08bc0df67133d7b50861be627614a94586bc69d640bcf"
            },
            "downloads": -1,
            "filename": "python_ldap_faker-1.3.4-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "4c0d9f6c452978e0df4e42bea2116d76",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 93860,
            "upload_time": "2025-07-25T00:56:43",
            "upload_time_iso_8601": "2025-07-25T00:56:43.373689Z",
            "url": "https://files.pythonhosted.org/packages/7c/76/5584e6d271fee8eae306f52d210e55b301d240dbce5f0e0d5be2f9022b6d/python_ldap_faker-1.3.4-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "e9b24e65ad176bded46ba231da20633f27c3663df5dc6a2c983bab60a6cbf001",
                "md5": "7349069120ed9b523b5d0560fa45332d",
                "sha256": "cda7f01ef2f5171508c171f05b532b39ca54be78d7cdb6040ef7d0757d16eff8"
            },
            "downloads": -1,
            "filename": "python_ldap_faker-1.3.4.tar.gz",
            "has_sig": false,
            "md5_digest": "7349069120ed9b523b5d0560fa45332d",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 80950,
            "upload_time": "2025-07-25T00:56:44",
            "upload_time_iso_8601": "2025-07-25T00:56:44.458328Z",
            "url": "https://files.pythonhosted.org/packages/e9/b2/4e65ad176bded46ba231da20633f27c3663df5dc6a2c983bab60a6cbf001/python_ldap_faker-1.3.4.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-07-25 00:56:44",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "caltechads",
    "github_project": "python-ldap-faker",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "requirements": [
        {
            "name": "alabaster",
            "specs": [
                [
                    "==",
                    "0.7.16"
                ]
            ]
        },
        {
            "name": "asn1",
            "specs": [
                [
                    "==",
                    "3.1.0"
                ]
            ]
        },
        {
            "name": "babel",
            "specs": [
                [
                    "==",
                    "2.17.0"
                ]
            ]
        },
        {
            "name": "case-insensitive-dictionary",
            "specs": [
                [
                    "==",
                    "0.2.1"
                ]
            ]
        },
        {
            "name": "certifi",
            "specs": [
                [
                    "==",
                    "2025.7.14"
                ]
            ]
        },
        {
            "name": "charset-normalizer",
            "specs": [
                [
                    "==",
                    "3.4.2"
                ]
            ]
        },
        {
            "name": "coverage",
            "specs": [
                [
                    "==",
                    "7.9.2"
                ]
            ]
        },
        {
            "name": "docutils",
            "specs": [
                [
                    "==",
                    "0.17.1"
                ]
            ]
        },
        {
            "name": "enum-compat",
            "specs": [
                [
                    "==",
                    "0.0.3"
                ]
            ]
        },
        {
            "name": "idna",
            "specs": [
                [
                    "==",
                    "3.10"
                ]
            ]
        },
        {
            "name": "imagesize",
            "specs": [
                [
                    "==",
                    "1.4.1"
                ]
            ]
        },
        {
            "name": "iniconfig",
            "specs": [
                [
                    "==",
                    "2.1.0"
                ]
            ]
        },
        {
            "name": "jinja2",
            "specs": [
                [
                    "==",
                    "3.1.6"
                ]
            ]
        },
        {
            "name": "ldap-filter",
            "specs": [
                [
                    "==",
                    "1.0.1"
                ]
            ]
        },
        {
            "name": "markupsafe",
            "specs": [
                [
                    "==",
                    "3.0.2"
                ]
            ]
        },
        {
            "name": "nose",
            "specs": [
                [
                    "==",
                    "1.3.7"
                ]
            ]
        },
        {
            "name": "packaging",
            "specs": [
                [
                    "==",
                    "25.0"
                ]
            ]
        },
        {
            "name": "pluggy",
            "specs": [
                [
                    "==",
                    "1.6.0"
                ]
            ]
        },
        {
            "name": "pyasn1",
            "specs": [
                [
                    "==",
                    "0.6.1"
                ]
            ]
        },
        {
            "name": "pyasn1-modules",
            "specs": [
                [
                    "==",
                    "0.4.2"
                ]
            ]
        },
        {
            "name": "pygments",
            "specs": [
                [
                    "==",
                    "2.19.2"
                ]
            ]
        },
        {
            "name": "pytest",
            "specs": [
                [
                    "==",
                    "8.4.1"
                ]
            ]
        },
        {
            "name": "python-ldap",
            "specs": [
                [
                    "==",
                    "3.4.4"
                ]
            ]
        },
        {
            "name": "requests",
            "specs": [
                [
                    "==",
                    "2.32.4"
                ]
            ]
        },
        {
            "name": "snowballstemmer",
            "specs": [
                [
                    "==",
                    "3.0.1"
                ]
            ]
        },
        {
            "name": "sphinx",
            "specs": [
                [
                    "==",
                    "5.2.3"
                ]
            ]
        },
        {
            "name": "sphinx-rtd-theme",
            "specs": [
                [
                    "==",
                    "1.0.0"
                ]
            ]
        },
        {
            "name": "sphinxcontrib-applehelp",
            "specs": [
                [
                    "==",
                    "2.0.0"
                ]
            ]
        },
        {
            "name": "sphinxcontrib-devhelp",
            "specs": [
                [
                    "==",
                    "2.0.0"
                ]
            ]
        },
        {
            "name": "sphinxcontrib-htmlhelp",
            "specs": [
                [
                    "==",
                    "2.1.0"
                ]
            ]
        },
        {
            "name": "sphinxcontrib-jsmath",
            "specs": [
                [
                    "==",
                    "1.0.1"
                ]
            ]
        },
        {
            "name": "sphinxcontrib-qthelp",
            "specs": [
                [
                    "==",
                    "2.0.0"
                ]
            ]
        },
        {
            "name": "sphinxcontrib-serializinghtml",
            "specs": [
                [
                    "==",
                    "2.0.0"
                ]
            ]
        },
        {
            "name": "urllib3",
            "specs": [
                [
                    "==",
                    "2.5.0"
                ]
            ]
        }
    ],
    "tox": true,
    "lcname": "python-ldap-faker"
}
        
Elapsed time: 0.54640s