summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mail/src/leap/mail/adaptors/soledad.py19
-rw-r--r--mail/src/leap/mail/mail.py46
-rw-r--r--mail/src/leap/mail/mailbox_indexer.py2
-rw-r--r--mail/src/leap/mail/tests/test_mail.py84
4 files changed, 110 insertions, 41 deletions
diff --git a/mail/src/leap/mail/adaptors/soledad.py b/mail/src/leap/mail/adaptors/soledad.py
index 522d2d32..389307fb 100644
--- a/mail/src/leap/mail/adaptors/soledad.py
+++ b/mail/src/leap/mail/adaptors/soledad.py
@@ -625,14 +625,11 @@ class SoledadIndexMixin(object):
leap_assert(store, "Need a store")
leap_assert_type(self.indexes, dict)
- self._index_creation_deferreds = []
- def _on_indexes_created(ignored):
- self.store_ready = True
+ self._index_creation_deferreds = []
def _create_index(name, expression):
- d = store.create_index(name, *expression)
- self._index_creation_deferreds.append(d)
+ return store.create_index(name, *expression)
def _create_indexes(db_indexes):
db_indexes = dict(db_indexes)
@@ -640,7 +637,8 @@ class SoledadIndexMixin(object):
for name, expression in self.indexes.items():
if name not in db_indexes:
# The index does not yet exist.
- _create_index(name, expression)
+ d = _create_index(name, expression)
+ self._index_creation_deferreds.append(d)
continue
if expression == db_indexes[name]:
@@ -650,11 +648,16 @@ class SoledadIndexMixin(object):
# we delete it and add the proper index expression.
d1 = store.delete_index(name)
d1.addCallback(lambda _: _create_index(name, expression))
+ self._index_creation_deferreds.append(d1)
- all_created = defer.gatherResults(self._index_creation_deferreds)
+ all_created = defer.gatherResults(
+ self._index_creation_deferreds, consumeErrors=True)
all_created.addCallback(_on_indexes_created)
return all_created
+ def _on_indexes_created(ignored):
+ self.store_ready = True
+
# Ask the database for currently existing indexes, and create them
# if not found.
d = store.list_indexes()
@@ -832,9 +835,11 @@ class SoledadMailAdaptor(SoledadIndexMixin):
have been updated.
:rtype: defer.Deferred
"""
+ leap_assert_type(mbox_wrapper, SoledadDocumentWrapper)
return mbox_wrapper.update(store)
def delete_mbox(self, store, mbox_wrapper):
+ leap_assert_type(mbox_wrapper, SoledadDocumentWrapper)
return mbox_wrapper.delete(store)
def get_all_mboxes(self, store):
diff --git a/mail/src/leap/mail/mail.py b/mail/src/leap/mail/mail.py
index 671642a2..0c9b7a3a 100644
--- a/mail/src/leap/mail/mail.py
+++ b/mail/src/leap/mail/mail.py
@@ -37,6 +37,9 @@ logger = logging.getLogger(name=__name__)
# TODO LIST
# [ ] Probably change the name of this module to "api" or "account", mail is
# too generic (there's also IncomingMail, and OutgoingMail
+# [ ] Change the doc_ids scheme for part-docs: use mailbox UID validity
+# identifier, instead of name! (renames are broken!)
+# [ ] Profile add_msg.
def _get_mdoc_id(mbox, chash):
"""
@@ -360,7 +363,7 @@ class MessageCollection(object):
:return: a Deferred that will fire with the integer for the next uid.
:rtype: Deferred
"""
- return self.mbox_indexer.get_uid_next(self.mbox_name)
+ return self.mbox_indexer.get_next_uid(self.mbox_name)
# Manipulate messages
@@ -464,8 +467,6 @@ class MessageCollection(object):
return self.adaptor.update_msg(self.store, msg)
-# TODO -------------------- split into account object?
-
class Account(object):
"""
Account is the top level abstraction to access collections of messages
@@ -485,7 +486,6 @@ class Account(object):
adaptor_class = SoledadMailAdaptor
store = None
- mailboxes = None
def __init__(self, store):
self.store = store
@@ -508,17 +508,17 @@ class Account(object):
self._deferred_initialization.callback(None)
d = self.adaptor.initialize_store(self.store)
- d.addCallback(self.list_all_mailbox_names)
+ d.addCallback(lambda _: self.list_all_mailbox_names())
d.addCallback(add_mailbox_if_none)
d.addCallback(finish_initialization)
- def callWhenReady(self, cb):
- # XXX this could use adaptor.store_ready instead...??
+ def callWhenReady(self, cb, *args, **kw):
+ # use adaptor.store_ready instead?
if self._initialized:
- cb(self)
+ cb(self, *args, **kw)
return defer.succeed(None)
else:
- self._deferred_initialization.addCallback(cb)
+ self._deferred_initialization.addCallback(cb, *args, **kw)
return self._deferred_initialization
#
@@ -527,7 +527,7 @@ class Account(object):
def list_all_mailbox_names(self):
def filter_names(mboxes):
- return [m.name for m in mboxes]
+ return [m.mbox for m in mboxes]
d = self.get_all_mailboxes()
d.addCallback(filter_names)
@@ -540,35 +540,44 @@ class Account(object):
def add_mailbox(self, name):
def create_uid_table_cb(res):
- d = self.mbox_uid.create_table(name)
+ d = self.mbox_indexer.create_table(name)
d.addCallback(lambda _: res)
return d
- d = self.adaptor.__class__.get_or_create(name)
+ d = self.adaptor.get_or_create_mbox(self.store, name)
d.addCallback(create_uid_table_cb)
return d
def delete_mailbox(self, name):
def delete_uid_table_cb(res):
- d = self.mbox_uid.delete_table(name)
+ d = self.mbox_indexer.delete_table(name)
d.addCallback(lambda _: res)
return d
- d = self.adaptor.delete_mbox(self.store)
+ d = self.adaptor.get_or_create_mbox(self.store, name)
+ 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):
+ # TODO incomplete/wrong!!!
+ # Should rename also ALL of the document ids that are pointing
+ # to the old mailbox!!!
+
+ # TODO part-docs identifiers should have the UID_validity of the
+ # mailbox embedded, instead of the name! (so they can survive a rename)
+
def _rename_mbox(wrapper):
wrapper.mbox = newname
- return wrapper.update()
+ return wrapper.update(self.store)
def rename_uid_table_cb(res):
- d = self.mbox_uid.rename_table(oldname, newname)
+ d = self.mbox_indexer.rename_table(oldname, newname)
d.addCallback(lambda _: res)
return d
- d = self.adaptor.__class__.get_or_create(oldname)
+ d = self.adaptor.get_or_create_mbox(self.store, oldname)
d.addCallback(_rename_mbox)
d.addCallback(rename_uid_table_cb)
return d
@@ -585,7 +594,8 @@ class Account(object):
self.adaptor, self.store, self.mbox_indexer, mbox_wrapper)
mboxwrapper_klass = self.adaptor.mboxwrapper_klass
- d = mboxwrapper_klass.get_or_create(name)
+ #d = mboxwrapper_klass.get_or_create(name)
+ d = self.adaptor.get_or_create_mbox(self.store, name)
d.addCallback(get_collection_for_mailbox)
return d
diff --git a/mail/src/leap/mail/mailbox_indexer.py b/mail/src/leap/mail/mailbox_indexer.py
index 1ceaec06..e5b813fa 100644
--- a/mail/src/leap/mail/mailbox_indexer.py
+++ b/mail/src/leap/mail/mailbox_indexer.py
@@ -256,7 +256,7 @@ class MailboxIndexer(object):
def increment(result):
uid = _maybe_first_query_item(result)
if uid is None:
- return None
+ return 1
return uid + 1
sql = ("SELECT MAX(rowid) FROM {preffix}{name} "
diff --git a/mail/src/leap/mail/tests/test_mail.py b/mail/src/leap/mail/tests/test_mail.py
index d11df403..2c4b9195 100644
--- a/mail/src/leap/mail/tests/test_mail.py
+++ b/mail/src/leap/mail/tests/test_mail.py
@@ -23,10 +23,8 @@ from functools import partial
from email.parser import Parser
from email.Utils import formatdate
-from twisted.python import util
-
from leap.mail.adaptors.soledad import SoledadMailAdaptor
-from leap.mail.mail import MessageCollection
+from leap.mail.mail import MessageCollection, Account
from leap.mail.mailbox_indexer import MailboxIndexer
from leap.mail.tests.common import SoledadTestMixin
@@ -57,7 +55,6 @@ def _get_msg_time():
return formatdate(timestamp)
-
class CollectionMixin(object):
def get_collection(self, mbox_collection=True):
@@ -86,6 +83,7 @@ class CollectionMixin(object):
return d
+# TODO profile add_msg. Why are these tests so SLOW??!
class MessageTestCase(unittest.TestCase, SoledadTestMixin, CollectionMixin):
"""
Tests for the Message class.
@@ -256,7 +254,9 @@ class MessageCollectionTestCase(unittest.TestCase,
return partial(self.assert_collection_count, expected=1)
def test_coppy_msg(self):
- self.fail()
+ # TODO ---- update when implementing messagecopier
+ # interface
+ self.fail("Not Yet Implemented")
def test_delete_msg(self):
d = self.add_msg_to_collection()
@@ -298,27 +298,81 @@ class AccountTestCase(unittest.TestCase, SoledadTestMixin):
"""
Tests for the Account class.
"""
+ def get_account(self):
+ store = self._soledad
+ return Account(store)
def test_add_mailbox(self):
- self.fail()
+ acc = self.get_account()
+ d = acc.callWhenReady(lambda _: acc.add_mailbox("TestMailbox"))
+ d.addCallback(lambda _: acc.list_all_mailbox_names())
+ d.addCallback(self._test_add_mailbox_cb)
+ return d
+
+ def _test_add_mailbox_cb(self, mboxes):
+ expected = ['INBOX', 'TestMailbox']
+ self.assertItemsEqual(mboxes, expected)
def test_delete_mailbox(self):
- self.fail()
+ acc = self.get_account()
+ d = acc.callWhenReady(lambda _: acc.delete_mailbox("Inbox"))
+ d.addCallback(lambda _: acc.list_all_mailbox_names())
+ d.addCallback(self._test_delete_mailbox_cb)
+ return d
+
+ def _test_delete_mailbox_cb(self, mboxes):
+ expected = []
+ self.assertItemsEqual(mboxes, expected)
def test_rename_mailbox(self):
- self.fail()
+ acc = self.get_account()
+ d = acc.callWhenReady(lambda _: acc.add_mailbox("TestMailbox"))
+ d = acc.callWhenReady(lambda _: acc.rename_mailbox(
+ "TestMailbox", "RenamedMailbox"))
+ d.addCallback(lambda _: acc.list_all_mailbox_names())
+ d.addCallback(self._test_rename_mailbox_cb)
+ return d
- def test_list_all_mailbox_names(self):
- self.fail()
+ def _test_rename_mailbox_cb(self, mboxes):
+ expected = ['INBOX', 'RenamedMailbox']
+ self.assertItemsEqual(mboxes, expected)
def test_get_all_mailboxes(self):
- self.fail()
+ acc = self.get_account()
+ d = acc.callWhenReady(lambda _: acc.add_mailbox("OneMailbox"))
+ d.addCallback(lambda _: acc.add_mailbox("TwoMailbox"))
+ d.addCallback(lambda _: acc.add_mailbox("ThreeMailbox"))
+ d.addCallback(lambda _: acc.add_mailbox("anotherthing"))
+ d.addCallback(lambda _: acc.add_mailbox("anotherthing2"))
+ d.addCallback(lambda _: acc.get_all_mailboxes())
+ d.addCallback(self._test_get_all_mailboxes_cb)
+ return d
- def test_get_collection_by_docs(self):
- self.fail()
+ def _test_get_all_mailboxes_cb(self, mailboxes):
+ expected = ["INBOX", "OneMailbox", "TwoMailbox", "ThreeMailbox",
+ "anotherthing", "anotherthing2"]
+ names = [m.mbox for m in mailboxes]
+ self.assertItemsEqual(names, expected)
def test_get_collection_by_mailbox(self):
- self.fail()
+ acc = self.get_account()
+ d = acc.callWhenReady(lambda _: acc.get_collection_by_mailbox("INBOX"))
+ d.addCallback(self._test_get_collection_by_mailbox_cb)
+ return d
+
+ def _test_get_collection_by_mailbox_cb(self, collection):
+ self.assertTrue(collection.is_mailbox_collection())
+
+ def assert_uid_next_empty_collection(uid):
+ self.assertEqual(uid, 1)
+ d = collection.get_uid_next()
+ d.addCallback(assert_uid_next_empty_collection)
+ return d
+
+ # XXX not yet implemented
+
+ def test_get_collection_by_docs(self):
+ self.fail("Not Yet Implemented")
def test_get_collection_by_tag(self):
- self.fail()
+ self.fail("Not Yet Implemented")