-#!/usr/bin/env python
+#!/usr/bin/env python3
# Simple tests for the ldb python bindings.
# Copyright (C) 2007 Jelmer Vernooij <jelmer@samba.org>
import os
from unittest import TestCase
import sys
+sys.path.insert(0, "bin/python")
import gc
import time
import ldb
import shutil
+import errno
-PY3 = sys.version_info > (3, 0)
TDB_PREFIX = "tdb://"
MDB_PREFIX = "mdb://"
+MDB_INDEX_OBJ = {
+ "dn": "@INDEXLIST",
+ "@IDXONE": [b"1"],
+ "@IDXGUID": [b"objectUUID"],
+ "@IDX_DN_GUID": [b"GUID"]
+}
+
def tempdir():
import tempfile
self.assertEqual("19700101000000.0Z", ldb.timestring(0))
self.assertEqual("20071119191012.0Z", ldb.timestring(1195499412))
+ self.assertEqual("00000101000000.0Z", ldb.timestring(-62167219200))
+ self.assertEqual("99991231235959.0Z", ldb.timestring(253402300799))
+
+ # should result with OSError EOVERFLOW from gmtime()
+ with self.assertRaises(OSError) as err:
+ ldb.timestring(-62167219201)
+ self.assertEqual(err.exception.errno, errno.EOVERFLOW)
+ with self.assertRaises(OSError) as err:
+ ldb.timestring(253402300800)
+ self.assertEqual(err.exception.errno, errno.EOVERFLOW)
+ with self.assertRaises(OSError) as err:
+ ldb.timestring(0x7fffffffffffffff)
+ self.assertEqual(err.exception.errno, errno.EOVERFLOW)
+
def test_string_to_time(self):
self.assertEqual(0, ldb.string_to_time("19700101000000.0Z"))
+ self.assertEqual(-1, ldb.string_to_time("19691231235959.0Z"))
self.assertEqual(1195499412, ldb.string_to_time("20071119191012.0Z"))
+ self.assertEqual(-62167219200, ldb.string_to_time("00000101000000.0Z"))
+ self.assertEqual(253402300799, ldb.string_to_time("99991231235959.0Z"))
+
def test_binary_encode(self):
encoded = ldb.binary_encode(b'test\\x')
decoded = ldb.binary_decode(encoded)
x = ldb.Ldb()
x.connect(self.url(), flags=self.flags())
- def test_repr(self):
- x = ldb.Ldb()
- self.assertTrue(repr(x).startswith("<ldb connection"))
+ def test_connect_twice(self):
+ url = self.url()
+ x = ldb.Ldb(url)
+ with self.assertRaises(ldb.LdbError):
+ x.connect(url, flags=self.flags())
- def test_set_create_perms(self):
+ def test_connect_twice_later(self):
+ url = self.url()
+ flags = self.flags()
x = ldb.Ldb()
- x.set_create_perms(0o600)
+ x.connect(url, flags)
+ with self.assertRaises(ldb.LdbError):
+ x.connect(url, flags)
- def test_modules_none(self):
+ def test_connect_and_disconnect(self):
+ url = self.url()
+ flags = self.flags()
x = ldb.Ldb()
- self.assertEqual([], x.modules())
-
- def test_modules_tdb(self):
- x = ldb.Ldb(self.url(), flags=self.flags())
- self.assertEqual("[<ldb module 'tdb'>]", repr(x.modules()))
+ x.connect(url, flags)
+ x.disconnect()
+ x.connect(url, flags)
+ x.disconnect()
- def test_firstmodule_none(self):
+ def test_repr(self):
x = ldb.Ldb()
- self.assertEqual(x.firstmodule, None)
+ self.assertTrue(repr(x).startswith("<ldb connection"))
- def test_firstmodule_tdb(self):
- x = ldb.Ldb(self.url(), flags=self.flags())
- mod = x.firstmodule
- self.assertEqual(repr(mod), "<ldb module 'tdb'>")
+ def test_set_create_perms(self):
+ x = ldb.Ldb()
+ x.set_create_perms(0o600)
def test_search(self):
l = ldb.Ldb(self.url(), flags=self.flags())
l = ldb.Ldb(self.url(), flags=self.flags())
self.assertEqual(len(l.search(controls=["paged_results:0:5"])), 0)
+ def test_utf8_ldb_Dn(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ dn = ldb.Dn(l, (b'a=' + b'\xc4\x85\xc4\x87\xc4\x99\xc5\x82\xc5\x84\xc3\xb3\xc5\x9b\xc5\xba\xc5\xbc').decode('utf8'))
+
+ def test_utf8_encoded_ldb_Dn(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ dn_encoded_utf8 = b'a=' + b'\xc4\x85\xc4\x87\xc4\x99\xc5\x82\xc5\x84\xc3\xb3\xc5\x9b\xc5\xba\xc5\xbc'
+ try:
+ dn = ldb.Dn(l, dn_encoded_utf8)
+ except UnicodeDecodeError as e:
+ raise
+ except TypeError as te:
+ p3errors = ["argument 2 must be str, not bytes",
+ "Can't convert 'bytes' object to str implicitly"]
+ self.assertIn(str(te), p3errors)
+
def test_search_attrs(self):
l = ldb.Ldb(self.url(), flags=self.flags())
self.assertEqual(len(l.search(ldb.Dn(l, ""), ldb.SCOPE_SUBTREE, "(dc=*)", ["dc"])), 0)
def test_opaque(self):
l = ldb.Ldb(self.url(), flags=self.flags())
- l.set_opaque("my_opaque", l)
+ l.set_opaque("my_opaque", True)
self.assertTrue(l.get_opaque("my_opaque") is not None)
self.assertEqual(None, l.get_opaque("unknown"))
+ def test_opaque_bool(self):
+ """Test that we can set boolean opaque values."""
+
+ db = ldb.Ldb(self.url(), flags=self.flags())
+ name = "my_opaque"
+
+ db.set_opaque(name, False)
+ self.assertEqual(False, db.get_opaque(name))
+
+ db.set_opaque(name, True)
+ self.assertEqual(True, db.get_opaque(name))
+
+ def test_opaque_int(self):
+ """Test that we can set (positive) integer opaque values."""
+
+ db = ldb.Ldb(self.url(), flags=self.flags())
+ name = "my_opaque"
+
+ db.set_opaque(name, 0)
+ self.assertEqual(0, db.get_opaque(name))
+
+ db.set_opaque(name, 12345678)
+ self.assertEqual(12345678, db.get_opaque(name))
+
+ # Negative values can’t be set.
+ self.assertRaises(OverflowError, db.set_opaque, name, -99999)
+
+ def test_opaque_string(self):
+ """Test that we can set string opaque values."""
+
+ db = ldb.Ldb(self.url(), flags=self.flags())
+ name = "my_opaque"
+
+ db.set_opaque(name, "")
+ self.assertEqual("", db.get_opaque(name))
+
+ db.set_opaque(name, "foo bar")
+ self.assertEqual("foo bar", db.get_opaque(name))
+
+ def test_opaque_none(self):
+ """Test that we can set an opaque to None to effectively unset it."""
+
+ db = ldb.Ldb(self.url(), flags=self.flags())
+ name = "my_opaque"
+
+ # An opaque that has not been set is the same as None.
+ self.assertIsNone(db.get_opaque(name))
+
+ # Give the opaque a value.
+ db.set_opaque(name, 3)
+ self.assertEqual(3, db.get_opaque(name))
+
+ # Test that we can set the opaque to None to unset it.
+ db.set_opaque(name, None)
+ self.assertIsNone(db.get_opaque(name))
+
+ def test_opaque_unsupported(self):
+ """Test that trying to set unsupported values raises an error."""
+
+ db = ldb.Ldb(self.url(), flags=self.flags())
+ name = "my_opaque"
+
+ self.assertRaises(ValueError, db.set_opaque, name, [])
+ self.assertRaises(ValueError, db.set_opaque, name, ())
+ self.assertRaises(ValueError, db.set_opaque, name, 3.14)
+ self.assertRaises(ValueError, db.set_opaque, name, 3+2j)
+ self.assertRaises(ValueError, db.set_opaque, name, b'foo')
+
def test_search_scope_base_empty_db(self):
l = ldb.Ldb(self.url(), flags=self.flags())
self.assertEqual(len(l.search(ldb.Dn(l, "dc=foo1"),
- ldb.SCOPE_BASE)), 0)
+ ldb.SCOPE_BASE)), 0)
def test_search_scope_onelevel_empty_db(self):
l = ldb.Ldb(self.url(), flags=self.flags())
self.assertEqual(len(l.search(ldb.Dn(l, "dc=foo1"),
- ldb.SCOPE_ONELEVEL)), 0)
+ ldb.SCOPE_ONELEVEL)), 0)
def test_delete(self):
l = ldb.Ldb(self.url(), flags=self.flags())
m.dn = ldb.Dn(l, "dc=foo4")
m["bla"] = b"bla"
self.assertEqual(len(l.search()), 0)
- self.assertRaises(ldb.LdbError, lambda: l.add(m,["search_options:1:2"]))
+ self.assertRaises(ldb.LdbError, lambda: l.add(m, ["search_options:1:2"]))
def test_add_dict(self):
l = ldb.Ldb(self.url(), flags=self.flags())
def test_add_dict_bytes_dn(self):
l = ldb.Ldb(self.url(), flags=self.flags())
m = {"dn": b"dc=foo6", "bla": b"bla",
- "objectUUID": b"0123456789abcdef"}
+ "objectUUID": b"0123456789abcdef"}
self.assertEqual(len(l.search()), 0)
l.add(m)
try:
finally:
l.delete(ldb.Dn(l, "dc=bar"))
+ def test_rename_bad_string_dns(self):
+ l = ldb.Ldb(self.url(), flags=self.flags())
+ m = ldb.Message()
+ m.dn = ldb.Dn(l, "dc=foo8")
+ m["bla"] = b"bla"
+ m["objectUUID"] = b"0123456789abcdef"
+ self.assertEqual(len(l.search()), 0)
+ l.add(m)
+ self.assertEqual(len(l.search()), 1)
+ self.assertRaises(ldb.LdbError,lambda: l.rename("dcXfoo8", "dc=bar"))
+ self.assertRaises(ldb.LdbError,lambda: l.rename("dc=foo8", "dcXbar"))
+ l.delete(ldb.Dn(l, "dc=foo8"))
+
def test_empty_dn(self):
l = ldb.Ldb(self.url(), flags=self.flags())
self.assertEqual(0, len(l.search()))
"""Testing we do not get trapped in the \0 byte in a property string."""
l = ldb.Ldb(self.url(), flags=self.flags())
l.add({
- "dn" : b"dc=somedn",
- "objectclass" : b"user",
- "cN" : b"LDAPtestUSER",
- "givenname" : b"ldap",
- "displayname" : b"foo\0bar",
- "objectUUID" : b"0123456789abcdef"
+ "dn": b"dc=somedn",
+ "objectclass": b"user",
+ "cN": b"LDAPtestUSER",
+ "givenname": b"ldap",
+ "displayname": b"foo\0bar",
+ "objectUUID": b"0123456789abcdef"
})
res = l.search(expression="(dn=dc=somedn)")
self.assertEqual(b"foo\0bar", res[0]["displayname"][0])
def test_no_crash_broken_expr(self):
l = ldb.Ldb(self.url(), flags=self.flags())
- self.assertRaises(ldb.LdbError,lambda: l.search("", ldb.SCOPE_SUBTREE, "&(dc=*)(dn=*)", ["dc"]))
+ self.assertRaises(ldb.LdbError, lambda: l.search("", ldb.SCOPE_SUBTREE, "&(dc=*)(dn=*)", ["dc"]))
+
+# Run the SimpleLdb tests against an lmdb backend
+
+
+class SimpleLdbLmdb(SimpleLdb):
+
+ def setUp(self):
+ if os.environ.get('HAVE_LMDB', '1') == '0':
+ self.skipTest("No lmdb backend")
+ self.prefix = MDB_PREFIX
+ self.index = MDB_INDEX_OBJ
+ super(SimpleLdbLmdb, self).setUp()
+
+ def tearDown(self):
+ super(SimpleLdbLmdb, self).tearDown()
+
+
+class SimpleLdbNoLmdb(LdbBaseTest):
+
+ def setUp(self):
+ if os.environ.get('HAVE_LMDB', '1') != '0':
+ self.skipTest("lmdb backend enabled")
+ self.prefix = MDB_PREFIX
+ self.index = MDB_INDEX_OBJ
+ super(SimpleLdbNoLmdb, self).setUp()
+
+ def tearDown(self):
+ super(SimpleLdbNoLmdb, self).tearDown()
+
+ def test_lmdb_disabled(self):
+ self.testdir = tempdir()
+ self.filename = os.path.join(self.testdir, "test.ldb")
+ try:
+ self.ldb = ldb.Ldb(self.url(), flags=self.flags())
+ self.fail("Should have failed on missing LMDB")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_OTHER)
+
class SearchTests(LdbBaseTest):
def tearDown(self):
# Ensure the LDB is closed now, so we close the FD
del(self.l)
-
def setUp(self):
super(SearchTests, self).setUp()
self.testdir = tempdir()
self.filename = os.path.join(self.testdir, "search_test.ldb")
+ options = ["modules:rdn_name"]
+ if hasattr(self, 'IDXCHECK'):
+ options.append("disable_full_db_scan_for_self_test:1")
self.l = ldb.Ldb(self.url(),
flags=self.flags(),
- options=["modules:rdn_name"])
+ options=options)
try:
self.l.add(self.index)
except AttributeError:
# instead use just the 16 bytes raw, which we just keep
# to printable chars here for ease of handling.
+ self.l.add({"dn": "DC=ORG",
+ "name": b"org",
+ "objectUUID": b"0000000000abcdef"})
+ self.l.add({"dn": "DC=EXAMPLE,DC=ORG",
+ "name": b"org",
+ "objectUUID": b"0000000001abcdef"})
+ self.l.add({"dn": "OU=OU1,DC=EXAMPLE,DC=ORG",
+ "name": b"OU #1",
+ "x": "y", "y": "a",
+ "objectUUID": b"0023456789abcde3"})
+ self.l.add({"dn": "OU=OU2,DC=EXAMPLE,DC=ORG",
+ "name": b"OU #2",
+ "x": "y", "y": "a",
+ "objectUUID": b"0023456789abcde4"})
+ self.l.add({"dn": "OU=OU3,DC=EXAMPLE,DC=ORG",
+ "name": b"OU #3",
+ "x": "y", "y": "a",
+ "objectUUID": b"0023456789abcde5"})
+ self.l.add({"dn": "OU=OU4,DC=EXAMPLE,DC=ORG",
+ "name": b"OU #4",
+ "x": "z", "y": "b",
+ "objectUUID": b"0023456789abcde6"})
+ self.l.add({"dn": "OU=OU5,DC=EXAMPLE,DC=ORG",
+ "name": b"OU #5",
+ "x": "y", "y": "a",
+ "objectUUID": b"0023456789abcde7"})
+ self.l.add({"dn": "OU=OU6,DC=EXAMPLE,DC=ORG",
+ "name": b"OU #6",
+ "x": "y", "y": "a",
+ "objectUUID": b"0023456789abcde8"})
+ self.l.add({"dn": "OU=OU7,DC=EXAMPLE,DC=ORG",
+ "name": b"OU #7",
+ "x": "y", "y": "c",
+ "objectUUID": b"0023456789abcde9"})
+ self.l.add({"dn": "OU=OU8,DC=EXAMPLE,DC=ORG",
+ "name": b"OU #8",
+ "x": "y", "y": "b",
+ "objectUUID": b"0023456789abcde0"})
+ self.l.add({"dn": "OU=OU9,DC=EXAMPLE,DC=ORG",
+ "name": b"OU #9",
+ "x": "y", "y": "a",
+ "objectUUID": b"0023456789abcdea"})
+
+ self.l.add({"dn": "DC=EXAMPLE,DC=COM",
+ "name": b"org",
+ "objectUUID": b"0000000011abcdef"})
+
+ self.l.add({"dn": "DC=EXAMPLE,DC=NET",
+ "name": b"org",
+ "objectUUID": b"0000000021abcdef"})
+
+ self.l.add({"dn": "OU=UNIQUE,DC=EXAMPLE,DC=NET",
+ "objectUUID": b"0000000022abcdef"})
+
self.l.add({"dn": "DC=SAMBA,DC=ORG",
"name": b"samba.org",
"objectUUID": b"0123456789abcdef"})
enum = err.args[0]
self.assertEqual(enum, ldb.ERR_NO_SUCH_OBJECT)
+ def test_subtree(self):
+ """Testing a search"""
+
+ try:
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE)
+ if hasattr(self, 'IDXCHECK'):
+ self.fail()
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ estr = err.args[1]
+ self.assertEqual(enum, ldb.ERR_INAPPROPRIATE_MATCHING)
+ self.assertIn(estr, "ldb FULL SEARCH disabled")
+ else:
+ self.assertEqual(len(res11), 25)
+
+ def test_subtree2(self):
+ """Testing a search"""
+
+ try:
+ res11 = self.l.search(base="DC=ORG",
+ scope=ldb.SCOPE_SUBTREE)
+ if hasattr(self, 'IDXCHECK'):
+ self.fail()
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ estr = err.args[1]
+ self.assertEqual(enum, ldb.ERR_INAPPROPRIATE_MATCHING)
+ self.assertIn(estr, "ldb FULL SEARCH disabled")
+ else:
+ self.assertEqual(len(res11), 36)
+
def test_subtree_and(self):
"""Testing a search"""
expression="(|(x=y)(y=b))")
self.assertEqual(len(res11), 20)
+ def test_one_unindexable(self):
+ """Testing a search"""
+
+ try:
+ res11 = self.l.search(base="DC=samba,DC=org",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(y=b*)")
+ if hasattr(self, 'IDX') and \
+ not hasattr(self, 'IDXONE') and \
+ hasattr(self, 'IDXCHECK'):
+ self.fail("Should have failed as un-indexed search")
+
+ self.assertEqual(len(res11), 9)
+
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ estr = err.args[1]
+ self.assertEqual(enum, ldb.ERR_INAPPROPRIATE_MATCHING)
+ self.assertIn(estr, "ldb FULL SEARCH disabled")
+
+ def test_one_unindexable_presence(self):
+ """Testing a search"""
+
+ try:
+ res11 = self.l.search(base="DC=samba,DC=org",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(y=*)")
+ if hasattr(self, 'IDX') and \
+ not hasattr(self, 'IDXONE') and \
+ hasattr(self, 'IDXCHECK'):
+ self.fail("Should have failed as un-indexed search")
+
+ self.assertEqual(len(res11), 24)
+
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ estr = err.args[1]
+ self.assertEqual(enum, ldb.ERR_INAPPROPRIATE_MATCHING)
+ self.assertIn(estr, "ldb FULL SEARCH disabled")
+
def test_subtree_and_or(self):
"""Testing a search"""
expression="(&(ou=ou10)(y=a))")
self.assertEqual(len(res11), 1)
+ def test_subtree_unique(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(ou=ou10)")
+ self.assertEqual(len(res11), 1)
+
+ def test_subtree_unique_elsewhere(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(ou=ou10)")
+ self.assertEqual(len(res11), 0)
+
+ def test_subtree_unique_elsewhere2(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=NET",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(ou=unique)")
+ self.assertEqual(len(res11), 1)
+
+ def test_subtree_uni123_elsewhere(self):
+ """Testing a search, where the search term contains a (normal ASCII)
+ dotted-i, that will be upper-cased to 'İ', U+0130, LATIN
+ CAPITAL LETTER I WITH DOT ABOVE in certain locales including
+ tr_TR in which this test is sometimes run.
+
+ The search term should fail because the ou does not exist, but
+ we used to get it wrong in unindexed searches which stopped
+ comparing at the i, ignoring the rest of the string, which is
+ not the same as the existing ou ('123' != 'que').
+ """
+ res11 = self.l.search(base="DC=EXAMPLE,DC=NET",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(ou=uni123)")
+ self.assertEqual(len(res11), 0)
+
+ def test_subtree_unique_elsewhere3(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(ou=unique)")
+ self.assertEqual(len(res11), 0)
+
+ def test_subtree_unique_elsewhere4(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(ou=unique)")
+ self.assertEqual(len(res11), 0)
+
+ def test_subtree_unique_elsewhere5(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=COM",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(ou=unique)")
+ self.assertEqual(len(res11), 0)
+
+ def test_subtree_unique_elsewhere6(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(ou=unique)")
+ self.assertEqual(len(res11), 0)
+
+ def test_subtree_unique_elsewhere7(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=COM",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(ou=ou10)")
+ self.assertEqual(len(res11), 0)
+
+ def test_subtree_unique_here(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="OU=UNIQUE,DC=EXAMPLE,DC=NET",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(ou=unique)")
+ self.assertEqual(len(res11), 1)
+
def test_subtree_and_none(self):
"""Testing a search"""
expression="(@IDXONE=DC=SAMBA,DC=ORG)")
self.assertEqual(len(res11), 0)
+ def test_onelevel(self):
+ """Testing a search"""
+
+ try:
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL)
+ if hasattr(self, 'IDXCHECK') \
+ and not hasattr(self, 'IDXONE'):
+ self.fail()
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ estr = err.args[1]
+ self.assertEqual(enum, ldb.ERR_INAPPROPRIATE_MATCHING)
+ self.assertIn(estr, "ldb FULL SEARCH disabled")
+ else:
+ self.assertEqual(len(res11), 24)
+
+ def test_onelevel2(self):
+ """Testing a search"""
+
+ try:
+ res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL)
+ if hasattr(self, 'IDXCHECK') \
+ and not hasattr(self, 'IDXONE'):
+ self.fail()
+ self.fail()
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ estr = err.args[1]
+ self.assertEqual(enum, ldb.ERR_INAPPROPRIATE_MATCHING)
+ self.assertIn(estr, "ldb FULL SEARCH disabled")
+ else:
+ self.assertEqual(len(res11), 9)
+
+ def test_onelevel_and_or(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(|(x=z)(y=b))(x=x)(y=c))")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_and_or2(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(x=x)(y=c)(|(x=z)(y=b)))")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_and_or3(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(|(ou=ou11)(ou=ou10))(|(x=y)(y=b)(y=c)))")
+ self.assertEqual(len(res11), 2)
+
+ def test_onelevel_and_or4(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(|(x=y)(y=b)(y=c))(|(ou=ou11)(ou=ou10)))")
+ self.assertEqual(len(res11), 2)
+
+ def test_onelevel_and_or5(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(|(x=y)(y=b)(y=c))(ou=ou11))")
+ self.assertEqual(len(res11), 1)
+
+ def test_onelevel_or_and(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(|(x=x)(y=c)(&(x=z)(y=b)))")
+ self.assertEqual(len(res11), 10)
+
+ def test_onelevel_large_and_unique(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(ou=ou10)(y=a))")
+ self.assertEqual(len(res11), 1)
+
+ def test_onelevel_unique(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(ou=ou10)")
+ self.assertEqual(len(res11), 1)
+
+ def test_onelevel_unique_elsewhere(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(ou=ou10)")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_unique_elsewhere2(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=NET",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(ou=unique)")
+ self.assertEqual(len(res11), 1)
+
+ def test_onelevel_unique_elsewhere3(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(ou=unique)")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_unique_elsewhere4(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(ou=unique)")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_unique_elsewhere5(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=COM",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(ou=unique)")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_unique_elsewhere6(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=COM",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(ou=ou10)")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_unique_here(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="OU=UNIQUE,DC=EXAMPLE,DC=NET",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(ou=unique)")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_and_none(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(ou=ouX)(y=a))")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_and_idx_record(self):
+ """Testing a search against the index record"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(@IDXDN=DC=SAMBA,DC=ORG)")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_and_idxone_record(self):
+ """Testing a search against the index record"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(@IDXONE=DC=SAMBA,DC=ORG)")
+ self.assertEqual(len(res11), 0)
+
+ def test_subtree_unindexable(self):
+ """Testing a search"""
+
+ try:
+ res11 = self.l.search(base="DC=samba,DC=org",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(y=b*)")
+ if hasattr(self, 'IDX') and \
+ hasattr(self, 'IDXCHECK'):
+ self.fail("Should have failed as un-indexed search")
+
+ self.assertEqual(len(res11), 9)
+
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ estr = err.args[1]
+ self.assertEqual(enum, ldb.ERR_INAPPROPRIATE_MATCHING)
+ self.assertIn(estr, "ldb FULL SEARCH disabled")
+
+ def test_onelevel_only_and_or(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(|(x=z)(y=b))(x=x)(y=c))")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_only_and_or2(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(x=x)(y=c)(|(x=z)(y=b)))")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_only_and_or3(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(|(ou=ou11)(ou=ou10))(|(x=y)(y=b)(y=c)))")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_only_and_or4(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(|(x=y)(y=b)(y=c))(|(ou=ou11)(ou=ou10)))")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_only_and_or5(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(|(x=y)(y=b)(y=c))(ou=ou11))")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_only_or_and(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(|(x=x)(y=c)(&(x=z)(y=b)))")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_only_large_and_unique(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(ou=ou10)(y=a))")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_only_unique(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(ou=ou10)")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_only_unique2(self):
+ """Testing a search"""
+
+ res11 = self.l.search(base="DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(ou=unique)")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_only_and_none(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(ou=ouX)(y=a))")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_small_and_or(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(|(x=z)(y=b))(x=x)(y=c))")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_small_and_or2(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(x=x)(y=c)(|(x=z)(y=b)))")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_small_and_or3(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(|(ou=ou1)(ou=ou2))(|(x=y)(y=b)(y=c)))")
+ self.assertEqual(len(res11), 2)
+
+ def test_onelevel_small_and_or4(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(|(x=y)(y=b)(y=c))(|(ou=ou1)(ou=ou2)))")
+ self.assertEqual(len(res11), 2)
+
+ def test_onelevel_small_and_or5(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(|(x=y)(y=b)(y=c))(ou=ou1))")
+ self.assertEqual(len(res11), 1)
+
+ def test_onelevel_small_or_and(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(|(x=x)(y=c)(&(x=z)(y=b)))")
+ self.assertEqual(len(res11), 2)
+
+ def test_onelevel_small_large_and_unique(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(ou=ou9)(y=a))")
+ self.assertEqual(len(res11), 1)
+
+ def test_onelevel_small_unique_elsewhere(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(ou=ou10)")
+ self.assertEqual(len(res11), 0)
+
+ def test_onelevel_small_and_none(self):
+ """Testing a search (showing that onelevel is not subtree)"""
+
+ res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(&(ou=ouX)(y=a))")
+ self.assertEqual(len(res11), 0)
+
+ def test_subtree_unindexable_presence(self):
+ """Testing a search"""
+
+ try:
+ res11 = self.l.search(base="DC=samba,DC=org",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(y=*)")
+ if hasattr(self, 'IDX') and \
+ hasattr(self, 'IDXCHECK'):
+ self.fail("Should have failed as un-indexed search")
+
+ self.assertEqual(len(res11), 24)
+
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ estr = err.args[1]
+ self.assertEqual(enum, ldb.ERR_INAPPROPRIATE_MATCHING)
+ self.assertIn(estr, "ldb FULL SEARCH disabled")
+
def test_dn_filter_one(self):
"""Testing that a dn= filter succeeds
(or fails with disallowDNFilter
expression="(dn=OU=OU1,DC=SAMBA,DC=ORG)")
if hasattr(self, 'disallowDNFilter') and \
hasattr(self, 'IDX') and \
- (hasattr(self, 'IDXGUID') or \
- ((hasattr(self, 'IDXONE') == False and hasattr(self, 'IDX')))):
+ (hasattr(self, 'IDXGUID') or
+ ((not hasattr(self, 'IDXONE') and hasattr(self, 'IDX')))):
self.assertEqual(len(res11), 0)
else:
self.assertEqual(len(res11), 1)
# At some point we should fix this, but it isn't trivial
self.assertEqual(len(res11), 1)
+ def test_distinguishedName_filter_one(self):
+ """Testing that a distinguishedName= filter succeeds
+ when the scope is SCOPE_ONELEVEL.
+
+ This should be made more consistent, but for now lock in
+ the behaviour
+
+ """
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(distinguishedName=OU=OU1,DC=SAMBA,DC=ORG)")
+ self.assertEqual(len(res11), 1)
+
+ def test_distinguishedName_filter_subtree(self):
+ """Testing that a distinguishedName= filter succeeds
+ when the scope is SCOPE_SUBTREE"""
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(distinguishedName=OU=OU1,DC=SAMBA,DC=ORG)")
+ self.assertEqual(len(res11), 1)
+
+ def test_distinguishedName_filter_base(self):
+ """Testing that (incorrectly) a distinguishedName= filter works
+ when the scope is SCOPE_BASE"""
+
+ res11 = self.l.search(base="OU=OU1,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE,
+ expression="(distinguishedName=OU=OU1,DC=SAMBA,DC=ORG)")
+
+ # At some point we should fix this, but it isn't trivial
+ self.assertEqual(len(res11), 1)
+
+ def test_bad_dn_filter_base(self):
+ """Testing that a dn= filter on an invalid DN works
+ when the scope is SCOPE_BASE but
+ returns zero results"""
+
+ res11 = self.l.search(base="OU=OU1,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE,
+ expression="(dn=OU=OU1,DC=SAMBA,DCXXXX)")
+
+ # At some point we should fix this, but it isn't trivial
+ self.assertEqual(len(res11), 0)
+
+
+ def test_bad_dn_filter_one(self):
+ """Testing that a dn= filter succeeds but returns zero
+ results when the DN is not valid on a SCOPE_ONELEVEL search
+
+ """
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(dn=OU=OU1,DC=SAMBA,DCXXXX)")
+ self.assertEqual(len(res11), 0)
+
+ def test_bad_dn_filter_subtree(self):
+ """Testing that a dn= filter succeeds but returns zero
+ results when the DN is not valid on a SCOPE_SUBTREE search
+
+ """
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(dn=OU=OU1,DC=SAMBA,DCXXXX)")
+ self.assertEqual(len(res11), 0)
+
+ def test_bad_distinguishedName_filter_base(self):
+ """Testing that a distinguishedName= filter on an invalid DN works
+ when the scope is SCOPE_BASE but
+ returns zero results"""
+
+ res11 = self.l.search(base="OU=OU1,DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_BASE,
+ expression="(distinguishedName=OU=OU1,DC=SAMBA,DCXXXX)")
+
+ # At some point we should fix this, but it isn't trivial
+ self.assertEqual(len(res11), 0)
+
+
+ def test_bad_distinguishedName_filter_one(self):
+ """Testing that a distinguishedName= filter succeeds but returns zero
+ results when the DN is not valid on a SCOPE_ONELEVEL search
+
+ """
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_ONELEVEL,
+ expression="(distinguishedName=OU=OU1,DC=SAMBA,DCXXXX)")
+ self.assertEqual(len(res11), 0)
+
+ def test_bad_distinguishedName_filter_subtree(self):
+ """Testing that a distinguishedName= filter succeeds but returns zero
+ results when the DN is not valid on a SCOPE_SUBTREE search
+
+ """
+
+ res11 = self.l.search(base="DC=SAMBA,DC=ORG",
+ scope=ldb.SCOPE_SUBTREE,
+ expression="(distinguishedName=OU=OU1,DC=SAMBA,DCXXXX)")
+ self.assertEqual(len(res11), 0)
+
+ def test_bad_dn_search_base(self):
+ """Testing with a bad base DN (SCOPE_BASE)"""
+
+ try:
+ res11 = self.l.search(base="OU=OU1,DC=SAMBA,DCXXX",
+ scope=ldb.SCOPE_BASE)
+ self.fail("Should have failed with ERR_INVALID_DN_SYNTAX")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_INVALID_DN_SYNTAX)
+
+
+ def test_bad_dn_search_one(self):
+ """Testing with a bad base DN (SCOPE_ONELEVEL)"""
+
+ try:
+ res11 = self.l.search(base="DC=SAMBA,DCXXXX",
+ scope=ldb.SCOPE_ONELEVEL)
+ self.fail("Should have failed with ERR_INVALID_DN_SYNTAX")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_INVALID_DN_SYNTAX)
+
+ def test_bad_dn_search_subtree(self):
+ """Testing with a bad base DN (SCOPE_SUBTREE)"""
+
+ try:
+ res11 = self.l.search(base="DC=SAMBA,DCXXXX",
+ scope=ldb.SCOPE_SUBTREE)
+ self.fail("Should have failed with ERR_INVALID_DN_SYNTAX")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_INVALID_DN_SYNTAX)
+
+
+
+# Run the search tests against an lmdb backend
+class SearchTestsLmdb(SearchTests):
+
+ def setUp(self):
+ if os.environ.get('HAVE_LMDB', '1') == '0':
+ self.skipTest("No lmdb backend")
+ self.prefix = MDB_PREFIX
+ self.index = MDB_INDEX_OBJ
+ super(SearchTestsLmdb, self).setUp()
+
+ def tearDown(self):
+ super(SearchTestsLmdb, self).tearDown()
+
class IndexedSearchTests(SearchTests):
"""Test searches using the index, to ensure the index doesn't
break things"""
+
def setUp(self):
super(IndexedSearchTests, self).setUp()
self.l.add({"dn": "@INDEXLIST",
"@IDXATTR": [b"x", b"y", b"ou"]})
self.IDX = True
+
+class IndexedCheckSearchTests(IndexedSearchTests):
+ """Test searches using the index, to ensure the index doesn't
+ break things (full scan disabled)"""
+
+ def setUp(self):
+ self.IDXCHECK = True
+ super(IndexedCheckSearchTests, self).setUp()
+
+
class IndexedSearchDnFilterTests(SearchTests):
"""Test searches using the index, to ensure the index doesn't
break things"""
+
def setUp(self):
super(IndexedSearchDnFilterTests, self).setUp()
self.l.add({"dn": "@OPTIONS",
"@IDXATTR": [b"x", b"y", b"ou"]})
self.IDX = True
+
class IndexedAndOneLevelSearchTests(SearchTests):
"""Test searches using the index including @IDXONE, to ensure
the index doesn't break things"""
+
def setUp(self):
super(IndexedAndOneLevelSearchTests, self).setUp()
self.l.add({"dn": "@INDEXLIST",
"@IDXATTR": [b"x", b"y", b"ou"],
"@IDXONE": [b"1"]})
self.IDX = True
+ self.IDXONE = True
+
+
+class IndexedCheckedAndOneLevelSearchTests(IndexedAndOneLevelSearchTests):
+ """Test searches using the index including @IDXONE, to ensure
+ the index doesn't break things (full scan disabled)"""
+
+ def setUp(self):
+ self.IDXCHECK = True
+ super(IndexedCheckedAndOneLevelSearchTests, self).setUp()
+
class IndexedAndOneLevelDNFilterSearchTests(SearchTests):
"""Test searches using the index including @IDXONE, to ensure
the index doesn't break things"""
+
def setUp(self):
super(IndexedAndOneLevelDNFilterSearchTests, self).setUp()
self.l.add({"dn": "@OPTIONS",
- "disallowDNFilter": "TRUE"})
+ "disallowDNFilter": "TRUE",
+ "checkBaseOnSearch": "TRUE"})
self.disallowDNFilter = True
+ self.checkBaseOnSearch = True
self.l.add({"dn": "@INDEXLIST",
"@IDXATTR": [b"x", b"y", b"ou"],
self.IDX = True
self.IDXONE = True
+
class GUIDIndexedSearchTests(SearchTests):
"""Test searches using the index, to ensure the index doesn't
break things"""
+
def setUp(self):
self.index = {"dn": "@INDEXLIST",
"@IDXATTR": [b"x", b"y", b"ou"],
super(GUIDIndexedSearchTests, self).setUp()
self.IDXGUID = True
- self.IDXONE = True
class GUIDIndexedDNFilterSearchTests(SearchTests):
"""Test searches using the index, to ensure the index doesn't
break things"""
+
def setUp(self):
self.index = {"dn": "@INDEXLIST",
"@IDXATTR": [b"x", b"y", b"ou"],
"@IDX_DN_GUID": [b"GUID"]}
super(GUIDIndexedDNFilterSearchTests, self).setUp()
self.l.add({"dn": "@OPTIONS",
- "disallowDNFilter": "TRUE"})
+ "disallowDNFilter": "TRUE",
+ "checkBaseOnSearch": "TRUE"})
self.disallowDNFilter = True
+ self.checkBaseOnSearch = True
self.IDX = True
self.IDXGUID = True
+
class GUIDAndOneLevelIndexedSearchTests(SearchTests):
"""Test searches using the index including @IDXONE, to ensure
the index doesn't break things"""
+
def setUp(self):
self.index = {"dn": "@INDEXLIST",
"@IDXATTR": [b"x", b"y", b"ou"],
+ "@IDXONE": [b"1"],
"@IDXGUID": [b"objectUUID"],
"@IDX_DN_GUID": [b"GUID"]}
super(GUIDAndOneLevelIndexedSearchTests, self).setUp()
self.l.add({"dn": "@OPTIONS",
- "disallowDNFilter": "TRUE"})
+ "disallowDNFilter": "TRUE",
+ "checkBaseOnSearch": "TRUE"})
self.disallowDNFilter = True
+ self.checkBaseOnSearch = True
self.IDX = True
self.IDXGUID = True
self.IDXONE = True
+class GUIDIndexedSearchTestsLmdb(GUIDIndexedSearchTests):
+
+ def setUp(self):
+ if os.environ.get('HAVE_LMDB', '1') == '0':
+ self.skipTest("No lmdb backend")
+ self.prefix = MDB_PREFIX
+ super(GUIDIndexedSearchTestsLmdb, self).setUp()
+
+ def tearDown(self):
+ super(GUIDIndexedSearchTestsLmdb, self).tearDown()
+
+
+class GUIDIndexedDNFilterSearchTestsLmdb(GUIDIndexedDNFilterSearchTests):
+
+ def setUp(self):
+ if os.environ.get('HAVE_LMDB', '1') == '0':
+ self.skipTest("No lmdb backend")
+ self.prefix = MDB_PREFIX
+ super(GUIDIndexedDNFilterSearchTestsLmdb, self).setUp()
+
+ def tearDown(self):
+ super(GUIDIndexedDNFilterSearchTestsLmdb, self).tearDown()
+
+
+class GUIDAndOneLevelIndexedSearchTestsLmdb(GUIDAndOneLevelIndexedSearchTests):
+
+ def setUp(self):
+ if os.environ.get('HAVE_LMDB', '1') == '0':
+ self.skipTest("No lmdb backend")
+ self.prefix = MDB_PREFIX
+ super(GUIDAndOneLevelIndexedSearchTestsLmdb, self).setUp()
+
+ def tearDown(self):
+ super(GUIDAndOneLevelIndexedSearchTestsLmdb, self).tearDown()
+
+
class AddModifyTests(LdbBaseTest):
def tearDown(self):
shutil.rmtree(self.testdir)
"name": b"Admins",
"x": "z", "y": "a",
"objectUUID": b"0123456789abcde2"})
- self.fail("Should have failed adding dupliate entry")
+ self.fail("Should have failed adding duplicate entry")
except ldb.LdbError as err:
enum = err.args[0]
self.assertEqual(enum, ldb.ERR_ENTRY_ALREADY_EXISTS)
+ def test_add_bad(self):
+ try:
+ self.l.add({"dn": "BAD,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde1"})
+ self.fail("Should have failed adding entry with invalid DN")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_INVALID_DN_SYNTAX)
+
def test_add_del_add(self):
self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
"name": b"Admins",
enum = err.args[0]
self.assertEqual(enum, ldb.ERR_NO_SUCH_OBJECT)
+ def test_move_bad(self):
+ self.l.add({"dn": "OU=DUP2,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde2"})
+
+ try:
+ self.l.rename("OUXDUP,DC=SAMBA,DC=ORG",
+ "OU=DUP2,DC=SAMBA,DC=ORG")
+ self.fail("Should have failed on invalid DN")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_INVALID_DN_SYNTAX)
+
+ def test_move_bad2(self):
+ self.l.add({"dn": "OU=DUP2,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "x": "z", "y": "a",
+ "objectUUID": b"0123456789abcde2"})
+
+ try:
+ self.l.rename("OU=DUP,DC=SAMBA,DC=ORG",
+ "OUXDUP2,DC=SAMBA,DC=ORG")
+ self.fail("Should have failed on missing")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_INVALID_DN_SYNTAX)
+
def test_move_fail_move_add(self):
self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
"name": b"Admins",
"objectUUID": b"0123456789abcde3"})
+class AddModifyTestsLmdb(AddModifyTests):
+
+ def setUp(self):
+ if os.environ.get('HAVE_LMDB', '1') == '0':
+ self.skipTest("No lmdb backend")
+ self.prefix = MDB_PREFIX
+ self.index = MDB_INDEX_OBJ
+ super(AddModifyTestsLmdb, self).setUp()
+
+ def tearDown(self):
+ super(AddModifyTestsLmdb, self).tearDown()
+
+
class IndexedAddModifyTests(AddModifyTests):
"""Test searches using the index, to ensure the index doesn't
break things"""
+
def setUp(self):
if not hasattr(self, 'index'):
self.index = {"dn": "@INDEXLIST",
- "@IDXATTR": [b"x", b"y", b"ou", b"objectUUID"],
+ "@IDXATTR": [b"x", b"y", b"ou", b"objectUUID", b"z"],
"@IDXONE": [b"1"]}
super(IndexedAddModifyTests, self).setUp()
"name": b"Admins",
"x": "z", "y": "a",
"objectUUID": b"0123456789abcdef"})
- self.fail("Should have failed adding dupliate GUID")
+ self.fail("Should have failed adding duplicate GUID")
except ldb.LdbError as err:
enum = err.args[0]
self.assertEqual(enum, ldb.ERR_CONSTRAINT_VIOLATION)
"name": b"Admins",
"x": "z", "y": "a",
"objectUUID": b"a123456789abcdef"})
- self.fail("Should have failed adding dupliate GUID")
+ self.fail("Should have failed adding duplicate GUID")
except ldb.LdbError as err:
enum = err.args[0]
self.assertEqual(enum, ldb.ERR_ENTRY_ALREADY_EXISTS)
"name": b"Admins",
"x": "z", "y": "a",
"objectUUID": b"aaa3456789abcdef"})
- self.fail("Should have failed adding dupliate DN")
+ self.fail("Should have failed adding duplicate DN")
except ldb.LdbError as err:
enum = err.args[0]
self.assertEqual(enum, ldb.ERR_ENTRY_ALREADY_EXISTS)
"x": "z", "y": "a",
"objectUUID": b"0123456789abcde2"})
+ def test_duplicate_index_values(self):
+ self.l.add({"dn": "OU=DIV1,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "z": "1",
+ "objectUUID": b"0123456789abcdff"})
+ self.l.add({"dn": "OU=DIV2,DC=SAMBA,DC=ORG",
+ "name": b"Admins",
+ "z": "1",
+ "objectUUID": b"0123456789abcdfd"})
+
+
class GUIDIndexedAddModifyTests(IndexedAddModifyTests):
"""Test searches using the index, to ensure the index doesn't
break things"""
+
def setUp(self):
self.index = {"dn": "@INDEXLIST",
"@IDXATTR": [b"x", b"y", b"ou"],
class GUIDTransIndexedAddModifyTests(GUIDIndexedAddModifyTests):
"""Test GUID index behaviour insdie the transaction"""
+
def setUp(self):
super(GUIDTransIndexedAddModifyTests, self).setUp()
self.l.transaction_start()
self.l.transaction_commit()
super(GUIDTransIndexedAddModifyTests, self).tearDown()
+
class TransIndexedAddModifyTests(IndexedAddModifyTests):
"""Test index behaviour insdie the transaction"""
+
def setUp(self):
super(TransIndexedAddModifyTests, self).setUp()
self.l.transaction_start()
super(TransIndexedAddModifyTests, self).tearDown()
+class GuidIndexedAddModifyTestsLmdb(GUIDIndexedAddModifyTests):
+
+ def setUp(self):
+ if os.environ.get('HAVE_LMDB', '1') == '0':
+ self.skipTest("No lmdb backend")
+ self.prefix = MDB_PREFIX
+ super(GuidIndexedAddModifyTestsLmdb, self).setUp()
+
+ def tearDown(self):
+ super(GuidIndexedAddModifyTestsLmdb, self).tearDown()
+
+
+class GuidTransIndexedAddModifyTestsLmdb(GUIDTransIndexedAddModifyTests):
+
+ def setUp(self):
+ if os.environ.get('HAVE_LMDB', '1') == '0':
+ self.skipTest("No lmdb backend")
+ self.prefix = MDB_PREFIX
+ super(GuidTransIndexedAddModifyTestsLmdb, self).setUp()
+
+ def tearDown(self):
+ super(GuidTransIndexedAddModifyTestsLmdb, self).tearDown()
+
+
class BadIndexTests(LdbBaseTest):
def setUp(self):
super(BadIndexTests, self).setUp()
res = self.ldb.search(expression="(y=1)",
base="dc=samba,dc=org")
- self.assertEquals(len(res), 3)
+ self.assertEqual(len(res), 3)
# Now set this to unique index, but forget to check the result
try:
self.ldb.add({"dn": "@ATTRIBUTES",
- "y": "UNIQUE_INDEX"})
+ "y": "UNIQUE_INDEX"})
self.fail()
except ldb.LdbError:
pass
# We must still have a working index
res = self.ldb.search(expression="(y=1)",
base="dc=samba,dc=org")
- self.assertEquals(len(res), 3)
+ self.assertEqual(len(res), 3)
def test_unique_transaction(self):
self.ldb.add({"dn": "x=x,dc=samba,dc=org",
res = self.ldb.search(expression="(y=1)",
base="dc=samba,dc=org")
- self.assertEquals(len(res), 3)
+ self.assertEqual(len(res), 3)
self.ldb.transaction_start()
# Now set this to unique index, but forget to check the result
try:
self.ldb.add({"dn": "@ATTRIBUTES",
- "y": "UNIQUE_INDEX"})
+ "y": "UNIQUE_INDEX"})
except ldb.LdbError:
pass
res = self.ldb.search(expression="(y=1)",
base="dc=samba,dc=org")
- self.assertEquals(len(res), 3)
+ self.assertEqual(len(res), 3)
def test_casefold(self):
self.ldb.add({"dn": "x=x,dc=samba,dc=org",
res = self.ldb.search(expression="(y=a)",
base="dc=samba,dc=org")
- self.assertEquals(len(res), 2)
+ self.assertEqual(len(res), 2)
self.ldb.add({"dn": "@ATTRIBUTES",
"y": "CASE_INSENSITIVE"})
base="dc=samba,dc=org")
if hasattr(self, 'IDXGUID'):
- self.assertEquals(len(res), 3)
+ self.assertEqual(len(res), 3)
else:
# We should not return this entry twice, but sadly
# we have not yet fixed
# https://bugzilla.samba.org/show_bug.cgi?id=13361
- self.assertEquals(len(res), 4)
+ self.assertEqual(len(res), 4)
def test_casefold_transaction(self):
self.ldb.add({"dn": "x=x,dc=samba,dc=org",
res = self.ldb.search(expression="(y=a)",
base="dc=samba,dc=org")
- self.assertEquals(len(res), 2)
+ self.assertEqual(len(res), 2)
self.ldb.transaction_start()
base="dc=samba,dc=org")
if hasattr(self, 'IDXGUID'):
- self.assertEquals(len(res), 3)
+ self.assertEqual(len(res), 3)
else:
# We should not return this entry twice, but sadly
# we have not yet fixed
# https://bugzilla.samba.org/show_bug.cgi?id=13361
- self.assertEquals(len(res), 4)
+ self.assertEqual(len(res), 4)
+
+ def test_modify_transaction(self):
+ self.ldb.add({"dn": "x=y,dc=samba,dc=org",
+ "objectUUID": b"0123456789abcde1",
+ "y": "2",
+ "z": "2"})
+
+ res = self.ldb.search(expression="(y=2)",
+ base="dc=samba,dc=org")
+ self.assertEqual(len(res), 1)
+
+ self.ldb.add({"dn": "@ATTRIBUTES",
+ "y": "UNIQUE_INDEX"})
+
+ self.ldb.transaction_start()
+
+ m = ldb.Message()
+ m.dn = ldb.Dn(self.ldb, "x=y,dc=samba,dc=org")
+ m["0"] = ldb.MessageElement([], ldb.FLAG_MOD_DELETE, "y")
+ m["1"] = ldb.MessageElement([], ldb.FLAG_MOD_DELETE, "not-here")
+
+ try:
+ self.ldb.modify(m)
+ self.fail()
+
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_NO_SUCH_ATTRIBUTE)
+
+ try:
+ self.ldb.transaction_commit()
+ # We should fail here, but we want to be sure
+ # we fail below
+
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_OPERATIONS_ERROR)
+ # The index should still be pointing to x=y
+ res = self.ldb.search(expression="(y=2)",
+ base="dc=samba,dc=org")
+ self.assertEqual(len(res), 1)
+
+ try:
+ self.ldb.add({"dn": "x=y2,dc=samba,dc=org",
+ "objectUUID": b"0123456789abcde2",
+ "y": "2"})
+ self.fail("Added unique attribute twice")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_CONSTRAINT_VIOLATION)
+
+ res = self.ldb.search(expression="(y=2)",
+ base="dc=samba,dc=org")
+ self.assertEqual(len(res), 1)
+ self.assertEqual(str(res[0].dn), "x=y,dc=samba,dc=org")
def tearDown(self):
super(BadIndexTests, self).tearDown()
class GUIDBadIndexTests(BadIndexTests):
"""Test Bad index things with GUID index mode"""
+
def setUp(self):
self.IDXGUID = True
super(GUIDBadIndexTests, self).setUp()
+class GUIDBadIndexTestsLmdb(BadIndexTests):
+
+ def setUp(self):
+ if os.environ.get('HAVE_LMDB', '1') == '0':
+ self.skipTest("No lmdb backend")
+ self.prefix = MDB_PREFIX
+ self.index = MDB_INDEX_OBJ
+ self.IDXGUID = True
+ super(GUIDBadIndexTestsLmdb, self).setUp()
+
+ def tearDown(self):
+ super(GUIDBadIndexTestsLmdb, self).tearDown()
+
+
+class BatchModeTests(LdbBaseTest):
+
+ def setUp(self):
+ super(BatchModeTests, self).setUp()
+ self.testdir = tempdir()
+ self.filename = os.path.join(self.testdir, "test.ldb")
+ self.ldb = ldb.Ldb(self.url(),
+ flags=self.flags(),
+ options=["batch_mode:1"])
+ if hasattr(self, 'IDXGUID'):
+ self.ldb.add({"dn": "@INDEXLIST",
+ "@IDXATTR": [b"x", b"y", b"ou"],
+ "@IDXGUID": [b"objectUUID"],
+ "@IDX_DN_GUID": [b"GUID"]})
+ else:
+ self.ldb.add({"dn": "@INDEXLIST",
+ "@IDXATTR": [b"x", b"y", b"ou"]})
+
+ def test_modify_transaction(self):
+ self.ldb.add({"dn": "x=y,dc=samba,dc=org",
+ "objectUUID": b"0123456789abcde1",
+ "y": "2",
+ "z": "2"})
+
+ res = self.ldb.search(expression="(y=2)",
+ base="dc=samba,dc=org")
+ self.assertEqual(len(res), 1)
+
+ self.ldb.add({"dn": "@ATTRIBUTES",
+ "y": "UNIQUE_INDEX"})
+
+ self.ldb.transaction_start()
+
+ m = ldb.Message()
+ m.dn = ldb.Dn(self.ldb, "x=y,dc=samba,dc=org")
+ m["0"] = ldb.MessageElement([], ldb.FLAG_MOD_DELETE, "y")
+ m["1"] = ldb.MessageElement([], ldb.FLAG_MOD_DELETE, "not-here")
+
+ try:
+ self.ldb.modify(m)
+ self.fail()
+
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_NO_SUCH_ATTRIBUTE)
+
+ try:
+ self.ldb.transaction_commit()
+ self.fail("Commit should have failed as we were in batch mode")
+ except ldb.LdbError as err:
+ enum = err.args[0]
+ self.assertEqual(enum, ldb.ERR_OPERATIONS_ERROR)
+
+ def tearDown(self):
+ super(BatchModeTests, self).tearDown()
+
+
class DnTests(TestCase):
def setUp(self):
def test_set_dn_invalid(self):
x = ldb.Message()
+
def assign():
x.dn = "astring"
self.assertRaises(TypeError, assign)
x = ldb.Dn(self.ldb, "dc=foo13,bla=blie")
self.assertEqual(x.__repr__(), "Dn('dc=foo13,bla=blie')")
- def test_get_casefold(self):
+ def test_get_casefold_2(self):
x = ldb.Dn(self.ldb, "dc=foo14,bar=bloe")
self.assertEqual(x.get_casefold(), "DC=FOO14,BAR=bloe")
+ def test_get_casefold_dotted_i(self):
+ x = ldb.Dn(self.ldb, "dc=foo14,bir=blie")
+ self.assertEqual(x.get_casefold(), "DC=FOO14,BIR=blie")
+
def test_validate(self):
x = ldb.Dn(self.ldb, "dc=foo15,bar=bloe")
self.assertTrue(x.validate())
def test_remove_base_components(self):
x = ldb.Dn(self.ldb, "dc=foo24,dc=samba,dc=org")
- x.remove_base_components(len(x)-1)
+ x.remove_base_components(len(x) - 1)
self.assertEqual("dc=foo24", str(x))
def test_parse_ldif(self):
msg = next(msgs)
self.assertEqual("bar=bar", str(msg[1].dn))
+ def test_print_ldif(self):
+ ldif = '''dn: dc=foo27
+foo: foo
+
+'''
+ self.msg = ldb.Message(ldb.Dn(self.ldb, "dc=foo27"))
+ self.msg["foo"] = [b"foo"]
+ self.assertEqual(ldif,
+ self.ldb.write_ldif(self.msg,
+ ldb.CHANGETYPE_NONE))
+
+ def test_print_ldif_binary(self):
+ # this also confirms that ldb flags are set even without a URL)
+ self.ldb = ldb.Ldb(flags=ldb.FLG_SHOW_BINARY)
+ ldif = '''dn: dc=foo27
+foo: f
+öö
+
+'''
+ self.msg = ldb.Message(ldb.Dn(self.ldb, "dc=foo27"))
+ self.msg["foo"] = ["f\nöö"]
+ self.assertEqual(ldif,
+ self.ldb.write_ldif(self.msg,
+ ldb.CHANGETYPE_NONE))
+
+
+ def test_print_ldif_no_base64_bad(self):
+ ldif = '''dn: dc=foo27
+foo: f
+öö
+
+'''
+ self.msg = ldb.Message(ldb.Dn(self.ldb, "dc=foo27"))
+ self.msg["foo"] = ["f\nöö"]
+ self.msg["foo"].set_flags(ldb.FLAG_FORCE_NO_BASE64_LDIF)
+ self.assertEqual(ldif,
+ self.ldb.write_ldif(self.msg,
+ ldb.CHANGETYPE_NONE))
+
+ def test_print_ldif_no_base64_good(self):
+ ldif = '''dn: dc=foo27
+foo: föö
+
+'''
+ self.msg = ldb.Message(ldb.Dn(self.ldb, "dc=foo27"))
+ self.msg["foo"] = ["föö"]
+ self.msg["foo"].set_flags(ldb.FLAG_FORCE_NO_BASE64_LDIF)
+ self.assertEqual(ldif,
+ self.ldb.write_ldif(self.msg,
+ ldb.CHANGETYPE_NONE))
+
def test_canonical_string(self):
x = ldb.Dn(self.ldb, "dc=foo25,bar=bloe")
self.assertEqual("/bloe/foo25", x.canonical_str())
dn = ldb.Dn(self.ldb, '')
self.assertTrue(dn.is_null())
+
class LdbMsgTests(TestCase):
def setUp(self):
self.msg.dn = ldb.Dn(ldb.Ldb(), "dc=foo28")
self.assertEqual(1, len(self.msg.items()))
+ def test_items(self):
+ self.msg["foo"] = ["foo"]
+ self.msg["bar"] = ["bar"]
+ try:
+ items = self.msg.items()
+ except:
+ self.fail()
+ self.assertEqual([("foo", ldb.MessageElement(["foo"])),
+ ("bar", ldb.MessageElement(["bar"]))],
+ items)
+
+ self.msg.dn = ldb.Dn(ldb.Ldb(), "dc=test")
+ try:
+ items = self.msg.items()
+ except:
+ self.fail()
+ self.assertEqual([("dn", ldb.Dn(ldb.Ldb(), "dc=test")),
+ ("foo", ldb.MessageElement(["foo"])),
+ ("bar", ldb.MessageElement(["bar"]))],
+ items)
+
def test_repr(self):
self.msg.dn = ldb.Dn(ldb.Ldb(), "dc=foo29")
self.msg["dc"] = b"foo"
- if PY3:
- self.assertIn(repr(self.msg), [
- "Message({'dn': Dn('dc=foo29'), 'dc': MessageElement([b'foo'])})",
- "Message({'dc': MessageElement([b'foo']), 'dn': Dn('dc=foo29')})",
- ])
- self.assertIn(repr(self.msg.text), [
- "Message({'dn': Dn('dc=foo29'), 'dc': MessageElement([b'foo'])}).text",
- "Message({'dc': MessageElement([b'foo']), 'dn': Dn('dc=foo29')}).text",
- ])
- else:
- self.assertEqual(
- repr(self.msg),
- "Message({'dn': Dn('dc=foo29'), 'dc': MessageElement(['foo'])})")
- self.assertEqual(
- repr(self.msg.text),
- "Message({'dn': Dn('dc=foo29'), 'dc': MessageElement(['foo'])}).text")
+ self.assertIn(repr(self.msg), [
+ "Message({'dn': Dn('dc=foo29'), 'dc': MessageElement([b'foo'])})",
+ "Message({'dc': MessageElement([b'foo']), 'dn': Dn('dc=foo29')})",
+ ])
+ self.assertIn(repr(self.msg.text), [
+ "Message({'dn': Dn('dc=foo29'), 'dc': MessageElement([b'foo'])}).text",
+ "Message({'dc': MessageElement([b'foo']), 'dn': Dn('dc=foo29')}).text",
+ ])
def test_len(self):
self.assertEqual(0, len(self.msg))
def test_notpresent(self):
self.assertRaises(KeyError, lambda: self.msg["foo"])
+ def test_invalid(self):
+ try:
+ self.assertRaises(TypeError, lambda: self.msg[42])
+ except KeyError:
+ self.fail()
+
def test_del(self):
del self.msg["foo"]
self.msg.dn = ldb.Dn(ldb.Ldb(), "@BASEINFO")
self.msg["foo"] = [b"bla"]
self.msg["bar"] = [b"bla"]
- self.assertEqual(["dn", "foo", "bar"], self.msg.keys())
+ self.assertEqual(["dn", "foo", "bar"], list(self.msg.keys()))
def test_keys_text(self):
self.msg.dn = ldb.Dn(ldb.Ldb(), "@BASEINFO")
self.msg["foo"] = ["bla"]
self.msg["bar"] = ["bla"]
- self.assertEqual(["dn", "foo", "bar"], self.msg.text.keys())
+ self.assertEqual(["dn", "foo", "bar"], list(self.msg.text.keys()))
def test_dn(self):
self.msg.dn = ldb.Dn(ldb.Ldb(), "@BASEINFO")
def test_get_unknown_text(self):
self.assertEqual(None, self.msg.text.get("lalalala"))
+ def test_contains(self):
+ self.msg['foo'] = ['bar']
+ self.assertIn('foo', self.msg)
+
+ self.msg['Foo'] = ['bar']
+ self.assertIn('Foo', self.msg)
+
+ def test_contains_case(self):
+ self.msg['foo'] = ['bar']
+ self.assertIn('Foo', self.msg)
+
+ self.msg['Foo'] = ['bar']
+ self.assertIn('foo', self.msg)
+
+ def test_contains_dn(self):
+ self.assertIn('dn', self.msg)
+
+ def test_contains_dn_case(self):
+ self.assertIn('DN', self.msg)
+
+ def test_contains_invalid(self):
+ self.assertRaises(TypeError, lambda: None in self.msg)
+
def test_msg_diff(self):
l = ldb.Ldb()
msgs = l.parse_ldif("dn: foo=bar\nfoo: bar\nbaz: do\n\ndn: foo=bar\nfoo: bar\nbaz: dont\n")
def test_repr(self):
x = ldb.MessageElement([b"foo"])
- if PY3:
- self.assertEqual("MessageElement([b'foo'])", repr(x))
- self.assertEqual("MessageElement([b'foo']).text", repr(x.text))
- else:
- self.assertEqual("MessageElement(['foo'])", repr(x))
- self.assertEqual("MessageElement(['foo']).text", repr(x.text))
+ self.assertEqual("MessageElement([b'foo'])", repr(x))
+ self.assertEqual("MessageElement([b'foo']).text", repr(x.text))
x = ldb.MessageElement([b"foo", b"bla"])
self.assertEqual(2, len(x))
- if PY3:
- self.assertEqual("MessageElement([b'foo',b'bla'])", repr(x))
- self.assertEqual("MessageElement([b'foo',b'bla']).text", repr(x.text))
- else:
- self.assertEqual("MessageElement(['foo','bla'])", repr(x))
- self.assertEqual("MessageElement(['foo','bla']).text", repr(x.text))
+ self.assertEqual("MessageElement([b'foo',b'bla'])", repr(x))
+ self.assertEqual("MessageElement([b'foo',b'bla']).text", repr(x.text))
def test_get_item(self):
x = ldb.MessageElement([b"foo", b"bar"])
def test_extended(self):
el = ldb.MessageElement([b"456"], ldb.FLAG_MOD_ADD, "bla")
- if PY3:
- self.assertEqual("MessageElement([b'456'])", repr(el))
- self.assertEqual("MessageElement([b'456']).text", repr(el.text))
- else:
- self.assertEqual("MessageElement(['456'])", repr(el))
- self.assertEqual("MessageElement(['456']).text", repr(el.text))
+ self.assertEqual("MessageElement([b'456'])", repr(el))
+ self.assertEqual("MessageElement([b'456']).text", repr(el.text))
def test_bad_text(self):
el = ldb.MessageElement(b'\xba\xdd')
self.assertRaises(UnicodeDecodeError, el.text.__getitem__, 0)
-class ModuleTests(TestCase):
-
- def setUp(self):
- super(ModuleTests, self).setUp()
- self.testdir = tempdir()
- self.filename = os.path.join(self.testdir, "test.ldb")
- self.ldb = ldb.Ldb(self.filename)
-
- def tearDown(self):
- shutil.rmtree(self.testdir)
- super(ModuleTests, self).setUp()
-
- def test_register_module(self):
- class ExampleModule:
- name = "example"
- ldb.register_module(ExampleModule)
-
- def test_use_module(self):
- ops = []
- class ExampleModule:
- name = "bla"
-
- def __init__(self, ldb, next):
- ops.append("init")
- self.next = next
-
- def search(self, *args, **kwargs):
- return self.next.search(*args, **kwargs)
-
- def request(self, *args, **kwargs):
- pass
-
- ldb.register_module(ExampleModule)
- l = ldb.Ldb(self.filename)
- l.add({"dn": "@MODULES", "@LIST": "bla"})
- self.assertEqual([], ops)
- l = ldb.Ldb(self.filename)
- self.assertEqual(["init"], ops)
-
class LdbResultTests(LdbBaseTest):
def setUp(self):
found = True
self.assertTrue(found)
-
# Show that search results can't see into a transaction
+
def test_search_against_trans(self):
found11 = False
# and commit
try:
child_ldb.transaction_commit()
- except LdbError as err:
+ except ldb.LdbError as err:
# We print this here to see what went wrong in the child
print(err)
os._exit(1)
# This should not turn up until the transaction is concluded
res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
- scope=ldb.SCOPE_BASE)
+ scope=ldb.SCOPE_BASE)
self.assertEqual(len(res11), 0)
os.write(w2, b"search")
# This should now turn up, as the transaction is over
res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
- scope=ldb.SCOPE_BASE)
+ scope=ldb.SCOPE_BASE)
self.assertEqual(len(res11), 1)
self.assertFalse(found11)
(got_pid, status) = os.waitpid(pid, 0)
self.assertEqual(got_pid, pid)
-
def test_search_iter_against_trans(self):
found = False
found11 = False
# and commit
try:
child_ldb.transaction_commit()
- except LdbError as err:
+ except ldb.LdbError as err:
# We print this here to see what went wrong in the child
print(err)
os._exit(1)
# This should not turn up until the transaction is concluded
res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
- scope=ldb.SCOPE_BASE)
+ scope=ldb.SCOPE_BASE)
self.assertEqual(len(res11), 0)
os.write(w2, b"search")
# removed the read lock, but for ldb_tdb that happened as soon
# as we called the first res.next()
res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
- scope=ldb.SCOPE_BASE)
+ scope=ldb.SCOPE_BASE)
self.assertEqual(len(res11), 0)
# These results are all collected at the first next(res) call
# This should now turn up, as the transaction is over and all
# read locks are gone
res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
- scope=ldb.SCOPE_BASE)
+ scope=ldb.SCOPE_BASE)
self.assertEqual(len(res11), 1)
self.assertTrue(found)
self.assertEqual(got_pid, pid)
+class LdbResultTestsLmdb(LdbResultTests):
+
+ def setUp(self):
+ if os.environ.get('HAVE_LMDB', '1') == '0':
+ self.skipTest("No lmdb backend")
+ self.prefix = MDB_PREFIX
+ self.index = MDB_INDEX_OBJ
+ super(LdbResultTestsLmdb, self).setUp()
+
+ def tearDown(self):
+ super(LdbResultTestsLmdb, self).tearDown()
+
+
class BadTypeTests(TestCase):
def test_control(self):
l = ldb.Ldb()
def test_version(self):
self.assertTrue(isinstance(ldb.__version__, str))
+class NestedTransactionTests(LdbBaseTest):
+ def setUp(self):
+ super(NestedTransactionTests, self).setUp()
+ self.testdir = tempdir()
+ self.filename = os.path.join(self.testdir, "test.ldb")
+ self.ldb = ldb.Ldb(self.url(), flags=self.flags())
+ self.ldb.add({"dn": "@INDEXLIST",
+ "@IDXATTR": [b"x", b"y", b"ou"],
+ "@IDXGUID": [b"objectUUID"],
+ "@IDX_DN_GUID": [b"GUID"]})
+
+ super(NestedTransactionTests, self).setUp()
+
+ #
+ # This test documents that currently ldb does not support true nested
+ # transactions.
+ #
+ # Note: The test is written so that it treats failure as pass.
+ # It is done this way as standalone ldb builds do not use the samba
+ # known fail mechanism
+ #
+ def test_nested_transactions(self):
+
+ self.ldb.transaction_start()
+
+ self.ldb.add({"dn": "x=x1,dc=samba,dc=org",
+ "objectUUID": b"0123456789abcde1"})
+ res = self.ldb.search(expression="(objectUUID=0123456789abcde1)",
+ base="dc=samba,dc=org")
+ self.assertEqual(len(res), 1)
+
+ self.ldb.add({"dn": "x=x2,dc=samba,dc=org",
+ "objectUUID": b"0123456789abcde2"})
+ res = self.ldb.search(expression="(objectUUID=0123456789abcde2)",
+ base="dc=samba,dc=org")
+ self.assertEqual(len(res), 1)
+
+ self.ldb.transaction_start()
+ self.ldb.add({"dn": "x=x3,dc=samba,dc=org",
+ "objectUUID": b"0123456789abcde3"})
+ res = self.ldb.search(expression="(objectUUID=0123456789abcde3)",
+ base="dc=samba,dc=org")
+ self.assertEqual(len(res), 1)
+ self.ldb.transaction_cancel()
+ #
+ # Check that we can not see the record added by the cancelled
+ # transaction.
+ # Currently this fails as ldb does not support true nested
+ # transactions, and only the outer commits and cancels have an effect
+ #
+ res = self.ldb.search(expression="(objectUUID=0123456789abcde3)",
+ base="dc=samba,dc=org")
+ #
+ # FIXME this test currently passes on a failure, i.e. if nested
+ # transaction support worked correctly the correct test would
+ # be.
+ # self.assertEqual(len(res), 0)
+ # as the add of objectUUID=0123456789abcde3 would reverted when
+ # the sub transaction it was nested in was rolled back.
+ #
+ # Currently this is not the case so the record is still present.
+ self.assertEqual(len(res), 1)
+
+
+ # Commit the outer transaction
+ #
+ self.ldb.transaction_commit()
+ #
+ # Now check we can still see the records added in the outer
+ # transaction.
+ #
+ res = self.ldb.search(expression="(objectUUID=0123456789abcde1)",
+ base="dc=samba,dc=org")
+ self.assertEqual(len(res), 1)
+ res = self.ldb.search(expression="(objectUUID=0123456789abcde2)",
+ base="dc=samba,dc=org")
+ self.assertEqual(len(res), 1)
+ #
+ # And that we can't see the records added by the nested transaction.
+ #
+ res = self.ldb.search(expression="(objectUUID=0123456789abcde3)",
+ base="dc=samba,dc=org")
+ # FIXME again if nested transactions worked correctly we would not
+ # see this record. The test should be.
+ # self.assertEqual(len(res), 0)
+ self.assertEqual(len(res), 1)
+
+ def tearDown(self):
+ super(NestedTransactionTests, self).tearDown()
+
+
+class LmdbNestedTransactionTests(NestedTransactionTests):
+
+ def setUp(self):
+ if os.environ.get('HAVE_LMDB', '1') == '0':
+ self.skipTest("No lmdb backend")
+ self.prefix = MDB_PREFIX
+ self.index = MDB_INDEX_OBJ
+ super(LmdbNestedTransactionTests, self).setUp()
+
+ def tearDown(self):
+ super(LmdbNestedTransactionTests, self).tearDown()
+
if __name__ == '__main__':
import unittest