From 7a0afb59a4aff9a23e5cd6837110fbcd8294bc79 Mon Sep 17 00:00:00 2001
From: Brian Warner <warner@allmydata.com>
Date: Fri, 5 Dec 2008 22:08:37 -0700
Subject: [PATCH] dirnode.py: dirnode.delete which hits UCWE should not fail
 with NoSuchChildError. Fixes #550.

---
 src/allmydata/dirnode.py           |  2 +-
 src/allmydata/test/test_dirnode.py | 46 +++++++++++++++++++++++++++++-
 2 files changed, 46 insertions(+), 2 deletions(-)

diff --git a/src/allmydata/dirnode.py b/src/allmydata/dirnode.py
index 39c377eb..3caec6b4 100644
--- a/src/allmydata/dirnode.py
+++ b/src/allmydata/dirnode.py
@@ -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
diff --git a/src/allmydata/test/test_dirnode.py b/src/allmydata/test/test_dirnode.py
index b1dd67f0..0447e9c1 100644
--- a/src/allmydata/test/test_dirnode.py
+++ b/src/allmydata/test/test_dirnode.py
@@ -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
+
-- 
2.45.2