2 # Simple tests for the ldb python bindings.
3 # Copyright (C) 2007 Jelmer Vernooij <jelmer@samba.org>
6 from unittest import TestCase
8 sys.path.insert(0, "bin/python")
22 "@IDXGUID": [b"objectUUID"],
23 "@IDX_DN_GUID": [b"GUID"]
30 dir_prefix = os.path.join(os.environ["SELFTEST_PREFIX"], "tmp")
33 return tempfile.mkdtemp(dir=dir_prefix)
36 class NoContextTests(TestCase):
38 def test_valid_attr_name(self):
39 self.assertTrue(ldb.valid_attr_name("foo"))
40 self.assertFalse(ldb.valid_attr_name("24foo"))
42 def test_timestring(self):
43 self.assertEqual("19700101000000.0Z", ldb.timestring(0))
44 self.assertEqual("20071119191012.0Z", ldb.timestring(1195499412))
46 self.assertEqual("00000101000000.0Z", ldb.timestring(-62167219200))
47 self.assertEqual("99991231235959.0Z", ldb.timestring(253402300799))
49 # should result with OSError EOVERFLOW from gmtime()
50 with self.assertRaises(OSError) as err:
51 ldb.timestring(-62167219201)
52 self.assertEqual(err.exception.errno, errno.EOVERFLOW)
53 with self.assertRaises(OSError) as err:
54 ldb.timestring(253402300800)
55 self.assertEqual(err.exception.errno, errno.EOVERFLOW)
56 with self.assertRaises(OSError) as err:
57 ldb.timestring(0x7fffffffffffffff)
58 self.assertEqual(err.exception.errno, errno.EOVERFLOW)
60 def test_string_to_time(self):
61 self.assertEqual(0, ldb.string_to_time("19700101000000.0Z"))
62 self.assertEqual(1195499412, ldb.string_to_time("20071119191012.0Z"))
64 self.assertEqual(-62167219200, ldb.string_to_time("00000101000000.0Z"))
65 self.assertEqual(253402300799, ldb.string_to_time("99991231235959.0Z"))
67 def test_binary_encode(self):
68 encoded = ldb.binary_encode(b'test\\x')
69 decoded = ldb.binary_decode(encoded)
70 self.assertEqual(decoded, b'test\\x')
72 encoded2 = ldb.binary_encode('test\\x')
73 self.assertEqual(encoded2, encoded)
76 class LdbBaseTest(TestCase):
78 super(LdbBaseTest, self).setUp()
80 if self.prefix is None:
81 self.prefix = TDB_PREFIX
82 except AttributeError:
83 self.prefix = TDB_PREFIX
86 super(LdbBaseTest, self).tearDown()
89 return self.prefix + self.filename
92 if self.prefix == MDB_PREFIX:
98 class SimpleLdb(LdbBaseTest):
101 super(SimpleLdb, self).setUp()
102 self.testdir = tempdir()
103 self.filename = os.path.join(self.testdir, "test.ldb")
104 self.ldb = ldb.Ldb(self.url(), flags=self.flags())
106 self.ldb.add(self.index)
107 except AttributeError:
111 shutil.rmtree(self.testdir)
112 super(SimpleLdb, self).tearDown()
113 # Ensure the LDB is closed now, so we close the FD
116 def test_connect(self):
117 ldb.Ldb(self.url(), flags=self.flags())
119 def test_connect_none(self):
122 def test_connect_later(self):
124 x.connect(self.url(), flags=self.flags())
128 self.assertTrue(repr(x).startswith("<ldb connection"))
130 def test_set_create_perms(self):
132 x.set_create_perms(0o600)
134 def test_modules_none(self):
136 self.assertEqual([], x.modules())
138 def test_modules_tdb(self):
139 x = ldb.Ldb(self.url(), flags=self.flags())
140 self.assertEqual("[<ldb module 'tdb'>]", repr(x.modules()))
142 def test_firstmodule_none(self):
144 self.assertEqual(x.firstmodule, None)
146 def test_firstmodule_tdb(self):
147 x = ldb.Ldb(self.url(), flags=self.flags())
149 self.assertEqual(repr(mod), "<ldb module 'tdb'>")
151 def test_search(self):
152 l = ldb.Ldb(self.url(), flags=self.flags())
153 self.assertEqual(len(l.search()), 0)
155 def test_search_controls(self):
156 l = ldb.Ldb(self.url(), flags=self.flags())
157 self.assertEqual(len(l.search(controls=["paged_results:0:5"])), 0)
159 def test_utf8_ldb_Dn(self):
160 l = ldb.Ldb(self.url(), flags=self.flags())
161 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'))
163 def test_utf8_encoded_ldb_Dn(self):
164 l = ldb.Ldb(self.url(), flags=self.flags())
165 dn_encoded_utf8 = b'a=' + b'\xc4\x85\xc4\x87\xc4\x99\xc5\x82\xc5\x84\xc3\xb3\xc5\x9b\xc5\xba\xc5\xbc'
167 dn = ldb.Dn(l, dn_encoded_utf8)
168 except UnicodeDecodeError as e:
170 except TypeError as te:
171 p3errors = ["argument 2 must be str, not bytes",
172 "Can't convert 'bytes' object to str implicitly"]
173 self.assertIn(str(te), p3errors)
175 def test_search_attrs(self):
176 l = ldb.Ldb(self.url(), flags=self.flags())
177 self.assertEqual(len(l.search(ldb.Dn(l, ""), ldb.SCOPE_SUBTREE, "(dc=*)", ["dc"])), 0)
179 def test_search_string_dn(self):
180 l = ldb.Ldb(self.url(), flags=self.flags())
181 self.assertEqual(len(l.search("", ldb.SCOPE_SUBTREE, "(dc=*)", ["dc"])), 0)
183 def test_search_attr_string(self):
184 l = ldb.Ldb(self.url(), flags=self.flags())
185 self.assertRaises(TypeError, l.search, attrs="dc")
186 self.assertRaises(TypeError, l.search, attrs=b"dc")
188 def test_opaque(self):
189 l = ldb.Ldb(self.url(), flags=self.flags())
190 l.set_opaque("my_opaque", l)
191 self.assertTrue(l.get_opaque("my_opaque") is not None)
192 self.assertEqual(None, l.get_opaque("unknown"))
194 def test_search_scope_base_empty_db(self):
195 l = ldb.Ldb(self.url(), flags=self.flags())
196 self.assertEqual(len(l.search(ldb.Dn(l, "dc=foo1"),
199 def test_search_scope_onelevel_empty_db(self):
200 l = ldb.Ldb(self.url(), flags=self.flags())
201 self.assertEqual(len(l.search(ldb.Dn(l, "dc=foo1"),
202 ldb.SCOPE_ONELEVEL)), 0)
204 def test_delete(self):
205 l = ldb.Ldb(self.url(), flags=self.flags())
206 self.assertRaises(ldb.LdbError, lambda: l.delete(ldb.Dn(l, "dc=foo2")))
208 def test_delete_w_unhandled_ctrl(self):
209 l = ldb.Ldb(self.url(), flags=self.flags())
211 m.dn = ldb.Dn(l, "dc=foo1")
213 m["objectUUID"] = b"0123456789abcdef"
215 self.assertRaises(ldb.LdbError, lambda: l.delete(m.dn, ["search_options:1:2"]))
218 def test_contains(self):
220 l = ldb.Ldb(name, flags=self.flags())
221 self.assertFalse(ldb.Dn(l, "dc=foo3") in l)
222 l = ldb.Ldb(name, flags=self.flags())
224 m.dn = ldb.Dn(l, "dc=foo3")
226 m["objectUUID"] = b"0123456789abcdef"
229 self.assertTrue(ldb.Dn(l, "dc=foo3") in l)
230 self.assertFalse(ldb.Dn(l, "dc=foo4") in l)
234 def test_get_config_basedn(self):
235 l = ldb.Ldb(self.url(), flags=self.flags())
236 self.assertEqual(None, l.get_config_basedn())
238 def test_get_root_basedn(self):
239 l = ldb.Ldb(self.url(), flags=self.flags())
240 self.assertEqual(None, l.get_root_basedn())
242 def test_get_schema_basedn(self):
243 l = ldb.Ldb(self.url(), flags=self.flags())
244 self.assertEqual(None, l.get_schema_basedn())
246 def test_get_default_basedn(self):
247 l = ldb.Ldb(self.url(), flags=self.flags())
248 self.assertEqual(None, l.get_default_basedn())
251 l = ldb.Ldb(self.url(), flags=self.flags())
253 m.dn = ldb.Dn(l, "dc=foo4")
255 m["objectUUID"] = b"0123456789abcdef"
256 self.assertEqual(len(l.search()), 0)
259 self.assertEqual(len(l.search()), 1)
261 l.delete(ldb.Dn(l, "dc=foo4"))
263 def test_search_iterator(self):
264 l = ldb.Ldb(self.url(), flags=self.flags())
265 s = l.search_iterator()
271 except RuntimeError as re:
276 except RuntimeError as re:
281 except RuntimeError as re:
284 s = l.search_iterator()
287 self.assertTrue(isinstance(me, ldb.Message))
290 self.assertEqual(len(r), 0)
291 self.assertEqual(count, 0)
294 m1.dn = ldb.Dn(l, "dc=foo4")
296 m1["objectUUID"] = b"0123456789abcdef"
299 s = l.search_iterator()
302 self.assertTrue(isinstance(me, ldb.Message))
306 self.assertEqual(len(r), 0)
307 self.assertEqual(len(msgs), 1)
308 self.assertEqual(msgs[0].dn, m1.dn)
311 m2.dn = ldb.Dn(l, "dc=foo5")
313 m2["objectUUID"] = b"0123456789abcdee"
316 s = l.search_iterator()
319 self.assertTrue(isinstance(me, ldb.Message))
323 self.assertEqual(len(r), 0)
324 self.assertEqual(len(msgs), 2)
325 if msgs[0].dn == m1.dn:
326 self.assertEqual(msgs[0].dn, m1.dn)
327 self.assertEqual(msgs[1].dn, m2.dn)
329 self.assertEqual(msgs[0].dn, m2.dn)
330 self.assertEqual(msgs[1].dn, m1.dn)
332 s = l.search_iterator()
335 self.assertTrue(isinstance(me, ldb.Message))
342 except RuntimeError as re:
345 self.assertTrue(isinstance(me, ldb.Message))
353 self.assertEqual(len(r), 0)
354 self.assertEqual(len(msgs), 2)
355 if msgs[0].dn == m1.dn:
356 self.assertEqual(msgs[0].dn, m1.dn)
357 self.assertEqual(msgs[1].dn, m2.dn)
359 self.assertEqual(msgs[0].dn, m2.dn)
360 self.assertEqual(msgs[1].dn, m1.dn)
362 l.delete(ldb.Dn(l, "dc=foo4"))
363 l.delete(ldb.Dn(l, "dc=foo5"))
365 def test_add_text(self):
366 l = ldb.Ldb(self.url(), flags=self.flags())
368 m.dn = ldb.Dn(l, "dc=foo4")
370 m["objectUUID"] = b"0123456789abcdef"
371 self.assertEqual(len(l.search()), 0)
374 self.assertEqual(len(l.search()), 1)
376 l.delete(ldb.Dn(l, "dc=foo4"))
378 def test_add_w_unhandled_ctrl(self):
379 l = ldb.Ldb(self.url(), flags=self.flags())
381 m.dn = ldb.Dn(l, "dc=foo4")
383 self.assertEqual(len(l.search()), 0)
384 self.assertRaises(ldb.LdbError, lambda: l.add(m, ["search_options:1:2"]))
386 def test_add_dict(self):
387 l = ldb.Ldb(self.url(), flags=self.flags())
388 m = {"dn": ldb.Dn(l, "dc=foo5"),
390 "objectUUID": b"0123456789abcdef"}
391 self.assertEqual(len(l.search()), 0)
394 self.assertEqual(len(l.search()), 1)
396 l.delete(ldb.Dn(l, "dc=foo5"))
398 def test_add_dict_text(self):
399 l = ldb.Ldb(self.url(), flags=self.flags())
400 m = {"dn": ldb.Dn(l, "dc=foo5"),
402 "objectUUID": b"0123456789abcdef"}
403 self.assertEqual(len(l.search()), 0)
406 self.assertEqual(len(l.search()), 1)
408 l.delete(ldb.Dn(l, "dc=foo5"))
410 def test_add_dict_string_dn(self):
411 l = ldb.Ldb(self.url(), flags=self.flags())
412 m = {"dn": "dc=foo6", "bla": b"bla",
413 "objectUUID": b"0123456789abcdef"}
414 self.assertEqual(len(l.search()), 0)
417 self.assertEqual(len(l.search()), 1)
419 l.delete(ldb.Dn(l, "dc=foo6"))
421 def test_add_dict_bytes_dn(self):
422 l = ldb.Ldb(self.url(), flags=self.flags())
423 m = {"dn": b"dc=foo6", "bla": b"bla",
424 "objectUUID": b"0123456789abcdef"}
425 self.assertEqual(len(l.search()), 0)
428 self.assertEqual(len(l.search()), 1)
430 l.delete(ldb.Dn(l, "dc=foo6"))
432 def test_rename(self):
433 l = ldb.Ldb(self.url(), flags=self.flags())
435 m.dn = ldb.Dn(l, "dc=foo7")
437 m["objectUUID"] = b"0123456789abcdef"
438 self.assertEqual(len(l.search()), 0)
441 l.rename(ldb.Dn(l, "dc=foo7"), ldb.Dn(l, "dc=bar"))
442 self.assertEqual(len(l.search()), 1)
444 l.delete(ldb.Dn(l, "dc=bar"))
446 def test_rename_string_dns(self):
447 l = ldb.Ldb(self.url(), flags=self.flags())
449 m.dn = ldb.Dn(l, "dc=foo8")
451 m["objectUUID"] = b"0123456789abcdef"
452 self.assertEqual(len(l.search()), 0)
454 self.assertEqual(len(l.search()), 1)
456 l.rename("dc=foo8", "dc=bar")
457 self.assertEqual(len(l.search()), 1)
459 l.delete(ldb.Dn(l, "dc=bar"))
461 def test_rename_bad_string_dns(self):
462 l = ldb.Ldb(self.url(), flags=self.flags())
464 m.dn = ldb.Dn(l, "dc=foo8")
466 m["objectUUID"] = b"0123456789abcdef"
467 self.assertEqual(len(l.search()), 0)
469 self.assertEqual(len(l.search()), 1)
470 self.assertRaises(ldb.LdbError,lambda: l.rename("dcXfoo8", "dc=bar"))
471 self.assertRaises(ldb.LdbError,lambda: l.rename("dc=foo8", "dcXbar"))
472 l.delete(ldb.Dn(l, "dc=foo8"))
474 def test_empty_dn(self):
475 l = ldb.Ldb(self.url(), flags=self.flags())
476 self.assertEqual(0, len(l.search()))
478 m.dn = ldb.Dn(l, "dc=empty")
479 m["objectUUID"] = b"0123456789abcdef"
482 self.assertEqual(1, len(rm))
483 self.assertEqual(set(["dn", "distinguishedName", "objectUUID"]),
487 self.assertEqual(1, len(rm))
488 self.assertEqual(set(["dn", "distinguishedName", "objectUUID"]),
490 rm = l.search(m.dn, attrs=["blah"])
491 self.assertEqual(1, len(rm))
492 self.assertEqual(0, len(rm[0]))
494 def test_modify_delete(self):
495 l = ldb.Ldb(self.url(), flags=self.flags())
497 m.dn = ldb.Dn(l, "dc=modifydelete")
499 m["objectUUID"] = b"0123456789abcdef"
501 rm = l.search(m.dn)[0]
502 self.assertEqual([b"1234"], list(rm["bla"]))
505 m.dn = ldb.Dn(l, "dc=modifydelete")
506 m["bla"] = ldb.MessageElement([], ldb.FLAG_MOD_DELETE, "bla")
507 self.assertEqual(ldb.FLAG_MOD_DELETE, m["bla"].flags())
510 self.assertEqual(1, len(rm))
511 self.assertEqual(set(["dn", "distinguishedName", "objectUUID"]),
513 rm = l.search(m.dn, attrs=["bla"])
514 self.assertEqual(1, len(rm))
515 self.assertEqual(0, len(rm[0]))
517 l.delete(ldb.Dn(l, "dc=modifydelete"))
519 def test_modify_delete_text(self):
520 l = ldb.Ldb(self.url(), flags=self.flags())
522 m.dn = ldb.Dn(l, "dc=modifydelete")
523 m.text["bla"] = ["1234"]
524 m["objectUUID"] = b"0123456789abcdef"
526 rm = l.search(m.dn)[0]
527 self.assertEqual(["1234"], list(rm.text["bla"]))
530 m.dn = ldb.Dn(l, "dc=modifydelete")
531 m["bla"] = ldb.MessageElement([], ldb.FLAG_MOD_DELETE, "bla")
532 self.assertEqual(ldb.FLAG_MOD_DELETE, m["bla"].flags())
535 self.assertEqual(1, len(rm))
536 self.assertEqual(set(["dn", "distinguishedName", "objectUUID"]),
538 rm = l.search(m.dn, attrs=["bla"])
539 self.assertEqual(1, len(rm))
540 self.assertEqual(0, len(rm[0]))
542 l.delete(ldb.Dn(l, "dc=modifydelete"))
544 def test_modify_add(self):
545 l = ldb.Ldb(self.url(), flags=self.flags())
547 m.dn = ldb.Dn(l, "dc=add")
549 m["objectUUID"] = b"0123456789abcdef"
553 m.dn = ldb.Dn(l, "dc=add")
554 m["bla"] = ldb.MessageElement([b"456"], ldb.FLAG_MOD_ADD, "bla")
555 self.assertEqual(ldb.FLAG_MOD_ADD, m["bla"].flags())
557 rm = l.search(m.dn)[0]
558 self.assertEqual(3, len(rm))
559 self.assertEqual([b"1234", b"456"], list(rm["bla"]))
561 l.delete(ldb.Dn(l, "dc=add"))
563 def test_modify_add_text(self):
564 l = ldb.Ldb(self.url(), flags=self.flags())
566 m.dn = ldb.Dn(l, "dc=add")
567 m.text["bla"] = ["1234"]
568 m["objectUUID"] = b"0123456789abcdef"
572 m.dn = ldb.Dn(l, "dc=add")
573 m["bla"] = ldb.MessageElement(["456"], ldb.FLAG_MOD_ADD, "bla")
574 self.assertEqual(ldb.FLAG_MOD_ADD, m["bla"].flags())
576 rm = l.search(m.dn)[0]
577 self.assertEqual(3, len(rm))
578 self.assertEqual(["1234", "456"], list(rm.text["bla"]))
580 l.delete(ldb.Dn(l, "dc=add"))
582 def test_modify_replace(self):
583 l = ldb.Ldb(self.url(), flags=self.flags())
585 m.dn = ldb.Dn(l, "dc=modify2")
586 m["bla"] = [b"1234", b"456"]
587 m["objectUUID"] = b"0123456789abcdef"
591 m.dn = ldb.Dn(l, "dc=modify2")
592 m["bla"] = ldb.MessageElement([b"789"], ldb.FLAG_MOD_REPLACE, "bla")
593 self.assertEqual(ldb.FLAG_MOD_REPLACE, m["bla"].flags())
595 rm = l.search(m.dn)[0]
596 self.assertEqual(3, len(rm))
597 self.assertEqual([b"789"], list(rm["bla"]))
598 rm = l.search(m.dn, attrs=["bla"])[0]
599 self.assertEqual(1, len(rm))
601 l.delete(ldb.Dn(l, "dc=modify2"))
603 def test_modify_replace_text(self):
604 l = ldb.Ldb(self.url(), flags=self.flags())
606 m.dn = ldb.Dn(l, "dc=modify2")
607 m.text["bla"] = ["1234", "456"]
608 m["objectUUID"] = b"0123456789abcdef"
612 m.dn = ldb.Dn(l, "dc=modify2")
613 m["bla"] = ldb.MessageElement(["789"], ldb.FLAG_MOD_REPLACE, "bla")
614 self.assertEqual(ldb.FLAG_MOD_REPLACE, m["bla"].flags())
616 rm = l.search(m.dn)[0]
617 self.assertEqual(3, len(rm))
618 self.assertEqual(["789"], list(rm.text["bla"]))
619 rm = l.search(m.dn, attrs=["bla"])[0]
620 self.assertEqual(1, len(rm))
622 l.delete(ldb.Dn(l, "dc=modify2"))
624 def test_modify_flags_change(self):
625 l = ldb.Ldb(self.url(), flags=self.flags())
627 m.dn = ldb.Dn(l, "dc=add")
629 m["objectUUID"] = b"0123456789abcdef"
633 m.dn = ldb.Dn(l, "dc=add")
634 m["bla"] = ldb.MessageElement([b"456"], ldb.FLAG_MOD_ADD, "bla")
635 self.assertEqual(ldb.FLAG_MOD_ADD, m["bla"].flags())
637 rm = l.search(m.dn)[0]
638 self.assertEqual(3, len(rm))
639 self.assertEqual([b"1234", b"456"], list(rm["bla"]))
641 # Now create another modify, but switch the flags before we do it
642 m["bla"] = ldb.MessageElement([b"456"], ldb.FLAG_MOD_ADD, "bla")
643 m["bla"].set_flags(ldb.FLAG_MOD_DELETE)
645 rm = l.search(m.dn, attrs=["bla"])[0]
646 self.assertEqual(1, len(rm))
647 self.assertEqual([b"1234"], list(rm["bla"]))
649 l.delete(ldb.Dn(l, "dc=add"))
651 def test_modify_flags_change_text(self):
652 l = ldb.Ldb(self.url(), flags=self.flags())
654 m.dn = ldb.Dn(l, "dc=add")
655 m.text["bla"] = ["1234"]
656 m["objectUUID"] = b"0123456789abcdef"
660 m.dn = ldb.Dn(l, "dc=add")
661 m["bla"] = ldb.MessageElement(["456"], ldb.FLAG_MOD_ADD, "bla")
662 self.assertEqual(ldb.FLAG_MOD_ADD, m["bla"].flags())
664 rm = l.search(m.dn)[0]
665 self.assertEqual(3, len(rm))
666 self.assertEqual(["1234", "456"], list(rm.text["bla"]))
668 # Now create another modify, but switch the flags before we do it
669 m["bla"] = ldb.MessageElement(["456"], ldb.FLAG_MOD_ADD, "bla")
670 m["bla"].set_flags(ldb.FLAG_MOD_DELETE)
672 rm = l.search(m.dn, attrs=["bla"])[0]
673 self.assertEqual(1, len(rm))
674 self.assertEqual(["1234"], list(rm.text["bla"]))
676 l.delete(ldb.Dn(l, "dc=add"))
678 def test_transaction_commit(self):
679 l = ldb.Ldb(self.url(), flags=self.flags())
680 l.transaction_start()
681 m = ldb.Message(ldb.Dn(l, "dc=foo9"))
683 m["objectUUID"] = b"0123456789abcdef"
685 l.transaction_commit()
688 def test_transaction_cancel(self):
689 l = ldb.Ldb(self.url(), flags=self.flags())
690 l.transaction_start()
691 m = ldb.Message(ldb.Dn(l, "dc=foo10"))
693 m["objectUUID"] = b"0123456789abcdee"
695 l.transaction_cancel()
696 self.assertEqual(0, len(l.search(ldb.Dn(l, "dc=foo10"))))
698 def test_set_debug(self):
699 def my_report_fn(level, text):
701 l = ldb.Ldb(self.url(), flags=self.flags())
702 l.set_debug(my_report_fn)
704 def test_zero_byte_string(self):
705 """Testing we do not get trapped in the \0 byte in a property string."""
706 l = ldb.Ldb(self.url(), flags=self.flags())
709 "objectclass": b"user",
710 "cN": b"LDAPtestUSER",
711 "givenname": b"ldap",
712 "displayname": b"foo\0bar",
713 "objectUUID": b"0123456789abcdef"
715 res = l.search(expression="(dn=dc=somedn)")
716 self.assertEqual(b"foo\0bar", res[0]["displayname"][0])
718 def test_no_crash_broken_expr(self):
719 l = ldb.Ldb(self.url(), flags=self.flags())
720 self.assertRaises(ldb.LdbError, lambda: l.search("", ldb.SCOPE_SUBTREE, "&(dc=*)(dn=*)", ["dc"]))
722 # Run the SimpleLdb tests against an lmdb backend
725 class SimpleLdbLmdb(SimpleLdb):
728 if os.environ.get('HAVE_LMDB', '1') == '0':
729 self.skipTest("No lmdb backend")
730 self.prefix = MDB_PREFIX
731 self.index = MDB_INDEX_OBJ
732 super(SimpleLdbLmdb, self).setUp()
735 super(SimpleLdbLmdb, self).tearDown()
738 class SimpleLdbNoLmdb(LdbBaseTest):
741 if os.environ.get('HAVE_LMDB', '1') != '0':
742 self.skipTest("lmdb backend enabled")
743 self.prefix = MDB_PREFIX
744 self.index = MDB_INDEX_OBJ
745 super(SimpleLdbNoLmdb, self).setUp()
748 super(SimpleLdbNoLmdb, self).tearDown()
750 def test_lmdb_disabled(self):
751 self.testdir = tempdir()
752 self.filename = os.path.join(self.testdir, "test.ldb")
754 self.ldb = ldb.Ldb(self.url(), flags=self.flags())
755 self.fail("Should have failed on missing LMDB")
756 except ldb.LdbError as err:
758 self.assertEqual(enum, ldb.ERR_OTHER)
761 class SearchTests(LdbBaseTest):
763 shutil.rmtree(self.testdir)
764 super(SearchTests, self).tearDown()
766 # Ensure the LDB is closed now, so we close the FD
770 super(SearchTests, self).setUp()
771 self.testdir = tempdir()
772 self.filename = os.path.join(self.testdir, "search_test.ldb")
773 options = ["modules:rdn_name"]
774 if hasattr(self, 'IDXCHECK'):
775 options.append("disable_full_db_scan_for_self_test:1")
776 self.l = ldb.Ldb(self.url(),
780 self.l.add(self.index)
781 except AttributeError:
784 self.l.add({"dn": "@ATTRIBUTES",
785 "DC": "CASE_INSENSITIVE"})
787 # Note that we can't use the name objectGUID here, as we
788 # want to stay clear of the objectGUID handler in LDB and
789 # instead use just the 16 bytes raw, which we just keep
790 # to printable chars here for ease of handling.
792 self.l.add({"dn": "DC=ORG",
794 "objectUUID": b"0000000000abcdef"})
795 self.l.add({"dn": "DC=EXAMPLE,DC=ORG",
797 "objectUUID": b"0000000001abcdef"})
798 self.l.add({"dn": "OU=OU1,DC=EXAMPLE,DC=ORG",
801 "objectUUID": b"0023456789abcde3"})
802 self.l.add({"dn": "OU=OU2,DC=EXAMPLE,DC=ORG",
805 "objectUUID": b"0023456789abcde4"})
806 self.l.add({"dn": "OU=OU3,DC=EXAMPLE,DC=ORG",
809 "objectUUID": b"0023456789abcde5"})
810 self.l.add({"dn": "OU=OU4,DC=EXAMPLE,DC=ORG",
813 "objectUUID": b"0023456789abcde6"})
814 self.l.add({"dn": "OU=OU5,DC=EXAMPLE,DC=ORG",
817 "objectUUID": b"0023456789abcde7"})
818 self.l.add({"dn": "OU=OU6,DC=EXAMPLE,DC=ORG",
821 "objectUUID": b"0023456789abcde8"})
822 self.l.add({"dn": "OU=OU7,DC=EXAMPLE,DC=ORG",
825 "objectUUID": b"0023456789abcde9"})
826 self.l.add({"dn": "OU=OU8,DC=EXAMPLE,DC=ORG",
829 "objectUUID": b"0023456789abcde0"})
830 self.l.add({"dn": "OU=OU9,DC=EXAMPLE,DC=ORG",
833 "objectUUID": b"0023456789abcdea"})
835 self.l.add({"dn": "DC=EXAMPLE,DC=COM",
837 "objectUUID": b"0000000011abcdef"})
839 self.l.add({"dn": "DC=EXAMPLE,DC=NET",
841 "objectUUID": b"0000000021abcdef"})
843 self.l.add({"dn": "OU=UNIQUE,DC=EXAMPLE,DC=NET",
844 "objectUUID": b"0000000022abcdef"})
846 self.l.add({"dn": "DC=SAMBA,DC=ORG",
847 "name": b"samba.org",
848 "objectUUID": b"0123456789abcdef"})
849 self.l.add({"dn": "OU=ADMIN,DC=SAMBA,DC=ORG",
852 "objectUUID": b"0123456789abcde1"})
853 self.l.add({"dn": "OU=USERS,DC=SAMBA,DC=ORG",
856 "objectUUID": b"0123456789abcde2"})
857 self.l.add({"dn": "OU=OU1,DC=SAMBA,DC=ORG",
860 "objectUUID": b"0123456789abcde3"})
861 self.l.add({"dn": "OU=OU2,DC=SAMBA,DC=ORG",
864 "objectUUID": b"0123456789abcde4"})
865 self.l.add({"dn": "OU=OU3,DC=SAMBA,DC=ORG",
868 "objectUUID": b"0123456789abcde5"})
869 self.l.add({"dn": "OU=OU4,DC=SAMBA,DC=ORG",
872 "objectUUID": b"0123456789abcde6"})
873 self.l.add({"dn": "OU=OU5,DC=SAMBA,DC=ORG",
876 "objectUUID": b"0123456789abcde7"})
877 self.l.add({"dn": "OU=OU6,DC=SAMBA,DC=ORG",
880 "objectUUID": b"0123456789abcde8"})
881 self.l.add({"dn": "OU=OU7,DC=SAMBA,DC=ORG",
884 "objectUUID": b"0123456789abcde9"})
885 self.l.add({"dn": "OU=OU8,DC=SAMBA,DC=ORG",
888 "objectUUID": b"0123456789abcde0"})
889 self.l.add({"dn": "OU=OU9,DC=SAMBA,DC=ORG",
892 "objectUUID": b"0123456789abcdea"})
893 self.l.add({"dn": "OU=OU10,DC=SAMBA,DC=ORG",
896 "objectUUID": b"0123456789abcdeb"})
897 self.l.add({"dn": "OU=OU11,DC=SAMBA,DC=ORG",
900 "objectUUID": b"0123456789abcdec"})
901 self.l.add({"dn": "OU=OU12,DC=SAMBA,DC=ORG",
904 "objectUUID": b"0123456789abcded"})
905 self.l.add({"dn": "OU=OU13,DC=SAMBA,DC=ORG",
908 "objectUUID": b"0123456789abcdee"})
909 self.l.add({"dn": "OU=OU14,DC=SAMBA,DC=ORG",
912 "objectUUID": b"0123456789abcd01"})
913 self.l.add({"dn": "OU=OU15,DC=SAMBA,DC=ORG",
916 "objectUUID": b"0123456789abcd02"})
917 self.l.add({"dn": "OU=OU16,DC=SAMBA,DC=ORG",
920 "objectUUID": b"0123456789abcd03"})
921 self.l.add({"dn": "OU=OU17,DC=SAMBA,DC=ORG",
924 "objectUUID": b"0123456789abcd04"})
925 self.l.add({"dn": "OU=OU18,DC=SAMBA,DC=ORG",
928 "objectUUID": b"0123456789abcd05"})
929 self.l.add({"dn": "OU=OU19,DC=SAMBA,DC=ORG",
932 "objectUUID": b"0123456789abcd06"})
933 self.l.add({"dn": "OU=OU20,DC=SAMBA,DC=ORG",
936 "objectUUID": b"0123456789abcd07"})
937 self.l.add({"dn": "OU=OU21,DC=SAMBA,DC=ORG",
940 "objectUUID": b"0123456789abcd08"})
941 self.l.add({"dn": "OU=OU22,DC=SAMBA,DC=ORG",
944 "objectUUID": b"0123456789abcd09"})
947 """Testing a search"""
949 res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
950 scope=ldb.SCOPE_BASE)
951 self.assertEqual(len(res11), 1)
953 def test_base_lower(self):
954 """Testing a search"""
956 res11 = self.l.search(base="OU=OU11,DC=samba,DC=org",
957 scope=ldb.SCOPE_BASE)
958 self.assertEqual(len(res11), 1)
960 def test_base_or(self):
961 """Testing a search"""
963 res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
964 scope=ldb.SCOPE_BASE,
965 expression="(|(ou=ou11)(ou=ou12))")
966 self.assertEqual(len(res11), 1)
968 def test_base_or2(self):
969 """Testing a search"""
971 res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
972 scope=ldb.SCOPE_BASE,
973 expression="(|(x=y)(y=b))")
974 self.assertEqual(len(res11), 1)
976 def test_base_and(self):
977 """Testing a search"""
979 res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
980 scope=ldb.SCOPE_BASE,
981 expression="(&(ou=ou11)(ou=ou12))")
982 self.assertEqual(len(res11), 0)
984 def test_base_and2(self):
985 """Testing a search"""
987 res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
988 scope=ldb.SCOPE_BASE,
989 expression="(&(x=y)(y=a))")
990 self.assertEqual(len(res11), 1)
992 def test_base_false(self):
993 """Testing a search"""
995 res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
996 scope=ldb.SCOPE_BASE,
997 expression="(|(ou=ou13)(ou=ou12))")
998 self.assertEqual(len(res11), 0)
1000 def test_check_base_false(self):
1001 """Testing a search"""
1002 res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
1003 scope=ldb.SCOPE_BASE,
1004 expression="(|(ou=ou13)(ou=ou12))")
1005 self.assertEqual(len(res11), 0)
1007 def test_check_base_error(self):
1008 """Testing a search"""
1009 checkbaseonsearch = {"dn": "@OPTIONS",
1010 "checkBaseOnSearch": b"TRUE"}
1012 self.l.add(checkbaseonsearch)
1013 except ldb.LdbError as err:
1015 self.assertEqual(enum, ldb.ERR_ENTRY_ALREADY_EXISTS)
1016 m = ldb.Message.from_dict(self.l,
1021 res11 = self.l.search(base="OU=OU11x,DC=SAMBA,DC=ORG",
1022 scope=ldb.SCOPE_BASE,
1023 expression="(|(ou=ou13)(ou=ou12))")
1024 self.fail("Should have failed on missing base")
1025 except ldb.LdbError as err:
1027 self.assertEqual(enum, ldb.ERR_NO_SUCH_OBJECT)
1029 def test_subtree(self):
1030 """Testing a search"""
1033 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1034 scope=ldb.SCOPE_SUBTREE)
1035 if hasattr(self, 'IDXCHECK'):
1037 except ldb.LdbError as err:
1040 self.assertEqual(enum, ldb.ERR_INAPPROPRIATE_MATCHING)
1041 self.assertIn(estr, "ldb FULL SEARCH disabled")
1043 self.assertEqual(len(res11), 25)
1045 def test_subtree2(self):
1046 """Testing a search"""
1049 res11 = self.l.search(base="DC=ORG",
1050 scope=ldb.SCOPE_SUBTREE)
1051 if hasattr(self, 'IDXCHECK'):
1053 except ldb.LdbError as err:
1056 self.assertEqual(enum, ldb.ERR_INAPPROPRIATE_MATCHING)
1057 self.assertIn(estr, "ldb FULL SEARCH disabled")
1059 self.assertEqual(len(res11), 36)
1061 def test_subtree_and(self):
1062 """Testing a search"""
1064 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1065 scope=ldb.SCOPE_SUBTREE,
1066 expression="(&(ou=ou11)(ou=ou12))")
1067 self.assertEqual(len(res11), 0)
1069 def test_subtree_and2(self):
1070 """Testing a search"""
1072 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1073 scope=ldb.SCOPE_SUBTREE,
1074 expression="(&(x=y)(|(y=b)(y=c)))")
1075 self.assertEqual(len(res11), 1)
1077 def test_subtree_and2_lower(self):
1078 """Testing a search"""
1080 res11 = self.l.search(base="DC=samba,DC=org",
1081 scope=ldb.SCOPE_SUBTREE,
1082 expression="(&(x=y)(|(y=b)(y=c)))")
1083 self.assertEqual(len(res11), 1)
1085 def test_subtree_or(self):
1086 """Testing a search"""
1088 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1089 scope=ldb.SCOPE_SUBTREE,
1090 expression="(|(ou=ou11)(ou=ou12))")
1091 self.assertEqual(len(res11), 2)
1093 def test_subtree_or2(self):
1094 """Testing a search"""
1096 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1097 scope=ldb.SCOPE_SUBTREE,
1098 expression="(|(x=y)(y=b))")
1099 self.assertEqual(len(res11), 20)
1101 def test_subtree_or3(self):
1102 """Testing a search"""
1104 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1105 scope=ldb.SCOPE_SUBTREE,
1106 expression="(|(x=y)(y=b)(y=c))")
1107 self.assertEqual(len(res11), 22)
1109 def test_one_and(self):
1110 """Testing a search"""
1112 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1113 scope=ldb.SCOPE_ONELEVEL,
1114 expression="(&(ou=ou11)(ou=ou12))")
1115 self.assertEqual(len(res11), 0)
1117 def test_one_and2(self):
1118 """Testing a search"""
1120 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1121 scope=ldb.SCOPE_ONELEVEL,
1122 expression="(&(x=y)(y=b))")
1123 self.assertEqual(len(res11), 1)
1125 def test_one_or(self):
1126 """Testing a search"""
1128 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1129 scope=ldb.SCOPE_ONELEVEL,
1130 expression="(|(ou=ou11)(ou=ou12))")
1131 self.assertEqual(len(res11), 2)
1133 def test_one_or2(self):
1134 """Testing a search"""
1136 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1137 scope=ldb.SCOPE_ONELEVEL,
1138 expression="(|(x=y)(y=b))")
1139 self.assertEqual(len(res11), 20)
1141 def test_one_or2_lower(self):
1142 """Testing a search"""
1144 res11 = self.l.search(base="DC=samba,DC=org",
1145 scope=ldb.SCOPE_ONELEVEL,
1146 expression="(|(x=y)(y=b))")
1147 self.assertEqual(len(res11), 20)
1149 def test_one_unindexable(self):
1150 """Testing a search"""
1153 res11 = self.l.search(base="DC=samba,DC=org",
1154 scope=ldb.SCOPE_ONELEVEL,
1155 expression="(y=b*)")
1156 if hasattr(self, 'IDX') and \
1157 not hasattr(self, 'IDXONE') and \
1158 hasattr(self, 'IDXCHECK'):
1159 self.fail("Should have failed as un-indexed search")
1161 self.assertEqual(len(res11), 9)
1163 except ldb.LdbError as err:
1166 self.assertEqual(enum, ldb.ERR_INAPPROPRIATE_MATCHING)
1167 self.assertIn(estr, "ldb FULL SEARCH disabled")
1169 def test_one_unindexable_presence(self):
1170 """Testing a search"""
1173 res11 = self.l.search(base="DC=samba,DC=org",
1174 scope=ldb.SCOPE_ONELEVEL,
1176 if hasattr(self, 'IDX') and \
1177 not hasattr(self, 'IDXONE') and \
1178 hasattr(self, 'IDXCHECK'):
1179 self.fail("Should have failed as un-indexed search")
1181 self.assertEqual(len(res11), 24)
1183 except ldb.LdbError as err:
1186 self.assertEqual(enum, ldb.ERR_INAPPROPRIATE_MATCHING)
1187 self.assertIn(estr, "ldb FULL SEARCH disabled")
1189 def test_subtree_and_or(self):
1190 """Testing a search"""
1192 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1193 scope=ldb.SCOPE_SUBTREE,
1194 expression="(&(|(x=z)(y=b))(x=x)(y=c))")
1195 self.assertEqual(len(res11), 0)
1197 def test_subtree_and_or2(self):
1198 """Testing a search"""
1200 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1201 scope=ldb.SCOPE_SUBTREE,
1202 expression="(&(x=x)(y=c)(|(x=z)(y=b)))")
1203 self.assertEqual(len(res11), 0)
1205 def test_subtree_and_or3(self):
1206 """Testing a search"""
1208 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1209 scope=ldb.SCOPE_SUBTREE,
1210 expression="(&(|(ou=ou11)(ou=ou10))(|(x=y)(y=b)(y=c)))")
1211 self.assertEqual(len(res11), 2)
1213 def test_subtree_and_or4(self):
1214 """Testing a search"""
1216 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1217 scope=ldb.SCOPE_SUBTREE,
1218 expression="(&(|(x=y)(y=b)(y=c))(|(ou=ou11)(ou=ou10)))")
1219 self.assertEqual(len(res11), 2)
1221 def test_subtree_and_or5(self):
1222 """Testing a search"""
1224 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1225 scope=ldb.SCOPE_SUBTREE,
1226 expression="(&(|(x=y)(y=b)(y=c))(ou=ou11))")
1227 self.assertEqual(len(res11), 1)
1229 def test_subtree_or_and(self):
1230 """Testing a search"""
1232 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1233 scope=ldb.SCOPE_SUBTREE,
1234 expression="(|(x=x)(y=c)(&(x=z)(y=b)))")
1235 self.assertEqual(len(res11), 10)
1237 def test_subtree_large_and_unique(self):
1238 """Testing a search"""
1240 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1241 scope=ldb.SCOPE_SUBTREE,
1242 expression="(&(ou=ou10)(y=a))")
1243 self.assertEqual(len(res11), 1)
1245 def test_subtree_unique(self):
1246 """Testing a search"""
1248 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1249 scope=ldb.SCOPE_SUBTREE,
1250 expression="(ou=ou10)")
1251 self.assertEqual(len(res11), 1)
1253 def test_subtree_unique_elsewhere(self):
1254 """Testing a search"""
1256 res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
1257 scope=ldb.SCOPE_SUBTREE,
1258 expression="(ou=ou10)")
1259 self.assertEqual(len(res11), 0)
1261 def test_subtree_unique_elsewhere2(self):
1262 """Testing a search"""
1264 res11 = self.l.search(base="DC=EXAMPLE,DC=NET",
1265 scope=ldb.SCOPE_SUBTREE,
1266 expression="(ou=unique)")
1267 self.assertEqual(len(res11), 1)
1269 def test_subtree_unique_elsewhere3(self):
1270 """Testing a search"""
1272 res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
1273 scope=ldb.SCOPE_SUBTREE,
1274 expression="(ou=unique)")
1275 self.assertEqual(len(res11), 0)
1277 def test_subtree_unique_elsewhere4(self):
1278 """Testing a search"""
1280 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1281 scope=ldb.SCOPE_SUBTREE,
1282 expression="(ou=unique)")
1283 self.assertEqual(len(res11), 0)
1285 def test_subtree_unique_elsewhere5(self):
1286 """Testing a search"""
1288 res11 = self.l.search(base="DC=EXAMPLE,DC=COM",
1289 scope=ldb.SCOPE_SUBTREE,
1290 expression="(ou=unique)")
1291 self.assertEqual(len(res11), 0)
1293 def test_subtree_unique_elsewhere6(self):
1294 """Testing a search"""
1296 res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
1297 scope=ldb.SCOPE_SUBTREE,
1298 expression="(ou=unique)")
1299 self.assertEqual(len(res11), 0)
1301 def test_subtree_unique_elsewhere7(self):
1302 """Testing a search"""
1304 res11 = self.l.search(base="DC=EXAMPLE,DC=COM",
1305 scope=ldb.SCOPE_SUBTREE,
1306 expression="(ou=ou10)")
1307 self.assertEqual(len(res11), 0)
1309 def test_subtree_unique_here(self):
1310 """Testing a search"""
1312 res11 = self.l.search(base="OU=UNIQUE,DC=EXAMPLE,DC=NET",
1313 scope=ldb.SCOPE_SUBTREE,
1314 expression="(ou=unique)")
1315 self.assertEqual(len(res11), 1)
1317 def test_subtree_and_none(self):
1318 """Testing a search"""
1320 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1321 scope=ldb.SCOPE_SUBTREE,
1322 expression="(&(ou=ouX)(y=a))")
1323 self.assertEqual(len(res11), 0)
1325 def test_subtree_and_idx_record(self):
1326 """Testing a search against the index record"""
1328 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1329 scope=ldb.SCOPE_SUBTREE,
1330 expression="(@IDXDN=DC=SAMBA,DC=ORG)")
1331 self.assertEqual(len(res11), 0)
1333 def test_subtree_and_idxone_record(self):
1334 """Testing a search against the index record"""
1336 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1337 scope=ldb.SCOPE_SUBTREE,
1338 expression="(@IDXONE=DC=SAMBA,DC=ORG)")
1339 self.assertEqual(len(res11), 0)
1341 def test_onelevel(self):
1342 """Testing a search"""
1345 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1346 scope=ldb.SCOPE_ONELEVEL)
1347 if hasattr(self, 'IDXCHECK') \
1348 and not hasattr(self, 'IDXONE'):
1350 except ldb.LdbError as err:
1353 self.assertEqual(enum, ldb.ERR_INAPPROPRIATE_MATCHING)
1354 self.assertIn(estr, "ldb FULL SEARCH disabled")
1356 self.assertEqual(len(res11), 24)
1358 def test_onelevel2(self):
1359 """Testing a search"""
1362 res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
1363 scope=ldb.SCOPE_ONELEVEL)
1364 if hasattr(self, 'IDXCHECK') \
1365 and not hasattr(self, 'IDXONE'):
1368 except ldb.LdbError as err:
1371 self.assertEqual(enum, ldb.ERR_INAPPROPRIATE_MATCHING)
1372 self.assertIn(estr, "ldb FULL SEARCH disabled")
1374 self.assertEqual(len(res11), 9)
1376 def test_onelevel_and_or(self):
1377 """Testing a search"""
1379 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1380 scope=ldb.SCOPE_ONELEVEL,
1381 expression="(&(|(x=z)(y=b))(x=x)(y=c))")
1382 self.assertEqual(len(res11), 0)
1384 def test_onelevel_and_or2(self):
1385 """Testing a search"""
1387 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1388 scope=ldb.SCOPE_ONELEVEL,
1389 expression="(&(x=x)(y=c)(|(x=z)(y=b)))")
1390 self.assertEqual(len(res11), 0)
1392 def test_onelevel_and_or3(self):
1393 """Testing a search"""
1395 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1396 scope=ldb.SCOPE_ONELEVEL,
1397 expression="(&(|(ou=ou11)(ou=ou10))(|(x=y)(y=b)(y=c)))")
1398 self.assertEqual(len(res11), 2)
1400 def test_onelevel_and_or4(self):
1401 """Testing a search"""
1403 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1404 scope=ldb.SCOPE_ONELEVEL,
1405 expression="(&(|(x=y)(y=b)(y=c))(|(ou=ou11)(ou=ou10)))")
1406 self.assertEqual(len(res11), 2)
1408 def test_onelevel_and_or5(self):
1409 """Testing a search"""
1411 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1412 scope=ldb.SCOPE_ONELEVEL,
1413 expression="(&(|(x=y)(y=b)(y=c))(ou=ou11))")
1414 self.assertEqual(len(res11), 1)
1416 def test_onelevel_or_and(self):
1417 """Testing a search"""
1419 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1420 scope=ldb.SCOPE_ONELEVEL,
1421 expression="(|(x=x)(y=c)(&(x=z)(y=b)))")
1422 self.assertEqual(len(res11), 10)
1424 def test_onelevel_large_and_unique(self):
1425 """Testing a search"""
1427 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1428 scope=ldb.SCOPE_ONELEVEL,
1429 expression="(&(ou=ou10)(y=a))")
1430 self.assertEqual(len(res11), 1)
1432 def test_onelevel_unique(self):
1433 """Testing a search"""
1435 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1436 scope=ldb.SCOPE_ONELEVEL,
1437 expression="(ou=ou10)")
1438 self.assertEqual(len(res11), 1)
1440 def test_onelevel_unique_elsewhere(self):
1441 """Testing a search"""
1443 res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
1444 scope=ldb.SCOPE_ONELEVEL,
1445 expression="(ou=ou10)")
1446 self.assertEqual(len(res11), 0)
1448 def test_onelevel_unique_elsewhere2(self):
1449 """Testing a search (showing that onelevel is not subtree)"""
1451 res11 = self.l.search(base="DC=EXAMPLE,DC=NET",
1452 scope=ldb.SCOPE_ONELEVEL,
1453 expression="(ou=unique)")
1454 self.assertEqual(len(res11), 1)
1456 def test_onelevel_unique_elsewhere3(self):
1457 """Testing a search (showing that onelevel is not subtree)"""
1459 res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
1460 scope=ldb.SCOPE_ONELEVEL,
1461 expression="(ou=unique)")
1462 self.assertEqual(len(res11), 0)
1464 def test_onelevel_unique_elsewhere4(self):
1465 """Testing a search (showing that onelevel is not subtree)"""
1467 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1468 scope=ldb.SCOPE_ONELEVEL,
1469 expression="(ou=unique)")
1470 self.assertEqual(len(res11), 0)
1472 def test_onelevel_unique_elsewhere5(self):
1473 """Testing a search (showing that onelevel is not subtree)"""
1475 res11 = self.l.search(base="DC=EXAMPLE,DC=COM",
1476 scope=ldb.SCOPE_ONELEVEL,
1477 expression="(ou=unique)")
1478 self.assertEqual(len(res11), 0)
1480 def test_onelevel_unique_elsewhere6(self):
1481 """Testing a search"""
1483 res11 = self.l.search(base="DC=EXAMPLE,DC=COM",
1484 scope=ldb.SCOPE_ONELEVEL,
1485 expression="(ou=ou10)")
1486 self.assertEqual(len(res11), 0)
1488 def test_onelevel_unique_here(self):
1489 """Testing a search"""
1491 res11 = self.l.search(base="OU=UNIQUE,DC=EXAMPLE,DC=NET",
1492 scope=ldb.SCOPE_ONELEVEL,
1493 expression="(ou=unique)")
1494 self.assertEqual(len(res11), 0)
1496 def test_onelevel_and_none(self):
1497 """Testing a search"""
1499 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1500 scope=ldb.SCOPE_ONELEVEL,
1501 expression="(&(ou=ouX)(y=a))")
1502 self.assertEqual(len(res11), 0)
1504 def test_onelevel_and_idx_record(self):
1505 """Testing a search against the index record"""
1507 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1508 scope=ldb.SCOPE_ONELEVEL,
1509 expression="(@IDXDN=DC=SAMBA,DC=ORG)")
1510 self.assertEqual(len(res11), 0)
1512 def test_onelevel_and_idxone_record(self):
1513 """Testing a search against the index record"""
1515 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1516 scope=ldb.SCOPE_ONELEVEL,
1517 expression="(@IDXONE=DC=SAMBA,DC=ORG)")
1518 self.assertEqual(len(res11), 0)
1520 def test_subtree_unindexable(self):
1521 """Testing a search"""
1524 res11 = self.l.search(base="DC=samba,DC=org",
1525 scope=ldb.SCOPE_SUBTREE,
1526 expression="(y=b*)")
1527 if hasattr(self, 'IDX') and \
1528 hasattr(self, 'IDXCHECK'):
1529 self.fail("Should have failed as un-indexed search")
1531 self.assertEqual(len(res11), 9)
1533 except ldb.LdbError as err:
1536 self.assertEqual(enum, ldb.ERR_INAPPROPRIATE_MATCHING)
1537 self.assertIn(estr, "ldb FULL SEARCH disabled")
1539 def test_onelevel_only_and_or(self):
1540 """Testing a search (showing that onelevel is not subtree)"""
1542 res11 = self.l.search(base="DC=ORG",
1543 scope=ldb.SCOPE_ONELEVEL,
1544 expression="(&(|(x=z)(y=b))(x=x)(y=c))")
1545 self.assertEqual(len(res11), 0)
1547 def test_onelevel_only_and_or2(self):
1548 """Testing a search (showing that onelevel is not subtree)"""
1550 res11 = self.l.search(base="DC=ORG",
1551 scope=ldb.SCOPE_ONELEVEL,
1552 expression="(&(x=x)(y=c)(|(x=z)(y=b)))")
1553 self.assertEqual(len(res11), 0)
1555 def test_onelevel_only_and_or3(self):
1556 """Testing a search (showing that onelevel is not subtree)"""
1558 res11 = self.l.search(base="DC=ORG",
1559 scope=ldb.SCOPE_ONELEVEL,
1560 expression="(&(|(ou=ou11)(ou=ou10))(|(x=y)(y=b)(y=c)))")
1561 self.assertEqual(len(res11), 0)
1563 def test_onelevel_only_and_or4(self):
1564 """Testing a search (showing that onelevel is not subtree)"""
1566 res11 = self.l.search(base="DC=ORG",
1567 scope=ldb.SCOPE_ONELEVEL,
1568 expression="(&(|(x=y)(y=b)(y=c))(|(ou=ou11)(ou=ou10)))")
1569 self.assertEqual(len(res11), 0)
1571 def test_onelevel_only_and_or5(self):
1572 """Testing a search (showing that onelevel is not subtree)"""
1574 res11 = self.l.search(base="DC=ORG",
1575 scope=ldb.SCOPE_ONELEVEL,
1576 expression="(&(|(x=y)(y=b)(y=c))(ou=ou11))")
1577 self.assertEqual(len(res11), 0)
1579 def test_onelevel_only_or_and(self):
1580 """Testing a search (showing that onelevel is not subtree)"""
1582 res11 = self.l.search(base="DC=ORG",
1583 scope=ldb.SCOPE_ONELEVEL,
1584 expression="(|(x=x)(y=c)(&(x=z)(y=b)))")
1585 self.assertEqual(len(res11), 0)
1587 def test_onelevel_only_large_and_unique(self):
1588 """Testing a search (showing that onelevel is not subtree)"""
1590 res11 = self.l.search(base="DC=ORG",
1591 scope=ldb.SCOPE_ONELEVEL,
1592 expression="(&(ou=ou10)(y=a))")
1593 self.assertEqual(len(res11), 0)
1595 def test_onelevel_only_unique(self):
1596 """Testing a search (showing that onelevel is not subtree)"""
1598 res11 = self.l.search(base="DC=ORG",
1599 scope=ldb.SCOPE_ONELEVEL,
1600 expression="(ou=ou10)")
1601 self.assertEqual(len(res11), 0)
1603 def test_onelevel_only_unique2(self):
1604 """Testing a search"""
1606 res11 = self.l.search(base="DC=ORG",
1607 scope=ldb.SCOPE_ONELEVEL,
1608 expression="(ou=unique)")
1609 self.assertEqual(len(res11), 0)
1611 def test_onelevel_only_and_none(self):
1612 """Testing a search (showing that onelevel is not subtree)"""
1614 res11 = self.l.search(base="DC=ORG",
1615 scope=ldb.SCOPE_ONELEVEL,
1616 expression="(&(ou=ouX)(y=a))")
1617 self.assertEqual(len(res11), 0)
1619 def test_onelevel_small_and_or(self):
1620 """Testing a search (showing that onelevel is not subtree)"""
1622 res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
1623 scope=ldb.SCOPE_ONELEVEL,
1624 expression="(&(|(x=z)(y=b))(x=x)(y=c))")
1625 self.assertEqual(len(res11), 0)
1627 def test_onelevel_small_and_or2(self):
1628 """Testing a search (showing that onelevel is not subtree)"""
1630 res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
1631 scope=ldb.SCOPE_ONELEVEL,
1632 expression="(&(x=x)(y=c)(|(x=z)(y=b)))")
1633 self.assertEqual(len(res11), 0)
1635 def test_onelevel_small_and_or3(self):
1636 """Testing a search (showing that onelevel is not subtree)"""
1638 res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
1639 scope=ldb.SCOPE_ONELEVEL,
1640 expression="(&(|(ou=ou1)(ou=ou2))(|(x=y)(y=b)(y=c)))")
1641 self.assertEqual(len(res11), 2)
1643 def test_onelevel_small_and_or4(self):
1644 """Testing a search (showing that onelevel is not subtree)"""
1646 res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
1647 scope=ldb.SCOPE_ONELEVEL,
1648 expression="(&(|(x=y)(y=b)(y=c))(|(ou=ou1)(ou=ou2)))")
1649 self.assertEqual(len(res11), 2)
1651 def test_onelevel_small_and_or5(self):
1652 """Testing a search (showing that onelevel is not subtree)"""
1654 res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
1655 scope=ldb.SCOPE_ONELEVEL,
1656 expression="(&(|(x=y)(y=b)(y=c))(ou=ou1))")
1657 self.assertEqual(len(res11), 1)
1659 def test_onelevel_small_or_and(self):
1660 """Testing a search (showing that onelevel is not subtree)"""
1662 res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
1663 scope=ldb.SCOPE_ONELEVEL,
1664 expression="(|(x=x)(y=c)(&(x=z)(y=b)))")
1665 self.assertEqual(len(res11), 2)
1667 def test_onelevel_small_large_and_unique(self):
1668 """Testing a search (showing that onelevel is not subtree)"""
1670 res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
1671 scope=ldb.SCOPE_ONELEVEL,
1672 expression="(&(ou=ou9)(y=a))")
1673 self.assertEqual(len(res11), 1)
1675 def test_onelevel_small_unique_elsewhere(self):
1676 """Testing a search (showing that onelevel is not subtree)"""
1678 res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
1679 scope=ldb.SCOPE_ONELEVEL,
1680 expression="(ou=ou10)")
1681 self.assertEqual(len(res11), 0)
1683 def test_onelevel_small_and_none(self):
1684 """Testing a search (showing that onelevel is not subtree)"""
1686 res11 = self.l.search(base="DC=EXAMPLE,DC=ORG",
1687 scope=ldb.SCOPE_ONELEVEL,
1688 expression="(&(ou=ouX)(y=a))")
1689 self.assertEqual(len(res11), 0)
1691 def test_subtree_unindexable_presence(self):
1692 """Testing a search"""
1695 res11 = self.l.search(base="DC=samba,DC=org",
1696 scope=ldb.SCOPE_SUBTREE,
1698 if hasattr(self, 'IDX') and \
1699 hasattr(self, 'IDXCHECK'):
1700 self.fail("Should have failed as un-indexed search")
1702 self.assertEqual(len(res11), 24)
1704 except ldb.LdbError as err:
1707 self.assertEqual(enum, ldb.ERR_INAPPROPRIATE_MATCHING)
1708 self.assertIn(estr, "ldb FULL SEARCH disabled")
1710 def test_dn_filter_one(self):
1711 """Testing that a dn= filter succeeds
1712 (or fails with disallowDNFilter
1713 set and IDXGUID or (IDX and not IDXONE) mode)
1714 when the scope is SCOPE_ONELEVEL.
1716 This should be made more consistent, but for now lock in
1721 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1722 scope=ldb.SCOPE_ONELEVEL,
1723 expression="(dn=OU=OU1,DC=SAMBA,DC=ORG)")
1724 if hasattr(self, 'disallowDNFilter') and \
1725 hasattr(self, 'IDX') and \
1726 (hasattr(self, 'IDXGUID') or
1727 ((not hasattr(self, 'IDXONE') and hasattr(self, 'IDX')))):
1728 self.assertEqual(len(res11), 0)
1730 self.assertEqual(len(res11), 1)
1732 def test_dn_filter_subtree(self):
1733 """Testing that a dn= filter succeeds
1734 (or fails with disallowDNFilter set)
1735 when the scope is SCOPE_SUBTREE"""
1737 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1738 scope=ldb.SCOPE_SUBTREE,
1739 expression="(dn=OU=OU1,DC=SAMBA,DC=ORG)")
1740 if hasattr(self, 'disallowDNFilter') \
1741 and hasattr(self, 'IDX'):
1742 self.assertEqual(len(res11), 0)
1744 self.assertEqual(len(res11), 1)
1746 def test_dn_filter_base(self):
1747 """Testing that (incorrectly) a dn= filter works
1748 when the scope is SCOPE_BASE"""
1750 res11 = self.l.search(base="OU=OU1,DC=SAMBA,DC=ORG",
1751 scope=ldb.SCOPE_BASE,
1752 expression="(dn=OU=OU1,DC=SAMBA,DC=ORG)")
1754 # At some point we should fix this, but it isn't trivial
1755 self.assertEqual(len(res11), 1)
1757 def test_distinguishedName_filter_one(self):
1758 """Testing that a distinguishedName= filter succeeds
1759 when the scope is SCOPE_ONELEVEL.
1761 This should be made more consistent, but for now lock in
1766 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1767 scope=ldb.SCOPE_ONELEVEL,
1768 expression="(distinguishedName=OU=OU1,DC=SAMBA,DC=ORG)")
1769 self.assertEqual(len(res11), 1)
1771 def test_distinguishedName_filter_subtree(self):
1772 """Testing that a distinguishedName= filter succeeds
1773 when the scope is SCOPE_SUBTREE"""
1775 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1776 scope=ldb.SCOPE_SUBTREE,
1777 expression="(distinguishedName=OU=OU1,DC=SAMBA,DC=ORG)")
1778 self.assertEqual(len(res11), 1)
1780 def test_distinguishedName_filter_base(self):
1781 """Testing that (incorrectly) a distinguishedName= filter works
1782 when the scope is SCOPE_BASE"""
1784 res11 = self.l.search(base="OU=OU1,DC=SAMBA,DC=ORG",
1785 scope=ldb.SCOPE_BASE,
1786 expression="(distinguishedName=OU=OU1,DC=SAMBA,DC=ORG)")
1788 # At some point we should fix this, but it isn't trivial
1789 self.assertEqual(len(res11), 1)
1791 def test_bad_dn_filter_base(self):
1792 """Testing that a dn= filter on an invalid DN works
1793 when the scope is SCOPE_BASE but
1794 returns zero results"""
1796 res11 = self.l.search(base="OU=OU1,DC=SAMBA,DC=ORG",
1797 scope=ldb.SCOPE_BASE,
1798 expression="(dn=OU=OU1,DC=SAMBA,DCXXXX)")
1800 # At some point we should fix this, but it isn't trivial
1801 self.assertEqual(len(res11), 0)
1804 def test_bad_dn_filter_one(self):
1805 """Testing that a dn= filter succeeds but returns zero
1806 results when the DN is not valid on a SCOPE_ONELEVEL search
1810 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1811 scope=ldb.SCOPE_ONELEVEL,
1812 expression="(dn=OU=OU1,DC=SAMBA,DCXXXX)")
1813 self.assertEqual(len(res11), 0)
1815 def test_bad_dn_filter_subtree(self):
1816 """Testing that a dn= filter succeeds but returns zero
1817 results when the DN is not valid on a SCOPE_SUBTREE search
1821 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1822 scope=ldb.SCOPE_SUBTREE,
1823 expression="(dn=OU=OU1,DC=SAMBA,DCXXXX)")
1824 self.assertEqual(len(res11), 0)
1826 def test_bad_distinguishedName_filter_base(self):
1827 """Testing that a distinguishedName= filter on an invalid DN works
1828 when the scope is SCOPE_BASE but
1829 returns zero results"""
1831 res11 = self.l.search(base="OU=OU1,DC=SAMBA,DC=ORG",
1832 scope=ldb.SCOPE_BASE,
1833 expression="(distinguishedName=OU=OU1,DC=SAMBA,DCXXXX)")
1835 # At some point we should fix this, but it isn't trivial
1836 self.assertEqual(len(res11), 0)
1839 def test_bad_distinguishedName_filter_one(self):
1840 """Testing that a distinguishedName= filter succeeds but returns zero
1841 results when the DN is not valid on a SCOPE_ONELEVEL search
1845 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1846 scope=ldb.SCOPE_ONELEVEL,
1847 expression="(distinguishedName=OU=OU1,DC=SAMBA,DCXXXX)")
1848 self.assertEqual(len(res11), 0)
1850 def test_bad_distinguishedName_filter_subtree(self):
1851 """Testing that a distinguishedName= filter succeeds but returns zero
1852 results when the DN is not valid on a SCOPE_SUBTREE search
1856 res11 = self.l.search(base="DC=SAMBA,DC=ORG",
1857 scope=ldb.SCOPE_SUBTREE,
1858 expression="(distinguishedName=OU=OU1,DC=SAMBA,DCXXXX)")
1859 self.assertEqual(len(res11), 0)
1861 def test_bad_dn_search_base(self):
1862 """Testing with a bad base DN (SCOPE_BASE)"""
1865 res11 = self.l.search(base="OU=OU1,DC=SAMBA,DCXXX",
1866 scope=ldb.SCOPE_BASE)
1867 self.fail("Should have failed with ERR_INVALID_DN_SYNTAX")
1868 except ldb.LdbError as err:
1870 self.assertEqual(enum, ldb.ERR_INVALID_DN_SYNTAX)
1873 def test_bad_dn_search_one(self):
1874 """Testing with a bad base DN (SCOPE_ONELEVEL)"""
1877 res11 = self.l.search(base="DC=SAMBA,DCXXXX",
1878 scope=ldb.SCOPE_ONELEVEL)
1879 self.fail("Should have failed with ERR_INVALID_DN_SYNTAX")
1880 except ldb.LdbError as err:
1882 self.assertEqual(enum, ldb.ERR_INVALID_DN_SYNTAX)
1884 def test_bad_dn_search_subtree(self):
1885 """Testing with a bad base DN (SCOPE_SUBTREE)"""
1888 res11 = self.l.search(base="DC=SAMBA,DCXXXX",
1889 scope=ldb.SCOPE_SUBTREE)
1890 self.fail("Should have failed with ERR_INVALID_DN_SYNTAX")
1891 except ldb.LdbError as err:
1893 self.assertEqual(enum, ldb.ERR_INVALID_DN_SYNTAX)
1897 # Run the search tests against an lmdb backend
1898 class SearchTestsLmdb(SearchTests):
1901 if os.environ.get('HAVE_LMDB', '1') == '0':
1902 self.skipTest("No lmdb backend")
1903 self.prefix = MDB_PREFIX
1904 self.index = MDB_INDEX_OBJ
1905 super(SearchTestsLmdb, self).setUp()
1908 super(SearchTestsLmdb, self).tearDown()
1911 class IndexedSearchTests(SearchTests):
1912 """Test searches using the index, to ensure the index doesn't
1916 super(IndexedSearchTests, self).setUp()
1917 self.l.add({"dn": "@INDEXLIST",
1918 "@IDXATTR": [b"x", b"y", b"ou"]})
1922 class IndexedCheckSearchTests(IndexedSearchTests):
1923 """Test searches using the index, to ensure the index doesn't
1924 break things (full scan disabled)"""
1927 self.IDXCHECK = True
1928 super(IndexedCheckSearchTests, self).setUp()
1931 class IndexedSearchDnFilterTests(SearchTests):
1932 """Test searches using the index, to ensure the index doesn't
1936 super(IndexedSearchDnFilterTests, self).setUp()
1937 self.l.add({"dn": "@OPTIONS",
1938 "disallowDNFilter": "TRUE"})
1939 self.disallowDNFilter = True
1941 self.l.add({"dn": "@INDEXLIST",
1942 "@IDXATTR": [b"x", b"y", b"ou"]})
1946 class IndexedAndOneLevelSearchTests(SearchTests):
1947 """Test searches using the index including @IDXONE, to ensure
1948 the index doesn't break things"""
1951 super(IndexedAndOneLevelSearchTests, self).setUp()
1952 self.l.add({"dn": "@INDEXLIST",
1953 "@IDXATTR": [b"x", b"y", b"ou"],
1959 class IndexedCheckedAndOneLevelSearchTests(IndexedAndOneLevelSearchTests):
1960 """Test searches using the index including @IDXONE, to ensure
1961 the index doesn't break things (full scan disabled)"""
1964 self.IDXCHECK = True
1965 super(IndexedCheckedAndOneLevelSearchTests, self).setUp()
1968 class IndexedAndOneLevelDNFilterSearchTests(SearchTests):
1969 """Test searches using the index including @IDXONE, to ensure
1970 the index doesn't break things"""
1973 super(IndexedAndOneLevelDNFilterSearchTests, self).setUp()
1974 self.l.add({"dn": "@OPTIONS",
1975 "disallowDNFilter": "TRUE",
1976 "checkBaseOnSearch": "TRUE"})
1977 self.disallowDNFilter = True
1978 self.checkBaseOnSearch = True
1980 self.l.add({"dn": "@INDEXLIST",
1981 "@IDXATTR": [b"x", b"y", b"ou"],
1987 class GUIDIndexedSearchTests(SearchTests):
1988 """Test searches using the index, to ensure the index doesn't
1992 self.index = {"dn": "@INDEXLIST",
1993 "@IDXATTR": [b"x", b"y", b"ou"],
1994 "@IDXGUID": [b"objectUUID"],
1995 "@IDX_DN_GUID": [b"GUID"]}
1996 super(GUIDIndexedSearchTests, self).setUp()
2001 class GUIDIndexedDNFilterSearchTests(SearchTests):
2002 """Test searches using the index, to ensure the index doesn't
2006 self.index = {"dn": "@INDEXLIST",
2007 "@IDXATTR": [b"x", b"y", b"ou"],
2008 "@IDXGUID": [b"objectUUID"],
2009 "@IDX_DN_GUID": [b"GUID"]}
2010 super(GUIDIndexedDNFilterSearchTests, self).setUp()
2011 self.l.add({"dn": "@OPTIONS",
2012 "disallowDNFilter": "TRUE",
2013 "checkBaseOnSearch": "TRUE"})
2014 self.disallowDNFilter = True
2015 self.checkBaseOnSearch = True
2020 class GUIDAndOneLevelIndexedSearchTests(SearchTests):
2021 """Test searches using the index including @IDXONE, to ensure
2022 the index doesn't break things"""
2025 self.index = {"dn": "@INDEXLIST",
2026 "@IDXATTR": [b"x", b"y", b"ou"],
2028 "@IDXGUID": [b"objectUUID"],
2029 "@IDX_DN_GUID": [b"GUID"]}
2030 super(GUIDAndOneLevelIndexedSearchTests, self).setUp()
2031 self.l.add({"dn": "@OPTIONS",
2032 "disallowDNFilter": "TRUE",
2033 "checkBaseOnSearch": "TRUE"})
2034 self.disallowDNFilter = True
2035 self.checkBaseOnSearch = True
2041 class GUIDIndexedSearchTestsLmdb(GUIDIndexedSearchTests):
2044 if os.environ.get('HAVE_LMDB', '1') == '0':
2045 self.skipTest("No lmdb backend")
2046 self.prefix = MDB_PREFIX
2047 super(GUIDIndexedSearchTestsLmdb, self).setUp()
2050 super(GUIDIndexedSearchTestsLmdb, self).tearDown()
2053 class GUIDIndexedDNFilterSearchTestsLmdb(GUIDIndexedDNFilterSearchTests):
2056 if os.environ.get('HAVE_LMDB', '1') == '0':
2057 self.skipTest("No lmdb backend")
2058 self.prefix = MDB_PREFIX
2059 super(GUIDIndexedDNFilterSearchTestsLmdb, self).setUp()
2062 super(GUIDIndexedDNFilterSearchTestsLmdb, self).tearDown()
2065 class GUIDAndOneLevelIndexedSearchTestsLmdb(GUIDAndOneLevelIndexedSearchTests):
2068 if os.environ.get('HAVE_LMDB', '1') == '0':
2069 self.skipTest("No lmdb backend")
2070 self.prefix = MDB_PREFIX
2071 super(GUIDAndOneLevelIndexedSearchTestsLmdb, self).setUp()
2074 super(GUIDAndOneLevelIndexedSearchTestsLmdb, self).tearDown()
2077 class AddModifyTests(LdbBaseTest):
2079 shutil.rmtree(self.testdir)
2080 super(AddModifyTests, self).tearDown()
2082 # Ensure the LDB is closed now, so we close the FD
2086 super(AddModifyTests, self).setUp()
2087 self.testdir = tempdir()
2088 self.filename = os.path.join(self.testdir, "add_test.ldb")
2089 self.l = ldb.Ldb(self.url(),
2091 options=["modules:rdn_name"])
2093 self.l.add(self.index)
2094 except AttributeError:
2097 self.l.add({"dn": "DC=SAMBA,DC=ORG",
2098 "name": b"samba.org",
2099 "objectUUID": b"0123456789abcdef"})
2100 self.l.add({"dn": "@ATTRIBUTES",
2101 "objectUUID": "UNIQUE_INDEX"})
2103 def test_add_dup(self):
2104 self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
2107 "objectUUID": b"0123456789abcde1"})
2109 self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
2112 "objectUUID": b"0123456789abcde2"})
2113 self.fail("Should have failed adding duplicate entry")
2114 except ldb.LdbError as err:
2116 self.assertEqual(enum, ldb.ERR_ENTRY_ALREADY_EXISTS)
2118 def test_add_bad(self):
2120 self.l.add({"dn": "BAD,DC=SAMBA,DC=ORG",
2123 "objectUUID": b"0123456789abcde1"})
2124 self.fail("Should have failed adding entry with invalid DN")
2125 except ldb.LdbError as err:
2127 self.assertEqual(enum, ldb.ERR_INVALID_DN_SYNTAX)
2129 def test_add_del_add(self):
2130 self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
2133 "objectUUID": b"0123456789abcde1"})
2134 self.l.delete("OU=DUP,DC=SAMBA,DC=ORG")
2135 self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
2138 "objectUUID": b"0123456789abcde2"})
2140 def test_add_move_add(self):
2141 self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
2144 "objectUUID": b"0123456789abcde1"})
2145 self.l.rename("OU=DUP,DC=SAMBA,DC=ORG",
2146 "OU=DUP2,DC=SAMBA,DC=ORG")
2147 self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
2150 "objectUUID": b"0123456789abcde2"})
2152 def test_add_move_fail_move_move(self):
2153 self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
2156 "objectUUID": b"0123456789abcde1"})
2157 self.l.add({"dn": "OU=DUP2,DC=SAMBA,DC=ORG",
2160 "objectUUID": b"0123456789abcde2"})
2162 res2 = self.l.search(base="DC=SAMBA,DC=ORG",
2163 scope=ldb.SCOPE_SUBTREE,
2164 expression="(objectUUID=0123456789abcde1)")
2165 self.assertEqual(len(res2), 1)
2166 self.assertEqual(str(res2[0].dn), "OU=DUP,DC=SAMBA,DC=ORG")
2168 res3 = self.l.search(base="DC=SAMBA,DC=ORG",
2169 scope=ldb.SCOPE_SUBTREE,
2170 expression="(objectUUID=0123456789abcde2)")
2171 self.assertEqual(len(res3), 1)
2172 self.assertEqual(str(res3[0].dn), "OU=DUP2,DC=SAMBA,DC=ORG")
2175 self.l.rename("OU=DUP,DC=SAMBA,DC=ORG",
2176 "OU=DUP2,DC=SAMBA,DC=ORG")
2177 self.fail("Should have failed on duplicate DN")
2178 except ldb.LdbError as err:
2180 self.assertEqual(enum, ldb.ERR_ENTRY_ALREADY_EXISTS)
2182 self.l.rename("OU=DUP2,DC=SAMBA,DC=ORG",
2183 "OU=DUP3,DC=SAMBA,DC=ORG")
2185 self.l.rename("OU=DUP,DC=SAMBA,DC=ORG",
2186 "OU=DUP2,DC=SAMBA,DC=ORG")
2188 res2 = self.l.search(base="DC=SAMBA,DC=ORG",
2189 scope=ldb.SCOPE_SUBTREE,
2190 expression="(objectUUID=0123456789abcde1)")
2191 self.assertEqual(len(res2), 1)
2192 self.assertEqual(str(res2[0].dn), "OU=DUP2,DC=SAMBA,DC=ORG")
2194 res3 = self.l.search(base="DC=SAMBA,DC=ORG",
2195 scope=ldb.SCOPE_SUBTREE,
2196 expression="(objectUUID=0123456789abcde2)")
2197 self.assertEqual(len(res3), 1)
2198 self.assertEqual(str(res3[0].dn), "OU=DUP3,DC=SAMBA,DC=ORG")
2200 def test_move_missing(self):
2202 self.l.rename("OU=DUP,DC=SAMBA,DC=ORG",
2203 "OU=DUP2,DC=SAMBA,DC=ORG")
2204 self.fail("Should have failed on missing")
2205 except ldb.LdbError as err:
2207 self.assertEqual(enum, ldb.ERR_NO_SUCH_OBJECT)
2209 def test_move_missing2(self):
2210 self.l.add({"dn": "OU=DUP2,DC=SAMBA,DC=ORG",
2213 "objectUUID": b"0123456789abcde2"})
2216 self.l.rename("OU=DUP,DC=SAMBA,DC=ORG",
2217 "OU=DUP2,DC=SAMBA,DC=ORG")
2218 self.fail("Should have failed on missing")
2219 except ldb.LdbError as err:
2221 self.assertEqual(enum, ldb.ERR_NO_SUCH_OBJECT)
2223 def test_move_bad(self):
2224 self.l.add({"dn": "OU=DUP2,DC=SAMBA,DC=ORG",
2227 "objectUUID": b"0123456789abcde2"})
2230 self.l.rename("OUXDUP,DC=SAMBA,DC=ORG",
2231 "OU=DUP2,DC=SAMBA,DC=ORG")
2232 self.fail("Should have failed on invalid DN")
2233 except ldb.LdbError as err:
2235 self.assertEqual(enum, ldb.ERR_INVALID_DN_SYNTAX)
2237 def test_move_bad2(self):
2238 self.l.add({"dn": "OU=DUP2,DC=SAMBA,DC=ORG",
2241 "objectUUID": b"0123456789abcde2"})
2244 self.l.rename("OU=DUP,DC=SAMBA,DC=ORG",
2245 "OUXDUP2,DC=SAMBA,DC=ORG")
2246 self.fail("Should have failed on missing")
2247 except ldb.LdbError as err:
2249 self.assertEqual(enum, ldb.ERR_INVALID_DN_SYNTAX)
2251 def test_move_fail_move_add(self):
2252 self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
2255 "objectUUID": b"0123456789abcde1"})
2256 self.l.add({"dn": "OU=DUP2,DC=SAMBA,DC=ORG",
2259 "objectUUID": b"0123456789abcde2"})
2261 self.l.rename("OU=DUP,DC=SAMBA,DC=ORG",
2262 "OU=DUP2,DC=SAMBA,DC=ORG")
2263 self.fail("Should have failed on duplicate DN")
2264 except ldb.LdbError as err:
2266 self.assertEqual(enum, ldb.ERR_ENTRY_ALREADY_EXISTS)
2268 self.l.rename("OU=DUP2,DC=SAMBA,DC=ORG",
2269 "OU=DUP3,DC=SAMBA,DC=ORG")
2271 self.l.add({"dn": "OU=DUP2,DC=SAMBA,DC=ORG",
2274 "objectUUID": b"0123456789abcde3"})
2277 class AddModifyTestsLmdb(AddModifyTests):
2280 if os.environ.get('HAVE_LMDB', '1') == '0':
2281 self.skipTest("No lmdb backend")
2282 self.prefix = MDB_PREFIX
2283 self.index = MDB_INDEX_OBJ
2284 super(AddModifyTestsLmdb, self).setUp()
2287 super(AddModifyTestsLmdb, self).tearDown()
2290 class IndexedAddModifyTests(AddModifyTests):
2291 """Test searches using the index, to ensure the index doesn't
2295 if not hasattr(self, 'index'):
2296 self.index = {"dn": "@INDEXLIST",
2297 "@IDXATTR": [b"x", b"y", b"ou", b"objectUUID", b"z"],
2299 super(IndexedAddModifyTests, self).setUp()
2301 def test_duplicate_GUID(self):
2303 self.l.add({"dn": "OU=DUPGUID,DC=SAMBA,DC=ORG",
2306 "objectUUID": b"0123456789abcdef"})
2307 self.fail("Should have failed adding duplicate GUID")
2308 except ldb.LdbError as err:
2310 self.assertEqual(enum, ldb.ERR_CONSTRAINT_VIOLATION)
2312 def test_duplicate_name_dup_GUID(self):
2313 self.l.add({"dn": "OU=ADMIN,DC=SAMBA,DC=ORG",
2316 "objectUUID": b"a123456789abcdef"})
2318 self.l.add({"dn": "OU=ADMIN,DC=SAMBA,DC=ORG",
2321 "objectUUID": b"a123456789abcdef"})
2322 self.fail("Should have failed adding duplicate GUID")
2323 except ldb.LdbError as err:
2325 self.assertEqual(enum, ldb.ERR_ENTRY_ALREADY_EXISTS)
2327 def test_duplicate_name_dup_GUID2(self):
2328 self.l.add({"dn": "OU=ADMIN,DC=SAMBA,DC=ORG",
2331 "objectUUID": b"abc3456789abcdef"})
2333 self.l.add({"dn": "OU=ADMIN,DC=SAMBA,DC=ORG",
2336 "objectUUID": b"aaa3456789abcdef"})
2337 self.fail("Should have failed adding duplicate DN")
2338 except ldb.LdbError as err:
2340 self.assertEqual(enum, ldb.ERR_ENTRY_ALREADY_EXISTS)
2342 # Checking the GUID didn't stick in the index
2343 self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
2346 "objectUUID": b"aaa3456789abcdef"})
2348 def test_add_dup_guid_add(self):
2349 self.l.add({"dn": "OU=DUP,DC=SAMBA,DC=ORG",
2352 "objectUUID": b"0123456789abcde1"})
2354 self.l.add({"dn": "OU=DUP2,DC=SAMBA,DC=ORG",
2357 "objectUUID": b"0123456789abcde1"})
2358 self.fail("Should have failed on duplicate GUID")
2360 except ldb.LdbError as err:
2362 self.assertEqual(enum, ldb.ERR_CONSTRAINT_VIOLATION)
2364 self.l.add({"dn": "OU=DUP2,DC=SAMBA,DC=ORG",
2367 "objectUUID": b"0123456789abcde2"})
2369 def test_duplicate_index_values(self):
2370 self.l.add({"dn": "OU=DIV1,DC=SAMBA,DC=ORG",
2373 "objectUUID": b"0123456789abcdff"})
2374 self.l.add({"dn": "OU=DIV2,DC=SAMBA,DC=ORG",
2377 "objectUUID": b"0123456789abcdfd"})
2380 class GUIDIndexedAddModifyTests(IndexedAddModifyTests):
2381 """Test searches using the index, to ensure the index doesn't
2385 self.index = {"dn": "@INDEXLIST",
2386 "@IDXATTR": [b"x", b"y", b"ou"],
2388 "@IDXGUID": [b"objectUUID"],
2389 "@IDX_DN_GUID": [b"GUID"]}
2390 super(GUIDIndexedAddModifyTests, self).setUp()
2393 class GUIDTransIndexedAddModifyTests(GUIDIndexedAddModifyTests):
2394 """Test GUID index behaviour insdie the transaction"""
2397 super(GUIDTransIndexedAddModifyTests, self).setUp()
2398 self.l.transaction_start()
2401 self.l.transaction_commit()
2402 super(GUIDTransIndexedAddModifyTests, self).tearDown()
2405 class TransIndexedAddModifyTests(IndexedAddModifyTests):
2406 """Test index behaviour insdie the transaction"""
2409 super(TransIndexedAddModifyTests, self).setUp()
2410 self.l.transaction_start()
2413 self.l.transaction_commit()
2414 super(TransIndexedAddModifyTests, self).tearDown()
2417 class GuidIndexedAddModifyTestsLmdb(GUIDIndexedAddModifyTests):
2420 if os.environ.get('HAVE_LMDB', '1') == '0':
2421 self.skipTest("No lmdb backend")
2422 self.prefix = MDB_PREFIX
2423 super(GuidIndexedAddModifyTestsLmdb, self).setUp()
2426 super(GuidIndexedAddModifyTestsLmdb, self).tearDown()
2429 class GuidTransIndexedAddModifyTestsLmdb(GUIDTransIndexedAddModifyTests):
2432 if os.environ.get('HAVE_LMDB', '1') == '0':
2433 self.skipTest("No lmdb backend")
2434 self.prefix = MDB_PREFIX
2435 super(GuidTransIndexedAddModifyTestsLmdb, self).setUp()
2438 super(GuidTransIndexedAddModifyTestsLmdb, self).tearDown()
2441 class BadIndexTests(LdbBaseTest):
2443 super(BadIndexTests, self).setUp()
2444 self.testdir = tempdir()
2445 self.filename = os.path.join(self.testdir, "test.ldb")
2446 self.ldb = ldb.Ldb(self.url(), flags=self.flags())
2447 if hasattr(self, 'IDXGUID'):
2448 self.ldb.add({"dn": "@INDEXLIST",
2449 "@IDXATTR": [b"x", b"y", b"ou"],
2450 "@IDXGUID": [b"objectUUID"],
2451 "@IDX_DN_GUID": [b"GUID"]})
2453 self.ldb.add({"dn": "@INDEXLIST",
2454 "@IDXATTR": [b"x", b"y", b"ou"]})
2456 super(BadIndexTests, self).setUp()
2458 def test_unique(self):
2459 self.ldb.add({"dn": "x=x,dc=samba,dc=org",
2460 "objectUUID": b"0123456789abcde1",
2462 self.ldb.add({"dn": "x=y,dc=samba,dc=org",
2463 "objectUUID": b"0123456789abcde2",
2465 self.ldb.add({"dn": "x=z,dc=samba,dc=org",
2466 "objectUUID": b"0123456789abcde3",
2469 res = self.ldb.search(expression="(y=1)",
2470 base="dc=samba,dc=org")
2471 self.assertEqual(len(res), 3)
2473 # Now set this to unique index, but forget to check the result
2475 self.ldb.add({"dn": "@ATTRIBUTES",
2476 "y": "UNIQUE_INDEX"})
2478 except ldb.LdbError:
2481 # We must still have a working index
2482 res = self.ldb.search(expression="(y=1)",
2483 base="dc=samba,dc=org")
2484 self.assertEqual(len(res), 3)
2486 def test_unique_transaction(self):
2487 self.ldb.add({"dn": "x=x,dc=samba,dc=org",
2488 "objectUUID": b"0123456789abcde1",
2490 self.ldb.add({"dn": "x=y,dc=samba,dc=org",
2491 "objectUUID": b"0123456789abcde2",
2493 self.ldb.add({"dn": "x=z,dc=samba,dc=org",
2494 "objectUUID": b"0123456789abcde3",
2497 res = self.ldb.search(expression="(y=1)",
2498 base="dc=samba,dc=org")
2499 self.assertEqual(len(res), 3)
2501 self.ldb.transaction_start()
2503 # Now set this to unique index, but forget to check the result
2505 self.ldb.add({"dn": "@ATTRIBUTES",
2506 "y": "UNIQUE_INDEX"})
2507 except ldb.LdbError:
2511 self.ldb.transaction_commit()
2514 except ldb.LdbError as err:
2516 self.assertEqual(enum, ldb.ERR_OPERATIONS_ERROR)
2518 # We must still have a working index
2519 res = self.ldb.search(expression="(y=1)",
2520 base="dc=samba,dc=org")
2522 self.assertEqual(len(res), 3)
2524 def test_casefold(self):
2525 self.ldb.add({"dn": "x=x,dc=samba,dc=org",
2526 "objectUUID": b"0123456789abcde1",
2528 self.ldb.add({"dn": "x=y,dc=samba,dc=org",
2529 "objectUUID": b"0123456789abcde2",
2531 self.ldb.add({"dn": "x=z,dc=samba,dc=org",
2532 "objectUUID": b"0123456789abcde3",
2535 res = self.ldb.search(expression="(y=a)",
2536 base="dc=samba,dc=org")
2537 self.assertEqual(len(res), 2)
2539 self.ldb.add({"dn": "@ATTRIBUTES",
2540 "y": "CASE_INSENSITIVE"})
2542 # We must still have a working index
2543 res = self.ldb.search(expression="(y=a)",
2544 base="dc=samba,dc=org")
2546 if hasattr(self, 'IDXGUID'):
2547 self.assertEqual(len(res), 3)
2549 # We should not return this entry twice, but sadly
2550 # we have not yet fixed
2551 # https://bugzilla.samba.org/show_bug.cgi?id=13361
2552 self.assertEqual(len(res), 4)
2554 def test_casefold_transaction(self):
2555 self.ldb.add({"dn": "x=x,dc=samba,dc=org",
2556 "objectUUID": b"0123456789abcde1",
2558 self.ldb.add({"dn": "x=y,dc=samba,dc=org",
2559 "objectUUID": b"0123456789abcde2",
2561 self.ldb.add({"dn": "x=z,dc=samba,dc=org",
2562 "objectUUID": b"0123456789abcde3",
2565 res = self.ldb.search(expression="(y=a)",
2566 base="dc=samba,dc=org")
2567 self.assertEqual(len(res), 2)
2569 self.ldb.transaction_start()
2571 self.ldb.add({"dn": "@ATTRIBUTES",
2572 "y": "CASE_INSENSITIVE"})
2574 self.ldb.transaction_commit()
2576 # We must still have a working index
2577 res = self.ldb.search(expression="(y=a)",
2578 base="dc=samba,dc=org")
2580 if hasattr(self, 'IDXGUID'):
2581 self.assertEqual(len(res), 3)
2583 # We should not return this entry twice, but sadly
2584 # we have not yet fixed
2585 # https://bugzilla.samba.org/show_bug.cgi?id=13361
2586 self.assertEqual(len(res), 4)
2588 def test_modify_transaction(self):
2589 self.ldb.add({"dn": "x=y,dc=samba,dc=org",
2590 "objectUUID": b"0123456789abcde1",
2594 res = self.ldb.search(expression="(y=2)",
2595 base="dc=samba,dc=org")
2596 self.assertEqual(len(res), 1)
2598 self.ldb.add({"dn": "@ATTRIBUTES",
2599 "y": "UNIQUE_INDEX"})
2601 self.ldb.transaction_start()
2604 m.dn = ldb.Dn(self.ldb, "x=y,dc=samba,dc=org")
2605 m["0"] = ldb.MessageElement([], ldb.FLAG_MOD_DELETE, "y")
2606 m["1"] = ldb.MessageElement([], ldb.FLAG_MOD_DELETE, "not-here")
2612 except ldb.LdbError as err:
2614 self.assertEqual(enum, ldb.ERR_NO_SUCH_ATTRIBUTE)
2617 self.ldb.transaction_commit()
2618 # We should fail here, but we want to be sure
2621 except ldb.LdbError as err:
2623 self.assertEqual(enum, ldb.ERR_OPERATIONS_ERROR)
2625 # The index should still be pointing to x=y
2626 res = self.ldb.search(expression="(y=2)",
2627 base="dc=samba,dc=org")
2628 self.assertEqual(len(res), 1)
2631 self.ldb.add({"dn": "x=y2,dc=samba,dc=org",
2632 "objectUUID": b"0123456789abcde2",
2634 self.fail("Added unique attribute twice")
2635 except ldb.LdbError as err:
2637 self.assertEqual(enum, ldb.ERR_CONSTRAINT_VIOLATION)
2639 res = self.ldb.search(expression="(y=2)",
2640 base="dc=samba,dc=org")
2641 self.assertEqual(len(res), 1)
2642 self.assertEqual(str(res[0].dn), "x=y,dc=samba,dc=org")
2645 super(BadIndexTests, self).tearDown()
2648 class GUIDBadIndexTests(BadIndexTests):
2649 """Test Bad index things with GUID index mode"""
2654 super(GUIDBadIndexTests, self).setUp()
2657 class GUIDBadIndexTestsLmdb(BadIndexTests):
2660 if os.environ.get('HAVE_LMDB', '1') == '0':
2661 self.skipTest("No lmdb backend")
2662 self.prefix = MDB_PREFIX
2663 self.index = MDB_INDEX_OBJ
2665 super(GUIDBadIndexTestsLmdb, self).setUp()
2668 super(GUIDBadIndexTestsLmdb, self).tearDown()
2671 class BatchModeTests(LdbBaseTest):
2674 super(BatchModeTests, self).setUp()
2675 self.testdir = tempdir()
2676 self.filename = os.path.join(self.testdir, "test.ldb")
2677 self.ldb = ldb.Ldb(self.url(),
2679 options=["batch_mode:1"])
2680 if hasattr(self, 'IDXGUID'):
2681 self.ldb.add({"dn": "@INDEXLIST",
2682 "@IDXATTR": [b"x", b"y", b"ou"],
2683 "@IDXGUID": [b"objectUUID"],
2684 "@IDX_DN_GUID": [b"GUID"]})
2686 self.ldb.add({"dn": "@INDEXLIST",
2687 "@IDXATTR": [b"x", b"y", b"ou"]})
2689 def test_modify_transaction(self):
2690 self.ldb.add({"dn": "x=y,dc=samba,dc=org",
2691 "objectUUID": b"0123456789abcde1",
2695 res = self.ldb.search(expression="(y=2)",
2696 base="dc=samba,dc=org")
2697 self.assertEqual(len(res), 1)
2699 self.ldb.add({"dn": "@ATTRIBUTES",
2700 "y": "UNIQUE_INDEX"})
2702 self.ldb.transaction_start()
2705 m.dn = ldb.Dn(self.ldb, "x=y,dc=samba,dc=org")
2706 m["0"] = ldb.MessageElement([], ldb.FLAG_MOD_DELETE, "y")
2707 m["1"] = ldb.MessageElement([], ldb.FLAG_MOD_DELETE, "not-here")
2713 except ldb.LdbError as err:
2715 self.assertEqual(enum, ldb.ERR_NO_SUCH_ATTRIBUTE)
2718 self.ldb.transaction_commit()
2719 self.fail("Commit should have failed as we were in batch mode")
2720 except ldb.LdbError as err:
2722 self.assertEqual(enum, ldb.ERR_OPERATIONS_ERROR)
2725 super(BatchModeTests, self).tearDown()
2728 class DnTests(TestCase):
2731 super(DnTests, self).setUp()
2732 self.ldb = ldb.Ldb()
2735 super(DnTests, self).tearDown()
2738 def test_set_dn_invalid(self):
2743 self.assertRaises(TypeError, assign)
2746 x = ldb.Dn(self.ldb, "dc=foo11,bar=bloe")
2747 y = ldb.Dn(self.ldb, "dc=foo11,bar=bloe")
2748 self.assertEqual(x, y)
2749 y = ldb.Dn(self.ldb, "dc=foo11,bar=blie")
2750 self.assertNotEqual(x, y)
2753 x = ldb.Dn(self.ldb, "dc=foo12,bar=bloe")
2754 self.assertEqual(x.__str__(), "dc=foo12,bar=bloe")
2756 def test_repr(self):
2757 x = ldb.Dn(self.ldb, "dc=foo13,bla=blie")
2758 self.assertEqual(x.__repr__(), "Dn('dc=foo13,bla=blie')")
2760 def test_get_casefold_2(self):
2761 x = ldb.Dn(self.ldb, "dc=foo14,bar=bloe")
2762 self.assertEqual(x.get_casefold(), "DC=FOO14,BAR=bloe")
2764 def test_validate(self):
2765 x = ldb.Dn(self.ldb, "dc=foo15,bar=bloe")
2766 self.assertTrue(x.validate())
2768 def test_parent(self):
2769 x = ldb.Dn(self.ldb, "dc=foo16,bar=bloe")
2770 self.assertEqual("bar=bloe", x.parent().__str__())
2772 def test_parent_nonexistent(self):
2773 x = ldb.Dn(self.ldb, "@BLA")
2774 self.assertEqual(None, x.parent())
2776 def test_is_valid(self):
2777 x = ldb.Dn(self.ldb, "dc=foo18,dc=bloe")
2778 self.assertTrue(x.is_valid())
2779 x = ldb.Dn(self.ldb, "")
2780 self.assertTrue(x.is_valid())
2782 def test_is_special(self):
2783 x = ldb.Dn(self.ldb, "dc=foo19,bar=bloe")
2784 self.assertFalse(x.is_special())
2785 x = ldb.Dn(self.ldb, "@FOOBAR")
2786 self.assertTrue(x.is_special())
2788 def test_check_special(self):
2789 x = ldb.Dn(self.ldb, "dc=foo20,bar=bloe")
2790 self.assertFalse(x.check_special("FOOBAR"))
2791 x = ldb.Dn(self.ldb, "@FOOBAR")
2792 self.assertTrue(x.check_special("@FOOBAR"))
2795 x = ldb.Dn(self.ldb, "dc=foo21,bar=bloe")
2796 self.assertEqual(2, len(x))
2797 x = ldb.Dn(self.ldb, "dc=foo21")
2798 self.assertEqual(1, len(x))
2800 def test_add_child(self):
2801 x = ldb.Dn(self.ldb, "dc=foo22,bar=bloe")
2802 self.assertTrue(x.add_child(ldb.Dn(self.ldb, "bla=bloe")))
2803 self.assertEqual("bla=bloe,dc=foo22,bar=bloe", x.__str__())
2805 def test_add_base(self):
2806 x = ldb.Dn(self.ldb, "dc=foo23,bar=bloe")
2807 base = ldb.Dn(self.ldb, "bla=bloe")
2808 self.assertTrue(x.add_base(base))
2809 self.assertEqual("dc=foo23,bar=bloe,bla=bloe", x.__str__())
2811 def test_add_child_str(self):
2812 x = ldb.Dn(self.ldb, "dc=foo22,bar=bloe")
2813 self.assertTrue(x.add_child("bla=bloe"))
2814 self.assertEqual("bla=bloe,dc=foo22,bar=bloe", x.__str__())
2816 def test_add_base_str(self):
2817 x = ldb.Dn(self.ldb, "dc=foo23,bar=bloe")
2819 self.assertTrue(x.add_base(base))
2820 self.assertEqual("dc=foo23,bar=bloe,bla=bloe", x.__str__())
2823 x = ldb.Dn(self.ldb, "dc=foo24")
2824 y = ldb.Dn(self.ldb, "bar=bla")
2825 self.assertEqual("dc=foo24,bar=bla", str(x + y))
2827 def test_remove_base_components(self):
2828 x = ldb.Dn(self.ldb, "dc=foo24,dc=samba,dc=org")
2829 x.remove_base_components(len(x) - 1)
2830 self.assertEqual("dc=foo24", str(x))
2832 def test_parse_ldif(self):
2833 msgs = self.ldb.parse_ldif("dn: foo=bar\n")
2835 self.assertEqual("foo=bar", str(msg[1].dn))
2836 self.assertTrue(isinstance(msg[1], ldb.Message))
2837 ldif = self.ldb.write_ldif(msg[1], ldb.CHANGETYPE_NONE)
2838 self.assertEqual("dn: foo=bar\n\n", ldif)
2840 def test_parse_ldif_more(self):
2841 msgs = self.ldb.parse_ldif("dn: foo=bar\n\n\ndn: bar=bar")
2843 self.assertEqual("foo=bar", str(msg[1].dn))
2845 self.assertEqual("bar=bar", str(msg[1].dn))
2847 def test_print_ldif(self):
2848 ldif = '''dn: dc=foo27
2852 self.msg = ldb.Message(ldb.Dn(self.ldb, "dc=foo27"))
2853 self.msg["foo"] = [b"foo"]
2854 self.assertEqual(ldif,
2855 self.ldb.write_ldif(self.msg,
2856 ldb.CHANGETYPE_NONE))
2858 def test_print_ldif_binary(self):
2859 # this also confirms that ldb flags are set even without a URL)
2860 self.ldb = ldb.Ldb(flags=ldb.FLG_SHOW_BINARY)
2861 ldif = '''dn: dc=foo27
2866 self.msg = ldb.Message(ldb.Dn(self.ldb, "dc=foo27"))
2867 self.msg["foo"] = ["f\nöö"]
2868 self.assertEqual(ldif,
2869 self.ldb.write_ldif(self.msg,
2870 ldb.CHANGETYPE_NONE))
2873 def test_print_ldif_no_base64_bad(self):
2874 ldif = '''dn: dc=foo27
2879 self.msg = ldb.Message(ldb.Dn(self.ldb, "dc=foo27"))
2880 self.msg["foo"] = ["f\nöö"]
2881 self.msg["foo"].set_flags(ldb.FLAG_FORCE_NO_BASE64_LDIF)
2882 self.assertEqual(ldif,
2883 self.ldb.write_ldif(self.msg,
2884 ldb.CHANGETYPE_NONE))
2886 def test_print_ldif_no_base64_good(self):
2887 ldif = '''dn: dc=foo27
2891 self.msg = ldb.Message(ldb.Dn(self.ldb, "dc=foo27"))
2892 self.msg["foo"] = ["föö"]
2893 self.msg["foo"].set_flags(ldb.FLAG_FORCE_NO_BASE64_LDIF)
2894 self.assertEqual(ldif,
2895 self.ldb.write_ldif(self.msg,
2896 ldb.CHANGETYPE_NONE))
2898 def test_canonical_string(self):
2899 x = ldb.Dn(self.ldb, "dc=foo25,bar=bloe")
2900 self.assertEqual("/bloe/foo25", x.canonical_str())
2902 def test_canonical_ex_string(self):
2903 x = ldb.Dn(self.ldb, "dc=foo26,bar=bloe")
2904 self.assertEqual("/bloe\nfoo26", x.canonical_ex_str())
2906 def test_ldb_is_child_of(self):
2907 """Testing ldb_dn_compare_dn"""
2908 dn1 = ldb.Dn(self.ldb, "dc=base")
2909 dn2 = ldb.Dn(self.ldb, "cn=foo,dc=base")
2910 dn3 = ldb.Dn(self.ldb, "cn=bar,dc=base")
2911 dn4 = ldb.Dn(self.ldb, "cn=baz,cn=bar,dc=base")
2913 self.assertTrue(dn1.is_child_of(dn1))
2914 self.assertTrue(dn2.is_child_of(dn1))
2915 self.assertTrue(dn4.is_child_of(dn1))
2916 self.assertTrue(dn4.is_child_of(dn3))
2917 self.assertTrue(dn4.is_child_of(dn4))
2918 self.assertFalse(dn3.is_child_of(dn2))
2919 self.assertFalse(dn1.is_child_of(dn4))
2921 def test_ldb_is_child_of_str(self):
2922 """Testing ldb_dn_compare_dn"""
2924 dn2_str = "cn=foo,dc=base"
2925 dn3_str = "cn=bar,dc=base"
2926 dn4_str = "cn=baz,cn=bar,dc=base"
2928 dn1 = ldb.Dn(self.ldb, dn1_str)
2929 dn2 = ldb.Dn(self.ldb, dn2_str)
2930 dn3 = ldb.Dn(self.ldb, dn3_str)
2931 dn4 = ldb.Dn(self.ldb, dn4_str)
2933 self.assertTrue(dn1.is_child_of(dn1_str))
2934 self.assertTrue(dn2.is_child_of(dn1_str))
2935 self.assertTrue(dn4.is_child_of(dn1_str))
2936 self.assertTrue(dn4.is_child_of(dn3_str))
2937 self.assertTrue(dn4.is_child_of(dn4_str))
2938 self.assertFalse(dn3.is_child_of(dn2_str))
2939 self.assertFalse(dn1.is_child_of(dn4_str))
2941 def test_get_component_name(self):
2942 dn = ldb.Dn(self.ldb, "cn=foo,dc=base")
2943 self.assertEqual(dn.get_component_name(0), 'cn')
2944 self.assertEqual(dn.get_component_name(1), 'dc')
2945 self.assertEqual(dn.get_component_name(2), None)
2946 self.assertEqual(dn.get_component_name(-1), None)
2948 def test_get_component_value(self):
2949 dn = ldb.Dn(self.ldb, "cn=foo,dc=base")
2950 self.assertEqual(dn.get_component_value(0), 'foo')
2951 self.assertEqual(dn.get_component_value(1), 'base')
2952 self.assertEqual(dn.get_component_name(2), None)
2953 self.assertEqual(dn.get_component_name(-1), None)
2955 def test_set_component(self):
2956 dn = ldb.Dn(self.ldb, "cn=foo,dc=base")
2957 dn.set_component(0, 'cn', 'bar')
2958 self.assertEqual(str(dn), "cn=bar,dc=base")
2959 dn.set_component(1, 'o', 'asep')
2960 self.assertEqual(str(dn), "cn=bar,o=asep")
2961 self.assertRaises(TypeError, dn.set_component, 2, 'dc', 'base')
2962 self.assertEqual(str(dn), "cn=bar,o=asep")
2963 dn.set_component(1, 'o', 'a,b+c')
2964 self.assertEqual(str(dn), r"cn=bar,o=a\,b\+c")
2966 def test_set_component_bytes(self):
2967 dn = ldb.Dn(self.ldb, "cn=foo,dc=base")
2968 dn.set_component(0, 'cn', b'bar')
2969 self.assertEqual(str(dn), "cn=bar,dc=base")
2970 dn.set_component(1, 'o', b'asep')
2971 self.assertEqual(str(dn), "cn=bar,o=asep")
2973 def test_set_component_none(self):
2974 dn = ldb.Dn(self.ldb, "cn=foo,cn=bar,dc=base")
2975 self.assertRaises(TypeError, dn.set_component, 1, 'cn', None)
2977 def test_get_extended_component_null(self):
2978 dn = ldb.Dn(self.ldb, "cn=foo,cn=bar,dc=base")
2979 self.assertEqual(dn.get_extended_component("TEST"), None)
2981 def test_get_extended_component(self):
2982 self.ldb._register_test_extensions()
2983 dn = ldb.Dn(self.ldb, "<TEST=foo>;cn=bar,dc=base")
2984 self.assertEqual(dn.get_extended_component("TEST"), b"foo")
2986 def test_set_extended_component(self):
2987 self.ldb._register_test_extensions()
2988 dn = ldb.Dn(self.ldb, "dc=base")
2989 dn.set_extended_component("TEST", "foo")
2990 self.assertEqual(dn.get_extended_component("TEST"), b"foo")
2991 dn.set_extended_component("TEST", b"bar")
2992 self.assertEqual(dn.get_extended_component("TEST"), b"bar")
2994 def test_extended_str(self):
2995 self.ldb._register_test_extensions()
2996 dn = ldb.Dn(self.ldb, "<TEST=foo>;cn=bar,dc=base")
2997 self.assertEqual(dn.extended_str(), "<TEST=foo>;cn=bar,dc=base")
2999 def test_get_rdn_name(self):
3000 dn = ldb.Dn(self.ldb, "cn=foo,dc=base")
3001 self.assertEqual(dn.get_rdn_name(), 'cn')
3003 def test_get_rdn_value(self):
3004 dn = ldb.Dn(self.ldb, "cn=foo,dc=base")
3005 self.assertEqual(dn.get_rdn_value(), 'foo')
3007 def test_get_casefold(self):
3008 dn = ldb.Dn(self.ldb, "cn=foo,dc=base")
3009 self.assertEqual(dn.get_casefold(), 'CN=FOO,DC=BASE')
3011 def test_get_linearized(self):
3012 dn = ldb.Dn(self.ldb, "cn=foo,dc=base")
3013 self.assertEqual(dn.get_linearized(), 'cn=foo,dc=base')
3015 def test_is_null(self):
3016 dn = ldb.Dn(self.ldb, "cn=foo,dc=base")
3017 self.assertFalse(dn.is_null())
3019 dn = ldb.Dn(self.ldb, '')
3020 self.assertTrue(dn.is_null())
3023 class LdbMsgTests(TestCase):
3026 super(LdbMsgTests, self).setUp()
3027 self.msg = ldb.Message()
3029 def test_init_dn(self):
3030 self.msg = ldb.Message(ldb.Dn(ldb.Ldb(), "dc=foo27"))
3031 self.assertEqual("dc=foo27", str(self.msg.dn))
3033 def test_iter_items(self):
3034 self.assertEqual(0, len(self.msg.items()))
3035 self.msg.dn = ldb.Dn(ldb.Ldb(), "dc=foo28")
3036 self.assertEqual(1, len(self.msg.items()))
3038 def test_items(self):
3039 self.msg["foo"] = ["foo"]
3040 self.msg["bar"] = ["bar"]
3042 items = self.msg.items()
3045 self.assertEqual([("foo", ldb.MessageElement(["foo"])),
3046 ("bar", ldb.MessageElement(["bar"]))],
3049 self.msg.dn = ldb.Dn(ldb.Ldb(), "dc=test")
3051 items = self.msg.items()
3054 self.assertEqual([("dn", ldb.Dn(ldb.Ldb(), "dc=test")),
3055 ("foo", ldb.MessageElement(["foo"])),
3056 ("bar", ldb.MessageElement(["bar"]))],
3059 def test_repr(self):
3060 self.msg.dn = ldb.Dn(ldb.Ldb(), "dc=foo29")
3061 self.msg["dc"] = b"foo"
3062 self.assertIn(repr(self.msg), [
3063 "Message({'dn': Dn('dc=foo29'), 'dc': MessageElement([b'foo'])})",
3064 "Message({'dc': MessageElement([b'foo']), 'dn': Dn('dc=foo29')})",
3066 self.assertIn(repr(self.msg.text), [
3067 "Message({'dn': Dn('dc=foo29'), 'dc': MessageElement([b'foo'])}).text",
3068 "Message({'dc': MessageElement([b'foo']), 'dn': Dn('dc=foo29')}).text",
3072 self.assertEqual(0, len(self.msg))
3074 def test_notpresent(self):
3075 self.assertRaises(KeyError, lambda: self.msg["foo"])
3077 def test_invalid(self):
3079 self.assertRaises(TypeError, lambda: self.msg[42])
3087 self.msg.add(ldb.MessageElement([b"456"], ldb.FLAG_MOD_ADD, "bla"))
3089 def test_add_text(self):
3090 self.msg.add(ldb.MessageElement(["456"], ldb.FLAG_MOD_ADD, "bla"))
3092 def test_elements_empty(self):
3093 self.assertEqual([], self.msg.elements())
3095 def test_elements(self):
3096 el = ldb.MessageElement([b"456"], ldb.FLAG_MOD_ADD, "bla")
3098 self.assertEqual([el], self.msg.elements())
3099 self.assertEqual([el.text], self.msg.text.elements())
3101 def test_add_value(self):
3102 self.assertEqual(0, len(self.msg))
3103 self.msg["foo"] = [b"foo"]
3104 self.assertEqual(1, len(self.msg))
3106 def test_add_value_text(self):
3107 self.assertEqual(0, len(self.msg))
3108 self.msg["foo"] = ["foo"]
3109 self.assertEqual(1, len(self.msg))
3111 def test_add_value_multiple(self):
3112 self.assertEqual(0, len(self.msg))
3113 self.msg["foo"] = [b"foo", b"bla"]
3114 self.assertEqual(1, len(self.msg))
3115 self.assertEqual([b"foo", b"bla"], list(self.msg["foo"]))
3117 def test_add_value_multiple_text(self):
3118 self.assertEqual(0, len(self.msg))
3119 self.msg["foo"] = ["foo", "bla"]
3120 self.assertEqual(1, len(self.msg))
3121 self.assertEqual(["foo", "bla"], list(self.msg.text["foo"]))
3123 def test_set_value(self):
3124 self.msg["foo"] = [b"fool"]
3125 self.assertEqual([b"fool"], list(self.msg["foo"]))
3126 self.msg["foo"] = [b"bar"]
3127 self.assertEqual([b"bar"], list(self.msg["foo"]))
3129 def test_set_value_text(self):
3130 self.msg["foo"] = ["fool"]
3131 self.assertEqual(["fool"], list(self.msg.text["foo"]))
3132 self.msg["foo"] = ["bar"]
3133 self.assertEqual(["bar"], list(self.msg.text["foo"]))
3135 def test_keys(self):
3136 self.msg.dn = ldb.Dn(ldb.Ldb(), "@BASEINFO")
3137 self.msg["foo"] = [b"bla"]
3138 self.msg["bar"] = [b"bla"]
3139 self.assertEqual(["dn", "foo", "bar"], list(self.msg.keys()))
3141 def test_keys_text(self):
3142 self.msg.dn = ldb.Dn(ldb.Ldb(), "@BASEINFO")
3143 self.msg["foo"] = ["bla"]
3144 self.msg["bar"] = ["bla"]
3145 self.assertEqual(["dn", "foo", "bar"], list(self.msg.text.keys()))
3148 self.msg.dn = ldb.Dn(ldb.Ldb(), "@BASEINFO")
3149 self.assertEqual("@BASEINFO", self.msg.dn.__str__())
3151 def test_get_dn(self):
3152 self.msg.dn = ldb.Dn(ldb.Ldb(), "@BASEINFO")
3153 self.assertEqual("@BASEINFO", self.msg.get("dn").__str__())
3155 def test_dn_text(self):
3156 self.msg.text.dn = ldb.Dn(ldb.Ldb(), "@BASEINFO")
3157 self.assertEqual("@BASEINFO", str(self.msg.dn))
3158 self.assertEqual("@BASEINFO", str(self.msg.text.dn))
3160 def test_get_dn_text(self):
3161 self.msg.dn = ldb.Dn(ldb.Ldb(), "@BASEINFO")
3162 self.assertEqual("@BASEINFO", str(self.msg.get("dn")))
3163 self.assertEqual("@BASEINFO", str(self.msg.text.get("dn")))
3165 def test_get_invalid(self):
3166 self.msg.dn = ldb.Dn(ldb.Ldb(), "@BASEINFO")
3167 self.assertRaises(TypeError, self.msg.get, 42)
3169 def test_get_other(self):
3170 self.msg["foo"] = [b"bar"]
3171 self.assertEqual(b"bar", self.msg.get("foo")[0])
3172 self.assertEqual(b"bar", self.msg.get("foo", idx=0))
3173 self.assertEqual(None, self.msg.get("foo", idx=1))
3174 self.assertEqual("", self.msg.get("foo", default='', idx=1))
3176 def test_get_other_text(self):
3177 self.msg["foo"] = ["bar"]
3178 self.assertEqual(["bar"], list(self.msg.text.get("foo")))
3179 self.assertEqual("bar", self.msg.text.get("foo")[0])
3180 self.assertEqual("bar", self.msg.text.get("foo", idx=0))
3181 self.assertEqual(None, self.msg.get("foo", idx=1))
3182 self.assertEqual("", self.msg.get("foo", default='', idx=1))
3184 def test_get_default(self):
3185 self.assertEqual(None, self.msg.get("tatayoyo", idx=0))
3186 self.assertEqual("anniecordie", self.msg.get("tatayoyo", "anniecordie"))
3188 def test_get_default_text(self):
3189 self.assertEqual(None, self.msg.text.get("tatayoyo", idx=0))
3190 self.assertEqual("anniecordie", self.msg.text.get("tatayoyo", "anniecordie"))
3192 def test_get_unknown(self):
3193 self.assertEqual(None, self.msg.get("lalalala"))
3195 def test_get_unknown_text(self):
3196 self.assertEqual(None, self.msg.text.get("lalalala"))
3198 def test_contains(self):
3199 self.msg['foo'] = ['bar']
3200 self.assertIn('foo', self.msg)
3202 self.msg['Foo'] = ['bar']
3203 self.assertIn('Foo', self.msg)
3205 def test_contains_case(self):
3206 self.msg['foo'] = ['bar']
3207 self.assertIn('Foo', self.msg)
3209 self.msg['Foo'] = ['bar']
3210 self.assertIn('foo', self.msg)
3212 def test_contains_dn(self):
3213 self.assertIn('dn', self.msg)
3215 def test_contains_dn_case(self):
3216 self.assertIn('DN', self.msg)
3218 def test_contains_invalid(self):
3219 self.assertRaises(TypeError, lambda: None in self.msg)
3221 def test_msg_diff(self):
3223 msgs = l.parse_ldif("dn: foo=bar\nfoo: bar\nbaz: do\n\ndn: foo=bar\nfoo: bar\nbaz: dont\n")
3224 msg1 = next(msgs)[1]
3225 msg2 = next(msgs)[1]
3226 msgdiff = l.msg_diff(msg1, msg2)
3227 self.assertEqual("foo=bar", msgdiff.get("dn").__str__())
3228 self.assertRaises(KeyError, lambda: msgdiff["foo"])
3229 self.assertEqual(1, len(msgdiff))
3231 def test_equal_empty(self):
3232 msg1 = ldb.Message()
3233 msg2 = ldb.Message()
3234 self.assertEqual(msg1, msg2)
3236 def test_equal_simplel(self):
3238 msg1 = ldb.Message()
3239 msg1.dn = ldb.Dn(db, "foo=bar")
3240 msg2 = ldb.Message()
3241 msg2.dn = ldb.Dn(db, "foo=bar")
3242 self.assertEqual(msg1, msg2)
3243 msg1['foo'] = b'bar'
3244 msg2['foo'] = b'bar'
3245 self.assertEqual(msg1, msg2)
3246 msg2['foo'] = b'blie'
3247 self.assertNotEqual(msg1, msg2)
3248 msg2['foo'] = b'blie'
3250 def test_from_dict(self):
3251 rec = {"dn": "dc=fromdict",
3252 "a1": [b"a1-val1", b"a1-val1"]}
3254 # check different types of input Flags
3255 for flags in [ldb.FLAG_MOD_ADD, ldb.FLAG_MOD_REPLACE, ldb.FLAG_MOD_DELETE]:
3256 m = ldb.Message.from_dict(l, rec, flags)
3257 self.assertEqual(rec["a1"], list(m["a1"]))
3258 self.assertEqual(flags, m["a1"].flags())
3259 # check input params
3260 self.assertRaises(TypeError, ldb.Message.from_dict, dict(), rec, ldb.FLAG_MOD_REPLACE)
3261 self.assertRaises(TypeError, ldb.Message.from_dict, l, list(), ldb.FLAG_MOD_REPLACE)
3262 self.assertRaises(ValueError, ldb.Message.from_dict, l, rec, 0)
3263 # Message.from_dict expects dictionary with 'dn'
3264 err_rec = {"a1": [b"a1-val1", b"a1-val1"]}
3265 self.assertRaises(TypeError, ldb.Message.from_dict, l, err_rec, ldb.FLAG_MOD_REPLACE)
3267 def test_from_dict_text(self):
3268 rec = {"dn": "dc=fromdict",
3269 "a1": ["a1-val1", "a1-val1"]}
3271 # check different types of input Flags
3272 for flags in [ldb.FLAG_MOD_ADD, ldb.FLAG_MOD_REPLACE, ldb.FLAG_MOD_DELETE]:
3273 m = ldb.Message.from_dict(l, rec, flags)
3274 self.assertEqual(rec["a1"], list(m.text["a1"]))
3275 self.assertEqual(flags, m.text["a1"].flags())
3276 # check input params
3277 self.assertRaises(TypeError, ldb.Message.from_dict, dict(), rec, ldb.FLAG_MOD_REPLACE)
3278 self.assertRaises(TypeError, ldb.Message.from_dict, l, list(), ldb.FLAG_MOD_REPLACE)
3279 self.assertRaises(ValueError, ldb.Message.from_dict, l, rec, 0)
3280 # Message.from_dict expects dictionary with 'dn'
3281 err_rec = {"a1": ["a1-val1", "a1-val1"]}
3282 self.assertRaises(TypeError, ldb.Message.from_dict, l, err_rec, ldb.FLAG_MOD_REPLACE)
3284 def test_copy_add_message_element(self):
3286 m["1"] = ldb.MessageElement([b"val 111"], ldb.FLAG_MOD_ADD, "1")
3287 m["2"] = ldb.MessageElement([b"val 222"], ldb.FLAG_MOD_ADD, "2")
3291 self.assertEqual(mto["1"], m["1"])
3292 self.assertEqual(mto["2"], m["2"])
3296 self.assertEqual(mto["1"], m["1"])
3297 self.assertEqual(mto["2"], m["2"])
3299 def test_copy_add_message_element_text(self):
3301 m["1"] = ldb.MessageElement(["val 111"], ldb.FLAG_MOD_ADD, "1")
3302 m["2"] = ldb.MessageElement(["val 222"], ldb.FLAG_MOD_ADD, "2")
3306 self.assertEqual(mto["1"], m.text["1"])
3307 self.assertEqual(mto["2"], m.text["2"])
3311 self.assertEqual(mto.text["1"], m.text["1"])
3312 self.assertEqual(mto.text["2"], m.text["2"])
3313 self.assertEqual(mto["1"], m["1"])
3314 self.assertEqual(mto["2"], m["2"])
3317 class MessageElementTests(TestCase):
3319 def test_cmp_element(self):
3320 x = ldb.MessageElement([b"foo"])
3321 y = ldb.MessageElement([b"foo"])
3322 z = ldb.MessageElement([b"bzr"])
3323 self.assertEqual(x, y)
3324 self.assertNotEqual(x, z)
3326 def test_cmp_element_text(self):
3327 x = ldb.MessageElement([b"foo"])
3328 y = ldb.MessageElement(["foo"])
3329 self.assertEqual(x, y)
3331 def test_create_iterable(self):
3332 x = ldb.MessageElement([b"foo"])
3333 self.assertEqual([b"foo"], list(x))
3334 self.assertEqual(["foo"], list(x.text))
3336 def test_repr(self):
3337 x = ldb.MessageElement([b"foo"])
3338 self.assertEqual("MessageElement([b'foo'])", repr(x))
3339 self.assertEqual("MessageElement([b'foo']).text", repr(x.text))
3340 x = ldb.MessageElement([b"foo", b"bla"])
3341 self.assertEqual(2, len(x))
3342 self.assertEqual("MessageElement([b'foo',b'bla'])", repr(x))
3343 self.assertEqual("MessageElement([b'foo',b'bla']).text", repr(x.text))
3345 def test_get_item(self):
3346 x = ldb.MessageElement([b"foo", b"bar"])
3347 self.assertEqual(b"foo", x[0])
3348 self.assertEqual(b"bar", x[1])
3349 self.assertEqual(b"bar", x[-1])
3350 self.assertRaises(IndexError, lambda: x[45])
3352 def test_get_item_text(self):
3353 x = ldb.MessageElement(["foo", "bar"])
3354 self.assertEqual("foo", x.text[0])
3355 self.assertEqual("bar", x.text[1])
3356 self.assertEqual("bar", x.text[-1])
3357 self.assertRaises(IndexError, lambda: x[45])
3360 x = ldb.MessageElement([b"foo", b"bar"])
3361 self.assertEqual(2, len(x))
3364 x = ldb.MessageElement([b"foo", b"bar"])
3365 y = ldb.MessageElement([b"foo", b"bar"])
3366 self.assertEqual(y, x)
3367 x = ldb.MessageElement([b"foo"])
3368 self.assertNotEqual(y, x)
3369 y = ldb.MessageElement([b"foo"])
3370 self.assertEqual(y, x)
3372 def test_extended(self):
3373 el = ldb.MessageElement([b"456"], ldb.FLAG_MOD_ADD, "bla")
3374 self.assertEqual("MessageElement([b'456'])", repr(el))
3375 self.assertEqual("MessageElement([b'456']).text", repr(el.text))
3377 def test_bad_text(self):
3378 el = ldb.MessageElement(b'\xba\xdd')
3379 self.assertRaises(UnicodeDecodeError, el.text.__getitem__, 0)
3382 class ModuleTests(TestCase):
3385 super(ModuleTests, self).setUp()
3386 self.testdir = tempdir()
3387 self.filename = os.path.join(self.testdir, "test.ldb")
3388 self.ldb = ldb.Ldb(self.filename)
3391 shutil.rmtree(self.testdir)
3392 super(ModuleTests, self).setUp()
3394 def test_register_module(self):
3395 class ExampleModule:
3397 ldb.register_module(ExampleModule)
3399 def test_use_module(self):
3402 class ExampleModule:
3405 def __init__(self, ldb, next):
3409 def search(self, *args, **kwargs):
3410 return self.next.search(*args, **kwargs)
3412 def request(self, *args, **kwargs):
3415 ldb.register_module(ExampleModule)
3416 l = ldb.Ldb(self.filename)
3417 l.add({"dn": "@MODULES", "@LIST": "bla"})
3418 self.assertEqual([], ops)
3419 l = ldb.Ldb(self.filename)
3420 self.assertEqual(["init"], ops)
3423 class LdbResultTests(LdbBaseTest):
3426 super(LdbResultTests, self).setUp()
3427 self.testdir = tempdir()
3428 self.filename = os.path.join(self.testdir, "test.ldb")
3429 self.l = ldb.Ldb(self.url(), flags=self.flags())
3431 self.l.add(self.index)
3432 except AttributeError:
3434 self.l.add({"dn": "DC=SAMBA,DC=ORG", "name": b"samba.org",
3435 "objectUUID": b"0123456789abcde0"})
3436 self.l.add({"dn": "OU=ADMIN,DC=SAMBA,DC=ORG", "name": b"Admins",
3437 "objectUUID": b"0123456789abcde1"})
3438 self.l.add({"dn": "OU=USERS,DC=SAMBA,DC=ORG", "name": b"Users",
3439 "objectUUID": b"0123456789abcde2"})
3440 self.l.add({"dn": "OU=OU1,DC=SAMBA,DC=ORG", "name": b"OU #1",
3441 "objectUUID": b"0123456789abcde3"})
3442 self.l.add({"dn": "OU=OU2,DC=SAMBA,DC=ORG", "name": b"OU #2",
3443 "objectUUID": b"0123456789abcde4"})
3444 self.l.add({"dn": "OU=OU3,DC=SAMBA,DC=ORG", "name": b"OU #3",
3445 "objectUUID": b"0123456789abcde5"})
3446 self.l.add({"dn": "OU=OU4,DC=SAMBA,DC=ORG", "name": b"OU #4",
3447 "objectUUID": b"0123456789abcde6"})
3448 self.l.add({"dn": "OU=OU5,DC=SAMBA,DC=ORG", "name": b"OU #5",
3449 "objectUUID": b"0123456789abcde7"})
3450 self.l.add({"dn": "OU=OU6,DC=SAMBA,DC=ORG", "name": b"OU #6",
3451 "objectUUID": b"0123456789abcde8"})
3452 self.l.add({"dn": "OU=OU7,DC=SAMBA,DC=ORG", "name": b"OU #7",
3453 "objectUUID": b"0123456789abcde9"})
3454 self.l.add({"dn": "OU=OU8,DC=SAMBA,DC=ORG", "name": b"OU #8",
3455 "objectUUID": b"0123456789abcdea"})
3456 self.l.add({"dn": "OU=OU9,DC=SAMBA,DC=ORG", "name": b"OU #9",
3457 "objectUUID": b"0123456789abcdeb"})
3458 self.l.add({"dn": "OU=OU10,DC=SAMBA,DC=ORG", "name": b"OU #10",
3459 "objectUUID": b"0123456789abcdec"})
3462 shutil.rmtree(self.testdir)
3463 super(LdbResultTests, self).tearDown()
3464 # Ensure the LDB is closed now, so we close the FD
3467 def test_return_type(self):
3468 res = self.l.search()
3469 self.assertEqual(str(res), "<ldb result>")
3471 def test_get_msgs(self):
3472 res = self.l.search()
3475 def test_get_controls(self):
3476 res = self.l.search()
3479 def test_get_referals(self):
3480 res = self.l.search()
3483 def test_iter_msgs(self):
3485 for l in self.l.search().msgs:
3486 if str(l.dn) == "OU=OU10,DC=SAMBA,DC=ORG":
3488 self.assertTrue(found)
3490 def test_iter_msgs_count(self):
3491 self.assertTrue(self.l.search().count > 0)
3492 # 13 objects has been added to the DC=SAMBA, DC=ORG
3493 self.assertEqual(self.l.search(base="DC=SAMBA,DC=ORG").count, 13)
3495 def test_iter_controls(self):
3496 res = self.l.search().controls
3499 def test_create_control(self):
3500 self.assertRaises(ValueError, ldb.Control, self.l, "tatayoyo:0")
3501 c = ldb.Control(self.l, "relax:1")
3502 self.assertEqual(c.critical, True)
3503 self.assertEqual(c.oid, "1.3.6.1.4.1.4203.666.5.12")
3505 def test_iter_refs(self):
3506 res = self.l.search().referals
3509 def test_search_sequence_msgs(self):
3511 res = self.l.search().msgs
3513 for i in range(0, len(res)):
3515 if str(l.dn) == "OU=OU10,DC=SAMBA,DC=ORG":
3517 self.assertTrue(found)
3519 def test_search_as_iter(self):
3521 res = self.l.search()
3524 if str(l.dn) == "OU=OU10,DC=SAMBA,DC=ORG":
3526 self.assertTrue(found)
3528 def test_search_iter(self):
3530 res = self.l.search_iterator()
3533 if str(l.dn) == "OU=OU10,DC=SAMBA,DC=ORG":
3535 self.assertTrue(found)
3537 # Show that search results can't see into a transaction
3539 def test_search_against_trans(self):
3542 (r1, w1) = os.pipe()
3544 (r2, w2) = os.pipe()
3546 # For the first element, fork a child that will
3550 # In the child, re-open
3554 child_ldb = ldb.Ldb(self.url(), flags=self.flags())
3555 # start a transaction
3556 child_ldb.transaction_start()
3559 child_ldb.add({"dn": "OU=OU11,DC=SAMBA,DC=ORG",
3560 "name": b"samba.org",
3561 "objectUUID": b"o123456789acbdef"})
3563 os.write(w1, b"added")
3565 # Now wait for the search to be done
3570 child_ldb.transaction_commit()
3571 except ldb.LdbError as err:
3572 # We print this here to see what went wrong in the child
3576 os.write(w1, b"transaction")
3579 self.assertEqual(os.read(r1, 5), b"added")
3581 # This should not turn up until the transaction is concluded
3582 res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
3583 scope=ldb.SCOPE_BASE)
3584 self.assertEqual(len(res11), 0)
3586 os.write(w2, b"search")
3588 # Now wait for the transaction to be done. This should
3589 # deadlock, but the search doesn't hold a read lock for the
3590 # iterator lifetime currently.
3591 self.assertEqual(os.read(r1, 11), b"transaction")
3593 # This should now turn up, as the transaction is over
3594 res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
3595 scope=ldb.SCOPE_BASE)
3596 self.assertEqual(len(res11), 1)
3598 self.assertFalse(found11)
3600 (got_pid, status) = os.waitpid(pid, 0)
3601 self.assertEqual(got_pid, pid)
3603 def test_search_iter_against_trans(self):
3607 # We need to hold this iterator open to hold the all-record
3609 res = self.l.search_iterator()
3611 (r1, w1) = os.pipe()
3613 (r2, w2) = os.pipe()
3615 # For the first element, with the sequence open (which
3616 # means with ldb locks held), fork a child that will
3620 # In the child, re-open
3625 child_ldb = ldb.Ldb(self.url(), flags=self.flags())
3626 # start a transaction
3627 child_ldb.transaction_start()
3630 child_ldb.add({"dn": "OU=OU11,DC=SAMBA,DC=ORG",
3631 "name": b"samba.org",
3632 "objectUUID": b"o123456789acbdef"})
3634 os.write(w1, b"added")
3636 # Now wait for the search to be done
3641 child_ldb.transaction_commit()
3642 except ldb.LdbError as err:
3643 # We print this here to see what went wrong in the child
3647 os.write(w1, b"transaction")
3650 self.assertEqual(os.read(r1, 5), b"added")
3652 # This should not turn up until the transaction is concluded
3653 res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
3654 scope=ldb.SCOPE_BASE)
3655 self.assertEqual(len(res11), 0)
3657 os.write(w2, b"search")
3659 # allow the transaction to start
3662 # This should not turn up until the search finishes and
3663 # removed the read lock, but for ldb_tdb that happened as soon
3664 # as we called the first res.next()
3665 res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
3666 scope=ldb.SCOPE_BASE)
3667 self.assertEqual(len(res11), 0)
3669 # These results are all collected at the first next(res) call
3671 if str(l.dn) == "OU=OU10,DC=SAMBA,DC=ORG":
3673 if str(l.dn) == "OU=OU11,DC=SAMBA,DC=ORG":
3676 # Now wait for the transaction to be done.
3677 self.assertEqual(os.read(r1, 11), b"transaction")
3679 # This should now turn up, as the transaction is over and all
3680 # read locks are gone
3681 res11 = self.l.search(base="OU=OU11,DC=SAMBA,DC=ORG",
3682 scope=ldb.SCOPE_BASE)
3683 self.assertEqual(len(res11), 1)
3685 self.assertTrue(found)
3686 self.assertFalse(found11)
3688 (got_pid, status) = os.waitpid(pid, 0)
3689 self.assertEqual(got_pid, pid)
3692 class LdbResultTestsLmdb(LdbResultTests):
3695 if os.environ.get('HAVE_LMDB', '1') == '0':
3696 self.skipTest("No lmdb backend")
3697 self.prefix = MDB_PREFIX
3698 self.index = MDB_INDEX_OBJ
3699 super(LdbResultTestsLmdb, self).setUp()
3702 super(LdbResultTestsLmdb, self).tearDown()
3705 class BadTypeTests(TestCase):
3706 def test_control(self):
3708 self.assertRaises(TypeError, ldb.Control, '<bad type>', 'relax:1')
3709 self.assertRaises(TypeError, ldb.Control, ldb, 1234)
3711 def test_modify(self):
3713 dn = ldb.Dn(l, 'a=b')
3715 self.assertRaises(TypeError, l.modify, '<bad type>')
3716 self.assertRaises(TypeError, l.modify, m, '<bad type>')
3720 dn = ldb.Dn(l, 'a=b')
3722 self.assertRaises(TypeError, l.add, '<bad type>')
3723 self.assertRaises(TypeError, l.add, m, '<bad type>')
3725 def test_delete(self):
3727 dn = ldb.Dn(l, 'a=b')
3728 self.assertRaises(TypeError, l.add, '<bad type>')
3729 self.assertRaises(TypeError, l.add, dn, '<bad type>')
3731 def test_rename(self):
3733 dn = ldb.Dn(l, 'a=b')
3734 self.assertRaises(TypeError, l.add, '<bad type>', dn)
3735 self.assertRaises(TypeError, l.add, dn, '<bad type>')
3736 self.assertRaises(TypeError, l.add, dn, dn, '<bad type>')
3738 def test_search(self):
3740 self.assertRaises(TypeError, l.search, base=1234)
3741 self.assertRaises(TypeError, l.search, scope='<bad type>')
3742 self.assertRaises(TypeError, l.search, expression=1234)
3743 self.assertRaises(TypeError, l.search, attrs='<bad type>')
3744 self.assertRaises(TypeError, l.search, controls='<bad type>')
3747 class VersionTests(TestCase):
3749 def test_version(self):
3750 self.assertTrue(isinstance(ldb.__version__, str))
3752 class NestedTransactionTests(LdbBaseTest):
3754 super(NestedTransactionTests, self).setUp()
3755 self.testdir = tempdir()
3756 self.filename = os.path.join(self.testdir, "test.ldb")
3757 self.ldb = ldb.Ldb(self.url(), flags=self.flags())
3758 self.ldb.add({"dn": "@INDEXLIST",
3759 "@IDXATTR": [b"x", b"y", b"ou"],
3760 "@IDXGUID": [b"objectUUID"],
3761 "@IDX_DN_GUID": [b"GUID"]})
3763 super(NestedTransactionTests, self).setUp()
3766 # This test documents that currently ldb does not support true nested
3769 # Note: The test is written so that it treats failure as pass.
3770 # It is done this way as standalone ldb builds do not use the samba
3771 # known fail mechanism
3773 def test_nested_transactions(self):
3775 self.ldb.transaction_start()
3777 self.ldb.add({"dn": "x=x1,dc=samba,dc=org",
3778 "objectUUID": b"0123456789abcde1"})
3779 res = self.ldb.search(expression="(objectUUID=0123456789abcde1)",
3780 base="dc=samba,dc=org")
3781 self.assertEqual(len(res), 1)
3783 self.ldb.add({"dn": "x=x2,dc=samba,dc=org",
3784 "objectUUID": b"0123456789abcde2"})
3785 res = self.ldb.search(expression="(objectUUID=0123456789abcde2)",
3786 base="dc=samba,dc=org")
3787 self.assertEqual(len(res), 1)
3789 self.ldb.transaction_start()
3790 self.ldb.add({"dn": "x=x3,dc=samba,dc=org",
3791 "objectUUID": b"0123456789abcde3"})
3792 res = self.ldb.search(expression="(objectUUID=0123456789abcde3)",
3793 base="dc=samba,dc=org")
3794 self.assertEqual(len(res), 1)
3795 self.ldb.transaction_cancel()
3797 # Check that we can not see the record added by the cancelled
3799 # Currently this fails as ldb does not support true nested
3800 # transactions, and only the outer commits and cancels have an effect
3802 res = self.ldb.search(expression="(objectUUID=0123456789abcde3)",
3803 base="dc=samba,dc=org")
3805 # FIXME this test currently passes on a failure, i.e. if nested
3806 # transaction support worked correctly the correct test would
3808 # self.assertEqual(len(res), 0)
3809 # as the add of objectUUID=0123456789abcde3 would reverted when
3810 # the sub transaction it was nested in was rolled back.
3812 # Currently this is not the case so the record is still present.
3813 self.assertEqual(len(res), 1)
3816 # Commit the outer transaction
3818 self.ldb.transaction_commit()
3820 # Now check we can still see the records added in the outer
3823 res = self.ldb.search(expression="(objectUUID=0123456789abcde1)",
3824 base="dc=samba,dc=org")
3825 self.assertEqual(len(res), 1)
3826 res = self.ldb.search(expression="(objectUUID=0123456789abcde2)",
3827 base="dc=samba,dc=org")
3828 self.assertEqual(len(res), 1)
3830 # And that we can't see the records added by the nested transaction.
3832 res = self.ldb.search(expression="(objectUUID=0123456789abcde3)",
3833 base="dc=samba,dc=org")
3834 # FIXME again if nested transactions worked correctly we would not
3835 # see this record. The test should be.
3836 # self.assertEqual(len(res), 0)
3837 self.assertEqual(len(res), 1)
3840 super(NestedTransactionTests, self).tearDown()
3843 class LmdbNestedTransactionTests(NestedTransactionTests):
3846 if os.environ.get('HAVE_LMDB', '1') == '0':
3847 self.skipTest("No lmdb backend")
3848 self.prefix = MDB_PREFIX
3849 self.index = MDB_INDEX_OBJ
3850 super(LmdbNestedTransactionTests, self).setUp()
3853 super(LmdbNestedTransactionTests, self).tearDown()
3856 if __name__ == '__main__':
3858 unittest.TestProgram()