dirnode.py: dirnode.delete which hits UCWE should not fail with NoSuchChildError...
authorBrian Warner <warner@allmydata.com>
Sat, 6 Dec 2008 05:08:37 +0000 (22:08 -0700)
committerBrian Warner <warner@allmydata.com>
Sat, 6 Dec 2008 05:08:37 +0000 (22:08 -0700)
src/allmydata/dirnode.py
src/allmydata/test/test_dirnode.py

index 39c377eb2190de57d63b5810935e4e729a2a66b0..3caec6b449e7afd15cb1feb0dc0441a5fabd479c 100644 (file)
@@ -27,7 +27,7 @@ class Deleter:
     def modify(self, old_contents, servermap, first_time):
         children = self.node._unpack_contents(old_contents)
         if self.name not in children:
-            if self.must_exist:
+            if first_time and self.must_exist:
                 raise NoSuchChildError(self.name)
             self.old_child = None
             return None
index b1dd67f0a0adaadfad40c722001209e0591d221c..0447e9c1b1eaf7a6a594514cf509b168e851ef10 100644 (file)
@@ -9,10 +9,12 @@ from allmydata.interfaces import IURI, IClient, IMutableFileNode, \
      INewDirectoryURI, IReadonlyNewDirectoryURI, IFileNode, \
      ExistingChildError, NoSuchChildError, \
      IDeepCheckResults, IDeepCheckAndRepairResults
+from allmydata.mutable.node import MutableFileNode
+from allmydata.mutable.common import UncoordinatedWriteError
 from allmydata.util import hashutil, base32
 from allmydata.monitor import Monitor
 from allmydata.test.common import make_chk_file_uri, make_mutable_file_uri, \
-     FakeDirectoryNode, create_chk_filenode, ErrorMixin
+     FakeDirectoryNode, create_chk_filenode, ErrorMixin, SystemTestMixin
 from allmydata.checker_results import CheckerResults, CheckAndRepairResults
 import common_util as testutil
 
@@ -761,3 +763,45 @@ class DeepStats(unittest.TestCase):
                                (3162277660169L, 10000000000000L, 1),
                                ])
 
+class UCWEingMutableFileNode(MutableFileNode):
+    please_ucwe_after_next_upload = False
+
+    def _upload(self, new_contents, servermap):
+        d = MutableFileNode._upload(self, new_contents, servermap)
+        def _ucwe(res):
+            raise UncoordinatedWriteError()
+        d.addCallback(_ucwe)
+        return d
+class UCWEingNewDirectoryNode(dirnode.NewDirectoryNode):
+    filenode_class = UCWEingMutableFileNode
+
+
+class Deleter(SystemTestMixin, unittest.TestCase):
+    def test_retry(self):
+        # ticket #550, a dirnode.delete which experiences an
+        # UncoordinatedWriteError will fail with an incorrect "you're
+        # deleting something which isn't there" NoSuchChildError exception.
+
+        # to trigger this, we start by creating a directory with a single
+        # file in it. Then we create a special dirnode that uses a modified
+        # MutableFileNode which will raise UncoordinatedWriteError once on
+        # demand. We then call dirnode.delete, which ought to retry and
+        # succeed.
+
+        self.basedir = self.mktemp()
+        d = self.set_up_nodes()
+        d.addCallback(lambda ignored: self.clients[0].create_empty_dirnode())
+        small = upload.Data("Small enough for a LIT", None)
+        def _created_dir(dn):
+            self.root = dn
+            self.root_uri = dn.get_uri()
+            return dn.add_file(u"file", small)
+        d.addCallback(_created_dir)
+        def _do_delete(ignored):
+            n = UCWEingNewDirectoryNode(self.clients[0]).init_from_uri(self.root_uri)
+            # This should succeed, not raise an exception
+            return n.delete(u"file")
+        d.addCallback(_do_delete)
+
+        return d
+