]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blobdiff - src/allmydata/test/test_magic_folder.py
Fix a type error.
[tahoe-lafs/tahoe-lafs.git] / src / allmydata / test / test_magic_folder.py
index 44769e833cd4db42dcc4072ad39a1d8384994599..c00ccac66c4aba61164797be178435c55723d3ff 100644 (file)
@@ -153,7 +153,8 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
             downloaded_d = self.magicfolder.downloader.set_hook('processed', ignore_count=1)
             uploaded_d = self.magicfolder.uploader.set_hook('processed', ignore_count=1)
             self.mkdir_nonascii(small_tree_dir)
-            fileutil.write(abspath_expanduser_unicode(u"what", base=small_tree_dir), "say when")
+            what_path = abspath_expanduser_unicode(u"what", base=small_tree_dir)
+            fileutil.write(what_path, "say when")
             os.rename(small_tree_dir, new_small_tree_dir)
             self.notify(to_filepath(new_small_tree_dir), self.inotify.IN_MOVED_TO)
 
@@ -169,8 +170,9 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
             print "_check_moved_tree_is_watched"
             downloaded_d = self.magicfolder.downloader.set_hook('processed', ignore_count=1)
             uploaded_d = self.magicfolder.uploader.set_hook('processed')
-            fileutil.write(abspath_expanduser_unicode(u"another", base=new_small_tree_dir), "file")
-            self.notify(to_filepath(abspath_expanduser_unicode(u"another", base=new_small_tree_dir)), self.inotify.IN_CLOSE_WRITE)
+            another_path = abspath_expanduser_unicode(u"another", base=new_small_tree_dir)
+            fileutil.write(another_path, "file")
+            self.notify(to_filepath(another_path), self.inotify.IN_CLOSE_WRITE)
 
             return DeferredListShouldSucceed([downloaded_d, uploaded_d])
         d.addCallback(_check_moved_tree_is_watched)
@@ -255,8 +257,7 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
             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')
+            fileutil.write(path, 'foo\n')
             self.notify(to_filepath(path), self.inotify.IN_CLOSE_WRITE)
             yield up_proc
             self.assertTrue(os.path.exists(path))
@@ -290,8 +291,7 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
             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')
+            fileutil.write(path, 'foo\n')
             self.notify(to_filepath(path), self.inotify.IN_CLOSE_WRITE)
             yield up_proc
             self.assertTrue(os.path.exists(path))
@@ -311,8 +311,7 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
             # 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')
+            fileutil.write(path, 'bar\n')
             self.notify(to_filepath(path), self.inotify.IN_CLOSE_WRITE)
             yield up_proc
 
@@ -340,8 +339,7 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
             alice_proc = self.alice_magicfolder.uploader.set_hook('processed')
             bob_proc = self.bob_magicfolder.downloader.set_hook('processed')
 
-            with open(alice_fname, 'wb') as f:
-                f.write('contents0\n')
+            fileutil.write(alice_fname, 'contents0\n')
             self.notify(to_filepath(alice_fname), self.inotify.IN_CLOSE_WRITE, magic=self.alice_magicfolder)
 
             alice_clock.advance(0)
@@ -388,8 +386,7 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
             # now alice restores it (alice should upload, bob download)
             alice_proc = self.alice_magicfolder.uploader.set_hook('processed')
             bob_proc = self.bob_magicfolder.downloader.set_hook('processed')
-            with open(alice_fname, 'wb') as f:
-                f.write('new contents\n')
+            fileutil.write(alice_fname, 'new contents\n')
             self.notify(to_filepath(alice_fname), self.inotify.IN_CLOSE_WRITE, magic=self.alice_magicfolder)
 
             alice_clock.advance(0)
@@ -430,8 +427,7 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
             alice_proc = self.alice_magicfolder.uploader.set_hook('processed')
             bob_proc = self.bob_magicfolder.downloader.set_hook('processed')
 
