[PATCH] This is what I call test suite for now. What a mouthful :-).

Sebastian Spaeth Sebastian at SSpaeth.de
Fri Dec 10 21:47:52 UTC 2010


It contains 2 working and one non-functional test so far and of course some test infrastructure. Works against current master. Run with "python test.py" :)

Signed-off-by: Sebastian Spaeth <Sebastian at SSpaeth.de>
---
 tests/test.py |  267 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 267 insertions(+), 0 deletions(-)
 create mode 100644 tests/test.py

diff --git a/tests/test.py b/tests/test.py
new file mode 100644
index 0000000..7aabc78
--- /dev/null
+++ b/tests/test.py
@@ -0,0 +1,267 @@
+import offlineimap
+from offlineimap.repository import Repository
+import random
+import tempfile
+import unittest
+import os
+import shutil
+import threading
+
+class Folder2FolderScaffold:
+    """This provides 'scaffolding' for testing Maildir<->Maildir syncing"""
+
+    def __init__(self):
+        #list of files (or directories that we have to cleanup on exit
+        self._tmpfiles = []
+        # True if cleanup() has been run, otherwise run automatically on
+        # destruction
+        self._cleaned_up = False
+
+        #save the ConfigParser() object here
+        self.config = self.create_config()
+
+        # we need to set up the global ui variable, choose the silent one.
+        ui = offlineimap.ui.Noninteractive.Quiet(self.config, verbose=-1)
+        offlineimap.ui.UIBase.setglobalui(ui)
+
+        # Create the account object for test1 and create the account metadatadir
+        self.account = offlineimap.accounts.SyncableAccount(
+            self.config, 'test1')
+
+        #Create 2 temporary maildir repos, for the account
+        self.create_maildir_repos(self.account)
+
+    def create_config(self):
+        """Create a fake ConfigParser object for syncing
+
+        It defines 'Account test1' syncing between Maildir 'local1'
+        and Maildir 'remote1'. Also create the directories for the
+        temporary Maildirs."""
+
+        config=offlineimap.CustomConfig.CustomConfigParser()
+        config.add_section('general')
+        config.set('general', 'accounts', 'test1')
+
+        config.add_section('Account test1')
+        config.set('Account test1','localrepository','local1')
+        config.set('Account test1','remoterepository','remote1')
+
+        #create 2 temporary directories for maildirs,
+        #we are responsible for deleting those again
+        tmpd1 = tempfile.mkdtemp(prefix='offlineimap_repo_')
+        tmpd2 = tempfile.mkdtemp(prefix='offlineimap_repo_')
+        self._tmpfiles.extend([tmpd1, tmpd2])
+
+        config.add_section('Repository local1')
+        config.set('Repository local1','type','Maildir')
+        config.set('Repository local1','localfolders',tmpd1)
+
+        config.add_section('Repository remote1')
+        config.set('Repository remote1','type','Maildir')
+        config.set('Repository remote1','localfolders',tmpd2)
+
+        #create and set temporary metadatadir too
+        metad = tempfile.mkdtemp(prefix='offlineimap_meta_')
+        self._tmpfiles.append(metad)
+        config.set('general', 'metadata', metad)
+
+        return config
+
+    def create_maildir_repos(self, account):
+        """Create the Maildir structure for account. Both repos names
+        are currently hardcoded to 'local1' and 'remote1' this
+        requires create_config to have run before.
+
+        :param account: The SyncableAccount() object"""
+
+        #create the account metadatadir
+        os.mkdir(self.account.getaccountmeta())            
+
+        #save the original current directory. Repository requires us to change it :-(
+        #This is a FIXME :-(.
+        origcwd = os.getcwd()
+
+        # Create Maildir repositories and the INBOX folder
+        repo = offlineimap.repository.Maildir.MaildirRepository(
+            'local1', self.account)
+        os.chdir(repo.root)
+        repo.makefolder('INBOX')
+
+        repo = offlineimap.repository.Maildir.MaildirRepository(
+            'remote1', self.account)
+        os.chdir(repo.root)
+        repo.makefolder('INBOX')
+
+        #and back to the original current dir
+        os.chdir(origcwd)
+
+
+    def putmail(self, repo, foldername, uid=None, new = False):
+        """Create a new mail file that is in repo.
+
+        The folder must already exist.
+        Mail files will be automatically cleaned up if they are in one
+        of the two repositories.
+
+        :param repo: A Repository() object.
+        :param foldername: A string for the mailbox, e.g. INBOX 
+        :param UID: Assign a random UID if None, or use as mail UID
+        :param new: if True, create mail in 'new' otehrwise in 'cur'
+        """
+        rtime = random.randint(1,99999999999999999)
+        if uid is None:
+            uid = random.randint(1,99999999999999999)
+        content = "From: XX <xx at yy.com>\n"+\
+                   "To: gark <ch at ch.ch>\n"+\
+                   "Subject: Firk\n\nGah"
+        if new:
+            flags=[]
+        else:
+            flags=["S"]
+        maildirfolder = repo.getfolder(foldername)
+        maildirfolder.savemessage(uid, content, flags, rtime)
+
+
+    def cleanup(self):
+        """Delete temporary files that have been created"""
+        for file in self._tmpfiles:
+            try:
+                os.unlink(file)
+            except OSError as e:
+                if e.errno == 21:
+                    #file is a directory
+                    shutil.rmtree(file)
+        self._cleaned_up = True
+
+    def __del__(self):
+         if not self._cleaned_up:
+            print "clean up after yourself, son!\nMake sure you call "\
+                  "scaffold.cleanup() when your tests are done!!! Thanks."
+
+
+
+class TestOfflineImapFunctions(unittest.TestCase):
+    """Test various sync situations for Maildiry<->Maildir"""
+
+    def __init__(self, test, scaffold):
+        self.scaffold = scaffold
+        unittest.TestCase.__init__(self, test)
+
+    def test_01_simplemailsync(self):
+        """with initially empty repositories, create a mail on the
+        local one and sync. The test succeeds if afterwards the number
+        of mails on the remote repository is 1 and both repos have the
+        same UIDs."""
+        ui = offlineimap.ui.UIBase.getglobalui()
+        acc = self.scaffold.account
+
+        remoterepo = offlineimap.repository.Maildir.MaildirRepository(
+            acc.getconf('remoterepository'), acc)
+        localrepo  = offlineimap.repository.Maildir.MaildirRepository(
+            acc.getconf('localrepository'), acc)
+        statusrepo = Repository(acc, 'status')
+
+        self.scaffold.putmail(localrepo, 'INBOX')
+
+        #the following is basically copied out of the syncfolder function
+
+        #create the folders on the local and statusrepo as on the remote
+        remoterepo.syncfoldersto(localrepo, [statusrepo])
+        folders = remoterepo.getfolders()
+
+        for remotefolder in folders:
+            offlineimap.accounts.syncfolder(acc.name, remoterepo, remotefolder,
+                                            localrepo, statusrepo, quick=False)
+
+            # make sure both repos contain the same files afterwards
+            # 1) get localfolder object, 2) comapre UIDs in both folders
+            localfolder = localrepo.\
+                getfolder(remotefolder.getvisiblename().\
+                                replace(remoterepo.getsep(), localrepo.getsep()))
+            #syncfolder does "ui.registerthread", so we need to kludge
+            #and delete the threads manually here
+            ui.threadaccounts= {}
+
+            #sync finished for this folder. Succeed?
+            # We should have 1 message
+            self.assertEqual(remotefolder.getmessagecount(),1)
+            # and the UIDs should be identical
+            self.assertEqual(remotefolder.getmessageuidlist(),
+                         localfolder.getmessageuidlist())
+
+
+    def test_02_repeat_sync_without_changes(self):
+        """Using the result of test01 as basis, we sync without
+        changing anything. Make sure that the sync does not change
+        anything either."""
+        ui = offlineimap.ui.UIBase.getglobalui()
+        acc = self.scaffold.account
+
+        remoterepo = offlineimap.repository.Maildir.MaildirRepository(
+            acc.getconf('remoterepository'), acc)
+        localrepo  = offlineimap.repository.Maildir.MaildirRepository(
+            acc.getconf('localrepository'), acc)
+        statusrepo = Repository(acc, 'status')
+
+        #sync without having changed anything since the last test to see that
+        folders = remoterepo.getfolders()
+        for remotefolder in folders:
+            offlineimap.accounts.syncfolder(acc.name, remoterepo,
+                                            remotefolder, localrepo, statusrepo, quick=False)
+
+            #syncfolder does "ui.registerthread", so we need to kludge
+            #and delete the stuff manually afterwards
+            ui.threadaccounts= {}
+
+            # make sure both repos contain the same files afterwards
+            # 1) get localfolder object, 2) comapre UIDs in both folders
+            localfolder = localrepo.\
+                getfolder(remotefolder.getvisiblename().\
+                                replace(remoterepo.getsep(), localrepo.getsep()))
+
+            #folder sync finish, succeeded?
+            # We should have 1 message
+            self.assertEqual(remotefolder.getmessagecount(),1)
+            # and the UIDs should be identical
+            self.assertEqual(remotefolder.getmessageuidlist(),
+                         localfolder.getmessageuidlist())
+
+        #debug print the messages in the maildir
+        #for f in os.listdir(remoterepo.root+'/INBOX/new'):
+        #    print "Repo1", f
+        #for f in os.listdir(localrepo.root+'/INBOX/cur'):
+        #    print "Repo2", f
+
+    def test_03_delete_remote_message_and_change_local_flag(self):
+        """Using the result of test02 as basis, we delete the remote
+        message and modify the local flags. Then sync and see what
+        happens. 
+        FIXME: Not Implemented yet"""
+        ui = offlineimap.ui.UIBase.getglobalui()
+        acc = self.scaffold.account
+
+        remoterepo = offlineimap.repository.Maildir.MaildirRepository(
+            acc.getconf('remoterepository'), acc)
+        localrepo  = offlineimap.repository.Maildir.MaildirRepository(
+            acc.getconf('localrepository'), acc)
+        statusrepo = Repository(acc, 'status')
+
+
+
+class MailDirTestSuite(unittest.TestSuite):
+    def __init__(self):
+        self.scaffold = Folder2FolderScaffold()
+        unittest.TestSuite.__init__(self)
+        self.addTest(TestOfflineImapFunctions("test_01_simplemailsync", self.scaffold))
+        self.addTest(TestOfflineImapFunctions("test_02_repeat_sync_without_changes", self.scaffold))
+        self.addTest(TestOfflineImapFunctions("test_03_delete_remote_message_and_change_local_flag", self.scaffold))
+
+    def __del__(self):
+        self.scaffold.cleanup()
+
+
+if __name__ == '__main__':
+    runner = unittest.TextTestRunner()
+    runner.run(MailDirTestSuite())
+
+    #unittest.main()
-- 
1.7.1




More information about the OfflineIMAP-project mailing list