dsdb: Add new test adding a record to the top level sam.ldb file
authorAndrew Bartlett <abartlet@samba.org>
Mon, 26 Jun 2017 01:16:01 +0000 (13:16 +1200)
committerStefan Metzmacher <metze@samba.org>
Sun, 2 Jul 2017 15:35:20 +0000 (17:35 +0200)
This shows that locks are made on this file as well

Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
python/samba/tests/dsdb.py

index 36da7225de8773b24058013d260f3194b7203938..cfe19093b9c7086a8c1878d2bb5bb5bab495121c 100644 (file)
@@ -278,6 +278,77 @@ class DsdbTests(TestCase):
             self.assertTrue(os.WIFEXITED(status))
             self.assertEqual(os.WEXITSTATUS(status), 0)
 
+    def test_db_lock3(self):
+        basedn = self.samdb.get_default_basedn()
+        (r1, w1) = os.pipe()
+        (r2, w2) = os.pipe()
+
+        pid = os.fork()
+        if pid == 0:
+            # In the child, close the main DB, re-open
+            del(self.samdb)
+            gc.collect()
+            self.samdb = SamDB(session_info=self.session,
+                           credentials=self.creds,
+                           lp=self.lp)
+
+            # We need to hold this iterator open to hold the all-record lock.
+            res = self.samdb.search_iterator()
+
+            os.write(w2, b"start")
+            if (os.read(r1, 7) != b"started"):
+                os._exit(1)
+
+            os.write(w2, b"add")
+            if (os.read(r1, 5) != b"added"):
+                os._exit(2)
+
+            # Wait 2 seconds to block prepare_commit() in the child.
+            os.write(w2, b"prepare")
+            time.sleep(2)
+
+            # Release the locks
+            for l in res:
+                pass
+
+            if (os.read(r1, 8) != b"prepared"):
+                os._exit(3)
+
+            os._exit(0)
+
+        # We can start the transaction during the search
+        # because both just grab the all-record read lock.
+        self.assertEqual(os.read(r2, 5), b"start")
+        self.samdb.transaction_start()
+        os.write(w1, b"started")
+
+        self.assertEqual(os.read(r2, 3), b"add")
+
+        # This will end up in the top level db
+        dn = "@DSDB_LOCK_TEST"
+        self.samdb.add({
+             "dn": dn})
+        self.samdb.delete(dn)
+        os.write(w1, b"added")
+
+        # Obtain a write lock, this will block until
+        # the child releases the read lock.
+        self.assertEqual(os.read(r2, 7), b"prepare")
+        start = time.time()
+        self.samdb.transaction_prepare_commit()
+        end = time.time()
+        self.assertGreater(end - start, 1.9)
+        os.write(w1, b"prepared")
+
+        # Drop the write lock
+        self.samdb.transaction_cancel()
+
+        (got_pid, status) = os.waitpid(pid, 0)
+        self.assertTrue(os.WIFEXITED(status))
+        self.assertEqual(os.WEXITSTATUS(status), 0)
+        self.assertEqual(got_pid, pid)
+
+
     def test_full_db_lock1(self):
         basedn = self.samdb.get_default_basedn()
         backend_filename = "%s.ldb" % basedn.get_casefold()