-            with open(alice_fname, 'wb') as f:
-                f.write('contents0\n')
+            fileutil.write(alice_fname, 'contents0\n')
             self.notify(to_filepath(alice_fname), self.inotify.IN_CLOSE_WRITE, magic=self.alice_magicfolder)
 
             alice_clock.advance(0)
@@ -457,8 +453,7 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
             # now bob updates it (bob should upload, alice download)
             bob_proc = self.bob_magicfolder.uploader.set_hook('processed')
             alice_proc = self.alice_magicfolder.downloader.set_hook('processed')
-            with open(bob_fname, 'wb') as f:
-                f.write('bob wuz here\n')
+            fileutil.write(bob_fname, 'bob wuz here\n')
             self.notify(to_filepath(bob_fname), self.inotify.IN_CLOSE_WRITE, magic=self.bob_magicfolder)
 
             bob_clock.advance(0)
@@ -497,8 +492,7 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
             alice_proc = self.alice_magicfolder.uploader.set_hook('processed')
             bob_proc = self.bob_magicfolder.downloader.set_hook('processed')
 
-            with open(alice_fname, 'wb') as f:
-                f.write('contents0\n')
+            fileutil.write(alice_fname, 'contents0\n')
             self.notify(to_filepath(alice_fname), self.inotify.IN_CLOSE_WRITE, magic=self.alice_magicfolder)
 
             alice_clock.advance(0)
@@ -543,8 +537,7 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
             # now alice restores the file (with new contents)
             alice_proc = self.alice_magicfolder.uploader.set_hook('processed')
             bob_proc = self.bob_magicfolder.downloader.set_hook('processed')
-            with open(alice_fname, 'wb') as f:
-                f.write('alice wuz here\n')
+            fileutil.write(alice_fname, 'alice wuz here\n')
             self.notify(to_filepath(alice_fname), self.inotify.IN_CLOSE_WRITE, magic=self.alice_magicfolder)
 
             alice_clock.advance(0)
@@ -628,10 +621,9 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
                 f.close()
             if temporary and sys.platform == "win32":
                 os.unlink(path_u)
-                self.notify(path, self.inotify.IN_DELETE)
+                self.notify(path, self.inotify.IN_DELETE, flush=False)
             event_mask = self.inotify.IN_CLOSE_WRITE
 
-        fileutil.flush_volume(path_u)
         self.notify(path, event_mask)
         encoded_name_u = magicpath.path2magic(name_u)
 
@@ -668,23 +660,19 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
         path = os.path.join(magicfolder.uploader._local_path_u, relpath_u)
         self.assertTrue(not os.path.exists(path))
 
+    def _check_uploader_count(self, name, expected, magic=None):
+        self.failUnlessReallyEqual(self._get_count('uploader.'+name, client=(magic or self.alice_magicfolder)._client),
+                                   expected)
+
+    def _check_downloader_count(self, name, expected, magic=None):
+        self.failUnlessReallyEqual(self._get_count('downloader.'+name, client=(magic or self.bob_magicfolder)._client),
+                                   expected)
+
     def test_alice_bob(self):
         alice_clock = task.Clock()
         bob_clock = task.Clock()
         d = self.setup_alice_and_bob(alice_clock, bob_clock)
 
-        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):
-            self.failUnlessReallyEqual(self._get_count('downloader.'+name, client=self.bob_magicfolder._client),
-                                       expected)
-
         def _wait_for_Alice(ign, downloaded_d):
             print "Now waiting for Alice to download\n"
             alice_clock.advance(0)
@@ -722,15 +710,18 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
 
         d.addCallback(lambda ign: self._check_version_in_dmd(self.alice_magicfolder, u"file1", 0))
         d.addCallback(lambda ign: self._check_version_in_local_db(self.alice_magicfolder, u"file1", 0))
