diff options
author | Kali Kaneko <kali@leap.se> | 2015-01-12 20:47:29 -0400 |
---|---|---|
committer | Kali Kaneko <kali@leap.se> | 2015-02-11 14:05:43 -0400 |
commit | d495fe597380d21109b5ccd7a3acf654af6698de (patch) | |
tree | 02a68b9197bfe0027277fa1552897a108a51b470 /mail | |
parent | f279c5b6761d2def3fb81b64fb1e6b34803e3c47 (diff) |
Use mailbox uuids
The previous implementation is naive, since it imposes a burden when
renaming mailboxes. We're using uuids in the local uid tables instead,
which is more cryptic but way more efficient.
* receive mbox uuid instead of name
* use mailbox uuid in identifiers
Diffstat (limited to 'mail')
-rw-r--r-- | mail/src/leap/mail/adaptors/soledad.py | 29 | ||||
-rw-r--r-- | mail/src/leap/mail/adaptors/tests/test_soledad_adaptor.py | 11 | ||||
-rw-r--r-- | mail/src/leap/mail/constants.py | 8 | ||||
-rw-r--r-- | mail/src/leap/mail/imap/mailbox.py | 12 | ||||
-rw-r--r-- | mail/src/leap/mail/imap/tests/test_imap.py | 26 | ||||
-rw-r--r-- | mail/src/leap/mail/mail.py | 57 | ||||
-rw-r--r-- | mail/src/leap/mail/mailbox_indexer.py | 101 | ||||
-rw-r--r-- | mail/src/leap/mail/tests/test_mailbox_indexer.py | 182 |
8 files changed, 235 insertions, 191 deletions
diff --git a/mail/src/leap/mail/adaptors/soledad.py b/mail/src/leap/mail/adaptors/soledad.py index 389307fb..c5cfce06 100644 --- a/mail/src/leap/mail/adaptors/soledad.py +++ b/mail/src/leap/mail/adaptors/soledad.py @@ -338,7 +338,7 @@ class FlagsDocWrapper(SoledadDocumentWrapper): type_ = "flags" chash = "" - mbox = "inbox" + mbox_uuid = "" seen = False deleted = False recent = False @@ -350,11 +350,12 @@ class FlagsDocWrapper(SoledadDocumentWrapper): class __meta__(object): index = "mbox" - def set_mbox(self, mbox): + def set_mbox_uuid(self, mbox_uuid): # XXX raise error if already created, should use copy instead - new_id = constants.FDOCID.format(mbox=mbox, chash=self.chash) + mbox_uuid = mbox_uuid.replace('-', '_') + new_id = constants.FDOCID.format(mbox_uuid=mbox_uuid, chash=self.chash) self._future_doc_id = new_id - self.mbox = mbox + self.mbox_uuid = mbox_uuid class HeaderDocWrapper(SoledadDocumentWrapper): @@ -401,11 +402,12 @@ class MetaMsgDocWrapper(SoledadDocumentWrapper): hdoc = "" cdocs = [] - def set_mbox(self, mbox): + def set_mbox_uuid(self, mbox_uuid): # XXX raise error if already created, should use copy instead + mbox_uuid = mbox_uuid.replace('-', '_') chash = re.findall(constants.FDOCID_CHASH_RE, self.fdoc)[0] - new_id = constants.METAMSGID.format(mbox=mbox, chash=chash) - new_fdoc_id = constants.FDOCID.format(mbox=mbox, chash=chash) + new_id = constants.METAMSGID.format(mbox_uuid=mbox_uuid, chash=chash) + new_fdoc_id = constants.FDOCID.format(mbox_uuid=mbox_uuid, chash=chash) self._future_doc_id = new_id self.fdoc = new_fdoc_id @@ -518,14 +520,15 @@ class MessageWrapper(object): # 4. return new wrapper (new meta too!) raise NotImplementedError() - def set_mbox(self, mbox): + def set_mbox_uuid(self, mbox_uuid): """ Set the mailbox for this wrapper. This method should only be used before the Documents for the MessageWrapper have been created, will raise otherwise. """ - self.mdoc.set_mbox(mbox) - self.fdoc.set_mbox(mbox) + mbox_uuid = mbox.uuid.replace('-', '_') + self.mdoc.set_mbox_uuid(mbox_uuid) + self.fdoc.set_mbox_uuid(mbox_uuid) def set_flags(self, flags): # TODO serialize the get + update @@ -574,6 +577,7 @@ class MailboxWrapper(SoledadDocumentWrapper): class model(models.SerializableModel): type_ = "mbox" mbox = INBOX_NAME + uuid = None flags = [] recent = [] created = 1 @@ -889,7 +893,10 @@ def _parse_msg(raw): def _build_meta_doc(chash, cdocs_phashes): _mdoc = MetaMsgDocWrapper() - _mdoc.fdoc = constants.FDOCID.format(mbox=INBOX_NAME, chash=chash) + # FIXME passing the inbox name because we don't have the uuid at this + # point. + + _mdoc.fdoc = constants.FDOCID.format(mbox_uuid=INBOX_NAME, chash=chash) _mdoc.hdoc = constants.HDOCID.format(chash=chash) _mdoc.cdocs = [constants.CDOCID.format(phash=p) for p in cdocs_phashes] return _mdoc.serialize() diff --git a/mail/src/leap/mail/adaptors/tests/test_soledad_adaptor.py b/mail/src/leap/mail/adaptors/tests/test_soledad_adaptor.py index 0cca5efe..7bdeef5b 100644 --- a/mail/src/leap/mail/adaptors/tests/test_soledad_adaptor.py +++ b/mail/src/leap/mail/adaptors/tests/test_soledad_adaptor.py @@ -21,7 +21,6 @@ import os from functools import partial from twisted.internet import defer -from twisted.trial import unittest from leap.mail.adaptors import models from leap.mail.adaptors.soledad import SoledadDocumentWrapper @@ -62,7 +61,7 @@ class TestAdaptor(SoledadIndexMixin): 'by-type': ['type']} -class SoledadDocWrapperTestCase(unittest.TestCase, SoledadTestMixin): +class SoledadDocWrapperTestCase(SoledadTestMixin): """ Tests for the SoledadDocumentWrapper. """ @@ -284,7 +283,7 @@ class TestMessageClass(object): return self.wrapper -class SoledadMailAdaptorTestCase(unittest.TestCase, SoledadTestMixin): +class SoledadMailAdaptorTestCase(SoledadTestMixin): """ Tests for the SoledadMailAdaptor. """ @@ -337,7 +336,7 @@ class SoledadMailAdaptorTestCase(unittest.TestCase, SoledadTestMixin): hdoc="H-deadbeef", cdocs=["C-deadabad"]) fdoc = dict( - mbox="Foobox", + mbox_uuid="Foobox", flags=('\Seen', '\Nice'), tags=('Personal', 'TODO'), seen=False, deleted=False, @@ -355,7 +354,7 @@ class SoledadMailAdaptorTestCase(unittest.TestCase, SoledadTestMixin): ('\Seen', '\Nice')) self.assertEqual(msg.wrapper.fdoc.tags, ('Personal', 'TODO')) - self.assertEqual(msg.wrapper.fdoc.mbox, "Foobox") + self.assertEqual(msg.wrapper.fdoc.mbox_uuid, "Foobox") self.assertEqual(msg.wrapper.hdoc.multi, False) self.assertEqual(msg.wrapper.hdoc.subject, "Test Msg") @@ -363,7 +362,7 @@ class SoledadMailAdaptorTestCase(unittest.TestCase, SoledadTestMixin): "This is a test message") def test_get_msg_from_metamsg_doc_id(self): - # XXX complete-me! + # TODO complete-me! self.fail() def test_create_msg(self): diff --git a/mail/src/leap/mail/constants.py b/mail/src/leap/mail/constants.py index d76e6522..4ef42cbb 100644 --- a/mail/src/leap/mail/constants.py +++ b/mail/src/leap/mail/constants.py @@ -22,13 +22,13 @@ INBOX_NAME = "INBOX" # Regular expressions for the identifiers to be used in the Message Data Layer. -METAMSGID = "M-{mbox}-{chash}" -METAMSGID_RE = "M\-{mbox}\-[0-9a-fA-F]+" +METAMSGID = "M-{mbox_uuid}-{chash}" +METAMSGID_RE = "M\-{mbox_uuid}\-[0-9a-fA-F]+" METAMSGID_CHASH_RE = "M\-\w+\-([0-9a-fA-F]+)" METAMSGID_MBOX_RE = "M\-(\w+)\-[0-9a-fA-F]+" -FDOCID = "F-{mbox}-{chash}" -FDOCID_RE = "F\-{mbox}\-[0-9a-fA-F]+" +FDOCID = "F-{mbox_uuid}-{chash}" +FDOCID_RE = "F\-{mbox_uuid}\-[0-9a-fA-F]+" FDOCID_CHASH_RE = "F\-\w+\-([0-9a-fA-F]+)" HDOCID = "H-{chash}" diff --git a/mail/src/leap/mail/imap/mailbox.py b/mail/src/leap/mail/imap/mailbox.py index faeba9d5..f2cbf75f 100644 --- a/mail/src/leap/mail/imap/mailbox.py +++ b/mail/src/leap/mail/imap/mailbox.py @@ -236,6 +236,7 @@ class IMAPMailbox(object): :rtype: int """ + # TODO --- return the uid if it has it!!! d = self.collection.get_msg_by_uid(message) d.addCallback(lambda m: m.getUID()) return d @@ -357,7 +358,7 @@ class IMAPMailbox(object): reactor.callLater(0, self.notify_new) return x - d = self.collection.add_message(flags=flags, date=date) + d = self.collection.add_msg(message, flags=flags, date=date) d.addCallback(notifyCallback) d.addErrback(lambda f: log.msg(f.getTraceback())) return d @@ -389,14 +390,15 @@ class IMAPMailbox(object): messages and number of recent messages. :rtype: Deferred """ - d_exists = self.getMessageCount() - d_recent = self.getRecentCount() + d_exists = defer.maybeDeferred(self.getMessageCount) + d_recent = defer.maybeDeferred(self.getRecentCount) d_list = [d_exists, d_recent] def log_num_msg(result): - exists, recent = result + exists, recent = tuple(result) logger.debug("NOTIFY (%r): there are %s messages, %s recent" % ( self.mbox_name, exists, recent)) + return result d = defer.gatherResults(d_list) d.addCallback(log_num_msg) @@ -654,7 +656,7 @@ class IMAPMailbox(object): return result def _get_unseen_deferred(self): - return self.getUnseenCount() + return defer.maybeDeferred(self.getUnseenCount) def __cb_signal_unread_to_ui(self, unseen): """ diff --git a/mail/src/leap/mail/imap/tests/test_imap.py b/mail/src/leap/mail/imap/tests/test_imap.py index 5af499fc..dbb823fb 100644 --- a/mail/src/leap/mail/imap/tests/test_imap.py +++ b/mail/src/leap/mail/imap/tests/test_imap.py @@ -926,31 +926,39 @@ class LeapIMAP4ServerTestCase(IMAP4HelperMixin, unittest.TestCase): """ infile = util.sibpath(__file__, 'rfc822.message') message = open(infile) - LeapIMAPServer.theAccount.addMailbox('root/subthing') + acc = self.server.theAccount + mailbox_name = "root_subthing" + + def add_mailbox(): + return acc.addMailbox(mailbox_name) def login(): return self.client.login(TEST_USER, TEST_PASSWD) def append(): return self.client.append( - 'root/subthing', - message, + mailbox_name, message, ('\\SEEN', '\\DELETED'), 'Tue, 17 Jun 2003 11:22:16 -0600 (MDT)', ) - d1 = self.connected.addCallback(strip(login)) + d1 = self.connected.addCallback(strip(add_mailbox)) + d1.addCallback(strip(login)) d1.addCallbacks(strip(append), self._ebGeneral) d1.addCallbacks(self._cbStopClient, self._ebGeneral) d2 = self.loopback() d = defer.gatherResults([d1, d2]) - return d.addCallback(self._cbTestFullAppend, infile) + d.addCallback(lambda _: acc.getMailbox(mailbox_name)) - def _cbTestFullAppend(self, ignored, infile): - mb = LeapIMAPServer.theAccount.getMailbox('root/subthing') - self.assertEqual(1, len(mb.messages)) + def print_mb(mb): + print "MB ----", mb + return mb + d.addCallback(print_mb) + d.addCallback(lambda mb: mb.collection.get_message_by_uid(1)) + return d.addCallback(self._cbTestFullAppend, infile) - msg = mb.messages.get_msg_by_uid(1) + def _cbTestFullAppend(self, msg, infile): + # TODO --- move to deferreds self.assertEqual( set(('\\Recent', '\\SEEN', '\\DELETED')), set(msg.getFlags())) diff --git a/mail/src/leap/mail/mail.py b/mail/src/leap/mail/mail.py index 0c9b7a3a..b2caa335 100644 --- a/mail/src/leap/mail/mail.py +++ b/mail/src/leap/mail/mail.py @@ -17,6 +17,7 @@ """ Generic Access to Mail objects: Public LEAP Mail API. """ +import uuid import logging import StringIO @@ -283,6 +284,20 @@ class MessageCollection(object): self.mbox_indexer = mbox_indexer self.mbox_wrapper = mbox_wrapper + # TODO need to initialize count here because imap server does not + # expect a defered for the count. caller should return the deferred for + # prime_count (ie, initialize) when returning the collection + # TODO should increment and decrement when adding/deleting. + # TODO recent count should also be static. + + if not count: + count = 0 + self._count = count + + #def initialize(self): + #d = self.prime_count() + #return d + def is_mailbox_collection(self): """ Return True if this collection represents a Mailbox. @@ -297,6 +312,13 @@ class MessageCollection(object): return None return wrapper.mbox + @property + def mbox_uuid(self): + wrapper = getattr(self, "mbox_wrapper", None) + if not wrapper: + return None + return wrapper.mbox_uuid + def get_mbox_attr(self, attr): return getattr(self.mbox_wrapper, attr) @@ -385,16 +407,16 @@ class MessageCollection(object): raise NotImplementedError() else: - mbox = self.mbox_name + mbox_id = self.mbox_uuid wrapper.set_flags(flags) wrapper.set_tags(tags) wrapper.set_date(date) - wrapper.set_mbox(mbox) + wrapper.set_mbox_uuid(mbox_id) def insert_mdoc_id(_, wrapper): doc_id = wrapper.mdoc.doc_id return self.mbox_indexer.insert_doc( - self.mbox_name, doc_id) + self.mbox_uuid, doc_id) d = wrapper.create(self.store) d.addCallback(insert_mdoc_id, wrapper) @@ -410,7 +432,7 @@ class MessageCollection(object): def insert_copied_mdoc_id(wrapper): return self.mbox_indexer.insert_doc( - newmailbox, wrapper.mdoc.doc_id) + newmailbox_uuid, wrapper.mdoc.doc_id) wrapper = msg.get_wrapper() d = wrapper.copy(self.store, newmailbox) @@ -539,25 +561,32 @@ class Account(object): def add_mailbox(self, name): - def create_uid_table_cb(res): - d = self.mbox_indexer.create_table(name) - d.addCallback(lambda _: res) + def create_uuid(wrapper): + if not wrapper.uuid: + wrapper.uuid = uuid.uuid4() + return wrapper.update(self.store) + + def create_uid_table_cb(wrapper): + d = self.mbox_indexer.create_table(wrapper.uuid) + d.addCallback(lambda _: wrapper) return d d = self.adaptor.get_or_create_mbox(self.store, name) + d.addCallback(create_uuid) d.addCallback(create_uid_table_cb) return d def delete_mailbox(self, name): - def delete_uid_table_cb(res): - d = self.mbox_indexer.delete_table(name) - d.addCallback(lambda _: res) + + def delete_uid_table_cb(wrapper): + d = self.mbox_indexer.delete_table(wrapper.uuid) + d.addCallback(lambda _: wrapper) return d d = self.adaptor.get_or_create_mbox(self.store, name) + d.addCallback(delete_uid_table_cb) d.addCallback( lambda wrapper: self.adaptor.delete_mbox(self.store, wrapper)) - d.addCallback(delete_uid_table_cb) return d def rename_mailbox(self, oldname, newname): @@ -572,14 +601,8 @@ class Account(object): wrapper.mbox = newname return wrapper.update(self.store) - def rename_uid_table_cb(res): - d = self.mbox_indexer.rename_table(oldname, newname) - d.addCallback(lambda _: res) - return d - d = self.adaptor.get_or_create_mbox(self.store, oldname) d.addCallback(_rename_mbox) - d.addCallback(rename_uid_table_cb) return d # Get Collections diff --git a/mail/src/leap/mail/mailbox_indexer.py b/mail/src/leap/mail/mailbox_indexer.py index e5b813fa..6155a7a9 100644 --- a/mail/src/leap/mail/mailbox_indexer.py +++ b/mail/src/leap/mail/mailbox_indexer.py @@ -18,6 +18,7 @@ Local tables to store the message Unique Identifiers for a given mailbox. """ import re +import uuid from leap.mail.constants import METAMSGID_RE @@ -37,6 +38,25 @@ class WrongMetaDocIDError(Exception): pass +def sanitize(mailbox_id): + return mailbox_id.replace("-", "_") + + +def check_good_uuid(mailbox_id): + """ + Check that the passed mailbox identifier is a valid UUID. + :param mailbox_id: the uuid to check + :type mailbox_id: str + :return: None + :raises: AssertionError if a wrong uuid was passed. + """ + try: + uuid.UUID(str(mailbox_id)) + except (AttributeError, ValueError): + raise AssertionError( + "the mbox_id is not a valid uuid: %s" % mailbox_id) + + class MailboxIndexer(object): """ This class contains the commands needed to create, modify and alter the @@ -68,51 +88,33 @@ class MailboxIndexer(object): assert self.store is not None return self.store.raw_sqlcipher_query(*args, **kw) - def create_table(self, mailbox): + def create_table(self, mailbox_id): """ Create the UID table for a given mailbox. - :param mailbox: the mailbox name + :param mailbox: the mailbox identifier. :type mailbox: str :rtype: Deferred """ - assert mailbox + check_good_uuid(mailbox_id) sql = ("CREATE TABLE if not exists {preffix}{name}( " "uid INTEGER PRIMARY KEY AUTOINCREMENT, " "hash TEXT UNIQUE NOT NULL)".format( - preffix=self.table_preffix, name=mailbox)) + preffix=self.table_preffix, name=sanitize(mailbox_id))) return self._query(sql) - def delete_table(self, mailbox): + def delete_table(self, mailbox_id): """ Delete the UID table for a given mailbox. :param mailbox: the mailbox name :type mailbox: str :rtype: Deferred """ - assert mailbox + check_good_uuid(mailbox_id) sql = ("DROP TABLE if exists {preffix}{name}".format( - preffix=self.table_preffix, name=mailbox)) - return self._query(sql) - - def rename_table(self, oldmailbox, newmailbox): - """ - Delete the UID table for a given mailbox. - :param oldmailbox: the old mailbox name - :type oldmailbox: str - :param newmailbox: the new mailbox name - :type newmailbox: str - :rtype: Deferred - """ - assert oldmailbox - assert newmailbox - assert oldmailbox != newmailbox - sql = ("ALTER TABLE {preffix}{old} " - "RENAME TO {preffix}{new}".format( - preffix=self.table_preffix, - old=oldmailbox, new=newmailbox)) + preffix=self.table_preffix, name=sanitize(mailbox_id))) return self._query(sql) - def insert_doc(self, mailbox, doc_id): + def insert_doc(self, mailbox_id, doc_id): """ Insert the doc_id for a MetaMsg in the UID table for a given mailbox. @@ -128,10 +130,11 @@ class MailboxIndexer(object): document. :rtype: Deferred """ - assert mailbox + check_good_uuid(mailbox_id) assert doc_id + mailbox_id = mailbox_id.replace('-', '_') - if not re.findall(METAMSGID_RE.format(mbox=mailbox), doc_id): + if not re.findall(METAMSGID_RE.format(mbox=mailbox_id), doc_id): raise WrongMetaDocIDError("Wrong format for the MetaMsg doc_id") def get_rowid(result): @@ -139,44 +142,44 @@ class MailboxIndexer(object): sql = ("INSERT INTO {preffix}{name} VALUES (" "NULL, ?)".format( - preffix=self.table_preffix, name=mailbox)) + preffix=self.table_preffix, name=sanitize(mailbox_id))) values = (doc_id,) sql_last = ("SELECT MAX(rowid) FROM {preffix}{name} " "LIMIT 1;").format( - preffix=self.table_preffix, name=mailbox) + preffix=self.table_preffix, name=sanitize(mailbox_id)) d = self._query(sql, values) d.addCallback(lambda _: self._query(sql_last)) d.addCallback(get_rowid) return d - def delete_doc_by_uid(self, mailbox, uid): + def delete_doc_by_uid(self, mailbox_id, uid): """ Delete the entry for a MetaMsg in the UID table for a given mailbox. - :param mailbox: the mailbox name + :param mailbox_id: the mailbox uuid :type mailbox: str :param uid: the UID of the message. :type uid: int :rtype: Deferred """ - assert mailbox + check_good_uuid(mailbox_id) assert uid sql = ("DELETE FROM {preffix}{name} " "WHERE uid=?".format( - preffix=self.table_preffix, name=mailbox)) + preffix=self.table_preffix, name=sanitize(mailbox_id))) values = (uid,) return self._query(sql, values) - def delete_doc_by_hash(self, mailbox, doc_id): + def delete_doc_by_hash(self, mailbox_id, doc_id): """ Delete the entry for a MetaMsg in the UID table for a given mailbox. The doc_id must be in the format: - M+<mailbox>+<content-hash-of-the-message> + M-<mailbox_uuid>-<content-hash-of-the-message> - :param mailbox: the mailbox name + :param mailbox_id: the mailbox uuid :type mailbox: str :param doc_id: the doc_id for the MetaMsg :type doc_id: str @@ -184,30 +187,32 @@ class MailboxIndexer(object): document. :rtype: Deferred """ - assert mailbox + check_good_uuid(mailbox_id) assert doc_id sql = ("DELETE FROM {preffix}{name} " "WHERE hash=?".format( - preffix=self.table_preffix, name=mailbox)) + preffix=self.table_preffix, name=sanitize(mailbox_id))) values = (doc_id,) return self._query(sql, values) - def get_doc_id_from_uid(self, mailbox, uid): + def get_doc_id_from_uid(self, mailbox_id, uid): """ Get the doc_id for a MetaMsg in the UID table for a given mailbox. - :param mailbox: the mailbox name + :param mailbox: the mailbox uuid :type mailbox: str :param uid: the uid for the MetaMsg for this mailbox :type uid: int :rtype: Deferred """ + check_good_uuid(mailbox_id) + def get_hash(result): return _maybe_first_query_item(result) sql = ("SELECT hash from {preffix}{name} " "WHERE uid=?".format( - preffix=self.table_preffix, name=mailbox)) + preffix=self.table_preffix, name=sanitize(mailbox_id))) values = (uid,) d = self._query(sql, values) d.addCallback(get_hash) @@ -218,7 +223,7 @@ class MailboxIndexer(object): # XXX dereference the range (n,*) raise NotImplementedError() - def count(self, mailbox): + def count(self, mailbox_id): """ Get the number of entries in the UID table for a given mailbox. @@ -227,16 +232,18 @@ class MailboxIndexer(object): :return: a deferred that will fire with an integer returning the count. :rtype: Deferred """ + check_good_uuid(mailbox_id) + def get_count(result): return _maybe_first_query_item(result) sql = ("SELECT Count(*) FROM {preffix}{name};".format( - preffix=self.table_preffix, name=mailbox)) + preffix=self.table_preffix, name=sanitize(mailbox_id))) d = self._query(sql) d.addCallback(get_count) return d - def get_next_uid(self, mailbox): + def get_next_uid(self, mailbox_id): """ Get the next integer beyond the highest UID count for a given mailbox. @@ -251,7 +258,7 @@ class MailboxIndexer(object): uid. :rtype: Deferred """ - assert mailbox + check_good_uuid(mailbox_id) def increment(result): uid = _maybe_first_query_item(result) @@ -261,7 +268,7 @@ class MailboxIndexer(object): sql = ("SELECT MAX(rowid) FROM {preffix}{name} " "LIMIT 1;").format( - preffix=self.table_preffix, name=mailbox) + preffix=self.table_preffix, name=sanitize(mailbox_id)) d = self._query(sql) d.addCallback(increment) diff --git a/mail/src/leap/mail/tests/test_mailbox_indexer.py b/mail/src/leap/mail/tests/test_mailbox_indexer.py index 47a3bdc9..2edf1d87 100644 --- a/mail/src/leap/mail/tests/test_mailbox_indexer.py +++ b/mail/src/leap/mail/tests/test_mailbox_indexer.py @@ -17,10 +17,9 @@ """ Tests for the mailbox_indexer module. """ +import uuid from functools import partial -from twisted.trial import unittest - from leap.mail import mailbox_indexer as mi from leap.mail.tests.common import SoledadTestMixin @@ -31,11 +30,13 @@ hash_test3 = 'fd61a03af4f77d870fc21e05e7e80678095c92d808cfb3b5c279ee04c74aca13' hash_test4 = 'a4e624d686e03ed2767c0abd85c14426b0b1157d2ce81d27bb4fe4f6f01d688a' -def fmt_hash(mailbox, hash): - return "M-" + mailbox + "-" + hash +def fmt_hash(mailbox_uuid, hash): + return "M-" + mailbox_uuid.replace('-', '_') + "-" + hash + +mbox_id = str(uuid.uuid4()) -class MailboxIndexerTestCase(unittest.TestCase, SoledadTestMixin): +class MailboxIndexerTestCase(SoledadTestMixin): """ Tests for the MailboxUID class. """ @@ -57,17 +58,17 @@ class MailboxIndexerTestCase(unittest.TestCase, SoledadTestMixin): def select_uid_rows(self, mailbox): sql = "SELECT * FROM %s%s;" % ( - mi.MailboxIndexer.table_preffix, mailbox) + mi.MailboxIndexer.table_preffix, mailbox.replace('-', '_')) d = self._soledad.raw_sqlcipher_query(sql) return d def test_create_table(self): def assert_table_created(tables): self.assertEqual( - tables, ["leapmail_uid_inbox"]) + tables, ["leapmail_uid_" + mbox_id.replace('-', '_')]) m_uid = self.get_mbox_uid() - d = m_uid.create_table('inbox') + d = m_uid.create_table(mbox_id) d.addCallback(self.list_mail_tables_cb) d.addCallback(assert_table_created) return d @@ -77,165 +78,162 @@ class MailboxIndexerTestCase(unittest.TestCase, SoledadTestMixin): self.assertEqual(tables, []) m_uid = self.get_mbox_uid() - d = m_uid.create_table('inbox') - d.addCallback(lambda _: m_uid.delete_table('inbox')) + d = m_uid.create_table(mbox_id) + d.addCallback(lambda _: m_uid.delete_table(mbox_id)) d.addCallback(self.list_mail_tables_cb) d.addCallback(assert_table_deleted) return d - def test_rename_table(self): - def assert_table_renamed(tables): - self.assertEqual( - tables, ["leapmail_uid_foomailbox"]) - - m_uid = self.get_mbox_uid() - d = m_uid.create_table('inbox') - d.addCallback(lambda _: m_uid.rename_table('inbox', 'foomailbox')) - d.addCallback(self.list_mail_tables_cb) - d.addCallback(assert_table_renamed) - return d + #def test_rename_table(self): + #def assert_table_renamed(tables): + #self.assertEqual( + #tables, ["leapmail_uid_foomailbox"]) +# + #m_uid = self.get_mbox_uid() + #d = m_uid.create_table('inbox') + #d.addCallback(lambda _: m_uid.rename_table('inbox', 'foomailbox')) + #d.addCallback(self.list_mail_tables_cb) + #d.addCallback(assert_table_renamed) + #return d def test_insert_doc(self): m_uid = self.get_mbox_uid() - mbox = 'foomailbox' - h1 = fmt_hash(mbox, hash_test0) - h2 = fmt_hash(mbox, hash_test1) - h3 = fmt_hash(mbox, hash_test2) - h4 = fmt_hash(mbox, hash_test3) - h5 = fmt_hash(mbox, hash_test4) + h1 = fmt_hash(mbox_id, hash_test0) + h2 = fmt_hash(mbox_id, hash_test1) + h3 = fmt_hash(mbox_id, hash_test2) + h4 = fmt_hash(mbox_id, hash_test3) + h5 = fmt_hash(mbox_id, hash_test4) def assert_uid_rows(rows): expected = [(1, h1), (2, h2), (3, h3), (4, h4), (5, h5)] self.assertEquals(rows, expected) - d = m_uid.create_table(mbox) - d.addCallback(lambda _: m_uid.insert_doc(mbox, h1)) - d.addCallback(lambda _: m_uid.insert_doc(mbox, h2)) - d.addCallback(lambda _: m_uid.insert_doc(mbox, h3)) - d.addCallback(lambda _: m_uid.insert_doc(mbox, h4)) - d.addCallback(lambda _: m_uid.insert_doc(mbox, h5)) - d.addCallback(lambda _: self.select_uid_rows(mbox)) + d = m_uid.create_table(mbox_id) + d.addCallback(lambda _: m_uid.insert_doc(mbox_id, h1)) + d.addCallback(lambda _: m_uid.insert_doc(mbox_id, h2)) + d.addCallback(lambda _: m_uid.insert_doc(mbox_id, h3)) + d.addCallback(lambda _: m_uid.insert_doc(mbox_id, h4)) + d.addCallback(lambda _: m_uid.insert_doc(mbox_id, h5)) + d.addCallback(lambda _: self.select_uid_rows(mbox_id)) d.addCallback(assert_uid_rows) return d def test_insert_doc_return(self): m_uid = self.get_mbox_uid() - mbox = 'foomailbox' def assert_rowid(rowid, expected=None): self.assertEqual(rowid, expected) - h1 = fmt_hash(mbox, hash_test0) - h2 = fmt_hash(mbox, hash_test1) - h3 = fmt_hash(mbox, hash_test2) + h1 = fmt_hash(mbox_id, hash_test0) + h2 = fmt_hash(mbox_id, hash_test1) + h3 = fmt_hash(mbox_id, hash_test2) - d = m_uid.create_table(mbox) - d.addCallback(lambda _: m_uid.insert_doc(mbox, h1)) + d = m_uid.create_table(mbox_id) + d.addCallback(lambda _: m_uid.insert_doc(mbox_id, h1)) d.addCallback(partial(assert_rowid, expected=1)) - d.addCallback(lambda _: m_uid.insert_doc(mbox, h2)) + d.addCallback(lambda _: m_uid.insert_doc(mbox_id, h2)) d.addCallback(partial(assert_rowid, expected=2)) - d.addCallback(lambda _: m_uid.insert_doc(mbox, h3)) + d.addCallback(lambda _: m_uid.insert_doc(mbox_id, h3)) d.addCallback(partial(assert_rowid, expected=3)) return d def test_delete_doc(self): m_uid = self.get_mbox_uid() - mbox = 'foomailbox' - h1 = fmt_hash(mbox, hash_test0) - h2 = fmt_hash(mbox, hash_test1) - h3 = fmt_hash(mbox, hash_test2) - h4 = fmt_hash(mbox, hash_test3) - h5 = fmt_hash(mbox, hash_test4) + h1 = fmt_hash(mbox_id, hash_test0) + h2 = fmt_hash(mbox_id, hash_test1) + h3 = fmt_hash(mbox_id, hash_test2) + h4 = fmt_hash(mbox_id, hash_test3) + h5 = fmt_hash(mbox_id, hash_test4) def assert_uid_rows(rows): expected = [(4, h4), (5, h5)] self.assertEquals(rows, expected) - d = m_uid.create_table(mbox) - d.addCallback(lambda _: m_uid.insert_doc(mbox, h1)) - d.addCallback(lambda _: m_uid.insert_doc(mbox, h2)) - d.addCallback(lambda _: m_uid.insert_doc(mbox, h3)) - d.addCallback(lambda _: m_uid.insert_doc(mbox, h4)) - d.addCallback(lambda _: m_uid.insert_doc(mbox, h5)) + d = m_uid.create_table(mbox_id) + d.addCallback(lambda _: m_uid.insert_doc(mbox_id, h1)) + d.addCallback(lambda _: m_uid.insert_doc(mbox_id, h2)) + d.addCallback(lambda _: m_uid.insert_doc(mbox_id, h3)) + d.addCallback(lambda _: m_uid.insert_doc(mbox_id, h4)) + d.addCallback(lambda _: m_uid.insert_doc(mbox_id, h5)) - d.addCallbacks(lambda _: m_uid.delete_doc_by_uid(mbox, 1)) - d.addCallbacks(lambda _: m_uid.delete_doc_by_uid(mbox, 2)) - d.addCallbacks(lambda _: m_uid.delete_doc_by_hash(mbox, h3)) + d.addCallbacks(lambda _: m_uid.delete_doc_by_uid(mbox_id, 1)) + d.addCallbacks(lambda _: m_uid.delete_doc_by_uid(mbox_id, 2)) + d.addCallbacks(lambda _: m_uid.delete_doc_by_hash(mbox_id, h3)) - d.addCallback(lambda _: self.select_uid_rows(mbox)) + d.addCallback(lambda _: self.select_uid_rows(mbox_id)) d.addCallback(assert_uid_rows) return d def test_get_doc_id_from_uid(self): m_uid = self.get_mbox_uid() - mbox = 'foomailbox' + #mbox = 'foomailbox' - h1 = fmt_hash(mbox, hash_test0) + h1 = fmt_hash(mbox_id, hash_test0) def assert_doc_hash(res): self.assertEqual(res, h1) - d = m_uid.create_table(mbox) - d.addCallback(lambda _: m_uid.insert_doc(mbox, h1)) - d.addCallback(lambda _: m_uid.get_doc_id_from_uid(mbox, 1)) + d = m_uid.create_table(mbox_id) + d.addCallback(lambda _: m_uid.insert_doc(mbox_id, h1)) + d.addCallback(lambda _: m_uid.get_doc_id_from_uid(mbox_id, 1)) d.addCallback(assert_doc_hash) return d def test_count(self): m_uid = self.get_mbox_uid() - mbox = 'foomailbox' + #mbox = 'foomailbox' - h1 = fmt_hash(mbox, hash_test0) - h2 = fmt_hash(mbox, hash_test1) - h3 = fmt_hash(mbox, hash_test2) - h4 = fmt_hash(mbox, hash_test3) - h5 = fmt_hash(mbox, hash_test4) + h1 = fmt_hash(mbox_id, hash_test0) + h2 = fmt_hash(mbox_id, hash_test1) + h3 = fmt_hash(mbox_id, hash_test2) + h4 = fmt_hash(mbox_id, hash_test3) + h5 = fmt_hash(mbox_id, hash_test4) - d = m_uid.create_table(mbox) - d.addCallback(lambda _: m_uid.insert_doc(mbox, h1)) - d.addCallback(lambda _: m_uid.insert_doc(mbox, h2)) - d.addCallback(lambda _: m_uid.insert_doc(mbox, h3)) - d.addCallback(lambda _: m_uid.insert_doc(mbox, h4)) - d.addCallback(lambda _: m_uid.insert_doc(mbox, h5)) + d = m_uid.create_table(mbox_id) + d.addCallback(lambda _: m_uid.insert_doc(mbox_id, h1)) + d.addCallback(lambda _: m_uid.insert_doc(mbox_id, h2)) + d.addCallback(lambda _: m_uid.insert_doc(mbox_id, h3)) + d.addCallback(lambda _: m_uid.insert_doc(mbox_id, h4)) + d.addCallback(lambda _: m_uid.insert_doc(mbox_id, h5)) def assert_count_after_inserts(count): self.assertEquals(count, 5) - d.addCallback(lambda _: m_uid.count(mbox)) + d.addCallback(lambda _: m_uid.count(mbox_id)) d.addCallback(assert_count_after_inserts) - d.addCallbacks(lambda _: m_uid.delete_doc_by_uid(mbox, 1)) - d.addCallbacks(lambda _: m_uid.delete_doc_by_uid(mbox, 2)) + d.addCallbacks(lambda _: m_uid.delete_doc_by_uid(mbox_id, 1)) + d.addCallbacks(lambda _: m_uid.delete_doc_by_uid(mbox_id, 2)) def assert_count_after_deletions(count): self.assertEquals(count, 3) - d.addCallback(lambda _: m_uid.count(mbox)) + d.addCallback(lambda _: m_uid.count(mbox_id)) d.addCallback(assert_count_after_deletions) return d def test_get_next_uid(self): m_uid = self.get_mbox_uid() - mbox = 'foomailbox' + #mbox = 'foomailbox' - h1 = fmt_hash(mbox, hash_test0) - h2 = fmt_hash(mbox, hash_test1) - h3 = fmt_hash(mbox, hash_test2) - h4 = fmt_hash(mbox, hash_test3) - h5 = fmt_hash(mbox, hash_test4) + h1 = fmt_hash(mbox_id, hash_test0) + h2 = fmt_hash(mbox_id, hash_test1) + h3 = fmt_hash(mbox_id, hash_test2) + h4 = fmt_hash(mbox_id, hash_test3) + h5 = fmt_hash(mbox_id, hash_test4) - d = m_uid.create_table(mbox) - d.addCallback(lambda _: m_uid.insert_doc(mbox, h1)) - d.addCallback(lambda _: m_uid.insert_doc(mbox, h2)) - d.addCallback(lambda _: m_uid.insert_doc(mbox, h3)) - d.addCallback(lambda _: m_uid.insert_doc(mbox, h4)) - d.addCallback(lambda _: m_uid.insert_doc(mbox, h5)) + d = m_uid.create_table(mbox_id) + d.addCallback(lambda _: m_uid.insert_doc(mbox_id, h1)) + d.addCallback(lambda _: m_uid.insert_doc(mbox_id, h2)) + d.addCallback(lambda _: m_uid.insert_doc(mbox_id, h3)) + d.addCallback(lambda _: m_uid.insert_doc(mbox_id, h4)) + d.addCallback(lambda _: m_uid.insert_doc(mbox_id, h5)) def assert_next_uid(result, expected=1): self.assertEquals(result, expected) - d.addCallback(lambda _: m_uid.get_next_uid(mbox)) + d.addCallback(lambda _: m_uid.get_next_uid(mbox_id)) d.addCallback(partial(assert_next_uid, expected=6)) return d |