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") | 
