diff options
-rw-r--r-- | mail/src/leap/mail/adaptors/soledad.py | 19 | ||||
-rw-r--r-- | mail/src/leap/mail/mail.py | 46 | ||||
-rw-r--r-- | mail/src/leap/mail/mailbox_indexer.py | 2 | ||||
-rw-r--r-- | mail/src/leap/mail/tests/test_mail.py | 84 |
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 522d2d3..389307f 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 671642a..0c9b7a3 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 1ceaec0..e5b813f 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 d11df40..2c4b919 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") |