Skip to content

Commit

Permalink
Merge pull request #313 from lorin/django-mail-queue
Browse files Browse the repository at this point in the history
Add Django email testing support
  • Loading branch information
gabrielfalcao committed Jan 14, 2013
2 parents 2aae759 + 234636c commit f84207b
Show file tree
Hide file tree
Showing 10 changed files with 150 additions and 3 deletions.
28 changes: 27 additions & 1 deletion docs/recipes/django-lxml.rst
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,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
===========================

Expand Down Expand Up @@ -412,4 +438,4 @@ You can also specify it at ``settings.py`` so that you won't need to type the sa
.. _windmill: http://www.getwindmill.com/
.. _webdriver: http://code.google.com/p/selenium/wiki/PythonBindings?redir=1
.. _GAE: http://code.google.com/appengine
.. _locmem: https://docs.djangoproject.com/en/dev/topics/email/#in-memory-backend
.. _locmem: https://docs.djangoproject.com/en/dev/topics/email/#in-memory-backend
Empty file added lettuce/django/mail/__init__.py
Empty file.
13 changes: 13 additions & 0 deletions lettuce/django/mail/backends.py
Original file line number Diff line number Diff line change
@@ -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)
19 changes: 17 additions & 2 deletions lettuce/django/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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"""
Expand Down
2 changes: 2 additions & 0 deletions lettuce/django/tests/functional/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
test:
PYTHONPATH=`pwd` DJANGO_SETTINGS_MODULE=djangoapp django-admin.py harvest email.feature
25 changes: 25 additions & 0 deletions lettuce/django/tests/functional/djangoapp.py
Original file line number Diff line number Diff line change
@@ -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))
7 changes: 7 additions & 0 deletions lettuce/django/tests/functional/email.feature
Original file line number Diff line number Diff line change
@@ -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"

22 changes: 22 additions & 0 deletions lettuce/django/tests/functional/steps.py
Original file line number Diff line number Diff line change
@@ -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])
12 changes: 12 additions & 0 deletions lettuce/django/tests/functional/terrain.py
Original file line number Diff line number Diff line change
@@ -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()
25 changes: 25 additions & 0 deletions lettuce/django/tests/functional/test_email.py
Original file line number Diff line number Diff line change
@@ -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 f84207b

Please sign in to comment.