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)
This commit is contained in:
meejah 2015-10-07 17:03:28 -06:00 committed by Brian Warner
parent 4ed2fb725a
commit 9aecfed421
2 changed files with 30 additions and 9 deletions

View File

@ -105,11 +105,22 @@ class MagicFolderCLITestMixin(CLITestMixin, GridTestMixin):
dbfile = abspath_expanduser_unicode(u"magicfolderdb.sqlite", base=self.get_clientdir(i=client_num)) 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, magicfolder = MagicFolder(self.get_client(client_num), upload_dircap, collective_dircap, local_magic_dir,
dbfile, pending_delay=0.2, clock=clock) 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.setServiceParent(self.get_client(client_num))
magicfolder.ready() magicfolder.ready()
return magicfolder 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) self.set_up_grid(num_clients=2)
alice_magic_dir = abspath_expanduser_unicode(u"Alice-magic", base=self.basedir) 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_joined_config(0, self.alice_upload_dircap))
d.addCallback(lambda x: self.check_config(0, alice_magic_dir)) d.addCallback(lambda x: self.check_config(0, alice_magic_dir))
def get_Alice_magicfolder(result): 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 return result
d.addCallback(get_Alice_magicfolder) 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_joined_config(1, self.bob_upload_dircap))
d.addCallback(lambda x: self.check_config(1, bob_magic_dir)) d.addCallback(lambda x: self.check_config(1, bob_magic_dir))
def get_Bob_magicfolder(result): 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 return result
d.addCallback(get_Bob_magicfolder) d.addCallback(get_Bob_magicfolder)

View File

@ -2,7 +2,7 @@
import os, sys import os, sys
from twisted.trial import unittest from twisted.trial import unittest
from twisted.internet import defer from twisted.internet import defer, task
from allmydata.interfaces import IDirectoryNode from allmydata.interfaces import IDirectoryNode
@ -313,7 +313,9 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
self.failUnlessEqual(version, expected_version) self.failUnlessEqual(version, expected_version)
def test_alice_bob(self): 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): def get_results(result):
# XXX are these used? # XXX are these used?
(self.alice_collective_dircap, self.alice_upload_dircap, self.alice_magicfolder, (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): def Alice_wait_for_upload(result):
print "Alice waits for an upload\n" print "Alice waits for an upload\n"
d2 = self.alice_magicfolder.uploader.set_hook('processed') d2 = self.alice_magicfolder.uploader.set_hook('processed')
alice_clock.advance(0)
return d2 return d2
d.addCallback(Alice_wait_for_upload) d.addCallback(Alice_wait_for_upload)
d.addCallback(lambda ign: self._check_version_in_dmd(self.alice_magicfolder, u"file1", 0)) 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): def Bob_wait_for_download(result):
print "Bob waits for a download\n" print "Bob waits for a download\n"
d2 = self.bob_magicfolder.downloader.set_hook('processed') d2 = self.bob_magicfolder.downloader.set_hook('processed')
bob_clock.advance(0)
return d2 return d2
d.addCallback(Bob_wait_for_download) d.addCallback(Bob_wait_for_download)
d.addCallback(lambda ign: self._check_version_in_local_db(self.bob_magicfolder, u"file1", 0)) 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" print "Alice deletes the file!\n"
os.unlink(self.file_path) os.unlink(self.file_path)
self.notify(to_filepath(self.file_path), self.inotify.IN_DELETE) self.notify(to_filepath(self.file_path), self.inotify.IN_DELETE)
alice_clock.advance(0)
return None return None
d.addCallback(Alice_delete_file) d.addCallback(Alice_delete_file)
d.addCallback(Alice_wait_for_upload) d.addCallback(Alice_wait_for_upload)
@ -378,9 +382,9 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
def Alice_rewrite_file(result): def Alice_rewrite_file(result):
print "Alice rewrites file\n" 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) 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.") 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) self.notify(to_filepath(self.file_path), self.inotify.IN_CLOSE_WRITE)
d.addCallback(Alice_rewrite_file) d.addCallback(Alice_rewrite_file)
@ -406,8 +410,14 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual
print "cleanup alice bob test\n" print "cleanup alice bob test\n"
d = defer.succeed(None) d = defer.succeed(None)
d.addCallback(lambda ign: self.alice_magicfolder.finish()) 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 return d
d.addCallback(cleanup_Alice_and_Bob) d.addCallback(cleanup_Alice_and_Bob)
return d return d