diff options
Diffstat (limited to '')
-rw-r--r-- | debian/tests/control | 14 | ||||
-rwxr-xr-x | debian/tests/doveadm | 7 | ||||
-rwxr-xr-x | debian/tests/systemd | 22 | ||||
-rwxr-xr-x | debian/tests/testmails | 256 | ||||
-rwxr-xr-x | debian/tests/usage/00_setup | 50 | ||||
-rwxr-xr-x | debian/tests/usage/imap | 38 | ||||
-rwxr-xr-x | debian/tests/usage/pop3 | 31 |
7 files changed, 418 insertions, 0 deletions
diff --git a/debian/tests/control b/debian/tests/control new file mode 100644 index 0000000..496cfcc --- /dev/null +++ b/debian/tests/control @@ -0,0 +1,14 @@ +Tests: doveadm +Depends: dovecot-core +Restrictions: needs-root + +Tests: systemd +Depends: dovecot-core, systemd-sysv + +Test-Command: run-parts --report --exit-on-error debian/tests/usage +Depends: dovecot-imapd, dovecot-pop3d, python3 +Restrictions: needs-root, breaks-testbed, allow-stderr + +Tests: testmails +Restrictions: needs-root, breaks-testbed +Depends: dovecot-imapd, dovecot-pop3d, lsb-release, python3, python3-passlib diff --git a/debian/tests/doveadm b/debian/tests/doveadm new file mode 100755 index 0000000..9e2bd04 --- /dev/null +++ b/debian/tests/doveadm @@ -0,0 +1,7 @@ +#!/bin/sh + +set -e + +echo "Checking if dovecot is running" +doveadm -f flow instance list | grep -q 'running=yes' +echo "OK" diff --git a/debian/tests/systemd b/debian/tests/systemd new file mode 100755 index 0000000..48afbf5 --- /dev/null +++ b/debian/tests/systemd @@ -0,0 +1,22 @@ +#!/bin/sh + +set -e + +echo "Checking whether dovecot.service is enabled" +systemctl is-enabled dovecot.service + +echo "Checking whether dovecot.service is a native unit" +source=$(systemctl show -pSourcePath dovecot.service | cut -d = -f 2) +if [ -n "$source" ]; then + echo $source + exit 1 +else + echo "OK (no SourcePath found)" +fi + +echo "Checking whether dovecot.socket is inactive" +status=$(systemctl show -pActiveState dovecot.socket | cut -d = -f 2) +echo $status +if [ "$status" != inactive ]; then + exit 1 +fi diff --git a/debian/tests/testmails b/debian/tests/testmails new file mode 100755 index 0000000..3329809 --- /dev/null +++ b/debian/tests/testmails @@ -0,0 +1,256 @@ +#!/usr/bin/python3 + +import grp +import imaplib +import os +import os.path +import poplib +import pwd +import random +import string +import subprocess +import sys +import unittest + +from passlib.hash import des_crypt + + +def random_string(length): + '''Return a random string, consisting of ASCII letters, with given + length.''' + + s = '' + maxind = len(string.ascii_letters)-1 + for _ in range(length): + s += string.ascii_letters[random.randint(0, maxind)] + return s.lower() + + +def login_exists(login): + '''Checks whether the given login exists on the system.''' + + try: + pwd.getpwnam(login) + return True + except KeyError: + return False + + +def get_distribution(): + '''Return the name of the Linux Distribution we are running.''' + cmd = ['lsb_release', '-si'] + output = subprocess.check_output(cmd) + return output.strip() + + +class TestUser: + '''Create a temporary test user and remove it again on close.''' + + def __init__(self): + '''Create a new user account with a random password.''' + + self.login = None + + while True: + login = random_string(8) + if not login_exists(login): + break + + self.salt = random_string(2) + self.password = random_string(8) + self.crypted = des_crypt.using(salt=self.salt).hash(self.password) + + subprocess.check_call(['useradd', '-p', self.crypted, '-m', login]) + + self.login = login + p = pwd.getpwnam(self.login) + self.uid = p[2] + self.gid = p[3] + + def __del__(self): + '''Remove the created user account.''' + + if self.login: + self.close() + + def close(self): + '''Remove the created user account.''' + + subprocess.check_call(['userdel', '-f', '-r', self.login]) + self.login = None + + +class DovecotBasics(unittest.TestCase): + '''Base operational tests for Dovecot server.''' + + def setUp(self): + '''Create test scenario. + + We want to test the default setup, but pre-setup an mbox on a tmp user + ''' + + self.distribution = get_distribution() + self.user = TestUser() + + # create fresh test mailbox with one new and one old mail + self.mailbox = '/var/mail/' + self.user.login + self.orig_mbox = '''From test1@test1.com Fri Nov 17 02:21:08 2006 +Date: Thu, 16 Nov 2006 17:12:23 -0800 +From: Test User 1 <test1@test1.com> +To: Dovecot tester <dovecot@test.com> +Subject: Test 1 +Status: N + +Some really important news. + +From test2@test1.com Tue Nov 28 11:29:34 2006 +Date: Tue, 28 Nov 2006 11:29:34 +0100 +From: Test User 2 <test2@test2.com> +To: Dovecot tester <dovecot@test.com> +Subject: Test 2 +Status: R + +More news. + +Get cracking! +''' + with open(self.mailbox, 'w') as f: + f.write(self.orig_mbox) + os.chown(self.mailbox, self.user.uid, grp.getgrnam('mail')[2]) + os.chmod(self.mailbox, 0o660) + + def tearDown(self): + self.user.close() + + def _test_pop3_proto(self, pop): + '''Internal factorization of POP3 protocol checks with an established + connection.''' + + # check empty password + self.assertEqual(pop.user(self.user.login), b'+OK') + self.assertRaises(poplib.error_proto, pop.pass_, '') + + # check wrong password + self.assertEqual(pop.user(self.user.login), b'+OK') + self.assertRaises(poplib.error_proto, pop.pass_, '123') + + # check correct password + self.assertEqual(pop.user(self.user.login), b'+OK') + self.assertEqual(pop.pass_(self.user.password), b'+OK Logged in.') + + # check messages + self.assertEqual(pop.stat()[0], 2, b'2 available messages') + self.assertEqual(pop.list()[1], [b'1 163', b'2 161']) + self.assertEqual('\n'.join(l.decode() for l in pop.retr(1)[1]), '''Date: Thu, 16 Nov 2006 17:12:23 -0800 +From: Test User 1 <test1@test1.com> +To: Dovecot tester <dovecot@test.com> +Subject: Test 1 + +Some really important news.''') + self.assertEqual('\n'.join(l.decode() for l in pop.retr(2)[1]), '''Date: Tue, 28 Nov 2006 11:29:34 +0100 +From: Test User 2 <test2@test2.com> +To: Dovecot tester <dovecot@test.com> +Subject: Test 2 + +More news. + +Get cracking!''') + + self.assertEqual(pop.quit(), b'+OK Logging out.') + + def test_pop3(self): + '''Test POP3 protocol.''' + + pop = poplib.POP3('localhost') + self.assertEqual(pop.getwelcome(), + b'+OK Dovecot (%s) ready.' % self.distribution) + + self._test_pop3_proto(pop) + + def test_pop3s(self): + '''Test POP3S protocol.''' + + pop = poplib.POP3_SSL('localhost') + self.assertEqual(pop.getwelcome(), + b'+OK Dovecot (%s) ready.' % self.distribution) + + self._test_pop3_proto(pop) + + def _test_imap_proto(self, imap): + '''Internal factorization of IMAP4 protocol checks with an established + connection.''' + + # invalid passwords + self.assertRaises(imaplib.IMAP4.error, imap.login, + self.user.login, '') + self.assertRaises(imaplib.IMAP4.error, imap.login, + self.user.login, '123') + + # correct password + imap.login(self.user.login, self.user.password) + + # list mailboxes + status, imlist = imap.list() + self.assertEqual(status, 'OK') + self.assertTrue(imlist[0].decode().endswith('INBOX')) + + # check mails + imap.select() + self.assertEqual(imap.search(None, 'ALL'), ('OK', [b'1 2'])) + self.assertEqual(imap.fetch('1', '(FLAGS)'), + ('OK', [b'1 (FLAGS (\\Recent))'])) + self.assertEqual(imap.fetch('2', '(FLAGS)'), + ('OK', [b'2 (FLAGS (\\Seen \\Recent))'])) + self.assertEqual(imap.fetch('1', '(BODY[TEXT])')[1][0][1], + b'Some really important news.\r\n') + self.assertEqual(imap.fetch('2', '(BODY[TEXT])')[1][0][1], + b'More news.\r\n\r\nGet cracking!') + + self.assertEqual(imap.fetch('1', '(RFC822)')[1], + [(b'1 (RFC822 {163}', + b'''Date: Thu, 16 Nov 2006 17:12:23 -0800\r +From: Test User 1 <test1@test1.com>\r +To: Dovecot tester <dovecot@test.com>\r +Subject: Test 1\r +\r +Some really important news.\r +'''), b')']) + + # delete mail 1 + self.assertEqual(imap.store('1', '+FLAGS', '\\Deleted')[0], 'OK') + self.assertEqual(imap.expunge()[0], 'OK') + self.assertEqual(imap.search(None, 'ALL'), ('OK', [b'1'])) + + # old mail 2 is mail 1 now + self.assertEqual(imap.fetch('1', '(RFC822)')[1], + [(b'1 (RFC822 {161}', + b'''Date: Tue, 28 Nov 2006 11:29:34 +0100\r +From: Test User 2 <test2@test2.com>\r +To: Dovecot tester <dovecot@test.com>\r +Subject: Test 2\r +\r +More news.\r +\r +Get cracking!'''), b')']) + imap.close() + imap.logout() + + def test_imap(self): + '''Test IMAP4 protocol.''' + + imap = imaplib.IMAP4('localhost') + self._test_imap_proto(imap) + + def test_imaps(self): + '''Test IMAP4S protocol.''' + + imap = imaplib.IMAP4_SSL('localhost') + self._test_imap_proto(imap) + + +if __name__ == '__main__': + os.dup2(1, 2) + suite = unittest.TestSuite() + suite.addTest(unittest.TestLoader().loadTestsFromTestCase(DovecotBasics)) + result = unittest.TextTestRunner(verbosity=2).run(suite) + sys.exit(not result.wasSuccessful()) diff --git a/debian/tests/usage/00_setup b/debian/tests/usage/00_setup new file mode 100755 index 0000000..2eeeb2f --- /dev/null +++ b/debian/tests/usage/00_setup @@ -0,0 +1,50 @@ +#!/bin/sh + +set -e + +echo "Setting up dovecot for the test" +# Move aside 10-auth.conf to disable passwd-based auth +if [ -f /etc/dovecot/conf.d/10-auth.conf ]; then + mv /etc/dovecot/conf.d/10-auth.conf /etc/dovecot/conf.d/10-auth.conf.bak +fi + +cat >/etc/dovecot/local.conf <<-EOF + auth_mechanisms = plain + mail_location = maildir:~/Maildir + + passdb { + driver = static + args = password=test + } + + userdb { + driver = static + args = uid=nobody gid=nogroup home=/srv/dovecot-dep8/%u + } +EOF + +mkdir -p /srv/dovecot-dep8 +chown nobody:nogroup /srv/dovecot-dep8 + +echo "Restarting the service" +systemctl restart dovecot + +echo "Sending a test message via the LDA" +/usr/lib/dovecot/dovecot-lda -f "test@example.com" -d dep8 <<EOF +Return-Path: <test@example.com> +Message-Id: <dep8-test-1@debian.org> +From: Test User <test@example.com> +To: dep8 <dep8@example.com> +Subject: DEP-8 test + +This is just a test +EOF + +echo "Verifying that the email was correctly delivered" +if [ -z "$(doveadm search -u dep8 header message-id dep8-test-1@debian.org)" ]; then + echo "Message not found" + exit 1 +fi + +echo "Done" +echo diff --git a/debian/tests/usage/imap b/debian/tests/usage/imap new file mode 100755 index 0000000..5bdede7 --- /dev/null +++ b/debian/tests/usage/imap @@ -0,0 +1,38 @@ +#!/usr/bin/python3 +import imaplib + +imaplib.Debug = 4 + +print("Testing IMAP") +print("Connecting") +client = imaplib.IMAP4('localhost') + +print("Checking for STARTTLS capability") +assert 'STARTTLS' in client.capabilities + +client.starttls() + +print("Logging in") +client.login('dep8', 'test') + +print("Selecting INBOX") +client.select() + +print("Looking for the test message") +res, uids = client.search(None, 'HEADER', 'MESSAGE-ID', '"<dep8-test-1@debian.org>"') + +assert res == 'OK' +assert len(uids[0]) > 0 + +uid = uids[0].split()[0] + +print("Fetching and verifying test message") +res, data = client.fetch(uid, '(RFC822)') + +assert res == 'OK' + +lines = data[0][1].splitlines() + +assert b'Subject: DEP-8 test' in lines + +print("Done") diff --git a/debian/tests/usage/pop3 b/debian/tests/usage/pop3 new file mode 100755 index 0000000..00b1657 --- /dev/null +++ b/debian/tests/usage/pop3 @@ -0,0 +1,31 @@ +#!/usr/bin/python3 +import poplib + +print("Testing POP3") +print("Connecting") +client = poplib.POP3('localhost') +client.set_debuglevel(2) + +print("Checking for STARTTLS capability") +assert 'STLS' in client.capa() + +client.stls() + +print("Logging in") +client.user('dep8') +client.pass_('test') + +print("Listing INBOX") +res, data, _ = client.list() +assert res.startswith(b'+OK') + +print("Fetching and verifying test message") +for entry in data: + _id, _ = entry.split(maxsplit=1) + res, body, _ = client.retr(int(_id)) + if b'Subject: DEP-8 test' in body: + break +else: + raise AssertionError("Test message not found") + +print("Done") |