From f4b1369ccd6ef67a169ef1e7adfc651bdd8589da Mon Sep 17 00:00:00 2001
From: meejah <meejah@meejah.ca>
Date: Wed, 7 Oct 2015 17:03:28 -0600
Subject: [PATCH] Teach unit-tests to time-warp

1. Split alice/bob clocks to avoid races conditions
   in the tests
2. Wrap ._notify so we can advance the clock after inotify
   calls in the RealTest (since it takes >0ms to do the "real" notifies)
---
 src/allmydata/test/test_cli_magic_folder.py | 17 +++++++++++++---
 src/allmydata/test/test_magic_folder.py     | 22 +++++++++++++++------
 2 files changed, 30 insertions(+), 9 deletions(-)

diff --git a/src/allmydata/test/test_cli_magic_folder.py b/src/allmydata/test/test_cli_magic_folder.py
index 1ba831ac..01fa6c2c 100644
--- a/src/allmydata/test/test_cli_magic_folder.py
+++ b/src/allmydata/test/test_cli_magic_folder.py
@@ -105,11 +105,22 @@ class MagicFolderCLITestMixin(CLITestMixin, GridTestMixin):
         dbfile = abspath_expanduser_unicode(u"magicfolderdb.sqlite", base=self.get_clientdir(i=client_num))
         magicfolder = MagicFolder(self.get_client(client_num), upload_dircap, collective_dircap, local_magic_dir,
                                        dbfile, pending_delay=0.2, clock=clock)
+        magicfolder.downloader._turn_delay = 0
+
+        orig = magicfolder.uploader._append_to_deque
+        # the _append_to_deque method queues a _turn_deque, so we
+        # immediately trigger it by wrapping _append_to_deque
+        def wrap(*args, **kw):
+            x = orig(*args, **kw)
+            clock.advance(0)  # _turn_delay is always 0 for the tests
+            return x
+        magicfolder.uploader._append_to_deque = wrap
+
         magicfolder.setServiceParent(self.get_client(client_num))
         magicfolder.ready()
         return magicfolder
 
-    def setup_alice_and_bob(self, clock=reactor):
+    def setup_alice_and_bob(self, alice_clock=reactor, bob_clock=reactor):
         self.set_up_grid(num_clients=2)
 
         alice_magic_dir = abspath_expanduser_unicode(u"Alice-magic", base=self.basedir)
@@ -131,7 +142,7 @@ class MagicFolderCLITestMixin(CLITestMixin, GridTestMixin):
         d.addCallback(lambda x: self.check_joined_config(0, self.alice_upload_dircap))
         d.addCallback(lambda x: self.check_config(0, alice_magic_dir))
         def get_Alice_magicfolder(result):
-            self.alice_magicfolder = self.init_magicfolder(0, self.alice_upload_dircap, self.alice_collective_dircap, alice_magic_dir, clock)
+            self.alice_magicfolder = self.init_magicfolder(0, self.alice_upload_dircap, self.alice_collective_dircap, alice_magic_dir, alice_clock)
             return result
         d.addCallback(get_Alice_magicfolder)
 
@@ -147,7 +158,7 @@ class MagicFolderCLITestMixin(CLITestMixin, GridTestMixin):
         d.addCallback(lambda x: self.check_joined_config(1, self.bob_upload_dircap))
         d.addCallback(lambda x: self.check_config(1, bob_magic_dir))
         def get_Bob_magicfolder(result):
-            self.bob_magicfolder = self.init_magicfolder(1, self.bob_upload_dircap, self.bob_collective_dircap, bob_magic_dir, clock)
+            self.bob_magicfolder = self.init_magicfolder(1, self.bob_upload_dircap, self.bob_collective_dircap, bob_magic_dir, bob_clock)
             return result
         d.addCallback(get_Bob_magicfolder)
 
diff --git a/src/allmydata/test/test_magic_folder.py b/src/allmydata/test/test_magic_folder.py
index e0396334..75511b79 100644
--- a/src/allmydata/test/test_magic_folder.py
+++ b/src/allmydata/test/test_magic_folder.py
@@ -2,7 +2,7 @@
 import os, sys
 
 from twisted.trial import unittest
-from twisted.internet import defer
+from twisted.internet import defer, task
 
 from allmydata.interfaces import IDirectoryNode
 
@@ -313,7 +313,9 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
         self.failUnlessEqual(version, expected_version)
 
     def test_alice_bob(self):
-        d = self.setup_alice_and_bob()
+        alice_clock = task.Clock()
+        bob_clock = task.Clock()
+        d = self.setup_alice_and_bob(alice_clock, bob_clock)
         def get_results(result):
             # XXX are these used?
             (self.alice_collective_dircap, self.alice_upload_dircap, self.alice_magicfolder,
@@ -334,6 +336,7 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
         def Alice_wait_for_upload(result):
             print "Alice waits for an upload\n"
             d2 = self.alice_magicfolder.uploader.set_hook('processed')
+            alice_clock.advance(0)
             return d2
         d.addCallback(Alice_wait_for_upload)
         d.addCallback(lambda ign: self._check_version_in_dmd(self.alice_magicfolder, u"file1", 0))
@@ -348,6 +351,7 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
         def Bob_wait_for_download(result):
             print "Bob waits for a download\n"
             d2 = self.bob_magicfolder.downloader.set_hook('processed')
+            bob_clock.advance(0)
             return d2
         d.addCallback(Bob_wait_for_download)
         d.addCallback(lambda ign: self._check_version_in_local_db(self.bob_magicfolder, u"file1", 0))
@@ -361,7 +365,7 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
             print "Alice deletes the file!\n"
             os.unlink(self.file_path)
             self.notify(to_filepath(self.file_path), self.inotify.IN_DELETE)
-
+            alice_clock.advance(0)
             return None
         d.addCallback(Alice_delete_file)
         d.addCallback(Alice_wait_for_upload)
@@ -378,9 +382,9 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
 
         def Alice_rewrite_file(result):
             print "Alice rewrites file\n"
+            self.magicfolder = self.alice_magicfolder
             self.file_path = abspath_expanduser_unicode(u"file1", base=self.alice_magicfolder.uploader._local_path_u)
             fileutil.write(self.file_path, "Alice suddenly sees the white rabbit running into the forest.")
-            self.magicfolder = self.alice_magicfolder
             self.notify(to_filepath(self.file_path), self.inotify.IN_CLOSE_WRITE)
 
         d.addCallback(Alice_rewrite_file)
@@ -406,8 +410,14 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
             print "cleanup alice bob test\n"
             d = defer.succeed(None)
             d.addCallback(lambda ign: self.alice_magicfolder.finish())
-            d.addCallback(lambda ign: self.bob_magicfolder.finish())
-            d.addCallback(lambda ign: result)
+
+            def clean_bob(_):
+                d2 = self.bob_magicfolder.finish()
+                d2.addCallback(lambda ign: result)
+                bob_clock.advance(0)
+                return d2
+            d.addCallback(clean_bob)
+            alice_clock.advance(0)
             return d
         d.addCallback(cleanup_Alice_and_Bob)
         return d
-- 
2.45.2