import os import tempfile import shutil from email import parser from mock import Mock from twisted.mail import imap4 from twisted.internet import defer from twisted.protocols import loopback from leap.common.testing.basetest import BaseLeapTest from leap.mail.imap.account import SoledadBackedAccount from leap.mail.imap.memorystore import MemoryStore from leap.mail.imap.server import LeapIMAPServer from leap.soledad.client import Soledad TEST_USER = "testuser@leap.se" TEST_PASSWD = "1234" # # Simple IMAP4 Client for testing # class SimpleClient(imap4.IMAP4Client): """ A Simple IMAP4 Client to test our Soledad-LEAPServer """ def __init__(self, deferred, contextFactory=None): imap4.IMAP4Client.__init__(self, contextFactory) self.deferred = deferred self.events = [] def serverGreeting(self, caps): self.deferred.callback(None) def modeChanged(self, writeable): self.events.append(['modeChanged', writeable]) self.transport.loseConnection() def flagsChanged(self, newFlags): self.events.append(['flagsChanged', newFlags]) self.transport.loseConnection() def newMessages(self, exists, recent): self.events.append(['newMessages', exists, recent]) self.transport.loseConnection() def initialize_soledad(email, gnupg_home, tempdir): """ Initializes soledad by hand :param email: ID for the user :param gnupg_home: path to home used by gnupg :param tempdir: path to temporal dir :rtype: Soledad instance """ uuid = "foobar-uuid" passphrase = u"verysecretpassphrase" secret_path = os.path.join(tempdir, "secret.gpg") local_db_path = os.path.join(tempdir, "soledad.u1db") server_url = "http://provider" cert_file = "" class MockSharedDB(object): get_doc = Mock(return_value=None) put_doc = Mock() lock = Mock(return_value=('atoken', 300)) unlock = Mock(return_value=True) def __call__(self): return self Soledad._shared_db = MockSharedDB() _soledad = Soledad( uuid, passphrase, secret_path, local_db_path, server_url, cert_file) return _soledad # XXX this is not properly a mixin, since helper already inherits from # uniittest.Testcase class IMAP4HelperMixin(BaseLeapTest): """ MixIn containing several utilities to be shared across different TestCases """ serverCTX = None clientCTX = None # setUpClass cannot be a classmethod in trial, see: # https://twistedmatrix.com/trac/ticket/1870 def setUp(self): """ Setup method for each test. Initializes and run a LEAP IMAP4 Server, but passing the same Soledad instance (it's costly to initialize), so we have to be sure to restore state across tests. """ self.old_path = os.environ['PATH'] self.old_home = os.environ['HOME'] self.tempdir = tempfile.mkdtemp(prefix="leap_tests-") self.home = self.tempdir bin_tdir = os.path.join( self.tempdir, 'bin') os.environ["PATH"] = bin_tdir os.environ["HOME"] = self.tempdir # Soledad: config info self.gnupg_home = "%s/gnupg" % self.tempdir self.email = 'leap@leap.se' # initialize soledad by hand so we can control keys self._soledad = initialize_soledad( self.email, self.gnupg_home, self.tempdir) UUID = 'deadbeef', USERID = TEST_USER memstore = MemoryStore() ########### d = defer.Deferred() self.server = LeapIMAPServer( uuid=UUID, userid=USERID, contextFactory=self.serverCTX, # XXX do we really need this?? soledad=self._soledad) self.client = SimpleClient(d, contextFactory=self.clientCTX) self.connected = d # XXX REVIEW-ME. # We're adding theAccount here to server # but it was also passed to initialization # as it was passed to realm. # I THINK we ONLY need to do it at one place now. theAccount = SoledadBackedAccount( USERID, soledad=self._soledad, memstore=memstore) LeapIMAPServer.theAccount = theAccount # in case we get something from previous tests... for mb in self.server.theAccount.mailboxes: self.server.theAccount.delete(mb) # email parser self.parser = parser.Parser() def tearDown(self): """ tearDown method called after each test. Deletes all documents in the Index, and deletes instances of server and client. """ try: self._soledad.close() os.environ["PATH"] = self.old_path os.environ["HOME"] = self.old_home # safety check assert 'leap_tests-' in self.tempdir shutil.rmtree(self.tempdir) except Exception: print "ERROR WHILE CLOSING SOLEDAD" def populateMessages(self): """ Populates soledad instance with several simple messages """ # XXX we should encapsulate this thru SoledadBackedAccount # instead. # XXX we also should put this in a mailbox! self._soledad.messages.add_msg('', subject="test1") self._soledad.messages.add_msg('', subject="test2") self._soledad.messages.add_msg('', subject="test3") # XXX should change Flags too self._soledad.messages.add_msg('', subject="test4") def delete_all_docs(self): """ Deletes all the docs in the testing instance of the SoledadBackedAccount. """ self.server.theAccount.deleteAllMessages( iknowhatiamdoing=True) def _cbStopClient(self, ignore): self.client.transport.loseConnection() def _ebGeneral(self, failure): self.client.transport.loseConnection() self.server.transport.loseConnection() # can we do something similar? # I guess this was ok with trial, but not in noseland... # log.err(failure, "Problem with %r" % (self.function,)) raise failure.value # failure.trap(Exception) def loopback(self): return loopback.loopbackAsync(self.server, self.client)