Permalink
Browse files

Add Django email testing support

This commit adds support for inspecting emails sent that were sent by the Django server started by lettuce.
  • Loading branch information...
1 parent 2c982d9 commit 234636c13c06ddffa7a3eaf3d991f1471f3a471b @lorin lorin committed Jan 12, 2013
@@ -256,6 +256,32 @@ Notice the ``terrain.py`` file at the project root, there you can
populate the :ref:`lettuce-world` and organize your features and steps
with it :)
+Checking email
+==============
+
+When you run your Django server under lettuce, emails sent by your server
+do not get transmitted over the Internet. Instead, these emails are
+added to a :class:`multiprocessing.Queue` object at
+``lettuce.django.mail.queue``.
+
+Example:
+
+.. highlight:: python
+
+::
+
+ from lettuce import step
+ from lettuce.django import mail
+ from nose.tools import assert_equals
+
+
+ @step(u'an email is sent to "([^"]*?)" with subject "([^"]*)"')
+ def email_sent(step, to, subject):
+ message = mail.queue.get(True, timeout=5)
+ assert_equals(message.subject, subject)
+ assert_equals(message.recipients(), [to])
+
+
Running without HTTP server
===========================
No changes.
@@ -0,0 +1,13 @@
+"""
+Email backend that sends mails to a multiprocessing queue
+"""
+from lettuce.django import mail
+from django.core.mail.backends.base import BaseEmailBackend
+
+
+class QueueEmailBackend(BaseEmailBackend):
+
+ def send_messages(self, messages):
+ for message in messages:
+ mail.queue.put(message)
+ return len(messages)
View
@@ -46,9 +46,15 @@
except ImportError:
pass
+from lettuce.django import mail
from lettuce.registry import call_hook
+def create_mail_queue():
+ mail.queue = multiprocessing.Queue()
+ return mail.queue
+
+
class LettuceServerException(WSGIServerException):
pass
@@ -104,10 +110,16 @@ class ThreadedServer(multiprocessing.Process):
lock = multiprocessing.Lock()
daemon = True
- def __init__(self, address, port, *args, **kw):
+ def __init__(self, address, port, mail_queue, *args, **kw):
multiprocessing.Process.__init__(self)
self.address = address
self.port = port
+ self.mail_queue = mail_queue
+
+ def configure_mail_queue(self):
+ mail.queue = self.mail_queue
+ settings.EMAIL_BACKEND = \
+ 'lettuce.django.mail.backends.QueueEmailBackend'
@staticmethod
def get_real_address(address):
@@ -162,6 +174,8 @@ def run(self):
open(pidfile, 'w').write(unicode(os.getpid()))
+ self.configure_mail_queue()
+
connector = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
@@ -217,7 +231,8 @@ class Server(object):
def __init__(self, address='0.0.0.0', port=None):
self.port = int(port or getattr(settings, 'LETTUCE_SERVER_PORT', 8000))
self.address = unicode(address)
- self._actual_server = ThreadedServer(self.address, self.port)
+ queue = create_mail_queue()
+ self._actual_server = ThreadedServer(self.address, self.port, queue)
def start(self):
"""Starts the webserver thread, and waits it to be available"""
@@ -0,0 +1,2 @@
+test:
+ PYTHONPATH=`pwd` DJANGO_SETTINGS_MODULE=djangoapp django-admin.py harvest email.feature
@@ -0,0 +1,25 @@
+"""
+
+A minimal Django app, just one file.
+
+See: http://olifante.blogs.com/covil/2010/04/minimal-django.html
+
+"""
+import os
+from django.conf.urls.defaults import patterns
+from django.core.mail import send_mail
+
+from django.http import HttpResponse
+filepath, extension = os.path.splitext(__file__)
+ROOT_URLCONF = os.path.basename(filepath)
+INSTALLED_APPS = (
+ "lettuce.django"
+ )
+
+
+def mail(request):
+ send_mail('Subject here', 'Here is the message.', 'from@example.com',
+ ['to@example.com'], fail_silently=False)
+ return HttpResponse('Mail has been sent')
+
+urlpatterns = patterns('', (r'^mail/$', mail))
@@ -0,0 +1,7 @@
+Feature: Check email sent by Django server
+
+Scenario: Access a web page which triggers an email
+ Given I visit "/mail/"
+ Then I see "Mail has been sent"
+ and an email is sent to "to@example.com" with subject "Subject here"
+
@@ -0,0 +1,22 @@
+from lettuce import world, step
+from lettuce.django import mail
+from lettuce.django import django_url
+
+from nose.tools import assert_equals
+
+
+@step(u'I visit "([^"]*)"')
+def visit(step, url):
+ world.browser.visit(django_url(url))
+
+
+@step(u'I see "([^"]*)"')
+def see(step, text):
+ assert world.browser.is_text_present(text)
+
+
+@step(u'an email is sent to "([^"]*?)" with subject "([^"]*)"')
+def email_sent(step, to, subject):
+ message = mail.queue.get(True, timeout=5)
+ assert_equals(message.subject, subject)
+ assert_equals(message.recipients(), [to])
@@ -0,0 +1,12 @@
+from splinter.browser import Browser
+from lettuce import before, after, world
+
+
+@before.harvest
+def setup(server):
+ world.browser = Browser()
+
+
+@after.harvest
+def cleanup(server):
+ world.browser.quit()
@@ -0,0 +1,25 @@
+import os
+import sys
+import commands
+
+from tests.asserts import assert_not_equals
+from lettuce.fs import FileSystem
+
+current_directory = FileSystem.dirname(__file__)
+
+OLD_PYTHONPATH = os.getenv('PYTHONPATH', ':'.join(sys.path))
+
+
+def teardown():
+ os.environ['PYTHONPATH'] = OLD_PYTHONPATH
+
+
+def test_email():
+ 'lettuce should be able to receive emails sent from django server'
+ os.environ['PYTHONPATH'] = current_directory
+ os.environ['DJANGO_SETTINGS_MODULE'] = 'djangoapp'
+
+ status, out = commands.getstatusoutput(
+ "django-admin.py harvest email.feature --verbosity=2")
+
+ assert_not_equals(status, 0)

0 comments on commit 234636c

Please sign in to comment.