diff --git a/setup.py b/setup.py index 3d04af2..27932eb 100644 --- a/setup.py +++ b/setup.py @@ -29,7 +29,10 @@ from test.OLItest import TextTestRunner, TestLoader, OLITestLib class TestCommand(Command): """runs the OLI testsuite""" - description = "Runs the test suite" + description = """Runs the test suite. In order to execute only a single + test, you could also issue e.g. 'python -m unittest + test.tests.test_01_basic.TestBasicFunctions.test_01_olistartup' on the + command line.""" user_options = [] def initialize_options(self): diff --git a/test/OLItest/TestRunner.py b/test/OLItest/TestRunner.py index 3c21257..e6277f2 100644 --- a/test/OLItest/TestRunner.py +++ b/test/OLItest/TestRunner.py @@ -13,9 +13,11 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +import imaplib import unittest import logging import os +import re import sys import shutil import subprocess @@ -50,6 +52,7 @@ class OLITestLib(): directory at a time. OLITestLib is not suited for running several tests in parallel. The user is responsible for cleaning that up herself.""" + assert cls.cred_file != None # creating temporary dir for testing in same dir as credentials.conf cls.testdir = os.path.abspath( tempfile.mkdtemp(prefix='tmp_%s_'%suffix, @@ -63,6 +66,7 @@ class OLITestLib(): The returned config can be manipulated and then saved with write_config_file()""" + #TODO, only do first time and cache then for subsequent calls? assert cls.cred_file != None assert cls.testdir != None config = SafeConfigParser() @@ -112,6 +116,51 @@ class OLITestLib(): return (e.returncode, e.output) return (0, output) + @classmethod + def delete_remote_testfolders(cls, reponame=None): + """Delete all INBOX.OLITEST* folders on the remote IMAP repository + + reponame: All on `reponame` or all IMAP-type repositories if None""" + config = cls.get_default_config() + if reponame: + sections = ['Repository {}'.format(reponame)] + else: + sections = [r for r in config.sections() \ + if r.startswith('Repository')] + sections = filter(lambda s: \ + config.get(s, 'Type', None).lower() == 'imap', + sections) + for sec in sections: + # Connect to each IMAP repo and delete all folders + # matching the folderfilter setting. We only allow basic + # settings and no fancy password getting here... + # 1) connect and get dir listing + host = config.get(sec, 'remotehost') + user = config.get(sec, 'remoteuser') + passwd = config.get(sec, 'remotepass') + imapobj = imaplib.IMAP4(host) + imapobj.login(user, passwd) + res_t, data = imapobj.list() + assert res_t == 'OK' + dirs = [] + for d in data: + m = re.search(r''' # Find last quote + "((?: # Non-tripple quoted can contain... + [^"] | # a non-quote + \\" # a backslashded quote + )*)" # closing quote + [^"]*$ # followed by no more quotes + ''', d, flags=re.VERBOSE) + folder = m.group(1) + folder = folder.replace(r'\"', '"') # remove quoting + dirs.append(folder) + # 2) filter out those not starting with INBOX.OLItest and del... + dirs = [d for d in dirs if d.startswith('INBOX.OLItest')] + for folder in dirs: + res_t, data = imapobj.delete(folder) + assert res_t == 'OK' + imapobj.logout() + @classmethod def create_maildir(cls, folder): """Create empty maildir 'folder' in our test maildir diff --git a/test/tests/test_01_basic.py b/test/tests/test_01_basic.py index 926baa0..0967d9d 100644 --- a/test/tests/test_01_basic.py +++ b/test/tests/test_01_basic.py @@ -19,6 +19,12 @@ import logging import os, sys from test.OLItest import OLITestLib +# Things need to be setup first, usually setup.py initializes everything. +# but if e.g. called from command line, we take care of default values here: +if not OLITestLib.cred_file: + OLITestLib(cred_file='./test/credentials.conf', cmd='./offlineimap.py') + + def setUpModule(): logging.info("Set Up test module %s" % __name__) tdir = OLITestLib.create_test_dir(suffix=__name__) @@ -52,13 +58,16 @@ class TestBasicFunctions(unittest.TestCase): def test_01_olistartup(self): """Tests if OLI can be invoked without exceptions - It syncs all "OLItest* (specified in the default config) to our - local Maildir at keeps it there.""" + Cleans existing remote tet folders. Then syncs all "OLItest* + (specified in the default config) to our local Maildir. The + result should be 0 folders and 0 mails.""" + OLITestLib.delete_remote_testfolders() code, res = OLITestLib.run_OLI() self.assertEqual(res, "") - boxes, mails = OLITestLib.count_maildir_mails('') - logging.warn("%d boxes and %d mails" % (boxes, mails)) + self.assertTrue((boxes, mails)==(0,0), msg="Expected 0 folders and 0" + "mails, but sync led to {} folders and {} mails".format( + boxes, mails)) def test_02_createdir(self): """Create local OLItest 1 & OLItest "1" maildir, sync @@ -71,7 +80,9 @@ class TestBasicFunctions(unittest.TestCase): #logging.warn("%s %s "% (code, res)) self.assertEqual(res, "") boxes, mails = OLITestLib.count_maildir_mails('') - logging.warn("%d boxes and %d mails" % (boxes, mails)) + self.assertTrue((boxes, mails)==(2,0), msg="Expected 2 folders and 0" + "mails, but sync led to {} folders and {} mails".format( + boxes, mails)) def test_03_nametransmismatch(self): """Create mismatching remote and local nametrans rules @@ -87,6 +98,7 @@ class TestBasicFunctions(unittest.TestCase): #logging.warn("%s %s "% (code, res)) # We expect an INFINITE FOLDER CREATION WARNING HERE.... mismatch = "ERROR: INFINITE FOLDER CREATION DETECTED!" in res - self.assertEqual(mismatch, True, "Mismatching nametrans rules did NOT" - "trigger an 'infinite folder generation' error.") - boxes, mails = OLITestLib.count_maildir_mails('') + self.assertEqual(mismatch, True, msg="Mismatching nametrans rules did " + "NOT trigger an 'infinite folder generation' error. Output was:\n" + "{}".format(res)) +