summaryrefslogtreecommitdiffstats
path: root/debian/tests
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--debian/tests/control14
-rwxr-xr-xdebian/tests/doveadm7
-rwxr-xr-xdebian/tests/systemd22
-rwxr-xr-xdebian/tests/testmails256
-rwxr-xr-xdebian/tests/usage/00_setup50
-rwxr-xr-xdebian/tests/usage/imap38
-rwxr-xr-xdebian/tests/usage/pop331
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")