aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatěj Cepl <mcepl@cepl.eu>2018-04-22 02:03:06 +0200
committerMatěj Cepl <mcepl@cepl.eu>2018-04-22 02:03:06 +0200
commitca9285e80b9fa2df82b135b3684f933d05222f69 (patch)
tree5f78c55a9385cc7726390360abfa436c3731ee6c
parent75be2c284dc0647765046b55655ecd0dbb64f131 (diff)
downloadimapArch-ca9285e80b9fa2df82b135b3684f933d05222f69.tar.gz
Add some more tests.
-rwxr-xr-xarchive_folder.py56
-rw-r--r--test/msg_test.eml98
-rw-r--r--test/test_email_server.py82
3 files changed, 201 insertions, 35 deletions
diff --git a/archive_folder.py b/archive_folder.py
index 744fcba..4b86707 100755
--- a/archive_folder.py
+++ b/archive_folder.py
@@ -1,11 +1,6 @@
#!/usr/bin/env python3.6
# note http://docs.python.org/lib/module-doctest.html
# resp. file:///usr/share/doc/python-docs-*/html/lib/module-doctest.html
-# FIXME
-# read https://www.toptal.com/python/an-introduction-to-mocking-in-python
-# & https://blog.fugue.co/2016-02-11-python-mocking-101.html
-# for unittest.mock tutorials
-# for testing
import argparse
import collections
import configparser
@@ -17,6 +12,7 @@ import locale
import logging
import imaplib
import os
+import re
import sys
from datetime import date, timedelta
@@ -34,6 +30,7 @@ class MessageError(IOError):
pass
Capas = collections.namedtuple('Capas', ['MOVE', 'UIDPLUS'])
+SEP_RE = re.compile(r'\s+"([/.])"\s+')
class Message(object):
@@ -69,14 +66,11 @@ class Message(object):
class Folder(object):
def __init__(self, box, fld_name, create=False):
self.box = box
- log.debug('fld_name = %s', fld_name)
self.fld_name = fld_name
self.selected = False
self.__create_missing = create
- self.__folder_sep = self.__get_separator()
+ self.folder_sep = self.__get_separator()
- log.debug('create_missing = %s', self.__create_missing)
- log.debug('list_folder = %s', self.__list_folder)
if self.__create_missing and self.__list_folder() is None:
self.__create_folder()
@@ -88,13 +82,11 @@ class Folder(object):
return self
def __create_folder(self):
- sep = self.__folder_sep
+ sep = self.folder_sep
split_name = self.fld_name.split(sep)
- log.debug('split_name = %s', split_name)
target = ''
for part in split_name:
- log.debug('part = %s', part)
- target += '{}{}'.format(part, self.__folder_sep)
+ target += '{}{}'.format(part, self.folder_sep)
if self.__list_folder(target) is None:
self.box.create(target)
self.box.subscribe(target)
@@ -117,14 +109,12 @@ class Folder(object):
"""
data = self.__list_folder()
- log.debug('data = %s (%s)', data, type(data))
-
if data is None:
data = self.__list_folder('""', '""')
- data = data.decode().split(' ')
- if len(data) == 3:
- return data[1].strip(' "')
+ parse_data = SEP_RE.search(data.decode())
+ if parse_data is not None:
+ return parse_data.group(1)
else:
raise ServerError('Cannot find folder separator from %s' % data)
@@ -143,26 +133,24 @@ class Folder(object):
return self.__emails_search('BEFORE', before_str)
def get_archive_folder(self, msg, aroot):
- return self.__folder_sep.join((aroot, msg.date.strftime("%Y"), self.fld_name))
+ return self.folder_sep.join((aroot, msg.date.strftime("%Y"), self.fld_name))
def move_messages(self, messages):
assert self.selected == False, 'Target folder should not be selected.'
if self.box.features_present.MOVE:
- ok, data = self.box.uid('MOVE',
- '%s %s' % (messages, self.fld_name))
+ ok, data = self.box.uid('MOVE', messages, self.fld_name)
log.debug('MOVE ok = %s, data = %s', ok, data)
if ok != 'OK':
raise FolderError('Cannot move messages to folder %s' %
self.fld_name)
elif self.box.features_present.UIDPLUS:
- ok, data = self.box.uid('COPY',
- '%s %s' % (messages, self.fld_name))
+ ok, data = self.box.uid('COPY', messages, self.fld_name)
log.debug('COPY ok = %s, data = %s', ok, data)
if ok != 'OK':
raise FolderError('Cannot copy messages to folder %s' %
self.fld_name)
ok, data = self.box.uid('STORE',
- r'+FLAGS.SILENT (\DELETED) %s' % messages)
+ r'+FLAGS.SILENT (\DELETED)', messages)
log.debug('STORE ok = %s, data = %s', ok, data)
if ok != 'OK':
raise FolderError('Cannot delete messages-')
@@ -171,14 +159,13 @@ class Folder(object):
if ok != 'OK':
raise FolderError('Cannot expunge messages.')
else:
- ok, data = self.box.uid('COPY',
- '%s %s' % (messages, self.fld_name))
+ ok, data = self.box.uid('COPY', messages, self.fld_name)
log.debug('COPY ok = %s, data = %s', ok, data)
if ok != 'OK':
raise FolderError('Cannot copy messages to folder %s' %
self.fld_name)
ok, data = self.box.uid('STORE',
- r'+FLAGS.SILENT (\DELETED) %s' % messages)
+ r'+FLAGS.SILENT (\DELETED)', messages)
log.debug('STORE ok = %s, data = %s', ok, data)
if ok != 'OK':
raise FolderError('Cannot delete messages-')
@@ -191,12 +178,11 @@ class EmailServer(object):
else config['general']['account']
self.cfg = dict(config.items(acc_name))
self.archive_root = archive_root
- self.__box = self.__login(**self.cfg)
+ self.box = self.__login(**self.cfg)
def __login(self, host='localhost', username=None, password=None, ssl=None):
box = imaplib.IMAP4_SSL(host=host)
- res = box.login(username, password)
- ok, data = res
+ ok, data = box.login(username, password)
if ok != 'OK':
raise ServerError('Cannot login with credentials %s' %
str((host, username, password,)))
@@ -204,9 +190,9 @@ class EmailServer(object):
ok, data = box.capability()
capas = data[0].decode()
box.features_present = Capas._make(['MOVE' in capas, 'UIDPLUS' in capas])
+ return box
@staticmethod
- @functools.lru_cache()
def get_config():
# In case the configuration file is missing, only empty list will be
# returned
@@ -223,7 +209,7 @@ class EmailServer(object):
:param: before_date
"""
copy_cache = {}
- fld = Folder(self.__box, folder_name).select()
+ fld = Folder(self.box, folder_name).select()
before_str = before_date.strftime('%d-%b-%Y')
for msg in fld.emails_before(before_str):
arch_folder = fld.get_archive_folder(msg, self.archive_root)
@@ -242,8 +228,8 @@ class EmailServer(object):
msg_ids = ','.join([x.uid for x in copy_cache[arch_dir]])
log.debug('arch_dir = %s, msgs = %s', arch_dir,
msg_ids)
- dir = Folder(self.__box, arch_dir, create=True)
- dir.move_messages(msg_ids)
+ dir = Folder(self.box, arch_dir, create=True)
+ # dir.move_messages(msg_ids)
def __enter__(self):
return self
@@ -251,7 +237,7 @@ class EmailServer(object):
def __exit__(self, *args):
if args != (None, None, None):
log.warning('args = %s', args)
- self.__box.close()
+ self.box.close()
if __name__ == '__main__':
diff --git a/test/msg_test.eml b/test/msg_test.eml
new file mode 100644
index 0000000..f9dc8e6
--- /dev/null
+++ b/test/msg_test.eml
@@ -0,0 +1,98 @@
+From ???@??? Wed Jul 18 17:27:27 2001
+Return-Path: <sentto-3642313-6-995471638-cepl=bigfoot.com@returns.onelist.com>
+Delivered-To: cepl@surfbest.net
+Received: from bigfoot.com (litemail.bigfoot.com [208.156.39.208])
+ by server12.safepages.com (Postfix) with SMTP id 5DA8C136099
+ for <cepl@surfbest.net>; Wed, 18 Jul 2001 15:54:52 +0000 (GMT)
+Received: from ci.egroups.com ([64.211.240.235])
+ by BFLITEMAIL1.bigfoot.com (LiteMail v3.01(BFLITEMAIL1)) with SMTP id 18Jul2001_BFLITEMAIL1_13769_126340112;
+ Wed, 18 Jul 2001 12:00:18 -0400 EST
+X-eGroups-Return:sentto-3642313-6-995471638-cepl=bigfoot.com@returns.onelist.com
+Received: from[10.1.4.56] by ci.egroups.com with NNFMP; 18 Jul 2001 15:53:58 -0000
+X-Sender:frederic.amblard@CLERMONT.cemagref.fr
+X-Apparently-To:dynnet@yahoogroups.com
+Received: (EGP: mail-7_2_0); 18 Jul 2001 15:53:57-0000
+Received: (qmail 59967 invoked from network); 18 Jul 2001 15:53:32-0000
+Received: from unknown (10.1.10.26) by l10.egroups.com with QMQP; 18 Jul2001 15:53:32 -0000
+Received: from unknown (HELO lassolas.clermont.cemagref.fr)(195.221.117.5) by mta1 with SMTP; 18 Jul 2001 15:53:32 -0000
+Received: bylassolas.clermont.cemagref.fr with Internet Mail Service (5.5.2448.0) id<M6H72S2M>; Wed, 18 Jul 2001 17:53:32 +0200
+Message-ID:<F17CAFD56F9CD1118E3A006097233920016DF085@lassolas.clermont.cemagref.fr>
+To:"'dynnet@yahoogroups.com'" <dynnet@yahoogroups.com>
+X-Mailer: Internet MailService (5.5.2448.0)
+From: Amblard Frederic<frederic.amblard@CLERMONT.cemagref.fr>
+MIME-Version: 1.0
+Mailing-List: listdynnet@yahoogroups.com; contact dynnet-owner@yahoogroups.com
+Delivered-To:mailing list dynnet@yahoogroups.com
+Precedence: bulk
+List-Unsubscribe:<mailto:dynnet-unsubscribe@yahoogroups.com>
+Date: Wed, 18 Jul 2001 17:53:30+0200
+Reply-To: dynnet@yahoogroups.com
+Subject: TR: [dynnet] Evolution ofnetworks a temptative of bibliography
+Content-Type: text/plain;charset=windows-1252
+Content-Transfer-Encoding: quoted-printable
+X-PMFLAGS:34078848 0 1 P52F70.CNM
+Content-Length: 1633
+Lines: 61
+
+Thank you Scottand please forgive my mistake, it is sometimes hard to
+follow the life ofworking papers ...=20
+in addition here comes the link to the book:=20
+http://www.amazon.com/exec/obidos/ASIN/354041522X/qid=3D995471342/sr=3D1-1/=
+ref=3Ds
+c_b_1/104-8956980-7775125
+andto the one published by Rosaria Conte, Rainer Hegselmann and Pietro
+Terna forthe article of Tom Snijders:=20
+http://www.amazon.com/exec/obidos/ASIN/3540633294/qid=3D995471480/sr=3D1-1/=
+ref=3Ds
+c_b_1/104-8956980-7775125
+
+ATB
+Fred=20
+
+-----Messaged'origine-----
+De : Scott Moss [mailto:s.moss@mmu.ac.uk]
+Envoy=E9 : mercredi18 juillet 2001 17:45
+=C0 : Frederic Amblard
+Objet : Re: [dynnet] Evolutionof networks a temptative of bibliography
+
+
+Hi Frederic
+
+The Axtellpaper has been published in the Springer LNAI series. The
+author, title anddate are the same but the location is Scott Moss and
+Paul Davidsson (eds),Multi-Agent-Based Simulation, Lecture Notes in
+Artificial Intelligence No. 1979,pp. 33-48.
+
+yours,
+Scott
+
+Amblard Frederic wrote:
+
+> Axtell,R., Effects of Interaction Topology and Activation Regime in
+> SeveralMulti-agent Systems. 2000, Center on Social and Economic
+>Dynamics.(http://www.brookings.edu/ES/dynamics/papers/)
+
+--
+ProfessorScott Moss
+Director
+Centre for Policy Modelling
+Manchester MetropolitanUniversity
+Aytoun Building
+Manchester M1 3GH
+UNITEDKINGDOM
+
+telephone: +44 (0)161 247 3886
+fax: +44 (0)161 2476802
+
+http://www.cpm.mmu.ac.uk/~scott
+
+
+To unsubscribe from thisgroup, send an emailto:
+dynnet-unsubscribe@yahoogroups.com
+
+=20
+
+Your use of Yahoo!Groups is subject to http://docs.yahoo.com/info/terms/=20
+
+
+
diff --git a/test/test_email_server.py b/test/test_email_server.py
index 8ff8788..737dd68 100644
--- a/test/test_email_server.py
+++ b/test/test_email_server.py
@@ -1,3 +1,4 @@
+import datetime
import logging
import unittest
from unittest import mock
@@ -6,6 +7,13 @@ import archive_folder
log = logging.getLogger('test')
+
+def create_test_message():
+ with open('test/msg_test.eml', 'rb') as msg_file:
+ msg_raw = msg_file.read()
+ return [(b'13 (UID 13 RFC822 {3776}', msg_raw), b')']
+
+
class TestEmailServer(unittest.TestCase):
@mock.patch.object(archive_folder.imaplib, 'IMAP4_SSL', autospec=True)
@mock.patch.object(archive_folder.configparser, 'ConfigParser', autospec=True)
@@ -25,3 +33,77 @@ class TestEmailServer(unittest.TestCase):
mock_imapobj().login.assert_called_once_with('fakeuser', 'veryverysecret')
mock_imapobj().capability.assert_called_once_with()
self.assertEqual(mock_imapobj().features_present, (False, True))
+ self.assertIsInstance(box, archive_folder.EmailServer)
+
+
+class TestFolder(unittest.TestCase):
+ @mock.patch.object(archive_folder.imaplib, 'IMAP4_SSL', autospec=True)
+ def test_folder_initialization(self, mock_imapobj):
+ mock_imapobj().list.return_value = ('OK',
+ [b'(\\HasNoChildren) "/" Work/sociology-junk'])
+ box = archive_folder.imaplib.IMAP4_SSL()
+ folder = archive_folder.Folder(box, 'INBOX/FakeFolder')
+ mock_imapobj().list.assert_called_once_with('INBOX/FakeFolder', '*')
+ self.assertIsInstance(folder, archive_folder.Folder)
+ self.assertEqual(folder.folder_sep, '/')
+ self.assertFalse(folder.selected)
+
+ @mock.patch.object(archive_folder.imaplib, 'IMAP4_SSL', autospec=True)
+ def test_folder_select(self, mock_imapobj):
+ mock_imapobj().list.return_value = ('OK',
+ [b'(\\HasNoChildren) "/" Work/sociology-junk'])
+ mock_imapobj().select.return_value = ('OK', 'FAKE success')
+ box = archive_folder.imaplib.IMAP4_SSL()
+ folder = archive_folder.Folder(box, 'INBOX/FakeFolder').select()
+ mock_imapobj().list.assert_called_once_with('INBOX/FakeFolder', '*')
+ mock_imapobj().select.assert_called_once_with('INBOX/FakeFolder')
+ self.assertIsInstance(folder, archive_folder.Folder)
+ self.assertEqual(folder.folder_sep, '/')
+ self.assertTrue(folder.selected)
+
+ @mock.patch.object(archive_folder.imaplib, 'IMAP4_SSL', autospec=True)
+ def test_folder_emails_before(self, mock_imapobj):
+ def fake_uid(cmd, param):
+ if cmd == 'FETCH':
+ return ('OK', create_test_message())
+ elif cmd == 'SEARCH':
+ return ('OK', [b'13'])
+
+ mock_imapobj().list.return_value = ('OK',
+ [b'(\\HasNoChildren) "/" Work/sociology-junk'])
+ mock_imapobj().select.return_value = ('OK', 'FAKE success')
+ mock_imapobj().uid.side_effect = fake_uid
+ box = archive_folder.imaplib.IMAP4_SSL()
+ folder = archive_folder.Folder(box, 'INBOX/FakeFolder').select()
+ msgs = folder.emails_before('25-Feb-1948')
+ self.assertIsInstance(msgs[0], archive_folder.Message)
+
+ @mock.patch.object(archive_folder.imaplib, 'IMAP4_SSL', autospec=True)
+ def test_folder_get_archive_folder(self, mock_imapobj):
+ mock_imapobj().list.return_value = ('OK',
+ [b'(\\HasNoChildren) "/" Work/sociology-junk'])
+ mock_imapobj().select.return_value = ('OK', 'FAKE success')
+ box = archive_folder.imaplib.IMAP4_SSL()
+ folder = archive_folder.Folder(box, 'INBOX/FakeFolder').select()
+
+ mock_imapobj().uid.return_value = ('OK', create_test_message())
+ box = archive_folder.imaplib.IMAP4_SSL()
+ msg = archive_folder.Message(box, '10')
+
+ arch_fld = folder.get_archive_folder(msg, 'FakeArchive')
+ self.assertEqual(arch_fld, 'FakeArchive/2001/INBOX/FakeFolder')
+
+
+class TestMessage(unittest.TestCase):
+ @mock.patch.object(archive_folder.imaplib, 'IMAP4_SSL', autospec=True)
+ def test_message_initialization(self, mock_imapobj):
+ mock_imapobj().uid.return_value = ('OK', create_test_message())
+ box = archive_folder.imaplib.IMAP4_SSL()
+ msg = archive_folder.Message(box, '10')
+ mock_imapobj().uid.assert_called_once_with('FETCH', '10 (RFC822)')
+ self.assertIsInstance(msg, archive_folder.Message)
+ self.assertEqual(msg.uid, '10')
+ self.assertEqual(msg.subject,
+ 'TR: [dynnet] Evolution ofnetworks a temptative of bibliography')
+ self.assertEqual(msg.date, datetime.datetime(2001, 7, 18, 17, 53, 30,
+ tzinfo=datetime.timezone(datetime.timedelta(0, 7200))))