From bf1812dabd2461ef8f2bde2eb6e9459ff86042ce Mon Sep 17 00:00:00 2001 From: David Stainton Date: Fri, 26 Jun 2015 19:47:17 -0700 Subject: [PATCH] Add helper to setup Alice and Bob magic-folders this will help us write unit tests with multiple writers to the magic-folder... --- src/allmydata/test/no_network.py | 3 + src/allmydata/test/test_cli.py | 19 +++ src/allmydata/test/test_cli_magic_folder.py | 134 +++++++++++++------- src/allmydata/test/test_magic_folder.py | 24 +--- 4 files changed, 115 insertions(+), 65 deletions(-) diff --git a/src/allmydata/test/no_network.py b/src/allmydata/test/no_network.py index 6c50bb17..7b7237bb 100644 --- a/src/allmydata/test/no_network.py +++ b/src/allmydata/test/no_network.py @@ -361,6 +361,9 @@ class GridTestMixin: def get_clientdir(self, i=0): return self.g.clients[i].basedir + def get_client(self, i=0): + return self.g.clients[i] + def get_serverdir(self, i): return self.g.servers_by_number[i].storedir diff --git a/src/allmydata/test/test_cli.py b/src/allmydata/test/test_cli.py index b59a2b1b..2bf4a086 100644 --- a/src/allmydata/test/test_cli.py +++ b/src/allmydata/test/test_cli.py @@ -48,6 +48,25 @@ def parse_options(basedir, command, args): return o class CLITestMixin(ReallyEqualMixin): + def do_cli_n(self, client_num, verb, *args, **kwargs): + """ + do_cli_n is used to execute client CLI commands when there is more + than one client in the test grid... you can specify clients by number. + """ + nodeargs = [ + "--node-directory", self.get_clientdir(i=client_num), + ] + argv = nodeargs + [verb] + list(args) + stdin = kwargs.get("stdin", "") + stdout, stderr = StringIO(), StringIO() + d = threads.deferToThread(runner.runner, argv, run_by_human=False, + stdin=StringIO(stdin), + stdout=stdout, stderr=stderr) + def _done(rc): + return rc, stdout.getvalue(), stderr.getvalue() + d.addCallback(_done) + return d + def do_cli(self, verb, *args, **kwargs): nodeargs = [ "--node-directory", self.get_clientdir(), diff --git a/src/allmydata/test/test_cli_magic_folder.py b/src/allmydata/test/test_cli_magic_folder.py index ea4ed113..a5815e66 100644 --- a/src/allmydata/test/test_cli_magic_folder.py +++ b/src/allmydata/test/test_cli_magic_folder.py @@ -12,9 +12,41 @@ from allmydata.test.no_network import GridTestMixin from allmydata.util.encodingutil import quote_output, get_io_encoding from .test_cli import CLITestMixin from allmydata.scripts import magic_folder_cli +from allmydata.util.fileutil import abspath_expanduser_unicode class MagicFolderCLITestMixin(CLITestMixin, GridTestMixin): + + def create_magic_folder(self, client_num): + d = self.do_cli_n(client_num, "magic-folder", "create", "magic") + def _done((rc,stdout,stderr)): + self.failUnless(rc == 0) + self.failUnless("Alias 'magic' created" in stdout) + self.failIf(stderr) + aliases = get_aliases(self.get_clientdir(i=client_num)) + self.failUnless("magic" in aliases) + self.failUnless(aliases["magic"].startswith("URI:DIR2:")) + d.addCallback(_done) + return d + + def invite(self, client_num, nickname): + d = self.do_cli_n(client_num, "magic-folder", "invite", u"magic", nickname) + def _done((rc,stdout,stderr)): + self.failUnless(rc == 0) + return (rc,stdout,stderr) + d.addCallback(_done) + return d + + def join(self, client_num, local_dir, invite_result): + invite_code = result[1].strip() + magic_readonly_cap, dmd_write_cap = invite_code.split(magic_folder_cli.INVITE_SEPERATOR) + d = self.do_cli_n(client_num, "magic-folder", "join", invite_code, local_dir) + def _done((rc,stdout,stderr)): + self.failUnless(rc == 0) + return (rc,stdout,stderr) + d.addCallback(_done) + return d + def diminish_readonly(self, write_cap): d = self.do_cli("ls", "--json", write_cap) def get_readonly_cap((rc,stdout,stderr)): @@ -24,18 +56,18 @@ class MagicFolderCLITestMixin(CLITestMixin, GridTestMixin): d.addCallback(get_readonly_cap) return d - def check_joined_config(self, result): - """Tests that wour collective directory has the readonly cap of + def check_joined_config(self, client_num, upload_dircap): + """Tests that our collective directory has the readonly cap of our upload directory. """ - collective_readonly_cap = fileutil.read(os.path.join(self.get_clientdir(), "private/collective_dircap")) - d = self.do_cli("ls", "--json", collective_readonly_cap) + collective_readonly_cap = fileutil.read(os.path.join(self.get_clientdir(i=client_num), "private/collective_dircap")) + d = self.do_cli_n(client_num, "ls", "--json", collective_readonly_cap) def _done((rc,stdout,stderr)): self.failUnless(rc == 0) return (rc,stdout,stderr) d.addCallback(_done) def test_joined_magic_folder((rc,stdout,stderr)): - d2 = self.diminish_readonly(self.upload_dircap) + d2 = self.diminish_readonly(upload_dircap) def fail_unless_dmd_readonly_exists(readonly_cap): s = re.search(readonly_cap, stdout) self.failUnless(s is not None) @@ -44,18 +76,18 @@ class MagicFolderCLITestMixin(CLITestMixin, GridTestMixin): d.addCallback(test_joined_magic_folder) return d - def get_caps_from_files(self, result): - self.collective_dircap = fileutil.read(os.path.join(self.get_clientdir(), "private/collective_dircap")) - self.upload_dircap = fileutil.read(os.path.join(self.get_clientdir(), "private/magic_folder_dircap")) - self.failIf(self.collective_dircap is None or self.upload_dircap is None) - return None + def get_caps_from_files(self, client_num): + collective_dircap = fileutil.read(os.path.join(self.get_clientdir(i=client_num), "private/collective_dircap")) + upload_dircap = fileutil.read(os.path.join(self.get_clientdir(i=client_num), "private/magic_folder_dircap")) + self.failIf(collective_dircap is None or upload_dircap is None) + return collective_dircap, upload_dircap - def check_config(self, result): - client_config = fileutil.read(os.path.join(self.get_clientdir(), "tahoe.cfg")) + def check_config(self, client_num, local_dir): + client_config = fileutil.read(os.path.join(self.get_clientdir(i=client_num), "tahoe.cfg")) # XXX utf-8? - ret = re.search("\[magic_folder\]\nenabled = True\nlocal.directory = %s" % (self.local_dir.encode('utf-8'),), client_config) + local_dir = local_dir.encode('utf-8') + ret = re.search("\[magic_folder\]\nenabled = True\nlocal.directory = %s" % (local_dir,), client_config) self.failIf(ret is None) - return result def create_invite_join_magic_folder(self, nickname, local_dir): d = self.do_cli("magic-folder", "create", u"magic", nickname, local_dir) @@ -68,45 +100,60 @@ class MagicFolderCLITestMixin(CLITestMixin, GridTestMixin): d.addCallback(self.check_config) return d - -class CreateMagicFolder(MagicFolderCLITestMixin, unittest.TestCase): - - def _create_magic_folder(self): - d = self.do_cli("magic-folder", "create", "magic") - def _done((rc,stdout,stderr)): - self.failUnless(rc == 0) - self.failUnless("Alias 'magic' created" in stdout) - self.failIf(stderr) - aliases = get_aliases(self.get_clientdir()) - self.failUnless("magic" in aliases) - self.failUnless(aliases["magic"].startswith("URI:DIR2:")) - d.addCallback(_done) + def cleanup(self, res): + d = defer.succeed(None) + if self.magicfolder is not None: + d.addCallback(lambda ign: self.magicfolder.finish(for_tests=True)) + d.addCallback(lambda ign: res) return d - def _invite(self, ignore): - d = self.do_cli("magic-folder", "invite", u"magic", u"Alice") - def _done((rc,stdout,stderr)): - self.failUnless(rc == 0) - return (rc,stdout,stderr) - d.addCallback(_done) - return d + def init_magicfolder(self, client_num, upload_dircap, collective_dircap, local_magic_dir): + dbfile = abspath_expanduser_unicode(u"magicfolderdb.sqlite", base=self.get_clientdir(i=client_num)) + self.magicfolder = MagicFolder(self.get_client(client_num), upload_dircap, collective_dircap, local_magic_dir, + dbfile, inotify=self.inotify, pending_delay=0.2) + self.magicfolder.setServiceParent(self.get_client(client_num)) + self.magicfolder.upload_ready() + + def setup_alice_and_bob(self): + self.set_up_grid(num_clients=2) + alice_dir = abspath_expanduser_unicode(u"Alice", base=self.basedir) + self.mkdir_nonascii(alice_dir) + alice_magic_dir = abspath_expanduser_unicode(u"Alice-magic", base=self.basedir) + self.mkdir_nonascii(alice_magic_dir) + bob_dir = abspath_expanduser_unicode(u"Bob", base=self.basedir) + self.mkdir_nonascii(bob_dir) + bob_magic_dir = abspath_expanduser_unicode(u"Bob-magic", base=self.basedir) + self.mkdir_nonascii(bob_magic_dir) + + d = self.create_magic_folder(0) + d.addCallback(lambda x: self.invite_n(0, x)) + d.addCallback(lambda x: self.join(0, alice_magic_dir, x)) + def get_alice_caps(x): + alice_collective_dircap, alice_upload_dircap = self.get_caps_from_files(0) + d.addCallback(get_alice_caps) + d.addCallback(lambda x: self.check_joined_config(0, alice_upload_dircap)) + d.addCallback(lambda x: self.check_config(0, alice_magic_dir)) + d.addCallback(lambda x: self.init_magicfolder(0, alice_upload_dircap, alice_collective_dircap, alice_magic_dir)) + + d.addCallback(lambda x: self.invite_n(0, u"Bob")) + d.addCallback(lambda x: self.join(1, bob_magic_dir, x)) + def get_bob_caps(x): + bob_collective_dircap, bob_upload_dircap = self.get_caps_from_files(1) + d.addCallback(get_bob_caps) + d.addCallback(lambda x: self.check_joined_config(1, bob_upload_dircap)) + d.addCallback(lambda x: self.check_config(1, bob_magic_dir)) + d.addCallback(lambda x: self.init_magicfolder(1, bob_upload_dircap, bob_collective_dircap, bob_magic_dir)) - def _join(self, result): - invite_code = result[1].strip() - self.magic_readonly_cap, self.dmd_write_cap = invite_code.split(magic_folder_cli.INVITE_SEPERATOR) - d = self.do_cli("magic-folder", "join", invite_code, self.local_dir) - def _done((rc,stdout,stderr)): - self.failUnless(rc == 0) - return (rc,stdout,stderr) - d.addCallback(_done) return d +class CreateMagicFolder(MagicFolderCLITestMixin, unittest.TestCase): + def test_create_and_then_invite_join(self): self.basedir = "cli/MagicFolder/create-and-then-invite-join" self.set_up_grid() self.local_dir = os.path.join(self.basedir, "magic") - d = self._create_magic_folder() + d = self.create_magic_folder(0) d.addCallback(self._invite) d.addCallback(self._join) d.addCallback(self.get_caps_from_files) @@ -127,3 +174,4 @@ class CreateMagicFolder(MagicFolderCLITestMixin, unittest.TestCase): d.addCallback(self.check_joined_config) d.addCallback(self.check_config) return d + diff --git a/src/allmydata/test/test_magic_folder.py b/src/allmydata/test/test_magic_folder.py index c809e8ad..df4b96d5 100644 --- a/src/allmydata/test/test_magic_folder.py +++ b/src/allmydata/test/test_magic_folder.py @@ -62,12 +62,6 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual self.magicfolder.upload_ready() # Prevent unclean reactor errors. - def _cleanup(self, res): - d = defer.succeed(None) - if self.magicfolder is not None: - d.addCallback(lambda ign: self.magicfolder.finish(for_tests=True)) - d.addCallback(lambda ign: res) - return d def test_db_basic(self): fileutil.make_dirs(self.basedir) @@ -321,22 +315,8 @@ class MagicFolderTestMixin(MagicFolderCLITestMixin, ShouldFailMixin, ReallyEqual d.addCallback(lambda ign: self.failUnlessReallyEqual(self._get_count('magic_folder.objects_queued'), 0)) return d - def test_remote_scan(self): - self.set_up_grid() - self.local_dir = abspath_expanduser_unicode(self.unicode_or_fallback(u"l\u00F8cal_dir", u"local_dir"), - base=self.basedir) - self.mkdir_nonascii(self.local_dir) - self.client = self.g.clients[0] - self.stats_provider = self.client.stats_provider - d = self.create_invite_join_magic_folder(u"Alice", self.local_dir) - d.addCallback(self._create_magicfolder) - d.addCallback(lambda x: self.magicfolder._scan_remote_collective()) - def display_list(results): - print "LIST ", results - d.addCallback(display_list) - d.addBoth(self._cleanup) - return d - + def test_alice_bob(self): + self.setup_alice_and_bob() class MockTest(MagicFolderTestMixin, unittest.TestCase): """This can run on any platform, and even if twisted.internet.inotify can't be imported.""" -- 2.45.2