[PATCH 10/14] tests: Add a utility class to create Series

Damien Lespiau damien.lespiau at intel.com
Wed Oct 21 08:59:39 AEDT 2015


So far we've been using real emails stored on-disk. While it's
interesting to have real data as input for unit tests, it's not as
flexible as having generated data. With generated data we can easily
create corner cases to improve the test coverage of the parsing code.

This is just a start, adding a TestSeries classes that can create a
series with n patches with or without a cover letter.

Signed-off-by: Damien Lespiau <damien.lespiau at intel.com>
Acked-by: Stephen Finucane <stephen.finucane at intel.com>
---
 patchwork/tests/test_series.py | 51 ++++++++++++++++++++-----
 patchwork/tests/utils.py       | 86 +++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 126 insertions(+), 11 deletions(-)

diff --git a/patchwork/tests/test_series.py b/patchwork/tests/test_series.py
index 2f44d2e..c57ea57 100644
--- a/patchwork/tests/test_series.py
+++ b/patchwork/tests/test_series.py
@@ -23,6 +23,7 @@ from django.test import TestCase
 from patchwork.models import Patch, Series, SeriesRevision, Project, \
                              SERIES_DEFAULT_NAME
 from patchwork.tests.utils import read_mail
+from patchwork.tests.utils import defaults, read_mail, TestSeries
 
 from patchwork.bin.parsemail import parse_mail
 
@@ -30,21 +31,23 @@ class SeriesTest(TestCase):
     fixtures = ['default_states']
 
     def setUp(self):
-        # subclasses are responsible for defining those variables
         self.assertTrue(self.project is not None)
-        self.assertTrue(self.n_patches is not None)
-        self.assertTrue(self.root_msgid is not None)
-        self.assertTrue(self.series_name is not None)
-
         self.project.save()
 
-        # insert the mails
-        self.n_mails = len(self.mails)
-        for filename in self.mails:
-            mail = read_mail(os.path.join('series', filename))
-            parse_mail(mail)
+        # insert the mails. 'mails' is an optional field, for subclasses
+        # that do have a list of on-disk emails.
+        if hasattr(self, 'mails'):
+            self.n_mails = len(self.mails)
+            for filename in self.mails:
+                mail = read_mail(os.path.join('series', filename))
+                parse_mail(mail)
 
     def commonInsertionChecks(self):
+        # subclasses are responsible for defining those variables
+        self.assertTrue(self.n_patches is not None)
+        self.assertTrue(self.root_msgid is not None)
+        self.assertTrue(self.series_name is not None)
+
         # make sure the series has been correctly populated
         series = Series.objects.all()
         self.assertEquals(series.count(), 1)
@@ -71,6 +74,34 @@ class SeriesTest(TestCase):
         patches = Patch.objects.all()
         self.assertEquals(patches.count(), self.n_patches)
 
+class GeneratedSeriesTest(SeriesTest):
+    project = defaults.project
+
+    def _create_series(self, n_patches, has_cover_letter=True):
+        self.n_patches = n_patches
+        series = TestSeries(self.n_patches, has_cover_letter)
+        mails = series.create_mails()
+        self.root_msgid = mails[0].get('Message-Id')
+        self.has_cover_letter = has_cover_letter
+        if has_cover_letter:
+            self.series_name = defaults.series_name
+            self.cover_letter = defaults.series_cover_letter
+        else:
+            self.series_name = SERIES_DEFAULT_NAME
+            self.cover_letter = None
+        return (series, mails)
+
+class BasicGeneratedSeriesTests(GeneratedSeriesTest):
+    def testInsertion(self):
+        (series, mails) = self._create_series(3)
+        series.insert(mails)
+        self.commonInsertionChecks()
+
+    def testInsertionNoCoverLetter(self):
+        (series, mails) = self._create_series(3, has_cover_letter=False)
+        series.insert(mails)
+        self.commonInsertionChecks()
+
 class IntelGfxTest(SeriesTest):
     project = Project(linkname = 'intel-gfx',
                       name = 'Intel Gfx',
diff --git a/patchwork/tests/utils.py b/patchwork/tests/utils.py
index 931462b..219e4bb 100644
--- a/patchwork/tests/utils.py
+++ b/patchwork/tests/utils.py
@@ -20,6 +20,7 @@
 import os
 import codecs
 from patchwork.models import Project, Person
+from patchwork.bin.parsemail import parse_mail
 from django.contrib.auth.models import User
 from django.forms.fields import EmailField
 
@@ -47,6 +48,11 @@ class defaults(object):
 
     subject = 'Test Subject'
 
+    series_name = 'Test Series'
+
+    series_cover_letter = """This is the test series cover letter.
+I hope you'll like it."""
+
     patch_name = 'Test Patch'
 
     patch = """--- /dev/null	2011-01-01 00:00:00.000000000 +0800
@@ -55,6 +61,8 @@ class defaults(object):
 +a
 """
 
+    review = """This is a great addition!"""
+
 error_strings = {
     'email': 'Enter a valid email address.',
 }
@@ -111,7 +119,8 @@ def read_mail(filename, project = None):
     return mail
 
 def create_email(content, subject = None, sender = None, multipart = False,
-        project = None, content_encoding = None):
+        project = None, content_encoding = None, in_reply_to = None,
+        references = None):
     if subject is None:
         subject = defaults.subject
     if sender is None:
@@ -134,5 +143,80 @@ def create_email(content, subject = None, sender = None, multipart = False,
     msg['Subject'] = subject
     msg['From'] = sender
     msg['List-Id'] = project.listid
+    if in_reply_to and references:
+        msg['References'] = ' '.join([m.get('Message-Id') for m in references])
+        msg['In-Reply-To'] = in_reply_to
+    elif references:
+        msg['References'] = references
+        msg['In-Reply-To'] = references.split()[-1]
+    elif in_reply_to:
+        msg['References'] = in_reply_to
+        msg['In-Reply-To'] = in_reply_to
 
     return msg
+
+class TestSeries(object):
+    def __init__(self, n_patches, has_cover_letter=True):
+        if n_patches < 1:
+            raise ValueError
+        self.n_patches = n_patches
+        self.has_cover_letter = has_cover_letter
+
+    def create_cover_letter(self):
+        return create_email(defaults.series_cover_letter,
+                            subject='[PATCH 0/%d] %s' % (self.n_patches,
+                                                         defaults.series_name))
+
+    # in_reply_to: a mail instance
+    def create_patch(self, n=0, in_reply_to=None, references=None,
+                     subject_prefix='PATCH'):
+        in_reply_to_str = None
+        if in_reply_to:
+            in_reply_to_str = in_reply_to.get('Message-Id')
+
+        if n != 0:
+            subject='[%s %d/%d] %s' % (subject_prefix, n,
+                                       self.n_patches,
+                                       defaults.patch_name)
+        else:
+            subject='[%s] %s' % (subject_prefix, defaults.patch_name)
+
+        mail = create_email(defaults.patch, subject=subject,
+                            in_reply_to=in_reply_to_str, references=references)
+        mail['X-Mailer'] = 'git-send-email 2.1.0'
+        return mail
+
+    def create_reply(self, mail, references=None):
+        if not references:
+            references = mail.get('References') + ' ' + mail.get('Message-Id')
+        return create_email(defaults.review,
+                            subject='Re: ' + mail.get('Subject'),
+                            references=references)
+
+    def create_mails(self):
+        mails = []
+        root_msg = None
+
+        # cover letter
+        if self.has_cover_letter:
+            cover_letter = self.create_cover_letter()
+            mails.append(cover_letter)
+            root_msg = cover_letter
+
+        # insert the first patch
+        patch = self.create_patch(1, root_msg)
+        mails.append(patch)
+        if not root_msg:
+            root_msg = patch
+
+        # and the remaining patches
+        for i in range(2, self.n_patches + 1):
+            mails.append(self.create_patch(i, root_msg))
+
+        return mails
+
+    def insert(self, mails=[]):
+        if not mails:
+            mails = self.create_mails()
+        for mail in mails:
+            parse_mail(mail)
-- 
2.4.3



More information about the Patchwork mailing list