-        d.addCallback(_check_uploader_count, 'objects_failed', 0)
-        d.addCallback(_check_uploader_count, 'objects_succeeded', 1)
-        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(lambda ign: self._check_uploader_count('objects_failed', 0))
+        d.addCallback(lambda ign: self._check_uploader_count('objects_succeeded', 1))
+        d.addCallback(lambda ign: self._check_uploader_count('files_uploaded', 1))
+        d.addCallback(lambda ign: self._check_uploader_count('objects_queued', 0))
+        d.addCallback(lambda ign: self._check_uploader_count('directories_created', 0))
+        d.addCallback(lambda ign: self._check_uploader_count('objects_conflicted', 0))
+        d.addCallback(lambda ign: self._check_uploader_count('objects_conflicted', 0, magic=self.bob_magicfolder))
 
         d.addCallback(lambda ign: self._check_version_in_local_db(self.bob_magicfolder, u"file1", 0))
-        d.addCallback(_check_downloader_count, 'objects_failed', 0)
-        d.addCallback(_check_downloader_count, 'objects_downloaded', 1)
+        d.addCallback(lambda ign: self._check_downloader_count('objects_failed', 0))
+        d.addCallback(lambda ign: self._check_downloader_count('objects_downloaded', 1))
+        d.addCallback(lambda ign: self._check_uploader_count('objects_succeeded', 0, magic=self.bob_magicfolder))
 
         def Alice_to_delete_file():
             print "Alice deletes the file!\n"
@@ -741,7 +732,7 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
         def notify_bob_moved(ign):
             d0 = self.bob_magicfolder.uploader.set_hook('processed')
             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), self.inotify.IN_MOVED_FROM, magic=self.bob_magicfolder, flush=False)
             self.notify(to_filepath(p + u'.backup'), self.inotify.IN_MOVED_TO, magic=self.bob_magicfolder)
             bob_clock.advance(0)
             return d0
@@ -749,16 +740,16 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
 
         d.addCallback(lambda ign: self._check_version_in_dmd(self.alice_magicfolder, u"file1", 1))
         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_uploader_count('objects_failed', 0))
+        d.addCallback(lambda ign: self._check_uploader_count('objects_succeeded', 2))
+        d.addCallback(lambda ign: self._check_uploader_count('objects_not_uploaded', 1, magic=self.bob_magicfolder))
+        d.addCallback(lambda ign: self._check_uploader_count('objects_succeeded', 1, magic=self.bob_magicfolder))
 
         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_downloaded', 2)
+        d.addCallback(lambda ign: self._check_downloader_count('objects_failed', 0))
+        d.addCallback(lambda ign: self._check_downloader_count('objects_downloaded', 2))
 
         def Alice_to_rewrite_file():
             print "Alice rewrites file\n"
@@ -769,16 +760,18 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
 
         d.addCallback(lambda ign: self._check_version_in_dmd(self.alice_magicfolder, u"file1", 2))
         d.addCallback(lambda ign: self._check_version_in_local_db(self.alice_magicfolder, u"file1", 2))
-        d.addCallback(_check_uploader_count, 'objects_failed', 0)
-        d.addCallback(_check_uploader_count, 'objects_succeeded', 3)
-        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(lambda ign: self._check_uploader_count('objects_failed', 0))
+        d.addCallback(lambda ign: self._check_uploader_count('objects_succeeded', 3))
+        d.addCallback(lambda ign: self._check_uploader_count('files_uploaded', 3))
+        d.addCallback(lambda ign: self._check_uploader_count('objects_queued', 0))
+        d.addCallback(lambda ign: self._check_uploader_count('directories_created', 0))
+        d.addCallback(lambda ign: self._check_downloader_count('objects_conflicted', 0, magic=self.alice_magicfolder))
+        d.addCallback(lambda ign: self._check_downloader_count('objects_conflicted', 0))
 
         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))
-        d.addCallback(_check_downloader_count, 'objects_failed', 0)
-        d.addCallback(_check_downloader_count, 'objects_downloaded', 3)
+        d.addCallback(lambda ign: self._check_downloader_count('objects_failed', 0))
+        d.addCallback(lambda ign: self._check_downloader_count('objects_downloaded', 3))
 
         path_u = u"/tmp/magic_folder_test"
         encoded_path_u = magicpath.path2magic(u"/tmp/magic_folder_test")
