Revert "Email Outbox"

This reverts commit 7e62b72503.

Change-Id: I578e4f67649d7a9c52996dd4884546b3919d61b8
This commit is contained in:
Adam Coldrick 2015-10-29 22:29:48 +00:00
parent a1f52db1d2
commit 1b498f0b45
4 changed files with 1 additions and 240 deletions

View File

@ -20,7 +20,6 @@ from oslo_log import log
from storyboard.plugin.base import PluginBase
from storyboard.plugin.email import get_email_directory
from storyboard.plugin.email.outbox import Outbox
from storyboard.plugin.email.smtp_client import get_smtp_client
CONF = cfg.CONF
@ -48,13 +47,6 @@ class EmailPluginBase(PluginBase):
(e,))
return False
# Assert that we can create an outbox.
try:
Outbox()
except OSError as e:
LOG.error('Cannot create mailbox, disabling plugin: %s' % (e,))
return False
# Assert that the smtp sender can connect to the server.
try:
with get_smtp_client():

View File

@ -1,80 +0,0 @@
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied. See the License for the specific language governing permissions and
# limitations under the License.
import mailbox
import os
import six
import time
import uuid
from oslo_config import cfg
from oslo_log import log
from storyboard.plugin.email import get_email_directory
CONF = cfg.CONF
LOG = log.getLogger(__name__)
class get_outbox(object):
"""This generator will create an instance of the email outbox, and make
sure it has been closed after use.
"""
def __init__(self):
self.outbox = None
def __enter__(self):
self.outbox = Outbox()
return self.outbox
def __exit__(self, exc_type, exc_val, exc_tb):
# On a clean use, flush the outbox.
if not exc_type:
self.outbox.flush()
# All outboxes get closed.
self.outbox.close()
self.outbox = None
class Outbox(mailbox.Maildir):
"""Our email outbox, a place where we store our generated email messages
before our cron mailer sends them out. It is implemented using the python
email.Maildir package, because, well, it quacks like a mailbox.
"""
def __init__(self):
"""Create a new instance of our outbox."""
working_directory = get_email_directory()
outbox_path = os.path.join(working_directory, 'outbox')
# Explicitly set the factory to None, because py2.7 defaults this to
# rfc822, which causes the return types to be different between 3.4
# and 2.7.
mailbox.Maildir.__init__(self, outbox_path, factory=None)
def _create_tmp(self):
"""Create a file in the tmp subdirectory and open and return it. This
is an intentional override of the parent class, in an attempt to
overcome the pid-based name generator that might cause conflicts when
there are two operating threads in a single pid.
"""
now = time.time()
uniq = six.text_type(uuid.uuid4())
uniq = "%sM%s_%s" % (int(now), int(now % 1 * 1e6), uniq)
path = os.path.join(self._path, 'tmp', uniq)
return mailbox._create_carefully(path)

View File

@ -21,7 +21,6 @@ from oslo_config import cfg
import mock_smtp as mock
from storyboard.plugin.email.base import EmailPluginBase
from storyboard.plugin.email import get_email_directory
from storyboard.tests import base
@ -33,8 +32,7 @@ PERM_ALL = stat.S_IRWXU + stat.S_IRWXG + stat.S_IRWXO
class TestEmailPluginBase(base.WorkingDirTestCase):
"""Unit tests for the base email plugin."""
def setup_helper(self, config=True, working_dir=True, outbox=True,
smtp=True):
def setup_helper(self, config=True, working_dir=True, smtp=True):
"""Setup helper: Setup the email test environment with various items
enabled/disabled.
"""
@ -42,10 +40,6 @@ class TestEmailPluginBase(base.WorkingDirTestCase):
if not working_dir:
os.chmod(CONF.working_directory, PERM_READ_ONLY)
elif not outbox:
# Can't modify this if the parent directory's already locked down.
email = get_email_directory()
os.chmod(email, PERM_READ_ONLY)
if not smtp:
mock.DummySMTP.exception = smtplib.SMTPException
@ -85,12 +79,6 @@ class TestEmailPluginBase(base.WorkingDirTestCase):
plugin = EmailPluginBase(CONF)
self.assertFalse(plugin.enabled())
def test_no_outbox(self):
"""Assert that we're not enabled when the outbox is not accessible."""
self.setup_helper(outbox=False)
plugin = EmailPluginBase(CONF)
self.assertFalse(plugin.enabled())
def test_no_smtp(self):
"""Assert that we're not enabled when smtp is misconfigured.
"""

