summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKali Kaneko <kali@leap.se>2015-01-12 20:47:29 -0400
committerKali Kaneko <kali@leap.se>2015-02-11 14:05:43 -0400
commitd495fe597380d21109b5ccd7a3acf654af6698de (patch)
tree02a68b9197bfe0027277fa1552897a108a51b470
parentf279c5b6761d2def3fb81b64fb1e6b34803e3c47 (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
-rw-r--r--mail/src/leap/mail/adaptors/soledad.py29
-rw-r--r--mail/src/leap/mail/adaptors/tests/test_soledad_adaptor.py11
-rw-r--r--mail/src/leap/mail/constants.py8
-rw-r--r--mail/src/leap/mail/imap/mailbox.py12
-rw-r--r--mail/src/leap/mail/imap/tests/test_imap.py26
-rw-r--r--mail/src/leap/mail/mail.py57
-rw-r--r--mail/src/leap/mail/mailbox_indexer.py101
-rw-r--r--mail/src/leap/mail/tests/test_mailbox_indexer.py182
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