3 # Unix SMB/CIFS implementation.
4 # Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2005-2008
5 # Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
7 # This is a Python port of the original in testprogs/ejs/samba3sam.js
9 # This program is free software; you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 3 of the License, or
12 # (at your option) any later version.
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <http://www.gnu.org/licenses/>.
23 """Tests for the samba3sam LDB module, which maps Samba3 LDAP to AD LDAP."""
27 from ldb import SCOPE_DEFAULT, SCOPE_BASE
28 from samba import Ldb, substitute_var
29 from samba.tests import TestCaseInTempDir, env_loadparm
30 import samba.dcerpc.security
32 from samba.auth import system_session
33 from operator import attrgetter
36 def read_datafile(filename):
37 paths = [ "../../../../../testdata/samba3",
38 "../../../../testdata/samba3" ]
40 datadir = os.path.join(os.path.dirname(__file__), p)
41 if os.path.exists(datadir):
43 return open(os.path.join(datadir, filename), 'r').read()
45 def ldb_debug(l, text):
49 class MapBaseTestCase(TestCaseInTempDir):
50 """Base test case for mapping tests."""
52 def setup_modules(self, ldb, s3, s4):
53 ldb.add({"dn": "@MAP=samba3sam",
55 "@TO": "sambaDomainName=TESTS," + s3.basedn})
57 ldb.add({"dn": "@MODULES",
58 "@LIST": "rootdse,paged_results,server_sort,asq,samldb,password_hash,operational,objectguid,rdn_name,samba3sam,samba3sid,partition"})
60 ldb.add({"dn": "@PARTITION",
61 "partition": ["%s" % (s4.basedn_casefold),
62 "%s" % (s3.basedn_casefold)],
63 "replicateEntries": ["@ATTRIBUTES", "@INDEXLIST"],
67 self.lp = env_loadparm()
68 self.lp.set("sid generator", "backend")
69 self.lp.set("workgroup", "TESTS")
70 self.lp.set("netbios name", "TESTS")
71 super(MapBaseTestCase, self).setUp()
73 def make_dn(basedn, rdn):
74 return "%s,sambaDomainName=TESTS,%s" % (rdn, basedn)
76 def make_s4dn(basedn, rdn):
77 return "%s,%s" % (rdn, basedn)
79 self.ldbfile = os.path.join(self.tempdir, "test.ldb")
80 self.ldburl = "tdb://" + self.ldbfile
82 tempdir = self.tempdir
85 """Simple helper class that contains data for a specific SAM
88 def __init__(self, basedn, dn, lp):
89 self.db = Ldb(lp=lp, session_info=system_session())
91 self.basedn_casefold = ldb.Dn(self.db, basedn).get_casefold()
92 self.substvars = {"BASEDN": self.basedn}
93 self.file = os.path.join(tempdir, "%s.ldb" % self.basedn_casefold)
94 self.url = "tdb://" + self.file
98 return self._dn(self.basedn, rdn)
101 return self.db.connect(self.url)
103 def setup_data(self, path):
104 self.add_ldif(read_datafile(path))
106 def subst(self, text):
107 return substitute_var(text, self.substvars)
109 def add_ldif(self, ldif):
110 self.db.add_ldif(self.subst(ldif))
112 def modify_ldif(self, ldif):
113 self.db.modify_ldif(self.subst(ldif))
115 self.samba4 = Target("dc=vernstok,dc=nl", make_s4dn, self.lp)
116 self.samba3 = Target("cn=Samba3Sam", make_dn, self.lp)
118 self.samba3.connect()
119 self.samba4.connect()
122 os.unlink(self.ldbfile)
123 os.unlink(self.samba3.file)
124 os.unlink(self.samba4.file)
125 super(MapBaseTestCase, self).tearDown()
127 def assertSidEquals(self, text, ndr_sid):
128 sid_obj1 = samba.ndr.ndr_unpack(samba.dcerpc.security.dom_sid,
130 sid_obj2 = samba.dcerpc.security.dom_sid(text)
131 self.assertEquals(sid_obj1, sid_obj2)
134 class Samba3SamTestCase(MapBaseTestCase):
137 super(Samba3SamTestCase, self).setUp()
138 ldb = Ldb(self.ldburl, lp=self.lp, session_info=system_session())
139 self.samba3.setup_data("samba3.ldif")
140 ldif = read_datafile("provision_samba3sam.ldif")
141 ldb.add_ldif(self.samba4.subst(ldif))
142 self.setup_modules(ldb, self.samba3, self.samba4)
144 self.ldb = Ldb(self.ldburl, lp=self.lp, session_info=system_session())
146 def test_search_non_mapped(self):
147 """Looking up by non-mapped attribute"""
148 msg = self.ldb.search(expression="(cn=Administrator)")
149 self.assertEquals(len(msg), 1)
150 self.assertEquals(msg[0]["cn"], "Administrator")
152 def test_search_non_mapped(self):
153 """Looking up by mapped attribute"""
154 msg = self.ldb.search(expression="(name=Backup Operators)")
155 self.assertEquals(len(msg), 1)
156 self.assertEquals(str(msg[0]["name"]), "Backup Operators")
158 def test_old_name_of_renamed(self):
159 """Looking up by old name of renamed attribute"""
160 msg = self.ldb.search(expression="(displayName=Backup Operators)")
161 self.assertEquals(len(msg), 0)
163 def test_mapped_containing_sid(self):
164 """Looking up mapped entry containing SID"""
165 msg = self.ldb.search(expression="(cn=Replicator)")
166 self.assertEquals(len(msg), 1)
167 self.assertEquals(str(msg[0].dn),
168 "cn=Replicator,ou=Groups,dc=vernstok,dc=nl")
169 self.assertTrue("objectSid" in msg[0])
170 self.assertSidEquals("S-1-5-21-4231626423-2410014848-2360679739-552",
172 oc = set(msg[0]["objectClass"])
173 self.assertEquals(oc, set(["group"]))
175 def test_search_by_objclass(self):
176 """Looking up by objectClass"""
177 msg = self.ldb.search(expression="(|(objectClass=user)(cn=Administrator))")
178 self.assertEquals(set([str(m.dn) for m in msg]),
179 set(["unixName=Administrator,ou=Users,dc=vernstok,dc=nl",
180 "unixName=nobody,ou=Users,dc=vernstok,dc=nl"]))
182 def test_s3sam_modify(self):
183 # Adding a record that will be fallbacked
184 self.ldb.add({"dn": "cn=Foo",
188 "showInAdvancedViewOnly": "TRUE"}
191 # Checking for existence of record (local)
192 # TODO: This record must be searched in the local database, which is
193 # currently only supported for base searches
194 # msg = ldb.search(expression="(cn=Foo)", ['foo','blah','cn','showInAdvancedViewOnly')]
195 # TODO: Actually, this version should work as well but doesn't...
198 msg = self.ldb.search(expression="(cn=Foo)", base="cn=Foo",
200 attrs=['foo','blah','cn','showInAdvancedViewOnly'])
201 self.assertEquals(len(msg), 1)
202 self.assertEquals(str(msg[0]["showInAdvancedViewOnly"]), "TRUE")
203 self.assertEquals(str(msg[0]["foo"]), "bar")
204 self.assertEquals(str(msg[0]["blah"]), "Blie")
206 # Adding record that will be mapped
207 self.ldb.add({"dn": "cn=Niemand,cn=Users,dc=vernstok,dc=nl",
208 "objectClass": "user",
210 "sambaUnicodePwd": "geheim",
213 # Checking for existence of record (remote)
214 msg = self.ldb.search(expression="(unixName=bin)",
215 attrs=['unixName','cn','dn', 'sambaUnicodePwd'])
216 self.assertEquals(len(msg), 1)
217 self.assertEquals(str(msg[0]["cn"]), "Niemand")
218 self.assertEquals(str(msg[0]["sambaUnicodePwd"]), "geheim")
220 # Checking for existence of record (local && remote)
221 msg = self.ldb.search(expression="(&(unixName=bin)(sambaUnicodePwd=geheim))",
222 attrs=['unixName','cn','dn', 'sambaUnicodePwd'])
223 self.assertEquals(len(msg), 1) # TODO: should check with more records
224 self.assertEquals(str(msg[0]["cn"]), "Niemand")
225 self.assertEquals(str(msg[0]["unixName"]), "bin")
226 self.assertEquals(str(msg[0]["sambaUnicodePwd"]), "geheim")
228 # Checking for existence of record (local || remote)
229 msg = self.ldb.search(expression="(|(unixName=bin)(sambaUnicodePwd=geheim))",
230 attrs=['unixName','cn','dn', 'sambaUnicodePwd'])
231 #print "got %d replies" % len(msg)
232 self.assertEquals(len(msg), 1) # TODO: should check with more records
233 self.assertEquals(str(msg[0]["cn"]), "Niemand")
234 self.assertEquals(str(msg[0]["unixName"]), "bin")
235 self.assertEquals(str(msg[0]["sambaUnicodePwd"]), "geheim")
237 # Checking for data in destination database
238 msg = self.samba3.db.search(expression="(cn=Niemand)")
239 self.assertTrue(len(msg) >= 1)
240 self.assertEquals(str(msg[0]["sambaSID"]),
241 "S-1-5-21-4231626423-2410014848-2360679739-2001")
242 self.assertEquals(str(msg[0]["displayName"]), "Niemand")
244 # Adding attribute...
245 self.ldb.modify_ldif("""
246 dn: cn=Niemand,cn=Users,dc=vernstok,dc=nl
252 # Checking whether changes are still there...
253 msg = self.ldb.search(expression="(cn=Niemand)")
254 self.assertTrue(len(msg) >= 1)
255 self.assertEquals(str(msg[0]["cn"]), "Niemand")
256 self.assertEquals(str(msg[0]["description"]), "Blah")
258 # Modifying attribute...
259 self.ldb.modify_ldif("""
260 dn: cn=Niemand,cn=Users,dc=vernstok,dc=nl
266 # Checking whether changes are still there...
267 msg = self.ldb.search(expression="(cn=Niemand)")
268 self.assertTrue(len(msg) >= 1)
269 self.assertEquals(str(msg[0]["description"]), "Blie")
271 # Deleting attribute...
272 self.ldb.modify_ldif("""
273 dn: cn=Niemand,cn=Users,dc=vernstok,dc=nl
278 # Checking whether changes are no longer there...
279 msg = self.ldb.search(expression="(cn=Niemand)")
280 self.assertTrue(len(msg) >= 1)
281 self.assertTrue(not "description" in msg[0])
284 self.ldb.rename("cn=Niemand,cn=Users,dc=vernstok,dc=nl",
285 "cn=Niemand2,cn=Users,dc=vernstok,dc=nl")
287 # Checking whether DN has changed...
288 msg = self.ldb.search(expression="(cn=Niemand2)")
289 self.assertEquals(len(msg), 1)
290 self.assertEquals(str(msg[0].dn),
291 "cn=Niemand2,cn=Users,dc=vernstok,dc=nl")
294 self.ldb.delete("cn=Niemand2,cn=Users,dc=vernstok,dc=nl")
296 # Checking whether record is gone...
297 msg = self.ldb.search(expression="(cn=Niemand2)")
298 self.assertEquals(len(msg), 0)
301 class MapTestCase(MapBaseTestCase):
304 super(MapTestCase, self).setUp()
305 ldb = Ldb(self.ldburl, lp=self.lp, session_info=system_session())
306 ldif = read_datafile("provision_samba3sam.ldif")
307 ldb.add_ldif(self.samba4.subst(ldif))
308 self.setup_modules(ldb, self.samba3, self.samba4)
310 self.ldb = Ldb(self.ldburl, lp=self.lp, session_info=system_session())
312 def test_map_search(self):
313 """Running search tests on mapped data."""
315 "dn": "sambaDomainName=TESTS," + self.samba3.basedn,
316 "objectclass": ["sambaDomain", "top"],
317 "sambaSID": "S-1-5-21-4231626423-2410014848-2360679739",
318 "sambaNextRid": "2000",
319 "sambaDomainName": "TESTS"
322 # Add a set of split records
323 self.ldb.add_ldif("""
324 dn: """+ self.samba4.dn("cn=Domain Users") + """
327 objectSid: S-1-5-21-4231626423-2410014848-2360679739-513
330 # Add a set of split records
331 self.ldb.add_ldif("""
332 dn: """+ self.samba4.dn("cn=X") + """
341 objectSid: S-1-5-21-4231626423-2410014848-2360679739-552
345 "dn": self.samba4.dn("cn=Y"),
346 "objectClass": "top",
356 "dn": self.samba4.dn("cn=Z"),
357 "objectClass": "top",
366 # Add a set of remote records
369 "dn": self.samba3.dn("cn=A"),
370 "objectClass": "posixAccount",
373 "sambaBadPasswordCount": "x",
374 "sambaLogonTime": "x",
376 "sambaSID": "S-1-5-21-4231626423-2410014848-2360679739-552",
377 "sambaPrimaryGroupSID": "S-1-5-21-4231626423-2410014848-2360679739-512"})
380 "dn": self.samba3.dn("cn=B"),
381 "objectClass": "top",
384 "sambaBadPasswordCount": "x",
385 "sambaLogonTime": "y",
389 "dn": self.samba3.dn("cn=C"),
390 "objectClass": "top",
393 "sambaBadPasswordCount": "y",
394 "sambaLogonTime": "z",
397 # Testing search by DN
399 # Search remote record by local DN
400 dn = self.samba4.dn("cn=A")
401 res = self.ldb.search(dn, scope=SCOPE_BASE,
402 attrs=["dnsHostName", "lastLogon"])
403 self.assertEquals(len(res), 1)
404 self.assertEquals(str(res[0].dn), dn)
405 self.assertTrue(not "dnsHostName" in res[0])
406 self.assertEquals(str(res[0]["lastLogon"]), "x")
408 # Search remote record by remote DN
409 dn = self.samba3.dn("cn=A")
410 res = self.samba3.db.search(dn, scope=SCOPE_BASE,
411 attrs=["dnsHostName", "lastLogon", "sambaLogonTime"])
412 self.assertEquals(len(res), 1)
413 self.assertEquals(str(res[0].dn), dn)
414 self.assertTrue(not "dnsHostName" in res[0])
415 self.assertTrue(not "lastLogon" in res[0])
416 self.assertEquals(str(res[0]["sambaLogonTime"]), "x")
418 # Search split record by local DN
419 dn = self.samba4.dn("cn=X")
420 res = self.ldb.search(dn, scope=SCOPE_BASE,
421 attrs=["dnsHostName", "lastLogon"])
422 self.assertEquals(len(res), 1)
423 self.assertEquals(str(res[0].dn), dn)
424 self.assertEquals(str(res[0]["dnsHostName"]), "x")
425 self.assertEquals(str(res[0]["lastLogon"]), "x")
427 # Search split record by remote DN
428 dn = self.samba3.dn("cn=X")
429 res = self.samba3.db.search(dn, scope=SCOPE_BASE,
430 attrs=["dnsHostName", "lastLogon", "sambaLogonTime"])
431 self.assertEquals(len(res), 1)
432 self.assertEquals(str(res[0].dn), dn)
433 self.assertTrue(not "dnsHostName" in res[0])
434 self.assertTrue(not "lastLogon" in res[0])
435 self.assertEquals(str(res[0]["sambaLogonTime"]), "x")
437 # Testing search by attribute
439 # Search by ignored attribute
440 res = self.ldb.search(expression="(revision=x)", scope=SCOPE_DEFAULT,
441 attrs=["dnsHostName", "lastLogon"])
442 self.assertEquals(len(res), 2)
443 res = sorted(res, key=attrgetter('dn'))
444 self.assertEquals(str(res[0].dn), self.samba4.dn("cn=X"))
445 self.assertEquals(str(res[0]["dnsHostName"]), "x")
446 self.assertEquals(str(res[0]["lastLogon"]), "x")
447 self.assertEquals(str(res[1].dn), self.samba4.dn("cn=Y"))
448 self.assertEquals(str(res[1]["dnsHostName"]), "y")
449 self.assertEquals(str(res[1]["lastLogon"]), "y")
451 # Search by kept attribute
452 res = self.ldb.search(expression="(description=y)",
453 scope=SCOPE_DEFAULT, attrs=["dnsHostName", "lastLogon"])
454 self.assertEquals(len(res), 2)
455 res = sorted(res, key=attrgetter('dn'))
456 self.assertEquals(str(res[0].dn), self.samba4.dn("cn=C"))
457 self.assertTrue(not "dnsHostName" in res[0])
458 self.assertEquals(str(res[0]["lastLogon"]), "z")
459 self.assertEquals(str(res[1].dn), self.samba4.dn("cn=Z"))
460 self.assertEquals(str(res[1]["dnsHostName"]), "z")
461 self.assertEquals(str(res[1]["lastLogon"]), "z")
463 # Search by renamed attribute
464 res = self.ldb.search(expression="(badPwdCount=x)", scope=SCOPE_DEFAULT,
465 attrs=["dnsHostName", "lastLogon"])
466 self.assertEquals(len(res), 2)
467 res = sorted(res, key=attrgetter('dn'))
468 self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A"))
469 self.assertTrue(not "dnsHostName" in res[0])
470 self.assertEquals(str(res[0]["lastLogon"]), "x")
471 self.assertEquals(str(res[1].dn), self.samba4.dn("cn=B"))
472 self.assertTrue(not "dnsHostName" in res[1])
473 self.assertEquals(str(res[1]["lastLogon"]), "y")
475 # Search by converted attribute
477 # Using the SID directly in the parse tree leads to conversion
478 # errors, letting the search fail with no results.
479 #res = self.ldb.search("(objectSid=S-1-5-21-4231626423-2410014848-2360679739-552)", scope=SCOPE_DEFAULT, attrs)
480 res = self.ldb.search(expression="(objectSid=*)", base=None, scope=SCOPE_DEFAULT, attrs=["dnsHostName", "lastLogon", "objectSid"])
481 self.assertEquals(len(res), 4)
482 res = sorted(res, key=attrgetter('dn'))
483 self.assertEquals(str(res[1].dn), self.samba4.dn("cn=X"))
484 self.assertEquals(str(res[1]["dnsHostName"]), "x")
485 self.assertEquals(str(res[1]["lastLogon"]), "x")
486 self.assertSidEquals("S-1-5-21-4231626423-2410014848-2360679739-552",
488 self.assertTrue("objectSid" in res[1])
489 self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A"))
490 self.assertTrue(not "dnsHostName" in res[0])
491 self.assertEquals(str(res[0]["lastLogon"]), "x")
492 self.assertSidEquals("S-1-5-21-4231626423-2410014848-2360679739-552",
494 self.assertTrue("objectSid" in res[0])
496 # Search by generated attribute
497 # In most cases, this even works when the mapping is missing
498 # a `convert_operator' by enumerating the remote db.
499 res = self.ldb.search(expression="(primaryGroupID=512)",
500 attrs=["dnsHostName", "lastLogon", "primaryGroupID"])
501 self.assertEquals(len(res), 1)
502 self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A"))
503 self.assertTrue(not "dnsHostName" in res[0])
504 self.assertEquals(str(res[0]["lastLogon"]), "x")
505 self.assertEquals(str(res[0]["primaryGroupID"]), "512")
507 # Note that Xs "objectSid" seems to be fine in the previous search for
509 #res = ldb.search(expression="(primaryGroupID=*)", NULL, ldb. SCOPE_DEFAULT, attrs)
510 #print len(res) + " results found"
511 #for i in range(len(res)):
512 # for (obj in res[i]) {
513 # print obj + ": " + res[i][obj]
518 # Search by remote name of renamed attribute */
519 res = self.ldb.search(expression="(sambaBadPasswordCount=*)",
520 attrs=["dnsHostName", "lastLogon"])
521 self.assertEquals(len(res), 0)
523 # Search by objectClass
524 attrs = ["dnsHostName", "lastLogon", "objectClass"]
525 res = self.ldb.search(expression="(objectClass=user)", attrs=attrs)
526 self.assertEquals(len(res), 2)
527 res = sorted(res, key=attrgetter('dn'))
528 self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A"))
529 self.assertTrue(not "dnsHostName" in res[0])
530 self.assertEquals(str(res[0]["lastLogon"]), "x")
531 self.assertEquals(str(res[0]["objectClass"][0]), "user")
532 self.assertEquals(str(res[1].dn), self.samba4.dn("cn=X"))
533 self.assertEquals(str(res[1]["dnsHostName"]), "x")
534 self.assertEquals(str(res[1]["lastLogon"]), "x")
535 self.assertEquals(str(res[1]["objectClass"][0]), "user")
537 # Prove that the objectClass is actually used for the search
538 res = self.ldb.search(expression="(|(objectClass=user)(badPwdCount=x))",
540 self.assertEquals(len(res), 3)
541 res = sorted(res, key=attrgetter('dn'))
542 self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A"))
543 self.assertTrue(not "dnsHostName" in res[0])
544 self.assertEquals(str(res[0]["lastLogon"]), "x")
545 self.assertEquals(res[0]["objectClass"][0], "user")
546 self.assertEquals(str(res[1].dn), self.samba4.dn("cn=B"))
547 self.assertTrue(not "dnsHostName" in res[1])
548 self.assertEquals(str(res[1]["lastLogon"]), "y")
549 self.assertEquals(set(res[1]["objectClass"]), set(["top"]))
550 self.assertEquals(str(res[2].dn), self.samba4.dn("cn=X"))
551 self.assertEquals(str(res[2]["dnsHostName"]), "x")
552 self.assertEquals(str(res[2]["lastLogon"]), "x")
553 self.assertEquals(str(res[2]["objectClass"][0]), "user")
555 # Testing search by parse tree
557 # Search by conjunction of local attributes
558 res = self.ldb.search(expression="(&(codePage=x)(revision=x))",
559 attrs=["dnsHostName", "lastLogon"])
560 self.assertEquals(len(res), 2)
561 res = sorted(res, key=attrgetter('dn'))
562 self.assertEquals(str(res[0].dn), self.samba4.dn("cn=X"))
563 self.assertEquals(str(res[0]["dnsHostName"]), "x")
564 self.assertEquals(str(res[0]["lastLogon"]), "x")
565 self.assertEquals(str(res[1].dn), self.samba4.dn("cn=Y"))
566 self.assertEquals(str(res[1]["dnsHostName"]), "y")
567 self.assertEquals(str(res[1]["lastLogon"]), "y")
569 # Search by conjunction of remote attributes
570 res = self.ldb.search(expression="(&(lastLogon=x)(description=x))",
571 attrs=["dnsHostName", "lastLogon"])
572 self.assertEquals(len(res), 2)
573 res = sorted(res, key=attrgetter('dn'))
574 self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A"))
575 self.assertTrue(not "dnsHostName" in res[0])
576 self.assertEquals(str(res[0]["lastLogon"]), "x")
577 self.assertEquals(str(res[1].dn), self.samba4.dn("cn=X"))
578 self.assertEquals(str(res[1]["dnsHostName"]), "x")
579 self.assertEquals(str(res[1]["lastLogon"]), "x")
581 # Search by conjunction of local and remote attribute
582 res = self.ldb.search(expression="(&(codePage=x)(description=x))",
583 attrs=["dnsHostName", "lastLogon"])
584 self.assertEquals(len(res), 2)
585 res = sorted(res, key=attrgetter('dn'))
586 self.assertEquals(str(res[0].dn), self.samba4.dn("cn=X"))
587 self.assertEquals(str(res[0]["dnsHostName"]), "x")
588 self.assertEquals(str(res[0]["lastLogon"]), "x")
589 self.assertEquals(str(res[1].dn), self.samba4.dn("cn=Y"))
590 self.assertEquals(str(res[1]["dnsHostName"]), "y")
591 self.assertEquals(str(res[1]["lastLogon"]), "y")
593 # Search by conjunction of local and remote attribute w/o match
594 attrs = ["dnsHostName", "lastLogon"]
595 res = self.ldb.search(expression="(&(codePage=x)(nextRid=x))",
597 self.assertEquals(len(res), 0)
598 res = self.ldb.search(expression="(&(revision=x)(lastLogon=z))",
600 self.assertEquals(len(res), 0)
602 # Search by disjunction of local attributes
603 res = self.ldb.search(expression="(|(revision=x)(dnsHostName=x))",
604 attrs=["dnsHostName", "lastLogon"])
605 self.assertEquals(len(res), 2)
606 res = sorted(res, key=attrgetter('dn'))
607 self.assertEquals(str(res[0].dn), self.samba4.dn("cn=X"))
608 self.assertEquals(str(res[0]["dnsHostName"]), "x")
609 self.assertEquals(str(res[0]["lastLogon"]), "x")
610 self.assertEquals(str(res[1].dn), self.samba4.dn("cn=Y"))
611 self.assertEquals(str(res[1]["dnsHostName"]), "y")
612 self.assertEquals(str(res[1]["lastLogon"]), "y")
614 # Search by disjunction of remote attributes
615 res = self.ldb.search(expression="(|(badPwdCount=x)(lastLogon=x))",
616 attrs=["dnsHostName", "lastLogon"])
617 self.assertEquals(len(res), 3)
618 res = sorted(res, key=attrgetter('dn'))
619 self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A"))
620 self.assertFalse("dnsHostName" in res[0])
621 self.assertEquals(str(res[0]["lastLogon"]), "x")
622 self.assertEquals(str(res[1].dn), self.samba4.dn("cn=B"))
623 self.assertFalse("dnsHostName" in res[1])
624 self.assertEquals(str(res[1]["lastLogon"]), "y")
625 self.assertEquals(str(res[2].dn), self.samba4.dn("cn=X"))
626 self.assertEquals(str(res[2]["dnsHostName"]), "x")
627 self.assertEquals(str(res[2]["lastLogon"]), "x")
629 # Search by disjunction of local and remote attribute
630 res = self.ldb.search(expression="(|(revision=x)(lastLogon=y))",
631 attrs=["dnsHostName", "lastLogon"])
632 self.assertEquals(len(res), 3)
633 res = sorted(res, key=attrgetter('dn'))
634 self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B"))
635 self.assertFalse("dnsHostName" in res[0])
636 self.assertEquals(str(res[0]["lastLogon"]), "y")
637 self.assertEquals(str(res[1].dn), self.samba4.dn("cn=X"))
638 self.assertEquals(str(res[1]["dnsHostName"]), "x")
639 self.assertEquals(str(res[1]["lastLogon"]), "x")
640 self.assertEquals(str(res[2].dn), self.samba4.dn("cn=Y"))
641 self.assertEquals(str(res[2]["dnsHostName"]), "y")
642 self.assertEquals(str(res[2]["lastLogon"]), "y")
644 # Search by disjunction of local and remote attribute w/o match
645 res = self.ldb.search(expression="(|(codePage=y)(nextRid=z))",
646 attrs=["dnsHostName", "lastLogon"])
647 self.assertEquals(len(res), 0)
649 # Search by negated local attribute
650 res = self.ldb.search(expression="(!(revision=x))",
651 attrs=["dnsHostName", "lastLogon"])
652 self.assertEquals(len(res), 6)
653 res = sorted(res, key=attrgetter('dn'))
654 self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A"))
655 self.assertTrue(not "dnsHostName" in res[0])
656 self.assertEquals(str(res[0]["lastLogon"]), "x")
657 self.assertEquals(str(res[1].dn), self.samba4.dn("cn=B"))
658 self.assertTrue(not "dnsHostName" in res[1])
659 self.assertEquals(str(res[1]["lastLogon"]), "y")
660 self.assertEquals(str(res[2].dn), self.samba4.dn("cn=C"))
661 self.assertTrue(not "dnsHostName" in res[2])
662 self.assertEquals(str(res[2]["lastLogon"]), "z")
663 self.assertEquals(str(res[3].dn), self.samba4.dn("cn=Z"))
664 self.assertEquals(str(res[3]["dnsHostName"]), "z")
665 self.assertEquals(str(res[3]["lastLogon"]), "z")
667 # Search by negated remote attribute
668 res = self.ldb.search(expression="(!(description=x))",
669 attrs=["dnsHostName", "lastLogon"])
670 self.assertEquals(len(res), 4)
671 res = sorted(res, key=attrgetter('dn'))
672 self.assertEquals(str(res[0].dn), self.samba4.dn("cn=C"))
673 self.assertTrue(not "dnsHostName" in res[0])
674 self.assertEquals(str(res[0]["lastLogon"]), "z")
675 self.assertEquals(str(res[1].dn), self.samba4.dn("cn=Z"))
676 self.assertEquals(str(res[1]["dnsHostName"]), "z")
677 self.assertEquals(str(res[1]["lastLogon"]), "z")
679 # Search by negated conjunction of local attributes
680 res = self.ldb.search(expression="(!(&(codePage=x)(revision=x)))",
681 attrs=["dnsHostName", "lastLogon"])
682 self.assertEquals(len(res), 6)
683 res = sorted(res, key=attrgetter('dn'))
684 self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A"))
685 self.assertTrue(not "dnsHostName" in res[0])
686 self.assertEquals(str(res[0]["lastLogon"]), "x")
687 self.assertEquals(str(res[1].dn), self.samba4.dn("cn=B"))
688 self.assertTrue(not "dnsHostName" in res[1])
689 self.assertEquals(str(res[1]["lastLogon"]), "y")
690 self.assertEquals(str(res[2].dn), self.samba4.dn("cn=C"))
691 self.assertTrue(not "dnsHostName" in res[2])
692 self.assertEquals(str(res[2]["lastLogon"]), "z")
693 self.assertEquals(str(res[3].dn), self.samba4.dn("cn=Z"))
694 self.assertEquals(str(res[3]["dnsHostName"]), "z")
695 self.assertEquals(str(res[3]["lastLogon"]), "z")
697 # Search by negated conjunction of remote attributes
698 res = self.ldb.search(expression="(!(&(lastLogon=x)(description=x)))",
699 attrs=["dnsHostName", "lastLogon"])
700 self.assertEquals(len(res), 6)
701 res = sorted(res, key=attrgetter('dn'))
702 self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B"))
703 self.assertTrue(not "dnsHostName" in res[0])
704 self.assertEquals(str(res[0]["lastLogon"]), "y")
705 self.assertEquals(str(res[1].dn), self.samba4.dn("cn=C"))
706 self.assertTrue(not "dnsHostName" in res[1])
707 self.assertEquals(str(res[1]["lastLogon"]), "z")
708 self.assertEquals(str(res[2].dn), self.samba4.dn("cn=Y"))
709 self.assertEquals(str(res[2]["dnsHostName"]), "y")
710 self.assertEquals(str(res[2]["lastLogon"]), "y")
711 self.assertEquals(str(res[3].dn), self.samba4.dn("cn=Z"))
712 self.assertEquals(str(res[3]["dnsHostName"]), "z")
713 self.assertEquals(str(res[3]["lastLogon"]), "z")
715 # Search by negated conjunction of local and remote attribute
716 res = self.ldb.search(expression="(!(&(codePage=x)(description=x)))",
717 attrs=["dnsHostName", "lastLogon"])
718 self.assertEquals(len(res), 6)
719 res = sorted(res, key=attrgetter('dn'))
720 self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A"))
721 self.assertTrue(not "dnsHostName" in res[0])
722 self.assertEquals(str(res[0]["lastLogon"]), "x")
723 self.assertEquals(str(res[1].dn), self.samba4.dn("cn=B"))
724 self.assertTrue(not "dnsHostName" in res[1])
725 self.assertEquals(str(res[1]["lastLogon"]), "y")
726 self.assertEquals(str(res[2].dn), self.samba4.dn("cn=C"))
727 self.assertTrue(not "dnsHostName" in res[2])
728 self.assertEquals(str(res[2]["lastLogon"]), "z")
729 self.assertEquals(str(res[3].dn), self.samba4.dn("cn=Z"))
730 self.assertEquals(str(res[3]["dnsHostName"]), "z")
731 self.assertEquals(str(res[3]["lastLogon"]), "z")
733 # Search by negated disjunction of local attributes
734 res = self.ldb.search(expression="(!(|(revision=x)(dnsHostName=x)))",
735 attrs=["dnsHostName", "lastLogon"])
736 res = sorted(res, key=attrgetter('dn'))
737 self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A"))
738 self.assertTrue(not "dnsHostName" in res[0])
739 self.assertEquals(str(res[0]["lastLogon"]), "x")
740 self.assertEquals(str(res[1].dn), self.samba4.dn("cn=B"))
741 self.assertTrue(not "dnsHostName" in res[1])
742 self.assertEquals(str(res[1]["lastLogon"]), "y")
743 self.assertEquals(str(res[2].dn), self.samba4.dn("cn=C"))
744 self.assertTrue(not "dnsHostName" in res[2])
745 self.assertEquals(str(res[2]["lastLogon"]), "z")
746 self.assertEquals(str(res[3].dn), self.samba4.dn("cn=Z"))
747 self.assertEquals(str(res[3]["dnsHostName"]), "z")
748 self.assertEquals(str(res[3]["lastLogon"]), "z")
750 # Search by negated disjunction of remote attributes
751 res = self.ldb.search(expression="(!(|(badPwdCount=x)(lastLogon=x)))",
752 attrs=["dnsHostName", "lastLogon"])
753 self.assertEquals(len(res), 5)
754 res = sorted(res, key=attrgetter('dn'))
755 self.assertEquals(str(res[0].dn), self.samba4.dn("cn=C"))
756 self.assertTrue(not "dnsHostName" in res[0])
757 self.assertEquals(str(res[0]["lastLogon"]), "z")
758 self.assertEquals(str(res[1].dn), self.samba4.dn("cn=Y"))
759 self.assertEquals(str(res[1]["dnsHostName"]), "y")
760 self.assertEquals(str(res[1]["lastLogon"]), "y")
761 self.assertEquals(str(res[2].dn), self.samba4.dn("cn=Z"))
762 self.assertEquals(str(res[2]["dnsHostName"]), "z")
763 self.assertEquals(str(res[2]["lastLogon"]), "z")
765 # Search by negated disjunction of local and remote attribute
766 res = self.ldb.search(expression="(!(|(revision=x)(lastLogon=y)))",
767 attrs=["dnsHostName", "lastLogon"])
768 self.assertEquals(len(res), 5)
769 res = sorted(res, key=attrgetter('dn'))
770 self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A"))
771 self.assertTrue(not "dnsHostName" in res[0])
772 self.assertEquals(str(res[0]["lastLogon"]), "x")
773 self.assertEquals(str(res[1].dn), self.samba4.dn("cn=C"))
774 self.assertTrue(not "dnsHostName" in res[1])
775 self.assertEquals(str(res[1]["lastLogon"]), "z")
776 self.assertEquals(str(res[2].dn), self.samba4.dn("cn=Z"))
777 self.assertEquals(str(res[2]["dnsHostName"]), "z")
778 self.assertEquals(str(res[2]["lastLogon"]), "z")
780 # Search by complex parse tree
781 res = self.ldb.search(expression="(|(&(revision=x)(dnsHostName=x))(!(&(description=x)(nextRid=y)))(badPwdCount=y))", attrs=["dnsHostName", "lastLogon"])
782 self.assertEquals(len(res), 7)
783 res = sorted(res, key=attrgetter('dn'))
784 self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A"))
785 self.assertTrue(not "dnsHostName" in res[0])
786 self.assertEquals(str(res[0]["lastLogon"]), "x")
787 self.assertEquals(str(res[1].dn), self.samba4.dn("cn=B"))
788 self.assertTrue(not "dnsHostName" in res[1])
789 self.assertEquals(str(res[1]["lastLogon"]), "y")
790 self.assertEquals(str(res[2].dn), self.samba4.dn("cn=C"))
791 self.assertTrue(not "dnsHostName" in res[2])
792 self.assertEquals(str(res[2]["lastLogon"]), "z")
793 self.assertEquals(str(res[3].dn), self.samba4.dn("cn=X"))
794 self.assertEquals(str(res[3]["dnsHostName"]), "x")
795 self.assertEquals(str(res[3]["lastLogon"]), "x")
796 self.assertEquals(str(res[4].dn), self.samba4.dn("cn=Z"))
797 self.assertEquals(str(res[4]["dnsHostName"]), "z")
798 self.assertEquals(str(res[4]["lastLogon"]), "z")
801 dns = [self.samba4.dn("cn=%s" % n) for n in ["A","B","C","X","Y","Z"]]
805 def test_map_modify_local(self):
806 """Modification of local records."""
808 dn = "cn=test,dc=idealx,dc=org"
809 self.ldb.add({"dn": dn,
813 "description": "test"})
815 attrs = ["foo", "revision", "description"]
816 res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=attrs)
817 self.assertEquals(len(res), 1)
818 self.assertEquals(str(res[0].dn), dn)
819 self.assertEquals(str(res[0]["foo"]), "bar")
820 self.assertEquals(str(res[0]["revision"]), "1")
821 self.assertEquals(str(res[0]["description"]), "test")
822 # Check it's not in the local db
823 res = self.samba4.db.search(expression="(cn=test)",
824 scope=SCOPE_DEFAULT, attrs=attrs)
825 self.assertEquals(len(res), 0)
826 # Check it's not in the remote db
827 res = self.samba3.db.search(expression="(cn=test)",
828 scope=SCOPE_DEFAULT, attrs=attrs)
829 self.assertEquals(len(res), 0)
831 # Modify local record
839 self.ldb.modify_ldif(ldif)
841 res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=attrs)
842 self.assertEquals(len(res), 1)
843 self.assertEquals(str(res[0].dn), dn)
844 self.assertEquals(str(res[0]["foo"]), "baz")
845 self.assertEquals(str(res[0]["revision"]), "1")
846 self.assertEquals(str(res[0]["description"]), "foo")
848 # Rename local record
849 dn2 = "cn=toast,dc=idealx,dc=org"
850 self.ldb.rename(dn, dn2)
852 res = self.ldb.search(dn2, scope=SCOPE_BASE, attrs=attrs)
853 self.assertEquals(len(res), 1)
854 self.assertEquals(str(res[0].dn), dn2)
855 self.assertEquals(str(res[0]["foo"]), "baz")
856 self.assertEquals(str(res[0]["revision"]), "1")
857 self.assertEquals(str(res[0]["description"]), "foo")
859 # Delete local record
862 res = self.ldb.search(dn2, scope=SCOPE_BASE)
863 self.assertEquals(len(res), 0)
865 def test_map_modify_remote_remote(self):
866 """Modification of remote data of remote records"""
868 dn = self.samba4.dn("cn=test")
869 dn2 = self.samba3.dn("cn=test")
870 self.samba3.db.add({"dn": dn2,
872 "description": "foo",
873 "sambaBadPasswordCount": "3",
874 "sambaNextRid": "1001"})
876 res = self.samba3.db.search(dn2, scope=SCOPE_BASE,
877 attrs=["description", "sambaBadPasswordCount", "sambaNextRid"])
878 self.assertEquals(len(res), 1)
879 self.assertEquals(str(res[0].dn), dn2)
880 self.assertEquals(str(res[0]["description"]), "foo")
881 self.assertEquals(str(res[0]["sambaBadPasswordCount"]), "3")
882 self.assertEquals(str(res[0]["sambaNextRid"]), "1001")
884 attrs = ["description", "badPwdCount", "nextRid"]
885 res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=attrs, expression="")
886 self.assertEquals(len(res), 1)
887 self.assertEquals(str(res[0].dn), dn)
888 self.assertEquals(str(res[0]["description"]), "foo")
889 self.assertEquals(str(res[0]["badPwdCount"]), "3")
890 self.assertEquals(str(res[0]["nextRid"]), "1001")
892 res = self.samba4.db.search(dn, scope=SCOPE_BASE, attrs=attrs)
893 self.assertEquals(len(res), 0)
895 # Modify remote data of remote record
903 self.ldb.modify_ldif(ldif)
905 res = self.ldb.search(dn, scope=SCOPE_BASE,
906 attrs=["description", "badPwdCount", "nextRid"])
907 self.assertEquals(len(res), 1)
908 self.assertEquals(str(res[0].dn), dn)
909 self.assertEquals(str(res[0]["description"]), "test")
910 self.assertEquals(str(res[0]["badPwdCount"]), "4")
911 self.assertEquals(str(res[0]["nextRid"]), "1001")
913 res = self.samba3.db.search(dn2, scope=SCOPE_BASE,
914 attrs=["description", "sambaBadPasswordCount", "sambaNextRid"])
915 self.assertEquals(len(res), 1)
916 self.assertEquals(str(res[0].dn), dn2)
917 self.assertEquals(str(res[0]["description"]), "test")
918 self.assertEquals(str(res[0]["sambaBadPasswordCount"]), "4")
919 self.assertEquals(str(res[0]["sambaNextRid"]), "1001")
921 # Rename remote record
922 dn2 = self.samba4.dn("cn=toast")
923 self.ldb.rename(dn, dn2)
926 res = self.ldb.search(dn, scope=SCOPE_BASE,
927 attrs=["description", "badPwdCount", "nextRid"])
928 self.assertEquals(len(res), 1)
929 self.assertEquals(str(res[0].dn), dn)
930 self.assertEquals(str(res[0]["description"]), "test")
931 self.assertEquals(str(res[0]["badPwdCount"]), "4")
932 self.assertEquals(str(res[0]["nextRid"]), "1001")
934 dn2 = self.samba3.dn("cn=toast")
935 res = self.samba3.db.search(dn2, scope=SCOPE_BASE,
936 attrs=["description", "sambaBadPasswordCount", "sambaNextRid"])
937 self.assertEquals(len(res), 1)
938 self.assertEquals(str(res[0].dn), dn2)
939 self.assertEquals(str(res[0]["description"]), "test")
940 self.assertEquals(str(res[0]["sambaBadPasswordCount"]), "4")
941 self.assertEquals(str(res[0]["sambaNextRid"]), "1001")
943 # Delete remote record
945 # Check in mapped db that it's removed
946 res = self.ldb.search(dn, scope=SCOPE_BASE)
947 self.assertEquals(len(res), 0)
949 res = self.samba3.db.search(dn2, scope=SCOPE_BASE)
950 self.assertEquals(len(res), 0)
952 def test_map_modify_remote_local(self):
953 """Modification of local data of remote records"""
954 # Add remote record (same as before)
955 dn = self.samba4.dn("cn=test")
956 dn2 = self.samba3.dn("cn=test")
957 self.samba3.db.add({"dn": dn2,
959 "description": "foo",
960 "sambaBadPasswordCount": "3",
961 "sambaNextRid": "1001"})
963 # Modify local data of remote record
972 self.ldb.modify_ldif(ldif)
974 attrs = ["revision", "description"]
975 res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=attrs)
976 self.assertEquals(len(res), 1)
977 self.assertEquals(str(res[0].dn), dn)
978 self.assertEquals(str(res[0]["description"]), "test")
979 self.assertEquals(str(res[0]["revision"]), "1")
981 res = self.samba3.db.search(dn2, scope=SCOPE_BASE, attrs=attrs)
982 self.assertEquals(len(res), 1)
983 self.assertEquals(str(res[0].dn), dn2)
984 self.assertEquals(str(res[0]["description"]), "test")
985 self.assertTrue(not "revision" in res[0])
987 res = self.samba4.db.search(dn, scope=SCOPE_BASE, attrs=attrs)
988 self.assertEquals(len(res), 1)
989 self.assertEquals(str(res[0].dn), dn)
990 self.assertTrue(not "description" in res[0])
991 self.assertEquals(str(res[0]["revision"]), "1")
993 # Delete (newly) split record
996 def test_map_modify_split(self):
997 """Testing modification of split records"""
999 dn = self.samba4.dn("cn=test")
1000 dn2 = self.samba3.dn("cn=test")
1004 "description": "foo",
1009 attrs = ["description", "badPwdCount", "nextRid", "revision"]
1010 res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=attrs)
1011 self.assertEquals(len(res), 1)
1012 self.assertEquals(str(res[0].dn), dn)
1013 self.assertEquals(str(res[0]["description"]), "foo")
1014 self.assertEquals(str(res[0]["badPwdCount"]), "3")
1015 self.assertEquals(str(res[0]["nextRid"]), "1001")
1016 self.assertEquals(str(res[0]["revision"]), "1")
1018 res = self.samba4.db.search(dn, scope=SCOPE_BASE, attrs=attrs)
1019 self.assertEquals(len(res), 1)
1020 self.assertEquals(str(res[0].dn), dn)
1021 self.assertTrue(not "description" in res[0])
1022 self.assertTrue(not "badPwdCount" in res[0])
1023 self.assertTrue(not "nextRid" in res[0])
1024 self.assertEquals(str(res[0]["revision"]), "1")
1025 # Check in remote db
1026 attrs = ["description", "sambaBadPasswordCount", "sambaNextRid",
1028 res = self.samba3.db.search(dn2, scope=SCOPE_BASE, attrs=attrs)
1029 self.assertEquals(len(res), 1)
1030 self.assertEquals(str(res[0].dn), dn2)
1031 self.assertEquals(str(res[0]["description"]), "foo")
1032 self.assertEquals(str(res[0]["sambaBadPasswordCount"]), "3")
1033 self.assertEquals(str(res[0]["sambaNextRid"]), "1001")
1034 self.assertTrue(not "revision" in res[0])
1036 # Modify of split record
1039 replace: description
1041 replace: badPwdCount
1046 self.ldb.modify_ldif(ldif)
1047 # Check in mapped db
1048 attrs = ["description", "badPwdCount", "nextRid", "revision"]
1049 res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=attrs)
1050 self.assertEquals(len(res), 1)
1051 self.assertEquals(str(res[0].dn), dn)
1052 self.assertEquals(str(res[0]["description"]), "test")
1053 self.assertEquals(str(res[0]["badPwdCount"]), "4")
1054 self.assertEquals(str(res[0]["nextRid"]), "1001")
1055 self.assertEquals(str(res[0]["revision"]), "2")
1057 res = self.samba4.db.search(dn, scope=SCOPE_BASE, attrs=attrs)
1058 self.assertEquals(len(res), 1)
1059 self.assertEquals(str(res[0].dn), dn)
1060 self.assertTrue(not "description" in res[0])
1061 self.assertTrue(not "badPwdCount" in res[0])
1062 self.assertTrue(not "nextRid" in res[0])
1063 self.assertEquals(str(res[0]["revision"]), "2")
1064 # Check in remote db
1065 attrs = ["description", "sambaBadPasswordCount", "sambaNextRid",
1067 res = self.samba3.db.search(dn2, scope=SCOPE_BASE, attrs=attrs)
1068 self.assertEquals(len(res), 1)
1069 self.assertEquals(str(res[0].dn), dn2)
1070 self.assertEquals(str(res[0]["description"]), "test")
1071 self.assertEquals(str(res[0]["sambaBadPasswordCount"]), "4")
1072 self.assertEquals(str(res[0]["sambaNextRid"]), "1001")
1073 self.assertTrue(not "revision" in res[0])
1075 # Rename split record
1076 dn2 = self.samba4.dn("cn=toast")
1077 self.ldb.rename(dn, dn2)
1078 # Check in mapped db
1080 attrs = ["description", "badPwdCount", "nextRid", "revision"]
1081 res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=attrs)
1082 self.assertEquals(len(res), 1)
1083 self.assertEquals(str(res[0].dn), dn)
1084 self.assertEquals(str(res[0]["description"]), "test")
1085 self.assertEquals(str(res[0]["badPwdCount"]), "4")
1086 self.assertEquals(str(res[0]["nextRid"]), "1001")
1087 self.assertEquals(str(res[0]["revision"]), "2")
1089 res = self.samba4.db.search(dn, scope=SCOPE_BASE, attrs=attrs)
1090 self.assertEquals(len(res), 1)
1091 self.assertEquals(str(res[0].dn), dn)
1092 self.assertTrue(not "description" in res[0])
1093 self.assertTrue(not "badPwdCount" in res[0])
1094 self.assertTrue(not "nextRid" in res[0])
1095 self.assertEquals(str(res[0]["revision"]), "2")
1096 # Check in remote db
1097 dn2 = self.samba3.dn("cn=toast")
1098 res = self.samba3.db.search(dn2, scope=SCOPE_BASE,
1099 attrs=["description", "sambaBadPasswordCount", "sambaNextRid",
1101 self.assertEquals(len(res), 1)
1102 self.assertEquals(str(res[0].dn), dn2)
1103 self.assertEquals(str(res[0]["description"]), "test")
1104 self.assertEquals(str(res[0]["sambaBadPasswordCount"]), "4")
1105 self.assertEquals(str(res[0]["sambaNextRid"]), "1001")
1106 self.assertTrue(not "revision" in res[0])
1108 # Delete split record
1110 # Check in mapped db
1111 res = self.ldb.search(dn, scope=SCOPE_BASE)
1112 self.assertEquals(len(res), 0)
1114 res = self.samba4.db.search(dn, scope=SCOPE_BASE)
1115 self.assertEquals(len(res), 0)
1116 # Check in remote db
1117 res = self.samba3.db.search(dn2, scope=SCOPE_BASE)
1118 self.assertEquals(len(res), 0)