diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 0000000..08ea7df --- /dev/null +++ b/test/.gitignore @@ -0,0 +1,2 @@ +credentials.conf +tmp_* \ No newline at end of file diff --git a/test/OLItest/TestRunner.py b/test/OLItest/TestRunner.py new file mode 100644 index 0000000..f984471 --- /dev/null +++ b/test/OLItest/TestRunner.py @@ -0,0 +1,102 @@ +# Copyright (C) 2012- Sebastian Spaeth & contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# 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 unittest +import logging +import os +import sys +import shutil +import subprocess +import tempfile +from ConfigParser import SafeConfigParser +from OLItest import default_conf + +class OLITestLib(): + cred_file = None + testdir = None + """Absolute path of the current temporary test directory""" + cmd = None + """command that will be executed to invoke offlineimap""" + + def __init__(self, cred_file = None, cmd='offlineimap'): + """ + + :param cred_file: file of the configuration + snippet for authenticating against the test IMAP server(s). + :param cmd: command that will be executed to invoke offlineimap""" + OLITestLib.cred_file = cred_file + OLITestLib.cmd = cmd + + @classmethod + def create_test_dir(cls, suffix=''): + """Creates a test directory and places OLI config there + + Note that this is a class method. There can only be one test + directory at a time. OLITestLib is not suited for running + several tests in parallel. The user is responsible for + cleaning that up herself.""" + # creating temporary directory for testing in current dir + cls.testdir = os.path.abspath( + tempfile.mkdtemp(prefix='tmp_%s_'%suffix, dir='.')) + cls.create_config_file() + return cls.testdir + + @classmethod + def create_config_file(cls): + """Creates a OLI configuration file + + It is created in testdir (so create_test_dir has to be called + earlier) using the credentials information given (so they had to + be set earlier). Failure to do either of them will raise an + AssertionException.""" + assert cls.cred_file != None + assert cls.testdir != None + config = SafeConfigParser() + config.readfp(default_conf) + config.read(cls.cred_file) + config.set("general", "metadata", cls.testdir) + localfolders = os.path.join(cls.testdir, 'mail') + config.set("Repository Maildir", "localfolders", localfolders) + with open(os.path.join(cls.testdir, 'offlineimap.conf'), "wa") as f: + config.write(f) + + @classmethod + def delete_test_dir(cls): + """Deletes the current test directory + + The users is responsible for cleaning that up herself.""" + if os.path.isdir(cls.testdir): + shutil.rmtree(cls.testdir) + + @classmethod + def run_OLI(cls): + """Runs OfflineImap + + :returns: (rescode, stdout) + """ + try: + output = subprocess.check_output( + [cls.cmd, + "-c%s" % os.path.join(cls.testdir, 'offlineimap.conf')], + shell=False) + except subprocess.CalledProcessError as e: + return (e.returncode, e.output) + return (0, output) + +class OLITextTestRunner(unittest.TextTestRunner): + + def __init__(self,*args, **kwargs): + logging.warning("OfflineImap testsuite") + return super(OLITextTestRunner, self).__init__(*args, **kwargs) diff --git a/test/OLItest/__init__.py b/test/OLItest/__init__.py new file mode 100644 index 0000000..c9bda69 --- /dev/null +++ b/test/OLItest/__init__.py @@ -0,0 +1,34 @@ +# OfflineImap test library +# Copyright (C) 2012- Sebastian Spaeth & contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# 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 + +__all__ = ['OLITestLib', 'OLITextTestRunner','TestLoader'] + +__productname__ = 'OfflineIMAP Test suite' +__version__ = '0' +__copyright__ = "Copyright 2012- Sebastian Spaeth & contributors" +__author__ = 'Sebastian Spaeth' +__author_email__= 'Sebastian@SSpaeth.de' +__description__ = 'Moo' +__license__ = "Licensed under the GNU GPL v2+ (v2 or any later version)" +__homepage__ = "http://offlineimap.org" +banner = """%(__productname__)s %(__version__)s + %(__license__)s""" % locals() + +import unittest +from unittest import TestLoader +from globals import default_conf +from TestRunner import OLITestLib, OLITextTestRunner diff --git a/test/OLItest/globals.py b/test/OLItest/globals.py new file mode 100644 index 0000000..4009b9b --- /dev/null +++ b/test/OLItest/globals.py @@ -0,0 +1,37 @@ +#Constants, that don't rely on anything else in the module +# Copyright (C) 2012- Sebastian Spaeth & contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# 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 +from cStringIO import StringIO + +default_conf=StringIO("""[general] +#will be set automatically +metadata = +accounts = test +ui = quiet + +[Account test] +localrepository = Maildir +remoterepository = IMAP + +[Repository Maildir] +Type = Maildir +# will be set automatically during tests +localfolders = + +[Repository IMAP] +type=IMAP +folderfilter= lambda f: f.startswith('OLItest') +""") diff --git a/test/README b/test/README new file mode 100644 index 0000000..3bf6694 --- /dev/null +++ b/test/README @@ -0,0 +1,17 @@ +Documentation for the OfflineImap Test suite. + +How to run the tests +==================== + +- Copy the credentials.conf.sample to credentials.conf and insert + credentials for an IMAP account and a Gmail account. Delete the Gmail + section if you don't have a Gmail account. Do note, that the tests + will change the account and upload/delete/modify it's contents and + folder structure. So don't use a real used account here... + +- Execute './test' + +System requirements +=================== + +This test suite depend on python>=2.7 to run out of the box. If you want to run this with python 2.6 you will need to install the backport from http://pypi.python.org/pypi/unittest2 instead. \ No newline at end of file diff --git a/test/credentials.conf.sample b/test/credentials.conf.sample new file mode 100644 index 0000000..cd22f77 --- /dev/null +++ b/test/credentials.conf.sample @@ -0,0 +1,13 @@ +[Repository IMAP] +type = IMAP +remotehost = localhost +ssl = no +#sslcacertfile = +#cert_fingerprint = +remoteuser = user@domain +remotepass = SeKr3t + +[Repository Gmail] +type = Gmail +remoteuser = user@domain +remotepass = SeKr3t diff --git a/test/test b/test/test new file mode 100755 index 0000000..08803f9 --- /dev/null +++ b/test/test @@ -0,0 +1,9 @@ +#!/usr/bin/env python +import logging +from OLItest import OLITextTestRunner, TestLoader, OLITestLib + +if __name__ == '__main__': + logging.basicConfig(format='%(message)s') + OLITestLib(cred_file='./credentials.conf', cmd='../offlineimap.py') + suite = TestLoader().discover('./tests') + OLITextTestRunner(verbosity=2).run(suite) diff --git a/test/tests/__init__.py b/test/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/tests/test_01_basic.py b/test/tests/test_01_basic.py new file mode 100644 index 0000000..4456890 --- /dev/null +++ b/test/tests/test_01_basic.py @@ -0,0 +1,75 @@ +# Copyright (C) 2012- Sebastian Spaeth & contributors +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# 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 random +import unittest +import logging +import os, sys +# Insert ".." into the python search path +cmd_folder = os.path.dirname(os.path.abspath(__file__)) +if cmd_folder not in sys.path: + sys.path.insert(0, cmd_folder) +from OLItest import OLITestLib + +def setUpModule(): + logging.info("Set Up test module %s" % __name__) + tdir = OLITestLib.create_test_dir(suffix=__name__) + +def tearDownModule(): + logging.info("Tear Down test module") + OLITestLib.delete_test_dir() + +#Stuff that can be used +#self.assertEqual(self.seq, range(10)) +# should raise an exception for an immutable sequence +#self.assertRaises(TypeError, random.shuffle, (1,2,3)) +#self.assertTrue(element in self.seq) +#self.assertFalse(element in self.seq) + +class TestBasicFunctions(unittest.TestCase): + #@classmethod + #def setUpClass(cls): + #This is run before all tests in this class + # cls._connection = createExpensiveConnectionObject() + + #@classmethod + #This is run after all tests in this class + #def tearDownClass(cls): + # cls._connection.destroy() + + # This will be run before each test + #def setUp(self): + # self.seq = range(10) + + 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.""" + code, res = OLITestLib.run_OLI() + #logging.warn("%s %s "% (code, res)) + self.assertEqual(res, "") + #TODO implement OLITestLib.countmails() + logging.warn("synced %d boxes, %d mails" % (0,0)) + + def test_02_wipedir(self): + """Wipe OLItest* maildir, sync and see if it's still empty + + Wipes all "OLItest* (specified in the default config) to our + local Maildir at keeps it there.""" + + code, res = OLITestLib.run_OLI() + #logging.warn("%s %s "% (code, res)) + self.assertEqual(res, "")