use shutil.move (to .tmp) instead of simple delete, additional utest
authormeejah <meejah@meejah.ca>
Tue, 20 Oct 2015 18:41:49 +0000 (12:41 -0600)
committermeejah <meejah@meejah.ca>
Mon, 26 Oct 2015 14:07:23 +0000 (08:07 -0600)
src/allmydata/frontends/magic_folder.py
src/allmydata/test/test_magic_folder.py

index b204227a8cf1e1aa53680e3a5a77803910d08347..4362add20f3bd8bff5cb4e6a7baaeb121ce3d113 100644 (file)
@@ -1,6 +1,7 @@
 
 import sys, os
 import os.path
+import shutil
 from collections import deque
 import time
 
@@ -649,7 +650,7 @@ class Downloader(QueueMixin, WriteFileMixin):
             if metadata.get('deleted', False):
                 d.addCallback(lambda result: self._unlink_deleted_file(abspath_u, result))
             else:
-                d.addCallback(lambda result: self._write_downloaded_file(abspath_u, result, is_conflict=False))
+                d.addCallback(lambda contents: self._write_downloaded_file(abspath_u, contents, is_conflict=False))
 
         def do_update_db(written_abspath_u):
             filecap = file_node.get_uri()
@@ -676,7 +677,8 @@ class Downloader(QueueMixin, WriteFileMixin):
 
     def _unlink_deleted_file(self, abspath_u, result):
         try:
-            os.unlink(abspath_u)
-        except OSError:
+            self._log('unlinking: %s' % (abspath_u,))
+            shutil.move(abspath_u, abspath_u + '.tmp')
+        except IOError:
             self._log("Already gone: '%s'" % (abspath_u,))
         return abspath_u
index 38c8e98c74a46de7fbc41973ece5ee54bb225e4b..9abe63f860c1e956ebf1c9c4a42592a7b0346eca 100644 (file)
@@ -262,10 +262,10 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
             self.assertTrue(os.path.exists(path))
 
             # the real test part: delete the file
-            proc = self.magicfolder.uploader.set_hook('processed')
+            up_proc = self.magicfolder.uploader.set_hook('processed')
             os.unlink(path)
             self.notify(to_filepath(path), self.inotify.IN_DELETE)
-            yield down_proc
+            yield up_proc
             self.assertFalse(os.path.exists(path))
 
             # ensure we still have a DB entry, and that the version is 1
@@ -276,6 +276,54 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
         finally:
             yield self.cleanup(None)
 
+    @defer.inlineCallbacks
+    def test_delete_and_restore(self):
+        self.set_up_grid()
+        self.local_dir = os.path.join(self.basedir, u"local_dir")
+        self.mkdir_nonascii(self.local_dir)
+
+        yield self.create_invite_join_magic_folder(u"Alice\u0101", self.local_dir)
+        yield self._restart_client(None)
+
+        try:
+            # create a file
+            up_proc = self.magicfolder.uploader.set_hook('processed')
+            # down_proc = self.magicfolder.downloader.set_hook('processed')
+            path = os.path.join(self.local_dir, u'foo')
+            with open(path, 'w') as f:
+                f.write('foo\n')
+            self.notify(to_filepath(path), self.inotify.IN_CLOSE_WRITE)
+            yield up_proc
+            self.assertTrue(os.path.exists(path))
+
+            # delete the file
+            up_proc = self.magicfolder.uploader.set_hook('processed')
+            os.unlink(path)
+            self.notify(to_filepath(path), self.inotify.IN_DELETE)
+            yield up_proc
+            self.assertFalse(os.path.exists(path))
+
+            # ensure we still have a DB entry, and that the version is 1
+            node, metadata = yield self.magicfolder.downloader._get_collective_latest_file(u'foo')
+            self.assertTrue(node is not None, "Failed to find '{}' in DMD".format(path))
+            self.failUnlessEqual(metadata['version'], 1)
+
+            # restore the file, with different contents
+            up_proc = self.magicfolder.uploader.set_hook('processed')
+            path = os.path.join(self.local_dir, u'foo')
+            with open(path, 'w') as f:
+                f.write('bar\n')
+            self.notify(to_filepath(path), self.inotify.IN_CLOSE_WRITE)
+            yield up_proc
+
+            # ensure we still have a DB entry, and that the version is 2
+            node, metadata = yield self.magicfolder.downloader._get_collective_latest_file(u'foo')
+            self.assertTrue(node is not None, "Failed to find '{}' in DMD".format(path))
+            self.failUnlessEqual(metadata['version'], 2)
+
+        finally:
+            yield self.cleanup(None)
+
     def test_magic_folder(self):
         self.set_up_grid()
         self.local_dir = os.path.join(self.basedir, self.unicode_or_fallback(u"loc\u0101l_dir", u"local_dir"))