Skip to content

Commit

Permalink
testresult: Send emails with test results
Browse files Browse the repository at this point in the history
Hook sending emails to the test results API. We can now configure
patchwork to send emails with test results with the couple of per-test
settings introduced in the previous patch.

Signed-off-by: Damien Lespiau <damien.lespiau@intel.com>
  • Loading branch information
Damien Lespiau committed Nov 23, 2015
1 parent 0f299c4 commit 6ff9520
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 3 deletions.
6 changes: 6 additions & 0 deletions patchwork/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ def display_name(self):
else:
return self.email

def email_name(self):
if (self.name):
return "%s <%s>" % (self.name, self.email)
else:
return self.email

def __unicode__(self):
return self.display_name()

Expand Down
92 changes: 92 additions & 0 deletions patchwork/tests/test_rest.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# Patchwork - automated patch tracking system
# coding=utf-8
#
# Copyright (C) 2015 Intel Corporation
#
# This file is part of the Patchwork package.
Expand All @@ -17,6 +19,7 @@
# along with Patchwork; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

from django.core import mail
from django.test import Client
import patchwork.tests.test_series as test_series
from patchwork.tests.test_user import TestUser
Expand Down Expand Up @@ -227,6 +230,17 @@ class TestResultTest(APITestBase):
result_url = 'http://example.org/logs/foo.txt'
result_summary = 'This contains a summary of the test results'

def _post_result(self, entry, test_name, state, summary=None, url=None):
data = {
'test_name': test_name,
'state': state,
}
if summary:
data['summary'] = summary
if url:
data['url'] = url
return self.post_json(entry, data=data, user=self.maintainer)

def testNoTestResults(self):
return
for url in self.test_urls:
Expand Down Expand Up @@ -280,6 +294,7 @@ def testSubmitTestResultNotMaintainer(self):
def _cleanup_tests(self):
TestResult.objects.all().delete()
Test.objects.all().delete()
mail.outbox = []

def testInvalidSubmissions(self):
"""test_name and state are required fields"""
Expand Down Expand Up @@ -392,3 +407,80 @@ def testUpdateTestResult(self):
self.assertEqual(result.summary, self.result_summary)

self._cleanup_tests()

def testNoMailByDefault(self):
for url in self.test_urls:
self._post_result(url, 'new test', 'success')
self.assertEqual(len(mail.outbox), 0)
self._cleanup_tests()

def _configure_test(self, url, test_name, recipient, condition):
"""Create test_name and configure it"""
self._post_result(url, test_name, 'pending')
tests = Test.objects.all()
self.assertEqual(len(tests), 1)
test = tests[0]
test.mail_recipient = recipient
test.mail_condition = condition
test.save()

def testMailRecipient(self):
for url in self.test_urls:
self.assertEqual(len(mail.outbox), 0)

self._configure_test(url, 'super test',
Test.RECIPIENT_SUBMITTER, Test.CONDITION_ALWAYS)
self._post_result(url, 'super test', 'success')
self.assertEqual(len(mail.outbox), 1)
email = mail.outbox[0]
self.assertEqual(email.to, [self.series.submitter.email_name()])
self.assertEqual(email.cc, [])

mail.outbox = []

self._configure_test(url, 'super test',
Test.RECIPIENT_MAILING_LIST, Test.CONDITION_ALWAYS)
self._post_result(url, 'super test', 'success')
self.assertEqual(len(mail.outbox), 1)
email = mail.outbox[0]
self.assertEqual(email.to, [self.series.submitter.email_name()])
self.assertEqual(email.cc, [self.project.listemail])

self._cleanup_tests()

def testMailCondition(self):
for url in self.test_urls:
self.assertEqual(len(mail.outbox), 0)

self._configure_test(url, 'super test',
Test.RECIPIENT_SUBMITTER, Test.CONDITION_ALWAYS)
self._post_result(url, 'super test', 'success')
self.assertEqual(len(mail.outbox), 1)
mail.outbox = []

self._configure_test(url, 'super test',
Test.RECIPIENT_SUBMITTER, Test.CONDITION_ALWAYS)
self._post_result(url, 'super test', 'pending')
self.assertEqual(len(mail.outbox), 0)

