diff --git a/apptools/logger/agent/attachments.py b/apptools/logger/agent/attachments.py index fdf9839e2..3ef8a43c8 100644 --- a/apptools/logger/agent/attachments.py +++ b/apptools/logger/agent/attachments.py @@ -8,8 +8,8 @@ import logging import os.path -from email import Encoders -from email.MIMEBase import MIMEBase +from email import encoders +from email.mime.base import MIMEBase from traits.api import Any, HasTraits @@ -58,20 +58,20 @@ def _attach_directory(self, dir): relpath = os.path.basename(dir) import zipfile - from cStringIO import StringIO + from io import BytesIO ctype = 'application/octet-stream' maintype, subtype = ctype.split('/', 1) msg = MIMEBase(maintype, subtype) - file_object = StringIO() + file_object = BytesIO() zip = zipfile.ZipFile(file_object, 'w') _append_to_zip_archive(zip, dir, relpath) zip.close() msg.set_payload(file_object.getvalue()) - Encoders.encode_base64(msg) # Encode the payload using Base64 + encoders.encode_base64(msg) # Encode the payload using Base64 msg.add_header('Content-Disposition', 'attachment', filename='project.zip') self.message.attach(msg) diff --git a/apptools/logger/agent/tests/__init__.py b/apptools/logger/agent/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/apptools/logger/agent/tests/test_attachments.py b/apptools/logger/agent/tests/test_attachments.py new file mode 100644 index 000000000..499499817 --- /dev/null +++ b/apptools/logger/agent/tests/test_attachments.py @@ -0,0 +1,65 @@ +from email.mime.multipart import MIMEMultipart +import io +import os +import shutil +import tempfile +import unittest + +try: + # On Python 3, mock is part of the standard library, + from unittest import mock +except ImportError: + # Whereas on Python 2 it is not. + import mock + +from apptools.logger.agent.attachments import Attachments + + +class AttachmentsTestCase(unittest.TestCase): + def setUp(self): + self.tmpdir = tempfile.mkdtemp() + self.addCleanup(shutil.rmtree, self.tmpdir) + + self.tmpfile = os.path.join(self.tmpdir, "dummy_file.txt") + with io.open(self.tmpfile, 'w', encoding='utf8') as filehandle: + filehandle.write(u"Dummy data in dummy file for dummies") + + def test_attaching_workspace(self): + class DummyWorkspace(object): + path = self.tmpdir + + class MockedApplication(object): + tmpdir = self.tmpdir + def get_service(self, service_id): + return DummyWorkspace() + + attachments = Attachments( + application=MockedApplication(), + message=MIMEMultipart() + ) + attachments.package_workspace() + + message = attachments.message + self.assertTrue(message.is_multipart()) + payload = message.get_payload() + self.assertEqual(len(payload), 1) + + def test_attaching_single_project(self): + class DummySingleProject(object): + location = self.tmpdir + + class MockedApplication(object): + tmpdir = self.tmpdir + def get_service(self, service_id): + return DummySingleProject() + + attachments = Attachments( + application=MockedApplication(), + message=MIMEMultipart() + ) + attachments.package_single_project() + + message = attachments.message + self.assertTrue(message.is_multipart()) + payload = message.get_payload() + self.assertEqual(len(payload), 1) diff --git a/apptools/logger/log_point.py b/apptools/logger/log_point.py index 0e4321ff5..ce6205862 100644 --- a/apptools/logger/log_point.py +++ b/apptools/logger/log_point.py @@ -19,7 +19,9 @@ # Standard library imports. import inspect -from cStringIO import StringIO + +# Third-party library imports. +from six import StringIO def log_point(msg='\n'): diff --git a/apptools/logger/plugin/logger_service.py b/apptools/logger/plugin/logger_service.py index 26b01d7de..520cd0481 100644 --- a/apptools/logger/plugin/logger_service.py +++ b/apptools/logger/plugin/logger_service.py @@ -1,9 +1,11 @@ # Standard library imports -from cStringIO import StringIO import logging import os import zipfile +# Third-party library imports +from io import BytesIO + # Enthought library imports from pyface.workbench.api import View as WorkbenchView from traits.api import Any, Callable, HasTraits, Instance, List, \ @@ -108,7 +110,7 @@ def create_email_message(self, fromaddr, toaddrs, ccaddrs, subject, message.attach(msg) if include_userdata and len(self.mail_files) != 0: - f = StringIO() + f = BytesIO() zf = zipfile.ZipFile(f, 'w') for mf in self.mail_files: mf(zf) diff --git a/apptools/logger/plugin/tests/__init__.py b/apptools/logger/plugin/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/apptools/logger/plugin/tests/test_logger_service.py b/apptools/logger/plugin/tests/test_logger_service.py new file mode 100644 index 000000000..bfa298207 --- /dev/null +++ b/apptools/logger/plugin/tests/test_logger_service.py @@ -0,0 +1,41 @@ +from email.mime.multipart import MIMEMultipart +import unittest + +try: + # On Python 3, mock is part of the standard library, + from unittest import mock +except ImportError: + # Whereas on Python 2 it is not. + import mock + +from apptools.logger.plugin.logger_service import LoggerService + + +class LoggerServiceTestCase(unittest.TestCase): + def test_create_email_message(self): + logger_service = LoggerService() + with mock.patch.object(logger_service, 'whole_log_text')\ + as mocked_log_txt: + mocked_log_txt.return_value = "Dummy log data" + msg = logger_service.create_email_message( + fromaddr='', toaddrs='', ccaddrs='', subject='', priority='' + ) + self.assertIsInstance(msg, MIMEMultipart) + + def test_create_email_message_with_user_data(self): + # We used a mocked logger service which doesn't depend on the + # application trait and the presence of extensions to the extension + # point `apptools.logger.plugin.mail_files` + class MockedLoggerService(LoggerService): + def _get_mail_files(self): + return [lambda zip_file : None] + + logger_service = MockedLoggerService() + with mock.patch.object(logger_service, 'whole_log_text')\ + as mocked_log_txt: + mocked_log_txt.return_value = "Dummy log data" + msg = logger_service.create_email_message( + fromaddr='', toaddrs='', ccaddrs='', subject='', priority='', + include_userdata=True, + ) + self.assertIsInstance(msg, MIMEMultipart)