2 # Simple tests for the ldb python bindings.
3 # Copyright (C) 2007 Jelmer Vernooij <jelmer@samba.org>
14 dir_prefix
= os
.path
.join(os
.environ
["SELFTEST_PREFIX"], "tmp")
17 return tempfile
.mktemp(dir=dir_prefix
)
19 class NoContextTests(unittest
.TestCase
):
21 def test_valid_attr_name(self
):
22 self
.assertTrue(ldb
.valid_attr_name("foo"))
23 self
.assertFalse(ldb
.valid_attr_name("24foo"))
25 def test_timestring(self
):
26 self
.assertEquals("19700101000000.0Z", ldb
.timestring(0))
27 self
.assertEquals("20071119191012.0Z", ldb
.timestring(1195499412))
29 def test_string_to_time(self
):
30 self
.assertEquals(0, ldb
.string_to_time("19700101000000.0Z"))
31 self
.assertEquals(1195499412, ldb
.string_to_time("20071119191012.0Z"))
34 class SimpleLdb(unittest
.TestCase
):
36 def test_connect(self
):
39 def test_connect_none(self
):
42 def test_connect_later(self
):
48 self
.assertTrue(repr(x
).startswith("<ldb connection"))
50 def test_set_create_perms(self
):
52 x
.set_create_perms(0600)
54 def test_set_modules_dir(self
):
56 x
.set_modules_dir("/tmp")
58 def test_modules_none(self
):
60 self
.assertEquals([], x
.modules())
62 def test_modules_tdb(self
):
63 x
= ldb
.Ldb("bar.ldb")
64 self
.assertEquals("[<ldb module 'tdb'>]", repr(x
.modules()))
66 def test_search(self
):
67 l
= ldb
.Ldb(filename())
68 self
.assertEquals(len(l
.search()), 1)
70 def test_search_controls(self
):
71 l
= ldb
.Ldb(filename())
72 self
.assertEquals(len(l
.search(controls
=["paged_results:0:5"])), 1)
74 def test_search_attrs(self
):
75 l
= ldb
.Ldb(filename())
76 self
.assertEquals(len(l
.search(ldb
.Dn(l
, ""), ldb
.SCOPE_SUBTREE
, "(dc=*)", ["dc"])), 0)
78 def test_search_string_dn(self
):
79 l
= ldb
.Ldb(filename())
80 self
.assertEquals(len(l
.search("", ldb
.SCOPE_SUBTREE
, "(dc=*)", ["dc"])), 0)
82 def test_search_attr_string(self
):
83 l
= ldb
.Ldb("foo.tdb")
84 self
.assertRaises(TypeError, l
.search
, attrs
="dc")
86 def test_opaque(self
):
87 l
= ldb
.Ldb(filename())
88 l
.set_opaque("my_opaque", l
)
89 self
.assertTrue(l
.get_opaque("my_opaque") is not None)
90 self
.assertEquals(None, l
.get_opaque("unknown"))
92 def test_search_scope_base(self
):
93 l
= ldb
.Ldb(filename())
94 self
.assertEquals(len(l
.search(ldb
.Dn(l
, "dc=foo1"),
95 ldb
.SCOPE_ONELEVEL
)), 0)
97 def test_delete(self
):
98 l
= ldb
.Ldb(filename())
99 self
.assertRaises(ldb
.LdbError
, lambda: l
.delete(ldb
.Dn(l
, "dc=foo2")))
101 def test_delete_w_unhandled_ctrl(self
):
102 l
= ldb
.Ldb(filename())
104 m
.dn
= ldb
.Dn(l
, "dc=foo1")
107 self
.assertRaises(ldb
.LdbError
, lambda: l
.delete(m
.dn
, ["search_options:1:2"]))
110 def test_contains(self
):
111 l
= ldb
.Ldb(filename())
112 self
.assertFalse(ldb
.Dn(l
, "dc=foo3") in l
)
113 l
= ldb
.Ldb(filename())
115 m
.dn
= ldb
.Dn(l
, "dc=foo3")
119 self
.assertTrue(ldb
.Dn(l
, "dc=foo3") in l
)
123 def test_get_config_basedn(self
):
124 l
= ldb
.Ldb(filename())
125 self
.assertEquals(None, l
.get_config_basedn())
127 def test_get_root_basedn(self
):
128 l
= ldb
.Ldb(filename())
129 self
.assertEquals(None, l
.get_root_basedn())
131 def test_get_schema_basedn(self
):
132 l
= ldb
.Ldb(filename())
133 self
.assertEquals(None, l
.get_schema_basedn())
135 def test_get_default_basedn(self
):
136 l
= ldb
.Ldb(filename())
137 self
.assertEquals(None, l
.get_default_basedn())
140 l
= ldb
.Ldb(filename())
142 m
.dn
= ldb
.Dn(l
, "dc=foo4")
144 self
.assertEquals(len(l
.search()), 1)
147 self
.assertEquals(len(l
.search()), 2)
149 l
.delete(ldb
.Dn(l
, "dc=foo4"))
151 def test_add_w_unhandled_ctrl(self
):
152 l
= ldb
.Ldb(filename())
154 m
.dn
= ldb
.Dn(l
, "dc=foo4")
156 self
.assertEquals(len(l
.search()), 1)
157 self
.assertRaises(ldb
.LdbError
, lambda: l
.add(m
,["search_options:1:2"]))
159 def test_add_dict(self
):
160 l
= ldb
.Ldb(filename())
161 m
= {"dn": ldb
.Dn(l
, "dc=foo5"),
163 self
.assertEquals(len(l
.search()), 1)
166 self
.assertEquals(len(l
.search()), 2)
168 l
.delete(ldb
.Dn(l
, "dc=foo5"))
170 def test_add_dict_string_dn(self
):
171 l
= ldb
.Ldb(filename())
172 m
= {"dn": "dc=foo6", "bla": "bla"}
173 self
.assertEquals(len(l
.search()), 1)
176 self
.assertEquals(len(l
.search()), 2)
178 l
.delete(ldb
.Dn(l
, "dc=foo6"))
180 def test_rename(self
):
181 l
= ldb
.Ldb(filename())
183 m
.dn
= ldb
.Dn(l
, "dc=foo7")
185 self
.assertEquals(len(l
.search()), 1)
188 l
.rename(ldb
.Dn(l
, "dc=foo7"), ldb
.Dn(l
, "dc=bar"))
189 self
.assertEquals(len(l
.search()), 2)
191 l
.delete(ldb
.Dn(l
, "dc=bar"))
193 def test_rename_string_dns(self
):
194 l
= ldb
.Ldb(filename())
196 m
.dn
= ldb
.Dn(l
, "dc=foo8")
198 self
.assertEquals(len(l
.search()), 1)
200 self
.assertEquals(len(l
.search()), 2)
202 l
.rename("dc=foo8", "dc=bar")
203 self
.assertEquals(len(l
.search()), 2)
205 l
.delete(ldb
.Dn(l
, "dc=bar"))
207 def test_modify_delete(self
):
208 l
= ldb
.Ldb(filename())
210 m
.dn
= ldb
.Dn(l
, "dc=modifydelete")
213 rm
= l
.search(m
.dn
)[0]
214 self
.assertEquals(["1234"], list(rm
["bla"]))
217 m
.dn
= ldb
.Dn(l
, "dc=modifydelete")
218 m
["bla"] = ldb
.MessageElement([], ldb
.FLAG_MOD_DELETE
, "bla")
219 self
.assertEquals(ldb
.FLAG_MOD_DELETE
, m
["bla"].flags())
221 rm
= l
.search(m
.dn
)[0]
222 self
.assertEquals(1, len(rm
))
223 rm
= l
.search(m
.dn
, attrs
=["bla"])
224 self
.assertEquals(0, len(rm
))
226 l
.delete(ldb
.Dn(l
, "dc=modifydelete"))
228 def test_modify_add(self
):
229 l
= ldb
.Ldb(filename())
231 m
.dn
= ldb
.Dn(l
, "dc=add")
236 m
.dn
= ldb
.Dn(l
, "dc=add")
237 m
["bla"] = ldb
.MessageElement(["456"], ldb
.FLAG_MOD_ADD
, "bla")
238 self
.assertEquals(ldb
.FLAG_MOD_ADD
, m
["bla"].flags())
240 rm
= l
.search(m
.dn
)[0]
241 self
.assertEquals(2, len(rm
))
242 self
.assertEquals(["1234", "456"], list(rm
["bla"]))
244 l
.delete(ldb
.Dn(l
, "dc=add"))
246 def test_modify_replace(self
):
247 l
= ldb
.Ldb(filename())
249 m
.dn
= ldb
.Dn(l
, "dc=modify2")
250 m
["bla"] = ["1234", "456"]
254 m
.dn
= ldb
.Dn(l
, "dc=modify2")
255 m
["bla"] = ldb
.MessageElement(["789"], ldb
.FLAG_MOD_REPLACE
, "bla")
256 self
.assertEquals(ldb
.FLAG_MOD_REPLACE
, m
["bla"].flags())
258 rm
= l
.search(m
.dn
)[0]
259 self
.assertEquals(2, len(rm
))
260 self
.assertEquals(["789"], list(rm
["bla"]))
261 rm
= l
.search(m
.dn
, attrs
=["bla"])[0]
262 self
.assertEquals(1, len(rm
))
264 l
.delete(ldb
.Dn(l
, "dc=modify2"))
266 def test_modify_flags_change(self
):
267 l
= ldb
.Ldb(filename())
269 m
.dn
= ldb
.Dn(l
, "dc=add")
274 m
.dn
= ldb
.Dn(l
, "dc=add")
275 m
["bla"] = ldb
.MessageElement(["456"], ldb
.FLAG_MOD_ADD
, "bla")
276 self
.assertEquals(ldb
.FLAG_MOD_ADD
, m
["bla"].flags())
278 rm
= l
.search(m
.dn
)[0]
279 self
.assertEquals(2, len(rm
))
280 self
.assertEquals(["1234", "456"], list(rm
["bla"]))
282 #Now create another modify, but switch the flags before we do it
283 m
["bla"] = ldb
.MessageElement(["456"], ldb
.FLAG_MOD_ADD
, "bla")
284 m
["bla"].set_flags(ldb
.FLAG_MOD_DELETE
)
286 rm
= l
.search(m
.dn
, attrs
=["bla"])[0]
287 self
.assertEquals(1, len(rm
))
288 self
.assertEquals(["1234"], list(rm
["bla"]))
291 l
.delete(ldb
.Dn(l
, "dc=add"))
293 def test_transaction_commit(self
):
294 l
= ldb
.Ldb(filename())
295 l
.transaction_start()
296 m
= ldb
.Message(ldb
.Dn(l
, "dc=foo9"))
299 l
.transaction_commit()
302 def test_transaction_cancel(self
):
303 l
= ldb
.Ldb(filename())
304 l
.transaction_start()
305 m
= ldb
.Message(ldb
.Dn(l
, "dc=foo10"))
308 l
.transaction_cancel()
309 self
.assertEquals(0, len(l
.search(ldb
.Dn(l
, "dc=foo10"))))
311 def test_set_debug(self
):
312 def my_report_fn(level
, text
):
314 l
= ldb
.Ldb(filename())
315 l
.set_debug(my_report_fn
)
317 def test_zero_byte_string(self
):
318 """Testing we do not get trapped in the \0 byte in a property string."""
319 l
= ldb
.Ldb(filename())
322 "objectclass" : "user",
323 "cN" : "LDAPtestUSER",
324 "givenname" : "ldap",
325 "displayname" : "foo\0bar",
327 res
= l
.search(expression
="(dn=dc=somedn)")
328 self
.assertEquals("foo\0bar", res
[0]["displayname"][0])
330 def test_no_crash_broken_expr(self
):
331 l
= ldb
.Ldb(filename())
332 self
.assertRaises(ldb
.LdbError
,lambda: l
.search("", ldb
.SCOPE_SUBTREE
, "&(dc=*)(dn=*)", ["dc"]))
335 class DnTests(unittest
.TestCase
):
338 self
.ldb
= ldb
.Ldb(filename())
340 def test_set_dn_invalid(self
):
344 self
.assertRaises(TypeError, assign
)
347 x
= ldb
.Dn(self
.ldb
, "dc=foo11,bar=bloe")
348 y
= ldb
.Dn(self
.ldb
, "dc=foo11,bar=bloe")
349 self
.assertEquals(x
, y
)
350 y
= ldb
.Dn(self
.ldb
, "dc=foo11,bar=blie")
351 self
.assertNotEquals(x
, y
)
354 x
= ldb
.Dn(self
.ldb
, "dc=foo12,bar=bloe")
355 self
.assertEquals(x
.__str
__(), "dc=foo12,bar=bloe")
358 x
= ldb
.Dn(self
.ldb
, "dc=foo13,bla=blie")
359 self
.assertEquals(x
.__repr
__(), "Dn('dc=foo13,bla=blie')")
361 def test_get_casefold(self
):
362 x
= ldb
.Dn(self
.ldb
, "dc=foo14,bar=bloe")
363 self
.assertEquals(x
.get_casefold(), "DC=FOO14,BAR=bloe")
365 def test_validate(self
):
366 x
= ldb
.Dn(self
.ldb
, "dc=foo15,bar=bloe")
367 self
.assertTrue(x
.validate())
369 def test_parent(self
):
370 x
= ldb
.Dn(self
.ldb
, "dc=foo16,bar=bloe")
371 self
.assertEquals("bar=bloe", x
.parent().__str
__())
373 def test_parent_nonexistant(self
):
374 x
= ldb
.Dn(self
.ldb
, "@BLA")
375 self
.assertEquals(None, x
.parent())
377 def test_is_valid(self
):
378 x
= ldb
.Dn(self
.ldb
, "dc=foo18,dc=bloe")
379 self
.assertTrue(x
.is_valid())
380 x
= ldb
.Dn(self
.ldb
, "")
381 self
.assertTrue(x
.is_valid())
383 def test_is_special(self
):
384 x
= ldb
.Dn(self
.ldb
, "dc=foo19,bar=bloe")
385 self
.assertFalse(x
.is_special())
386 x
= ldb
.Dn(self
.ldb
, "@FOOBAR")
387 self
.assertTrue(x
.is_special())
389 def test_check_special(self
):
390 x
= ldb
.Dn(self
.ldb
, "dc=foo20,bar=bloe")
391 self
.assertFalse(x
.check_special("FOOBAR"))
392 x
= ldb
.Dn(self
.ldb
, "@FOOBAR")
393 self
.assertTrue(x
.check_special("@FOOBAR"))
396 x
= ldb
.Dn(self
.ldb
, "dc=foo21,bar=bloe")
397 self
.assertEquals(2, len(x
))
398 x
= ldb
.Dn(self
.ldb
, "dc=foo21")
399 self
.assertEquals(1, len(x
))
401 def test_add_child(self
):
402 x
= ldb
.Dn(self
.ldb
, "dc=foo22,bar=bloe")
403 self
.assertTrue(x
.add_child(ldb
.Dn(self
.ldb
, "bla=bloe")))
404 self
.assertEquals("bla=bloe,dc=foo22,bar=bloe", x
.__str
__())
406 def test_add_base(self
):
407 x
= ldb
.Dn(self
.ldb
, "dc=foo23,bar=bloe")
408 base
= ldb
.Dn(self
.ldb
, "bla=bloe")
409 self
.assertTrue(x
.add_base(base
))
410 self
.assertEquals("dc=foo23,bar=bloe,bla=bloe", x
.__str
__())
413 x
= ldb
.Dn(self
.ldb
, "dc=foo24")
414 y
= ldb
.Dn(self
.ldb
, "bar=bla")
415 self
.assertEquals("dc=foo24,bar=bla", str(y
+ x
))
417 def test_parse_ldif(self
):
418 msgs
= self
.ldb
.parse_ldif("dn: foo=bar\n")
420 self
.assertEquals("foo=bar", str(msg
[1].dn
))
421 self
.assertTrue(isinstance(msg
[1], ldb
.Message
))
422 ldif
= self
.ldb
.write_ldif(msg
[1], ldb
.CHANGETYPE_NONE
)
423 self
.assertEquals("dn: foo=bar\n\n", ldif
)
425 def test_parse_ldif_more(self
):
426 msgs
= self
.ldb
.parse_ldif("dn: foo=bar\n\n\ndn: bar=bar")
428 self
.assertEquals("foo=bar", str(msg
[1].dn
))
430 self
.assertEquals("bar=bar", str(msg
[1].dn
))
432 def test_canonical_string(self
):
433 x
= ldb
.Dn(self
.ldb
, "dc=foo25,bar=bloe")
434 self
.assertEquals("/bloe/foo25", x
.canonical_str())
436 def test_canonical_ex_string(self
):
437 x
= ldb
.Dn(self
.ldb
, "dc=foo26,bar=bloe")
438 self
.assertEquals("/bloe\nfoo26", x
.canonical_ex_str())
441 class LdbMsgTests(unittest
.TestCase
):
444 self
.msg
= ldb
.Message()
446 def test_init_dn(self
):
447 self
.msg
= ldb
.Message(ldb
.Dn(ldb
.Ldb(), "dc=foo27"))
448 self
.assertEquals("dc=foo27", str(self
.msg
.dn
))
450 def test_iter_items(self
):
451 self
.assertEquals(0, len(self
.msg
.items()))
452 self
.msg
.dn
= ldb
.Dn(ldb
.Ldb("foo.tdb"), "dc=foo28")
453 self
.assertEquals(1, len(self
.msg
.items()))
456 self
.msg
.dn
= ldb
.Dn(ldb
.Ldb("foo.tdb"), "dc=foo29")
457 self
.msg
["dc"] = "foo"
458 self
.assertEquals("Message({'dn': Dn('dc=foo29'), 'dc': MessageElement(['foo'])})", repr(self
.msg
))
461 self
.assertEquals(0, len(self
.msg
))
463 def test_notpresent(self
):
464 self
.assertRaises(KeyError, lambda: self
.msg
["foo"])
469 def test_add_value(self
):
470 self
.assertEquals(0, len(self
.msg
))
471 self
.msg
["foo"] = ["foo"]
472 self
.assertEquals(1, len(self
.msg
))
474 def test_add_value_multiple(self
):
475 self
.assertEquals(0, len(self
.msg
))
476 self
.msg
["foo"] = ["foo", "bla"]
477 self
.assertEquals(1, len(self
.msg
))
478 self
.assertEquals(["foo", "bla"], list(self
.msg
["foo"]))
480 def test_set_value(self
):
481 self
.msg
["foo"] = ["fool"]
482 self
.assertEquals(["fool"], list(self
.msg
["foo"]))
483 self
.msg
["foo"] = ["bar"]
484 self
.assertEquals(["bar"], list(self
.msg
["foo"]))
487 self
.msg
.dn
= ldb
.Dn(ldb
.Ldb("foo.tdb"), "@BASEINFO")
488 self
.msg
["foo"] = ["bla"]
489 self
.msg
["bar"] = ["bla"]
490 self
.assertEquals(["dn", "foo", "bar"], self
.msg
.keys())
493 self
.msg
.dn
= ldb
.Dn(ldb
.Ldb(filename()), "@BASEINFO")
494 self
.assertEquals("@BASEINFO", self
.msg
.dn
.__str
__())
496 def test_get_dn(self
):
497 self
.msg
.dn
= ldb
.Dn(ldb
.Ldb("foo.tdb"), "@BASEINFO")
498 self
.assertEquals("@BASEINFO", self
.msg
.get("dn").__str
__())
500 def test_get_invalid(self
):
501 self
.msg
.dn
= ldb
.Dn(ldb
.Ldb("foo.tdb"), "@BASEINFO")
502 self
.assertRaises(TypeError, self
.msg
.get
, 42)
504 def test_get_other(self
):
505 self
.msg
["foo"] = ["bar"]
506 self
.assertEquals("bar", self
.msg
.get("foo")[0])
508 def test_get_unknown(self
):
509 self
.assertEquals(None, self
.msg
.get("lalalala"))
511 def test_msg_diff(self
):
513 msgs
= l
.parse_ldif("dn: foo=bar\nfoo: bar\nbaz: do\n\ndn: foo=bar\nfoo: bar\nbaz: dont\n")
514 msg1
= msgs
.next()[1]
515 msg2
= msgs
.next()[1]
516 msgdiff
= l
.msg_diff(msg1
, msg2
)
517 self
.assertEquals("foo=bar", msgdiff
.get("dn").__str
__())
518 self
.assertRaises(KeyError, lambda: msgdiff
["foo"])
519 self
.assertEquals(1, len(msgdiff
))
521 def test_equal_empty(self
):
524 self
.assertEquals(msg1
, msg2
)
526 def test_equal_simplel(self
):
527 db
= ldb
.Ldb("foo.tdb")
529 msg1
.dn
= ldb
.Dn(db
, "foo=bar")
531 msg2
.dn
= ldb
.Dn(db
, "foo=bar")
532 self
.assertEquals(msg1
, msg2
)
535 self
.assertEquals(msg1
, msg2
)
537 self
.assertNotEquals(msg1
, msg2
)
540 def test_from_dict(self
):
541 rec
= {"dn": "dc=fromdict",
542 "a1": ["a1-val1", "a1-val1"]}
544 # check different types of input Flags
545 for flags
in [ldb
.FLAG_MOD_ADD
, ldb
.FLAG_MOD_REPLACE
, ldb
.FLAG_MOD_DELETE
]:
546 m
= ldb
.Message
.from_dict(l
, rec
, flags
)
547 self
.assertEquals(rec
["a1"], list(m
["a1"]))
548 self
.assertEquals(flags
, m
["a1"].flags())
550 self
.assertRaises(TypeError, ldb
.Message
.from_dict
, dict(), rec
, ldb
.FLAG_MOD_REPLACE
)
551 self
.assertRaises(TypeError, ldb
.Message
.from_dict
, l
, list(), ldb
.FLAG_MOD_REPLACE
)
552 self
.assertRaises(ValueError, ldb
.Message
.from_dict
, l
, rec
, 0)
553 # Message.from_dict expects dictionary with 'dn'
554 err_rec
= {"a1": ["a1-val1", "a1-val1"]}
555 self
.assertRaises(TypeError, ldb
.Message
.from_dict
, l
, err_rec
, ldb
.FLAG_MOD_REPLACE
)
559 class MessageElementTests(unittest
.TestCase
):
561 def test_cmp_element(self
):
562 x
= ldb
.MessageElement(["foo"])
563 y
= ldb
.MessageElement(["foo"])
564 z
= ldb
.MessageElement(["bzr"])
565 self
.assertEquals(x
, y
)
566 self
.assertNotEquals(x
, z
)
568 def test_create_iterable(self
):
569 x
= ldb
.MessageElement(["foo"])
570 self
.assertEquals(["foo"], list(x
))
573 x
= ldb
.MessageElement(["foo"])
574 self
.assertEquals("MessageElement(['foo'])", repr(x
))
575 x
= ldb
.MessageElement(["foo", "bla"])
576 self
.assertEquals(2, len(x
))
577 self
.assertEquals("MessageElement(['foo','bla'])", repr(x
))
579 def test_get_item(self
):
580 x
= ldb
.MessageElement(["foo", "bar"])
581 self
.assertEquals("foo", x
[0])
582 self
.assertEquals("bar", x
[1])
583 self
.assertEquals("bar", x
[-1])
584 self
.assertRaises(IndexError, lambda: x
[45])
587 x
= ldb
.MessageElement(["foo", "bar"])
588 self
.assertEquals(2, len(x
))
591 x
= ldb
.MessageElement(["foo", "bar"])
592 y
= ldb
.MessageElement(["foo", "bar"])
593 self
.assertEquals(y
, x
)
594 x
= ldb
.MessageElement(["foo"])
595 self
.assertNotEquals(y
, x
)
596 y
= ldb
.MessageElement(["foo"])
597 self
.assertEquals(y
, x
)
600 class ModuleTests(unittest
.TestCase
):
602 def test_register_module(self
):
605 ldb
.register_module(ExampleModule
)
607 def test_use_module(self
):
612 def __init__(self
, ldb
, next
):
616 def search(self
, *args
, **kwargs
):
617 return self
.next
.search(*args
, **kwargs
)
619 ldb
.register_module(ExampleModule
)
620 if os
.path
.exists("usemodule.ldb"):
621 os
.unlink("usemodule.ldb")
622 l
= ldb
.Ldb("usemodule.ldb")
623 l
.add({"dn": "@MODULES", "@LIST": "bla"})
624 self
.assertEquals([], ops
)
625 l
= ldb
.Ldb("usemodule.ldb")
626 self
.assertEquals(["init"], ops
)
629 class VersionTests(unittest
.TestCase
):
631 def test_version(self
):
632 self
.assertTrue(isinstance(ldb
.__version
__, str))
635 if __name__
== '__main__':
637 unittest
.TestProgram()