]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blobdiff - src/allmydata/test/test_magic_folder.py
Add file conflict unit test
[tahoe-lafs/tahoe-lafs.git] / src / allmydata / test / test_magic_folder.py
index 34a6d856daa7a08ca6ca88614a5736a568120c3b..3f1f37ac68bf070c5a6d1ece129b9be176ac96d6 100644 (file)
@@ -270,7 +270,7 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
 
             # 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.assertTrue(node is not None, "Failed to find %r in DMD" % (path,))
             self.failUnlessEqual(metadata['version'], 1)
 
         finally:
@@ -305,7 +305,7 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
 
             # 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.assertTrue(node is not None, "Failed to find %r in DMD" % (path,))
             self.failUnlessEqual(metadata['version'], 1)
 
             # restore the file, with different contents
@@ -318,7 +318,7 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
 
             # 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.assertTrue(node is not None, "Failed to find %r in DMD" % (path,))
             self.failUnlessEqual(metadata['version'], 2)
 
         finally:
@@ -673,25 +673,48 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
         bob_clock = task.Clock()
         d = self.setup_alice_and_bob(alice_clock, bob_clock)
 
-        def _check_uploader_count(ign, name, expected):
-            self.failUnlessReallyEqual(self._get_count('uploader.'+name, client=self.alice_magicfolder._client),
-                                       expected)
-        def _check_downloader_count(ign, name, expected):
-            self.failUnlessReallyEqual(self._get_count('downloader.'+name, client=self.bob_magicfolder._client),
-                                       expected)
+        def _check_uploader_count(ign, name, expected, alice=True):
+            if alice:
+                self.failUnlessReallyEqual(self._get_count('uploader.'+name, client=self.alice_magicfolder._client),
+                                           expected)
+            else:
+                self.failUnlessReallyEqual(self._get_count('uploader.'+name, client=self.bob_magicfolder._client),
+                                           expected)
+
+        def _check_downloader_count(ign, name, expected, alice=True):
+            if alice:
+                self.failUnlessReallyEqual(self._get_count('downloader.'+name, client=self.bob_magicfolder._client),
+                                           expected)
+            else:
+                self.failUnlessReallyEqual(self._get_count('downloader.'+name, client=self.alice_magicfolder._client),
+                                           expected)
+
+        def _wait_for_Alice(ign, downloaded_d):
+            print "Now waiting for Alice to download\n"
+            alice_clock.advance(0)
+            return downloaded_d
 
         def _wait_for_Bob(ign, downloaded_d):
             print "Now waiting for Bob to download\n"
             bob_clock.advance(0)
             return downloaded_d
 
-        def _wait_for(ign, something_to_do):
-            downloaded_d = self.bob_magicfolder.downloader.set_hook('processed')
-            uploaded_d = self.alice_magicfolder.uploader.set_hook('processed')
+        def _wait_for(ign, something_to_do, alice=True):
+            if alice:
+                downloaded_d = self.bob_magicfolder.downloader.set_hook('processed')
+                uploaded_d = self.alice_magicfolder.uploader.set_hook('processed')
+            else:
+                downloaded_d = self.alice_magicfolder.downloader.set_hook('processed')
+                uploaded_d = self.bob_magicfolder.uploader.set_hook('processed')
             something_to_do()
-            print "Waiting for Alice to upload\n"
-            alice_clock.advance(0)
-            uploaded_d.addCallback(_wait_for_Bob, downloaded_d)
+            if alice:
+                print "Waiting for Alice to upload\n"
+                alice_clock.advance(0)
+                uploaded_d.addCallback(_wait_for_Bob, downloaded_d)
+            else:
+                print "Waiting for Bob to upload\n"
+                bob_clock.advance(0)
+                uploaded_d.addCallback(_wait_for_Alice, downloaded_d)
             return uploaded_d
 
         def Alice_to_write_a_file():
@@ -708,6 +731,8 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
         d.addCallback(_check_uploader_count, 'files_uploaded', 1)
         d.addCallback(_check_uploader_count, 'objects_queued', 0)
         d.addCallback(_check_uploader_count, 'directories_created', 0)
+        d.addCallback(_check_uploader_count, 'objects_conflicted', 0)
+        d.addCallback(_check_uploader_count, 'objects_conflicted', 0, alice=False)
 
         d.addCallback(lambda ign: self._check_version_in_local_db(self.bob_magicfolder, u"file1", 0))
         d.addCallback(_check_downloader_count, 'objects_failed', 0)
@@ -724,6 +749,7 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
             p = abspath_expanduser_unicode(u"file1", base=self.bob_magicfolder.uploader._local_path_u)
             self.notify(to_filepath(p), self.inotify.IN_MOVED_FROM, magic=self.bob_magicfolder)
             self.notify(to_filepath(p + u'.backup'), self.inotify.IN_MOVED_TO, magic=self.bob_magicfolder)
+            bob_clock.advance(0)
             return d0
         d.addCallback(notify_bob_moved)
 
@@ -731,12 +757,13 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
         d.addCallback(lambda ign: self._check_version_in_local_db(self.alice_magicfolder, u"file1", 1))
         d.addCallback(_check_uploader_count, 'objects_failed', 0)
         d.addCallback(_check_uploader_count, 'objects_succeeded', 2)