self._configure_test(url, 'super test',
Test.RECIPIENT_SUBMITTER, Test.CONDITION_ON_FAILURE)
self._post_result(url, 'super test', 'success')
self.assertEqual(len(mail.outbox), 0)

self._configure_test(url, 'super test',
Test.RECIPIENT_SUBMITTER, Test.CONDITION_ON_FAILURE)
self._post_result(url, 'super test', 'pending')
self.assertEqual(len(mail.outbox), 0)

self._configure_test(url, 'super test',
Test.RECIPIENT_SUBMITTER, Test.CONDITION_ON_FAILURE)
self._post_result(url, 'super test', 'warning')
self.assertEqual(len(mail.outbox), 1)
mail.outbox = []

self._configure_test(url, 'super test',
Test.RECIPIENT_SUBMITTER, Test.CONDITION_ON_FAILURE)
self._post_result(url, 'super test', 'failure')
self.assertEqual(len(mail.outbox), 1)
mail.outbox = []
61 changes: 58 additions & 3 deletions patchwork/views/api.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Patchwork - automated patch tracking system
# Copyright (C) 2014 Intel Corporation
# coding=utf-8
#
# Copyright (C) 2014,2015 Intel Corporation
#
# This file is part of the Patchwork package.
#
Expand All @@ -22,10 +24,12 @@
from django.core.exceptions import FieldDoesNotExist
except:
from django.db.models.fields import FieldDoesNotExist
from django.conf import settings
from django.core import mail
from django.db.models import Q
from django.http import HttpResponse
from patchwork.models import Project, Series, SeriesRevision, Patch, EventLog, \
TestResult
Test, TestResult
from rest_framework import views, viewsets, mixins, generics, filters, \
permissions, status
from rest_framework.authentication import BasicAuthentication
Expand Down Expand Up @@ -184,13 +188,37 @@ def mbox(self, request, series_pk=None, pk=None):
return series_mbox(rev)

class ResultMixin(object):
def _prepare_mail(self, result):
if result.state == TestResult.STATE_SUCCESS:
tick = u"✓"
else:
tick = u"✗"
subject = tick + u" %s: %s" % (result.get_state_display(),
result.test.name)
body = ''
if result.summary:
body += "== Summary ==\n\n"
body += result.summary
if body.endswith('\n'):
body += "\n"
else:
body += "\n\n"
if result.url:
body += "== Logs ==\n\n"
body += "For more details see: " + result.url
body += "\n"

return (subject, body)

def handle_test_results(self, request, obj, check_obj, q, ctx):
# auth
if not 'test_name' in request.DATA:
return Response({'test_name': ['This field is required.', ]},
status=status.HTTP_400_BAD_REQUEST)

self.check_object_permissions(request, check_obj)

# update test result and prepare the JSON response
try:
test = request.DATA['test_name']
instance = TestResult.objects.get(q, test__name=test)
Expand All @@ -205,7 +233,34 @@ def handle_test_results(self, request, obj, check_obj, q, ctx):
if not result.is_valid():
return Response(result.errors, status=status.HTTP_400_BAD_REQUEST)

result.save()
instance = result.save()

# mailing, done synchronously with the request, for now
to = []
cc = []
if instance.test.mail_recipient == Test.RECIPIENT_SUBMITTER:
to.append(check_obj.submitter.email_name())
elif instance.test.mail_recipient == Test.RECIPIENT_MAILING_LIST:
to.append(check_obj.submitter.email_name())
cc.append(check_obj.project.listemail)

if to:
# never send mail on pending
if instance.state == TestResult.STATE_PENDING:
to = []

if (instance.test.mail_condition == Test.CONDITION_ON_FAILURE and
instance.state not in (TestResult.STATE_WARNING,
TestResult.STATE_FAILURE)):
to = []

if to:
subject, body = self._prepare_mail(instance)
email = mail.EmailMessage(subject, body,
settings.DEFAULT_FROM_EMAIL,
to=to, cc=cc)
email.send()

return Response(result.data, status=status.HTTP_201_CREATED)

class RevisionResultViewSet(viewsets.ViewSet, ResultMixin):
Expand Down

0 comments on commit 6ff9520

Please sign in to comment.