@@ -800,21 +793,56 @@ 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(lambda ign: _check_downloader_count(None, 'objects_excluded', self.objects_excluded+1))
-        d.addCallback(_check_downloader_count, 'objects_downloaded', 3)
-
+        d.addCallback(lambda ign: self._check_downloader_count('objects_excluded', self.objects_excluded+1))
+        d.addCallback(lambda ign: self._check_downloader_count('objects_downloaded', 3))
+        d.addCallback(lambda ign: self._check_downloader_count('objects_conflicted', 0, magic=self.alice_magicfolder))
+        d.addCallback(lambda ign: self._check_downloader_count('objects_conflicted', 0))
 
-        # XXX
         def Bob_to_rewrite_file():
             print "Bob rewrites file\n"
-            self.file_path = abspath_expanduser_unicode(u"file2", base=self.bob_magicfolder.uploader._local_path_u)
+            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(lambda ign: self._check_uploader_count('objects_failed', 0, magic=self.bob_magicfolder))
+        d.addCallback(lambda ign: self._check_uploader_count('objects_succeeded', 2, magic=self.bob_magicfolder))
+        d.addCallback(lambda ign: self._check_uploader_count('files_uploaded', 1, magic=self.bob_magicfolder))
+        d.addCallback(lambda ign: self._check_uploader_count('objects_queued', 0, magic=self.bob_magicfolder))
+        d.addCallback(lambda ign: self._check_uploader_count('directories_created', 0, magic=self.bob_magicfolder))
+        d.addCallback(lambda ign: self._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(lambda ign: self._check_downloader_count('objects_failed', 0, magic=self.alice_magicfolder))
+        d.addCallback(lambda ign: self._check_downloader_count('objects_downloaded', 1, magic=self.alice_magicfolder))
+        d.addCallback(lambda ign: self._check_downloader_count('objects_conflicted', 0, magic=self.alice_magicfolder))
+
+        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(lambda ign: self._check_downloader_count('objects_excluded', 1))
+        d.addCallback(lambda ign: self._check_downloader_count('objects_downloaded', 4))
+        d.addCallback(lambda ign: self._check_downloader_count('objects_conflicted', 1))
+
         def _cleanup(ign, magicfolder, clock):
             if magicfolder is not None:
                 d2 = magicfolder.finish()
@@ -840,10 +868,11 @@ class MockTest(MagicFolderTestMixin, unittest.TestCase):
         self.inotify = fake_inotify
         self.patch(magic_folder, 'get_inotify_module', lambda: self.inotify)
 
-    def notify(self, path, mask, magic=None):
+    def notify(self, path, mask, magic=None, flush=True):
         if magic is None:
             magic = self.magicfolder
         magic.uploader._notifier.event(path, mask)
+        # no flush for the mock test.
 
     def test_errors(self):
         self.set_up_grid()
@@ -873,7 +902,7 @@ class MockTest(MagicFolderTestMixin, unittest.TestCase):
             self.shouldFail(AssertionError, 'readonly upload.dircap', 'is not a writecap to a directory',
                             MagicFolder, client, readonly_dircap, '', errors_dir, magicfolderdb,)
             self.shouldFail(AssertionError, 'collective dircap',
-                            "The URI in 'private/collective_dircap' is not a readonly cap to a directory.",
+                            "The URI in '%s' is not a readonly cap to a directory." % os.path.join('private', 'collective_dircap'),
                             MagicFolder, client, upload_dircap, upload_dircap, errors_dir, magicfolderdb)
 
             def _not_implemented():
@@ -930,9 +959,11 @@ class RealTest(MagicFolderTestMixin, unittest.TestCase):
         MagicFolderTestMixin.setUp(self)
         self.inotify = magic_folder.get_inotify_module()
 
-    def notify(self, path, mask, **kw):
+    def notify(self, path, mask, magic=None, flush=True):
         # Writing to the filesystem causes the notification.
-        pass
+        # However, flushing filesystem buffers may be necessary on Windows.
+        if flush:
+            fileutil.flush_volume(path.path)
 
 try:
     magic_folder.get_inotify_module()