+        d.addCallback(lambda ign: self.failUnlessReallyEqual(self._get_count('uploader.objects_not_uploaded',
+                                                                             client=self.bob_magicfolder._client), 1))
 
         d.addCallback(lambda ign: self._check_version_in_local_db(self.bob_magicfolder, u"file1", 1))
         d.addCallback(lambda ign: self._check_version_in_dmd(self.bob_magicfolder, u"file1", 1))
         d.addCallback(lambda ign: self._check_file_gone(self.bob_magicfolder, u"file1"))
         d.addCallback(_check_downloader_count, 'objects_failed', 0)
-        d.addCallback(_check_downloader_count, 'objects_excluded', 1)
         d.addCallback(_check_downloader_count, 'objects_downloaded', 2)
 
         def Alice_to_rewrite_file():
@@ -753,6 +780,8 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
         d.addCallback(_check_uploader_count, 'files_uploaded', 3)
         d.addCallback(_check_uploader_count, 'objects_queued', 0)
         d.addCallback(_check_uploader_count, 'directories_created', 0)
+        d.addCallback(_check_downloader_count, 'objects_conflicted', 0)
+        d.addCallback(_check_downloader_count, 'objects_conflicted', 0, alice=False)
 
         d.addCallback(lambda ign: self._check_version_in_dmd(self.bob_magicfolder, u"file1", 2))
         d.addCallback(lambda ign: self._check_version_in_local_db(self.bob_magicfolder, u"file1", 2))
@@ -764,6 +793,7 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
 
         def Alice_tries_to_p0wn_Bob(ign):
             print "Alice tries to p0wn Bob\n"
+            self.objects_excluded = self._get_count('downloader.objects_excluded', client=self.bob_magicfolder._client)
             processed_d = self.bob_magicfolder.downloader.set_hook('processed')
 
             # upload a file that would provoke the security bug from #2506
@@ -778,8 +808,55 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
 
         d.addCallback(lambda ign: self.failIf(os.path.exists(path_u)))
         d.addCallback(lambda ign: self._check_version_in_local_db(self.bob_magicfolder, encoded_path_u, None))
-        d.addCallback(_check_downloader_count, 'objects_excluded', 2)
+        d.addCallback(lambda ign: _check_downloader_count(None, 'objects_excluded', self.objects_excluded+1))
         d.addCallback(_check_downloader_count, 'objects_downloaded', 3)
+        d.addCallback(_check_downloader_count, 'objects_conflicted', 0)
+        d.addCallback(_check_downloader_count, 'objects_conflicted', 0, alice=False)
+
+        def Bob_to_rewrite_file():
+            print "Bob rewrites file\n"
+            self.file_path = abspath_expanduser_unicode(u"file1", base=self.bob_magicfolder.uploader._local_path_u)
+            print "---- bob's file is %r" % (self.file_path,)
+            fileutil.write(self.file_path, "No white rabbit to be found.")
+            self.magicfolder = self.bob_magicfolder
+            self.notify(to_filepath(self.file_path), self.inotify.IN_CLOSE_WRITE)
+        d.addCallback(lambda ign: _wait_for(None, Bob_to_rewrite_file, alice=False))
+
+        d.addCallback(lambda ign: self._check_version_in_dmd(self.bob_magicfolder, u"file1", 3))
+        d.addCallback(lambda ign: self._check_version_in_local_db(self.bob_magicfolder, u"file1", 3))
+        d.addCallback(_check_uploader_count, 'objects_failed', 0, alice=False)
+        d.addCallback(_check_uploader_count, 'objects_succeeded', 1, alice=False)
+        d.addCallback(_check_uploader_count, 'files_uploaded', 1, alice=False)
+        d.addCallback(_check_uploader_count, 'objects_queued', 0, alice=False)
+        d.addCallback(_check_uploader_count, 'directories_created', 0, alice=False)
+        d.addCallback(_check_downloader_count, 'objects_conflicted', 0)
+
+        d.addCallback(lambda ign: self._check_version_in_dmd(self.alice_magicfolder, u"file1", 3))
+        d.addCallback(lambda ign: self._check_version_in_local_db(self.alice_magicfolder, u"file1", 3))
+        d.addCallback(_check_downloader_count, 'objects_failed', 0, alice=False)
+        d.addCallback(_check_downloader_count, 'objects_downloaded', 1, alice=False)
+        d.addCallback(_check_downloader_count, 'objects_conflicted', 0, alice=False)
+
+        def Alice_conflicts_with_Bob():
+            print "Alice conflicts with Bob\n"
+            downloaded_d = self.bob_magicfolder.downloader.set_hook('processed')
+            uploadable = Data("do not follow the white rabbit", self.alice_magicfolder._client.convergence)
+            alice_dmd = self.alice_magicfolder.uploader._upload_dirnode
+            d2 = alice_dmd.add_file(u"file1", uploadable,
+                                    metadata={"version": 5,
+                                              "last_downloaded_uri" : "URI:LIT:" },
+                                    overwrite=True)
+            print "Waiting for Alice to upload\n"
+            d2.addCallback(lambda ign: bob_clock.advance(6))
+            d2.addCallback(lambda ign: downloaded_d)
+            d2.addCallback(lambda ign: self.failUnless(alice_dmd.has_child(encoded_path_u)))
+            return d2
+
+        d.addCallback(lambda ign: Alice_conflicts_with_Bob())
+        # XXX fix the code so that it doesn't increment objects_excluded each turn
+        #d.addCallback(_check_downloader_count, 'objects_excluded', 1)
+        d.addCallback(_check_downloader_count, 'objects_downloaded', 4)
+        d.addCallback(_check_downloader_count, 'objects_conflicted', 1)
 
         def _cleanup(ign, magicfolder, clock):
             if magicfolder is not None: