aboutsummaryrefslogtreecommitdiffstats
path: root/debian/tests
diff options
context:
space:
mode:
Diffstat (limited to 'debian/tests')
-rw-r--r--debian/tests/control15
-rw-r--r--debian/tests/installation23
-rw-r--r--debian/tests/mock-pop3-server.py214
-rw-r--r--debian/tests/operation47
-rw-r--r--debian/tests/service13
5 files changed, 312 insertions, 0 deletions
diff --git a/debian/tests/control b/debian/tests/control
new file mode 100644
index 00000000..83ed5bd0
--- /dev/null
+++ b/debian/tests/control
@@ -0,0 +1,15 @@
+Test-Command: ./configure && make check
+Depends: @, build-essential, gcc, libssl-dev, python3
+Restrictions: allow-stderr
+
+Tests: installation
+Depends: @
+Restrictions:
+
+Tests: service
+Depends: @, systemd-sysv
+Restrictions: needs-root, allow-stderr
+
+Tests: operation
+Depends: @, sudo, python3
+Restrictions: needs-root
diff --git a/debian/tests/installation b/debian/tests/installation
new file mode 100644
index 00000000..271fc6ca
--- /dev/null
+++ b/debian/tests/installation
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+############################################
+### Check main installation requirements ###
+############################################
+
+set -e
+
+# Config file
+echo "Checking config file present"
+test -e /etc/default/fetchmail
+
+# Service
+echo "Checking service scripts are installed"
+test -e /etc/init.d/fetchmail
+test -e /etc/ppp/ip-down.d/fetchmail
+
+# Script
+echo "Checking fetchmail is present"
+test -e /usr/bin/fetchmail
+fetchmail --version > /dev/null 2>&1
+c=$(fetchmail --help 2>&1 | wc -l)
+test $c -gt 5
diff --git a/debian/tests/mock-pop3-server.py b/debian/tests/mock-pop3-server.py
new file mode 100644
index 00000000..159069b4
--- /dev/null
+++ b/debian/tests/mock-pop3-server.py
@@ -0,0 +1,214 @@
+#!/usr/bin/env python3
+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
+
+# Copyright (C) 2019 Bryce W. Harrington
+#
+# Released under GNU GPLv2 or later, read the file 'LICENSE.GPLv2+' for
+# more information.
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Author: Bryce Harrington <bryce@canonical.com>
+
+import os
+import sys
+import socket
+from tempfile import mkstemp
+
+DEBUGGING = True
+DEFAULT_HOST = ''
+DEFAULT_PORT = 11110
+NEWLINE = b"\r\n"
+MESSAGE_CONTENT = b'''
+From: test@example.com\r
+Subject: Test message\r
+\r
+This is a body for testing\r
+\r
+'''
+
+def dbg(msg):
+ """Prints information to stdout if debugging is enabled"""
+ if DEBUGGING:
+ sys.stdout.write("{}\n".format(msg))
+
+def command_user(data, msg):
+ return b'+OK user accepted'
+
+def command_pass(data, msg):
+ return b'+OK pass accepted'
+
+def command_stat(data, msg):
+ return b'+OK 1 %i' %(msg.size)
+
+def command_list(data, msg):
+ if data == b'LIST':
+ return b'+OK 1 messages (%i octets)'%(msg.size) \
+ + NEWLINE \
+ + b'1 %i'%(msg.size) \
+ + NEWLINE \
+ + b'.'
+ else:
+ cmd, num = data.split()
+ return b'+OK 1 (%i octects)'%(msg.size)
+
+def command_last(data, msg):
+ return b'+OK 0'
+
+def command_top(data, msg):
+ cmd, num, lines = data.split()
+ assert num == b'1', "unknown message number: {num}".format(num)
+ bottom = NEWLINE.join(msg.bottom[:int(lines)])
+ text = msg.top + NEWLINE + NEWLINE + bottom
+ dbg(text)
+ return b'+OK top of message follows%s' % (NEWLINE + text + NEWLINE + b'.')
+
+def command_retr(data, msg):
+ return b'+OK %i octets'%(msg.size) \
+ + NEWLINE \
+ + data \
+ + NEWLINE \
+ + b'.'
+
+def command_dele(data, msg):
+ return b'+OK 1 %i'%(msg.size)
+
+def command_noop(data, msg):
+ return b'+OK 1 %i'%(msg.size)
+
+def command_quit(data, msg):
+ return b'+OK mock pop3 server signing off'
+
+COMMANDS = {
+ b'USER' : command_user,
+ b'PASS' : command_pass,
+ b'STAT' : command_stat,
+ b'LIST' : command_list,
+ b'LAST' : command_last,
+ b'TOP' : command_top,
+ b'RETR' : command_retr,
+ b'DELE' : command_dele,
+ b'NOOP' : command_noop,
+ b'QUIT' : command_quit,
+}
+
+class Mailbox:
+ """Encapsulates a mailbox containing a single email message"""
+ def __init__(self, message_filename):
+ with open(message_filename, "rb") as msg:
+ data = msg.read()
+ self.data = data
+ self.size = len(data)
+ self.top, rest = data.split(NEWLINE + NEWLINE, 1)
+ self.bottom = rest.split(NEWLINE)
+
+
+class Mailserver:
+ def __init__(self, conn, mbox):
+ self._conn = conn
+ self._mbox = mbox
+ self._chunk_size = 4096
+
+ def close(self):
+ dbg(" - Server exiting")
+ self._conn.close()
+
+ def send(self, data):
+ dbg(" - Server sending")
+ self._conn.sendall(data + NEWLINE)
+
+ def receive(self):
+ dbg(" - Server receiving")
+ data = []
+ while True:
+ chunk = self._conn.recv(self._chunk_size)
+ if NEWLINE in chunk:
+ data.append(chunk[:chunk.index(NEWLINE)])
+ break
+ data.append(chunk)
+ return b"".join(data)
+
+ def process(self):
+ data = self.receive()
+ dbg(" - Received: '{}'".format(data))
+ command = data.split(None, 1)[0]
+ if command in COMMANDS.keys():
+ response = COMMANDS[command](data, self._mbox)
+ dbg(" - Response: {}".format(response))
+ try:
+ self.send(response)
+ if command == b'QUIT':
+ return False
+ except BrokenPipeError:
+ dbg(" - Client terminated connection")
+ return False
+ else:
+ self.send(b"-ERR unrecognized command")
+ return True
+
+def serve(messages_filename, host=DEFAULT_HOST, port=DEFAULT_PORT):
+ dbg("Serving for {} on {}".format(host, port))
+
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ sock.bind((host, port))
+
+ mailbox = Mailbox(messages_filename)
+
+ try:
+ dbg("* mock-pop3-server ready on {}:{}".format(host, port))
+ while True:
+ sock.listen(1)
+ conn, address = sock.accept()
+ dbg("* Connection from {}".format(address))
+ server = Mailserver(conn, mailbox)
+ server.send(b"+OK mock-pop3-server pop3 server ready")
+ try:
+ dbg("* Processing commands for connection...")
+ while server.process():
+ dbg("* Finished command")
+ pass
+ finally:
+ dbg("* Closing remote connection")
+ server.close()
+ except KeyboardInterrupt:
+ dbg("* mock-pop3-server interrupted")
+ return 1
+ except SystemExit:
+ dbg("* mock-pop3-server exiting")
+ return 1
+ finally:
+ sock.shutdown(socket.SHUT_RDWR)
+ sock.close()
+ return 0
+
+
+if __name__ == "__main__":
+ fd, message_filename = mkstemp(prefix='message-', suffix='.txt')
+ dbg("Creating message file '{}'".format(message_filename))
+
+ with open(message_filename, 'wb') as f:
+ f.write(MESSAGE_CONTENT.lstrip())
+
+ try:
+ exit(serve(message_filename, host=DEFAULT_HOST, port=DEFAULT_PORT))
+ except KeyError:
+ sys.stderr.write("Exiting\n")
+ sys.exit(1)
diff --git a/debian/tests/operation b/debian/tests/operation
new file mode 100644
index 00000000..c36dfb6d
--- /dev/null
+++ b/debian/tests/operation
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+###########################
+### Test fetching email ###
+###########################
+
+set -e
+
+POP3_SERVER=127.0.0.1
+POP3_PORT=11110
+USER=${USER:-user}
+PASSWORD=ubuntu
+WORKDIR=$(mktemp -d)
+trap "rm -rf $WORKDIR" 0 INT QUIT ABRT PIPE TERM
+
+LOG="${WORKDIR}/fetchmail.log"
+MBOX="${WORKDIR}/test-mbox-$(date +%''s_%N)"
+CONFIG="${WORKDIR}/fetchmailrc"
+
+echo "Configuring a functional local mail system"
+
+python3 "$(dirname ${0})/mock-pop3-server.py" &
+SERVER_PID=$!
+sleep 1
+
+# Configure fetchmail
+cat > "${CONFIG}" <<EOF
+poll ${POP3_SERVER} port ${POP3_PORT} no uidl with protocol POP3:
+ auth password
+ user '${USER}' there with password '${PASSWORD}'
+ is ${USER} here
+ sslproto ''
+ mda "/bin/sh -c 'cat > ${MBOX}'"
+EOF
+chmod 700 "${CONFIG}"
+chown -R fetchmail "${WORKDIR}"
+
+# Run fetchmail
+echo "Checking fetchmail operates"
+sudo -u fetchmail /usr/bin/fetchmail -d0 -vvv -f "${CONFIG}" "${POP3_SERVER}"
+
+# TODO: Verify the test email was delivered to expected destination
+echo "Checking test email was received"
+grep "Received: from " "${MBOX}"
+
+kill ${SERVER_PID}
+echo "OK"
diff --git a/debian/tests/service b/debian/tests/service
new file mode 100644
index 00000000..95f9abcd
--- /dev/null
+++ b/debian/tests/service
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+###############################
+### Check fetchmail service ###
+###############################
+
+set -e
+
+echo "Checking fetchmail service is enabled"
+systemctl is-enabled fetchmail.service
+
+echo "Checking fetchmail service is active"
+systemctl is-active fetchmail.service