View File

@ -1,139 +0,0 @@
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied. See the License for the specific language governing permissions and
# limitations under the License.
import datetime
from email.message import Message
from mock import patch
import re
import six
import uuid
from oslo_config import cfg
from storyboard.plugin.email.factory import EmailFactory
from storyboard.plugin.email.outbox import get_outbox
from storyboard.plugin.email.outbox import Outbox
from storyboard.tests import base
CONF = cfg.CONF
class TestGetOutbox(base.WorkingDirTestCase):
def test_single_scope(self):
"""Assert that get_outbox returns an Outbox. This test brought to you
by the department of redundancy department.
"""
with get_outbox() as outbox:
self.assertIsInstance(outbox, Outbox)
@patch.object(Outbox, 'close')
def test_was_closed(self, mock_close):
"""Assert that the close() method is called when the scope exits."""
with get_outbox():
pass
self.assertTrue(mock_close.called)
@patch.object(Outbox, 'flush')
def test_was_flushed(self, mock_flush):
"""Assert that the flush() method is called when the scope exits."""
with get_outbox():
pass
self.assertTrue(mock_flush.called)
class TestOutbox(base.WorkingDirTestCase):
def test_create_outbox(self):
'''Assert that we can create an outbox. At this point, given all of
the other IOError and working directory checks, we are not bothering
with additional sanity checks to make sure the outbox can be created.
If things are broken at this point, it should have already gotten
picked up.
'''
outbox = Outbox()
self.assertIsNotNone(outbox)
def test_basic_outbox_functions(self):
'''Assert that we can list elements of our outbox.'''
outbox = Outbox()
self.assertIsNotNone(outbox)
factory = EmailFactory('test@example.org',
'test_subject',
'test.txt',
'plugin.email')
for i in range(0, 100):
recipient = 'test_%s@example.com' % (i,)
message = factory.build(recipient, test_parameter=i)
# This will throw an error if the message ID already exists.
outbox.add(message)
outbox.flush()
values = []
for key, email in six.iteritems(outbox):
# Assert that the type of the email is correct.
self.assertIsInstance(email, Message)
# Assert that the message has a date header. While we can extract
# this from the ID, it's also helpful for us to timebox the
# emails to send by worker.
self.assertIsNotNone(email.get('Date'))
# Make sure we only have one payload (since that's what the
# factory was configured with)
self.assertEqual(1, len(email.get_payload()))
# Pull the ID from the payload and check it against all the
# emails we've found so far.
text_part = email.get_payload(0)
key = int(text_part.get_payload(decode=True))
self.assertNotIn(key, values)
# Store the key for later comparison.
values.append(key)
self.assertEqual(100, len(values))
def test_uuid_ids(self):
'''Assert that our message id's are not thread-based.'''
outbox = Outbox()
self.assertIsNotNone(outbox)
factory = EmailFactory('test@example.org',
'test_subject',
'test.txt',
'plugin.email')
for i in range(0, 100):
recipient = 'test_%s@example.com' % (i,)
message = factory.build(recipient, test_parameter=i)
# This will throw an error if the message ID already exists.
key = outbox.add(message)
parts = re.match(r'^([0-9]+)M([0-9]+)_(.*)$', key)
self.assertIsNotNone(parts)
# The first part should be a timestamp.
timestamp = float(parts.group(1)) + (float(parts.group(2)) / 1e6)
send_date = datetime.datetime.fromtimestamp(timestamp)
self.assertIsNotNone(send_date)
# The last part should be a UUID. Trying to construct it will
# cause a value error if it is not.
uuid.UUID(parts.group(3), version=4)
outbox.flush()