Revert "Email Outbox"
This reverts commit 7e62b72503
.
Change-Id: I578e4f67649d7a9c52996dd4884546b3919d61b8
This commit is contained in:
parent
a1f52db1d2
commit
1b498f0b45
@ -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():
|
||||
|
@ -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)
|
@ -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.
|
||||
"""
|
||||
|
@ -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()
|
Loading…
Reference in New Issue
Block a user